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 2008 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 * global system message queue 92 */ 93 msg_queue_t *sys_q = NULL; 94 msg_queue_t *scn_q = NULL; 95 96 #ifdef DEBUG 97 extern void *cli_test(void *argv); 98 extern dump_db(void); 99 #endif 100 101 extern void sigalrm(int); 102 103 /* 104 * sigusr2_handler -- SIGUSR2 Handler 105 * sigusr2 is exepected only when child is running okay. 106 */ 107 /* ARGSUSED */ 108 static void 109 sigusr2_handler( 110 int sig 111 ) 112 { 113 /* post okay status. */ 114 isnslog(LOG_DEBUG, "sigusr2_handler", 115 "SIGUSR@ is received. Parent is existing..."); 116 isns_child_smf_exit_code = SMF_EXIT_OK; 117 118 (void) sem_post(&isns_child_sem); 119 } 120 121 /* 122 * sigchld_handler -- SIGCHLD Handler 123 * sigchld is exepected only when there is an error. 124 */ 125 /* ARGSUSED */ 126 static void 127 sigchld_handler( 128 int sig 129 ) 130 { 131 int status; 132 pid_t ret_pid; 133 134 /* This is the default code. */ 135 isns_child_smf_exit_code = SMF_EXIT_ERR_OTHER; 136 137 ret_pid = waitpid(isns_child_pid, &status, WNOHANG); 138 139 if (ret_pid == isns_child_pid) { 140 if (WIFEXITED(status)) { 141 isns_child_smf_exit_code = WEXITSTATUS(status); 142 } 143 } 144 (void) sem_post(&isns_child_sem); 145 } 146 147 /* ARGSUSED */ 148 static void 149 sighup_handler( 150 int sig 151 ) 152 { 153 154 isnslog(LOG_DEBUG, "sighup_handle", 155 "SIGHUP is received. Reloading config..."); 156 (void) queue_msg_set(sys_q, CONFIG_RELOAD, NULL); 157 } 158 159 /* ARGSUSED */ 160 static void 161 sigexit_handler( 162 int sig 163 ) 164 { 165 isnslog(LOG_DEBUG, "sigexit_handler", 166 "Signal: %d received and sending server exit.", sig); 167 shutdown_server(); 168 } 169 170 void 171 inc_thr_count( 172 ) 173 { 174 (void) pthread_mutex_lock(&thr_count_mtx); 175 176 isnslog(LOG_DEBUG, "inc_thr_count", 177 "increase thread reference count(%d).", thr_ref_count); 178 179 thr_ref_count++; 180 181 (void) pthread_mutex_unlock(&thr_count_mtx); 182 } 183 184 void 185 dec_thr_count( 186 ) 187 { 188 (void) pthread_mutex_lock(&thr_count_mtx); 189 190 isnslog(LOG_DEBUG, "dec_thr_count", 191 "decrease thread reference count(%d).", thr_ref_count); 192 193 thr_ref_count--; 194 195 (void) pthread_mutex_unlock(&thr_count_mtx); 196 } 197 198 uint32_t 199 get_thr_count( 200 ) 201 { 202 uint32_t ref; 203 204 (void) pthread_mutex_lock(&thr_count_mtx); 205 206 ref = thr_ref_count; 207 208 (void) pthread_mutex_unlock(&thr_count_mtx); 209 210 isnslog(LOG_DEBUG, "get_thr_count", 211 "checking thread reference count %d.", ref); 212 213 return (ref); 214 } 215 216 void 217 shutdown_server( 218 ) 219 { 220 isnslog(LOG_DEBUG, "shutdown", "raise exit flag."); 221 time_to_exit = B_TRUE; 222 (void) queue_msg_set(sys_q, SERVER_EXIT, NULL); 223 } 224 225 int 226 main( 227 /* LINTED E_FUNC_ARG_UNUSED */ 228 int argc, 229 /* LINTED E_FUNC_ARG_UNUSED */ 230 char *argv[] 231 ) 232 { 233 int opt_i = 0; 234 pthread_t port_tid, esi_tid, scn_tid; 235 uint32_t thr_cnt; 236 int i; 237 238 #ifdef DEBUG 239 time_t t; 240 clock_t c; 241 #endif 242 243 #ifdef DEBUG 244 if (getopt(argc, argv, "i") == 'i') { 245 opt_i = 1; /* interactive mode */ 246 } 247 #endif 248 249 /* set locale */ 250 openlog(ISNS_DAEMON_SYSLOG_PP, LOG_PID | LOG_CONS, LOG_DAEMON); 251 252 /* load administative settings. pick up data location. */ 253 if (load_config(B_TRUE) != 0) { 254 isnslog(LOG_ERR, "main", "administrative settings load error."); 255 exit(SMF_EXIT_ERR_OTHER); 256 } 257 258 /* A signal handler is set for SIGCHLD. */ 259 (void) signal(SIGCHLD, sigchld_handler); 260 (void) signal(SIGUSR2, sigusr2_handler); 261 (void) sigset(SIGALRM, sigalrm); 262 263 #ifdef DEBUG 264 printf("start daemon\n"); 265 #endif 266 if (opt_i == 0 || daemonlize) { 267 isnslog(LOG_DEBUG, "main", "now forking... pid %d", getpid()); 268 daemonlize = 1; 269 /* daemonlize */ 270 isns_child_pid = fork(); 271 if (isns_child_pid < 0) { 272 /* 273 * cannot fork(), terminate the server. 274 */ 275 exit(SMF_EXIT_ERR_CONFIG); 276 } 277 if (isns_child_pid > 0) { 278 /* 279 * terminate parent. 280 */ 281 (void) sem_wait(&isns_child_sem); 282 (void) sem_destroy(&isns_child_sem); 283 isnslog(LOG_DEBUG, "main", "exiting with %d", 284 isns_child_smf_exit_code); 285 exit(isns_child_smf_exit_code); 286 } 287 288 /* 289 * redirect stdout, and stderr to /dev/null. 290 */ 291 i = open("/dev/null", O_RDWR); 292 (void) dup2(i, 1); 293 (void) dup2(i, 2); 294 } /* end of daemonlize */ 295 296 #ifdef DEBUG 297 printf("calling cache init\n"); 298 #endif 299 /* initialize object hash table */ 300 if (cache_init() != 0) { 301 isnslog(LOG_ERR, "main", 302 "object hash table initialization error."); 303 exit(SMF_EXIT_ERR_OTHER); 304 } 305 306 /* initialize event list */ 307 if (el_init(10, 60, 6) != 0) { 308 isnslog(LOG_ERR, "main", 309 "ESI event list initialization error."); 310 exit(SMF_EXIT_ERR_OTHER); 311 } 312 313 /* initialize iSNS database */ 314 if (init_data() != 0) { 315 isnslog(LOG_ERR, "main", 316 "internal database initialization error"); 317 exit(SMF_EXIT_ERR_OTHER); 318 } 319 320 #ifdef DEBUG 321 printf("calling load_data\n"); 322 t = time(NULL); 323 c = clock(); 324 #endif 325 326 if (load_data() != 0) { 327 isnslog(LOG_ERR, "main", "loading data store failed"); 328 exit(SMF_EXIT_ERR_OTHER); 329 } 330 331 #ifdef DEBUG 332 t = time(NULL) - t; 333 c = clock() - c; 334 printf("time %d clock %.4lf -loading data\n", 335 t, c / (double)CLOCKS_PER_SEC); 336 #endif 337 338 #ifdef DEBUG 339 printf("sys queue creating...\n"); 340 #endif 341 /* create a message queue for system control */ 342 sys_q = queue_calloc(); 343 if (!sys_q) { 344 exit(SMF_EXIT_ERR_OTHER); 345 } 346 347 /* create a message queue for scn thread */ 348 scn_q = queue_calloc(); 349 if (!scn_q) { 350 exit(SMF_EXIT_ERR_OTHER); 351 } 352 353 /* create scn thread */ 354 /* Check for Default DD/DD-set existence and */ 355 /* create them if they are not there. */ 356 if (verify_ddd() != 0) { 357 exit(SMF_EXIT_ERR_OTHER); 358 } 359 360 /* setup and verify the portal(s) for scn(s) */ 361 /* after scn registry is loaded from data store. */ 362 if (verify_scn_portal() != 0) { 363 exit(SMF_EXIT_ERR_OTHER); 364 } 365 366 /* setup and verify the portal(s) for esi(s) */ 367 /* after esi list is loaded from data store. */ 368 if (verify_esi_portal() != 0) { 369 exit(SMF_EXIT_ERR_OTHER); 370 } 371 372 #ifdef DEBUG 373 printf("scn queue creating...\n"); 374 #endif 375 376 (void) sigset(SIGHUP, sighup_handler); 377 (void) sigset(SIGINT, sigexit_handler); 378 (void) sigset(SIGTERM, sigexit_handler); 379 (void) sigset(SIGQUIT, sigexit_handler); 380 381 /* create scn thread */ 382 if (pthread_create(&scn_tid, NULL, scn_proc, NULL) != 0) { 383 isnslog(LOG_ERR, "main", "SCN thread creating error."); 384 exit(SMF_EXIT_ERR_OTHER); 385 } 386 387 /* setup a door for management interface */ 388 if (setup_mgmt_door(sys_q) != 0) { 389 exit(SMF_EXIT_ERR_OTHER); 390 } 391 392 /* create server port watcher */ 393 if (pthread_create(&port_tid, NULL, 394 isns_port_watcher, (void *)sys_q) != 0) { 395 isnslog(LOG_ERR, "main", "iSNS port thread creating error."); 396 exit(SMF_EXIT_ERR_OTHER); 397 } 398 399 /* create entity status inquiry thread */ 400 if (pthread_create(&esi_tid, NULL, 401 esi_proc, NULL) != 0) { 402 isnslog(LOG_ERR, "main", "ESI thread creating error."); 403 exit(SMF_EXIT_ERR_OTHER); 404 } 405 406 #ifdef DEBUG 407 if (!daemonlize) { 408 (void) pthread_create(&tid, 409 NULL, 410 cli_test, 411 (void *)sys_q); 412 } 413 #endif 414 if (opt_i == 0 || daemonlize) { 415 isnslog(LOG_DEBUG, "main", "issuing SIGUSR2.. parent pid %d", 416 getppid()); 417 (void) kill(getppid(), SIGUSR2); 418 } 419 420 /* pause */ 421 for (;;) { 422 msg_text_t *msg = queue_msg_get(sys_q); 423 switch (msg->id) { 424 case DATA_ADD: 425 case DATA_UPDATE: 426 case DATA_DELETE: 427 case DATA_DELETE_ASSOC: 428 case DATA_COMMIT: 429 case DATA_RETREAT: 430 break; 431 case REG_EXP: 432 /* registration expiring */ 433 reg_expiring(msg->data); 434 break; 435 case DEAD_PORTAL: 436 portal_dies((uint32_t)msg->data); 437 break; 438 case SERVER_EXIT: 439 /* graceful exit. */ 440 (void) queue_msg_free(msg); 441 isnslog(LOG_DEBUG, "main", 442 "wake up ESI and stop it."); 443 (void) get_stopwatch(1); 444 isnslog(LOG_DEBUG, "main", 445 "sending SCN stop msg."); 446 (void) queue_msg_set(scn_q, SCN_STOP, NULL); 447 isnslog(LOG_DEBUG, "main", "closing the door."); 448 (void) fdetach(ISNS_DOOR_NAME); 449 (void) pthread_join(esi_tid, NULL); 450 isnslog(LOG_DEBUG, "main", 451 "esi thread %d exited.", esi_tid); 452 (void) pthread_join(port_tid, NULL); 453 isnslog(LOG_DEBUG, "main", 454 "port watcher thread %d exited.", port_tid); 455 (void) pthread_join(scn_tid, NULL); 456 isnslog(LOG_DEBUG, "main", 457 "scn thread %d exited.", scn_tid); 458 459 /* now check any remaining threads. */ 460 i = 0; 461 do { 462 thr_cnt = get_thr_count(); 463 if (thr_cnt == 0) { 464 isnslog(LOG_DEBUG, "main", 465 "main thread %d is done.", 466 pthread_self()); 467 exit(1); 468 } else { 469 (void) sleep(1); 470 i++; 471 } 472 } while (MAX_RETRY_COUNT > i); 473 isnslog(LOG_DEBUG, "main", 474 "main thread %d existing ...", 475 pthread_self()); 476 exit(1); 477 break; 478 case CONFIG_RELOAD: 479 /* load config again. don't pick data store. */ 480 (void) load_config(B_FALSE); 481 break; 482 case SYS_QUIT_OK: 483 (void) queue_msg_free(msg); 484 exit(0); 485 default: 486 break; 487 } 488 (void) queue_msg_free(msg); 489 } 490 491 /* LINTED E_STMT_NOT_REACHED */ 492 return (0); 493 } 494