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