Home | History | Annotate | Download | only in isnsd
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 
     22 /*
     23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 #include <sys/types.h>
     28 #include <unistd.h>
     29 #include <stdio.h>
     30 #include <stdlib.h>
     31 #include <sys/stat.h>
     32 #include <fcntl.h>
     33 #include <pthread.h>
     34 #include <errno.h>
     35 #include <libscf.h>
     36 #ifdef DEBUG
     37 #include <time.h>
     38 #endif
     39 #include <signal.h>
     40 #include <semaphore.h>
     41 #include <sys/wait.h>
     42 
     43 #include "isns_server.h"
     44 #include "isns_dseng.h"
     45 #include "isns_msgq.h"
     46 #include "isns_log.h"
     47 #include "isns_cfg.h"
     48 #include "isns_utils.h"
     49 #include "isns_cache.h"
     50 #include "isns_obj.h"
     51 #include "isns_dd.h"
     52 #include "isns_scn.h"
     53 #include "isns_sched.h"
     54 #include "isns_esi.h"
     55 #include "isns_mgmt.h"
     56 
     57 /*
     58  * iSNS Server administrative settings.
     59  */
     60 uint8_t daemonlize = 0;
     61 int dbg_level = 7;
     62 uint64_t esi_threshold;
     63 uint8_t mgmt_scn;
     64 ctrl_node_t *control_nodes = NULL;
     65 pthread_mutex_t ctrl_node_mtx = PTHREAD_MUTEX_INITIALIZER;
     66 char data_store[MAXPATHLEN];
     67 
     68 
     69 /* semaphore for handling exit */
     70 static sem_t	isns_child_sem;
     71 static int	isns_child_smf_exit_code;
     72 static pid_t	isns_child_pid;
     73 
     74 #if !defined(SMF_EXIT_ERR_OTHER)
     75 #define	SMF_EXIT_ERR_OTHER	-1
     76 #endif
     77 
     78 /*
     79  * Globals for singal handling.  time_to_exit is set by sig_handle()
     80  * when set the main thread(daemon) and othere threads should exit.
     81  *
     82  * semaphone is used to make sure all threads that are created
     83  * by isns_port_watcher and esi.
     84  */
     85 boolean_t time_to_exit = B_FALSE;
     86 static uint32_t thr_ref_count;
     87 static pthread_mutex_t thr_count_mtx = PTHREAD_MUTEX_INITIALIZER;
     88 #define	MAX_RETRY_COUNT	10 /* for checking remaining threads before exit. */
     89 
     90 /*
     91  * Door creation flag.
     92  */
     93 boolean_t door_created = B_FALSE;
     94 
     95 /*
     96  * global system message queue
     97  */
     98 msg_queue_t *sys_q = NULL;
     99 msg_queue_t *scn_q = NULL;
    100 
    101 #ifdef DEBUG
    102 extern void *cli_test(void *argv);
    103 extern dump_db(void);
    104 #endif
    105 
    106 extern void sigalrm(int);
    107 
    108 /*
    109  * sigusr2_handler -- SIGUSR2 Handler
    110  * sigusr2 is exepected only when child is running okay.
    111  */
    112 /* ARGSUSED */
    113 static void
    114 sigusr2_handler(
    115 	int	sig
    116 )
    117 {
    118 	/* post okay status. */
    119 	isnslog(LOG_DEBUG, "sigusr2_handler",
    120 	    "SIGUSR@ is received.  Parent is existing...");
    121 	isns_child_smf_exit_code = SMF_EXIT_OK;
    122 
    123 	(void) sem_post(&isns_child_sem);
    124 }
    125 
    126 /*
    127  * sigchld_handler -- SIGCHLD Handler
    128  * sigchld is exepected only when there is an error.
    129  */
    130 /* ARGSUSED */
    131 static void
    132 sigchld_handler(
    133 	int	sig
    134 )
    135 {
    136 	int	status;
    137 	pid_t	ret_pid;
    138 
    139 	/* This is the default code. */
    140 	isns_child_smf_exit_code = SMF_EXIT_ERR_OTHER;
    141 
    142 	ret_pid = waitpid(isns_child_pid, &status, WNOHANG);
    143 
    144 	if (ret_pid == isns_child_pid) {
    145 		if (WIFEXITED(status)) {
    146 			isns_child_smf_exit_code = WEXITSTATUS(status);
    147 		}
    148 	}
    149 	(void) sem_post(&isns_child_sem);
    150 }
    151 
    152 /* ARGSUSED */
    153 static void
    154 sighup_handler(
    155 	int	sig
    156 )
    157 {
    158 
    159 	isnslog(LOG_DEBUG, "sighup_handle",
    160 	    "SIGHUP is received.  Reloading config...");
    161 	(void) queue_msg_set(sys_q, CONFIG_RELOAD, NULL);
    162 }
    163 
    164 /* ARGSUSED */
    165 static void
    166 sigexit_handler(
    167 	int	sig
    168 )
    169 {
    170 	isnslog(LOG_DEBUG, "sigexit_handler",
    171 	    "Signal: %d received and sending server exit.", sig);
    172 	shutdown_server();
    173 }
    174 
    175 void
    176 inc_thr_count(
    177 )
    178 {
    179 	(void) pthread_mutex_lock(&thr_count_mtx);
    180 
    181 	isnslog(LOG_DEBUG, "inc_thr_count",
    182 	    "increase thread reference count(%d).", thr_ref_count);
    183 
    184 	thr_ref_count++;
    185 
    186 	(void) pthread_mutex_unlock(&thr_count_mtx);
    187 }
    188 
    189 void
    190 dec_thr_count(
    191 )
    192 {
    193 	(void) pthread_mutex_lock(&thr_count_mtx);
    194 
    195 	isnslog(LOG_DEBUG, "dec_thr_count",
    196 	    "decrease thread reference count(%d).", thr_ref_count);
    197 
    198 	thr_ref_count--;
    199 
    200 	(void) pthread_mutex_unlock(&thr_count_mtx);
    201 }
    202 
    203 uint32_t
    204 get_thr_count(
    205 )
    206 {
    207 	uint32_t ref;
    208 
    209 	(void) pthread_mutex_lock(&thr_count_mtx);
    210 
    211 	ref = thr_ref_count;
    212 
    213 	(void) pthread_mutex_unlock(&thr_count_mtx);
    214 
    215 	isnslog(LOG_DEBUG, "get_thr_count",
    216 	    "checking thread reference count %d.", ref);
    217 
    218 	return (ref);
    219 }
    220 
    221 void
    222 shutdown_server(
    223 )
    224 {
    225 	isnslog(LOG_DEBUG, "shutdown", "raise exit flag.");
    226 	time_to_exit = B_TRUE;
    227 	(void) queue_msg_set(sys_q, SERVER_EXIT, NULL);
    228 }
    229 
    230 int
    231 main(
    232 	/* LINTED E_FUNC_ARG_UNUSED */
    233 	int	argc,
    234 	/* LINTED E_FUNC_ARG_UNUSED */
    235 	char	*argv[]
    236 )
    237 {
    238 	int opt_i = 0;
    239 	pthread_t port_tid, esi_tid, scn_tid;
    240 	uint32_t thr_cnt;
    241 	int i;
    242 
    243 #ifdef DEBUG
    244 	time_t t;
    245 	clock_t c;
    246 #endif
    247 
    248 #ifdef DEBUG
    249 	if (getopt(argc, argv, "i") == 'i') {
    250 		opt_i = 1; /* interactive mode */
    251 	}
    252 #endif
    253 
    254 	/* set locale */
    255 	openlog(ISNS_DAEMON_SYSLOG_PP, LOG_PID | LOG_CONS, LOG_DAEMON);
    256 
    257 	/* load administative settings. pick up data location. */
    258 	if (load_config(B_TRUE) != 0) {
    259 		isnslog(LOG_ERR, "main", "administrative settings load error.");
    260 		exit(SMF_EXIT_ERR_OTHER);
    261 	}
    262 
    263 	/* A signal handler is set for SIGCHLD. */
    264 	(void) signal(SIGCHLD, sigchld_handler);
    265 	(void) signal(SIGUSR2, sigusr2_handler);
    266 	(void) sigset(SIGALRM, sigalrm);
    267 
    268 #ifdef DEBUG
    269 	printf("start daemon\n");
    270 #endif
    271 	if (opt_i == 0 || daemonlize) {
    272 		isnslog(LOG_DEBUG, "main", "now forking... pid %d", getpid());
    273 		daemonlize = 1;
    274 		/* daemonlize */
    275 		isns_child_pid = fork();
    276 		if (isns_child_pid < 0) {
    277 			/*
    278 			 * cannot fork(), terminate the server.
    279 			 */
    280 			exit(SMF_EXIT_ERR_CONFIG);
    281 		}
    282 		if (isns_child_pid > 0) {
    283 			/*
    284 			 * terminate parent.
    285 			 */
    286 			(void) sem_wait(&isns_child_sem);
    287 			(void) sem_destroy(&isns_child_sem);
    288 			isnslog(LOG_DEBUG, "main", "exiting with %d",
    289 				isns_child_smf_exit_code);
    290 			exit(isns_child_smf_exit_code);
    291 		}
    292 
    293 		/*
    294 		 * redirect stdout, and stderr to /dev/null.
    295 		 */
    296 		i = open("/dev/null", O_RDWR);
    297 		(void) dup2(i, 1);
    298 		(void) dup2(i, 2);
    299 	} /* end of daemonlize */
    300 
    301 #ifdef DEBUG
    302 	printf("calling cache init\n");
    303 #endif
    304 	/* initialize object hash table */
    305 	if (cache_init() != 0) {
    306 		isnslog(LOG_ERR, "main",
    307 		    "object hash table initialization error.");
    308 		exit(SMF_EXIT_ERR_OTHER);
    309 	}
    310 
    311 	/* initialize event list */
    312 	if (el_init(10, 60, 6) != 0) {
    313 		isnslog(LOG_ERR, "main",
    314 		"ESI event list initialization error.");
    315 		exit(SMF_EXIT_ERR_OTHER);
    316 	}
    317 
    318 	/* initialize iSNS database */
    319 	if (init_data() != 0) {
    320 		isnslog(LOG_ERR, "main",
    321 		    "internal database initialization error");
    322 		exit(SMF_EXIT_ERR_OTHER);
    323 	}
    324 
    325 #ifdef DEBUG
    326 	printf("calling load_data\n");
    327 	t = time(NULL);
    328 	c = clock();
    329 #endif
    330 
    331 	if (load_data() != 0) {
    332 		isnslog(LOG_ERR, "main", "loading data store failed");
    333 		exit(SMF_EXIT_ERR_OTHER);
    334 	}
    335 
    336 #ifdef DEBUG
    337 	t = time(NULL) - t;
    338 	c = clock() - c;
    339 	printf("time %d clock %.4lf -loading data\n",
    340 	    t, c / (double)CLOCKS_PER_SEC);
    341 #endif
    342 
    343 #ifdef DEBUG
    344 	printf("sys queue creating...\n");
    345 #endif
    346 	/* create a message queue for system control */
    347 	sys_q = queue_calloc();
    348 	if (!sys_q) {
    349 		exit(SMF_EXIT_ERR_OTHER);
    350 	}
    351 
    352 	/* create a message queue for scn thread */
    353 	scn_q = queue_calloc();
    354 	if (!scn_q) {
    355 		exit(SMF_EXIT_ERR_OTHER);
    356 	}
    357 
    358 	/* create scn thread */
    359 	/* Check for Default DD/DD-set existence and */
    360 	/* create them if they are not there. */
    361 	if (verify_ddd() != 0) {
    362 		exit(SMF_EXIT_ERR_OTHER);
    363 	}
    364 
    365 	/* setup and verify the portal(s) for scn(s) */
    366 	/* after scn registry is loaded from data store. */
    367 	if (verify_scn_portal() != 0) {
    368 		exit(SMF_EXIT_ERR_OTHER);
    369 	}
    370 
    371 	/* setup and verify the portal(s) for esi(s) */
    372 	/* after esi list is loaded from data store. */
    373 	if (verify_esi_portal() != 0) {
    374 		exit(SMF_EXIT_ERR_OTHER);
    375 	}
    376 
    377 #ifdef DEBUG
    378 	printf("scn queue creating...\n");
    379 #endif
    380 
    381 	(void) sigset(SIGHUP, sighup_handler);
    382 	(void) sigset(SIGINT, sigexit_handler);
    383 	(void) sigset(SIGTERM, sigexit_handler);
    384 	(void) sigset(SIGQUIT, sigexit_handler);
    385 
    386 	/* create scn thread */
    387 	if (pthread_create(&scn_tid, NULL, scn_proc, NULL) != 0) {
    388 		isnslog(LOG_ERR, "main", "SCN thread creating error.");
    389 		exit(SMF_EXIT_ERR_OTHER);
    390 	}
    391 
    392 	/* setup a door for management interface */
    393 	if (setup_mgmt_door(sys_q) != 0) {
    394 		exit(SMF_EXIT_ERR_OTHER);
    395 	}
    396 
    397 	/* create server port watcher */
    398 	if (pthread_create(&port_tid, NULL,
    399 	    isns_port_watcher, (void *)sys_q) != 0) {
    400 		isnslog(LOG_ERR, "main", "iSNS port thread creating error.");
    401 		exit(SMF_EXIT_ERR_OTHER);
    402 	}
    403 
    404 	/* create entity status inquiry thread */
    405 	if (pthread_create(&esi_tid, NULL,
    406 	    esi_proc, NULL) != 0) {
    407 		isnslog(LOG_ERR, "main", "ESI thread creating error.");
    408 		exit(SMF_EXIT_ERR_OTHER);
    409 	}
    410 
    411 #ifdef DEBUG
    412 	if (!daemonlize) {
    413 		(void) pthread_create(&tid,
    414 		    NULL,
    415 		    cli_test,
    416 		    (void *)sys_q);
    417 	}
    418 #endif
    419 	if (opt_i == 0 || daemonlize) {
    420 		isnslog(LOG_DEBUG, "main", "issuing SIGUSR2.. parent pid %d",
    421 		    getppid());
    422 		(void) kill(getppid(), SIGUSR2);
    423 	}
    424 
    425 	/* pause */
    426 	for (;;) {
    427 		msg_text_t *msg = queue_msg_get(sys_q);
    428 		switch (msg->id) {
    429 			case DATA_ADD:
    430 			case DATA_UPDATE:
    431 			case DATA_DELETE:
    432 			case DATA_DELETE_ASSOC:
    433 			case DATA_COMMIT:
    434 			case DATA_RETREAT:
    435 				break;
    436 			case REG_EXP:
    437 				/* registration expiring */
    438 				reg_expiring(msg->data);
    439 				break;
    440 			case DEAD_PORTAL:
    441 				portal_dies((uint32_t)msg->data);
    442 				break;
    443 			case SERVER_EXIT:
    444 				/* graceful exit. */
    445 				(void) queue_msg_free(msg);
    446 				isnslog(LOG_DEBUG, "main",
    447 				    "wake up ESI and stop it.");
    448 				(void) get_stopwatch(1);
    449 				isnslog(LOG_DEBUG, "main",
    450 				    "sending SCN stop msg.");
    451 				(void) queue_msg_set(scn_q, SCN_STOP, NULL);
    452 				if (door_created) {
    453 					isnslog(LOG_DEBUG, "main",
    454 					    "closing the door.");
    455 					(void) fdetach(ISNS_DOOR_NAME);
    456 				}
    457 				(void) pthread_join(esi_tid, NULL);
    458 				isnslog(LOG_DEBUG, "main",
    459 				    "esi thread %d exited.", esi_tid);
    460 				(void) pthread_join(port_tid, NULL);
    461 				isnslog(LOG_DEBUG, "main",
    462 				    "port watcher thread %d exited.", port_tid);
    463 				(void) pthread_join(scn_tid, NULL);
    464 				isnslog(LOG_DEBUG, "main",
    465 				    "scn thread %d exited.", scn_tid);
    466 
    467 				/* now check any remaining threads. */
    468 				i = 0;
    469 				do {
    470 					thr_cnt = get_thr_count();
    471 					if (thr_cnt == 0) {
    472 						isnslog(LOG_DEBUG, "main",
    473 						    "main thread %d is done.",
    474 						    pthread_self());
    475 						exit(1);
    476 					} else {
    477 						(void) sleep(1);
    478 						i++;
    479 					}
    480 				} while (MAX_RETRY_COUNT > i);
    481 				isnslog(LOG_DEBUG, "main",
    482 				    "main thread %d existing ...",
    483 				    pthread_self());
    484 				exit(1);
    485 				break;
    486 			case CONFIG_RELOAD:
    487 				/* load config again. don't pick data store. */
    488 				(void) load_config(B_FALSE);
    489 				break;
    490 			case SYS_QUIT_OK:
    491 				(void) queue_msg_free(msg);
    492 				exit(0);
    493 			default:
    494 				break;
    495 		}
    496 		(void) queue_msg_free(msg);
    497 	}
    498 
    499 	/* LINTED E_STMT_NOT_REACHED */
    500 	return (0);
    501 }
    502