/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_limits.h" #include "gtm_inet.h" #include "gtm_stdio.h" #include "gtm_string.h" #include "gtm_stdlib.h" #include "gtm_time.h" #include "gtm_stat.h" #include #include #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "mlkdef.h" #include "gdscc.h" #include "cmidef.h" #include "hashtab_mname.h" #include "cmmdef.h" #include "cmi.h" #include "gt_timer.h" #include "gtcmlkdef.h" #include "stp_parms.h" #include "stringpool.h" #include "repl_msg.h" #include "gtmsource.h" #include "gtmimagename.h" #include "trans_log_name.h" #include "get_page_size.h" #include "filestruct.h" #include "jnl.h" #include "gdskill.h" #include "buddy_list.h" #include "hashtab_int4.h" #include "tp.h" #include "init_secshr_addrs.h" #include "cli.h" #include "cli_parse.h" #include "iosp.h" #include "error.h" #include "gtcml.h" #include "getjobnum.h" #include "gtmmsg.h" #include "sig_init.h" #include "patcode.h" #include "copy.h" #include "lockconst.h" #include "generic_signal_handler.h" #include "gtcmtr_protos.h" #include "gtcm_shutdown_ast.h" #include "gtcm_neterr.h" #include "gtcm_link_accept.h" #include "gtcm_remove_from_action_queue.h" #include "gtcm_read_ast.h" #include "gtcm_write_ast.h" #include "gtcm_int_unpack.h" #include "gtcm_init_ast.h" #include "gtcm_urgread_ast.h" #include "gtcm_exi_handler.h" #include "mu_gv_cur_reg_init.h" #include "gtcm_open_cmerrlog.h" #include "gtcm_gnp_pktdmp.h" #include "util.h" #include "getzdir.h" #include "gtm_env_init.h" /* for gtm_env_init() prototype */ #include "suspsigs_handler.h" #include "gtm_imagetype_init.h" #include "gtm_threadgbl_init.h" #include "fork_init.h" #ifdef UNICODE_SUPPORTED #include "gtm_icu_api.h" #include "gtm_utf8.h" #endif #ifdef __osf__ #pragma pointer_size (save) #pragma pointer_size (long) #endif GBLDEF char **gtmenvp; GBLREF char cli_err_str[]; #ifdef __osf__ #pragma pointer_size (restore) #endif GBLREF FILE *gtcm_errfs; GBLREF bool licensed; GBLREF boolean_t run_time; GBLREF boolean_t gtcm_connection; GBLREF uint4 process_id; GBLREF cm_lckblkreg *blkdlist; GBLREF gd_region *gv_cur_region; GBLREF sgmnt_addrs *cs_addrs; GBLREF sgmnt_data_ptr_t cs_data; GBLREF gv_namehead *gv_target; GBLREF struct NTD *ntd_root; GBLREF spdesc rts_stringpool, stringpool; GBLREF enum gtmImageTypes image_type; GBLREF IN_PARMS *cli_lex_in_ptr; GBLREF char cli_token_buf[]; GBLREF CLI_ENTRY gtcm_gnp_cmd_ary[]; GBLDEF CLI_ENTRY *cmd_ary = >cm_gnp_cmd_ary[0]; /* Define cmd_ary to be the GTCM_GNP server specific cmd table */ GBLDEF bool cm_timeout = FALSE; GBLDEF bool cm_shutdown = FALSE; GBLDEF unsigned short procnum; GBLDEF int gtcm_users = 0; GBLDEF int4 gtcm_exi_condition; GBLDEF connection_struct *curr_entry; GBLDEF relque ALIGN_QUAD action_que; GBLDEF struct CLB *proc_to_clb[USHRT_MAX + 1]; /* for index 0 */ GBLDEF gd_region *action_que_dummy_reg; /* the file is the actual file being used */ GBLDEF char gtcm_gnp_server_log[MAX_FN_LEN + 1]; /* the length is the orignal length */ GBLDEF int gtcm_gnp_log_path_len; OS_PAGE_SIZE_DECLARE static uint4 closewait; #define CM_SERV_WAIT_FOR_INPUT 100 /* ms */ #define CM_CLB_POOL_SIZE 32 static void gtcm_gnp_server_actions(void); static void gtcm_gnp_switch_interrupt(int sig); static void gtcm_gnp_trace(struct CLB *lnk, int sta, unsigned char *buf, size_t len); static void gtcm_gnp_trace_on(int sig); static void gtcm_gnp_trace_off(int sig); static VSIG_ATOMIC_T switch_log = FALSE; static VSIG_ATOMIC_T trace_on = FALSE; error_def(CMERR_CMINTQUE); error_def(ERR_BADGTMNETMSG); error_def(ERR_NETFAIL); error_def(ERR_TEXT); static void gtcm_gnp_server_actions(void) { int4 status; unsigned short value; char reply; connection_struct *prev_curr_entry; CMI_MUTEX_DECL; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; ESTABLISH(gtcm_ch); TREF(issue_DBROLLEDBACK_anyways) = TRUE; /* to let t_retry issue DBROLLEDBACK error for GT.CM as well */ while (!cm_shutdown) { if (switch_log) { gtcm_open_cmerrlog(); switch_log = FALSE; } if (trace_on) { if (!ntd_root->trc) ntd_root->trc = gtcm_gnp_trace; } else { if (ntd_root->trc) ntd_root->trc = NULL; } if (blkdlist) gtcml_chkreg(); CMI_MUTEX_BLOCK; gtcm_remove_from_action_queue(); CMI_MUTEX_RESTORE; if ((connection_struct *)INTERLOCK_FAIL == curr_entry) rts_error(VARLSTCNT(1) CMERR_CMINTQUE); if ((connection_struct *)EMPTY_QUEUE != curr_entry) { if (1 == (curr_entry->int_cancel.laflag & 1)) { /* valid interrupt cancel msg, handle in gtcm_urgread_ast */ CMI_MUTEX_BLOCK; prev_curr_entry = curr_entry; curr_entry = EMPTY_QUEUE; gtcm_int_unpack(prev_curr_entry); CMI_MUTEX_RESTORE; continue; } switch (*curr_entry->clb_ptr->mbf) { case CMMS_L_LKCANALL: reply = gtcmtr_lkcanall(); break; case CMMS_L_LKCANCEL: reply = gtcmtr_lkcancel(); break; case CMMS_L_LKREQIMMED: reply = gtcmtr_lkreqimmed(); break; case CMMS_L_LKREQNODE: reply = gtcmtr_lkreqnode(); break; case CMMS_L_LKREQUEST: reply = gtcmtr_lkrequest(); break; case CMMS_L_LKRESUME: reply = gtcmtr_lkresume(); break; case CMMS_L_LKACQUIRE: reply = gtcmtr_lkacquire(); break; case CMMS_L_LKSUSPEND: reply = gtcmtr_lksuspend(); break; case CMMS_L_LKDELETE: reply = gtcmtr_lkdelete(); break; case CMMS_Q_DATA: reply = gtcmtr_data(); break; case CMMS_Q_GET: reply = gtcmtr_get(); break; case CMMS_Q_KILL: reply = gtcmtr_kill(); break; case CMMS_Q_ORDER: reply = gtcmtr_order(); break; case CMMS_Q_PREV: reply = gtcmtr_zprevious(); break; case CMMS_Q_PUT: reply = gtcmtr_put(); break; case CMMS_Q_QUERY: reply = gtcmtr_query(); break; case CMMS_Q_ZWITHDRAW: reply = gtcmtr_zwithdraw(); break; case CMMS_S_INITPROC: reply = gtcmtr_initproc(); break; case CMMS_S_INITREG: reply = gtcmtr_initreg(); break; case CMMS_S_TERMINATE: reply = gtcmtr_terminate(TRUE); break; case CMMS_E_TERMINATE: reply = gtcmtr_terminate(FALSE); break; #ifdef notdef case CMMS_U_LKEDELETE: reply = gtcmtr_lke_clearrep(curr_entry->clb_ptr, (clear_request *)curr_entry->clb_ptr->mbf); break; case CMMS_U_LKESHOW: reply = gtcmtr_lke_showrep(curr_entry->clb_ptr, (show_request *)curr_entry->clb_ptr->mbf); break; #endif case CMMS_B_BUFRESIZE: reply = CM_WRITE; GET_USHORT(value, curr_entry->clb_ptr->mbf + 1); value += CM_BUFFER_OVERHEAD; if (value > curr_entry->clb_ptr->mbl) cmi_realloc_mbf(curr_entry->clb_ptr, value); *curr_entry->clb_ptr->mbf = CMMS_C_BUFRESIZE; curr_entry->clb_ptr->cbl = 1; break; case CMMS_B_BUFFLUSH: reply = gtcmtr_bufflush(); break; case CMMS_Q_INCREMENT: reply = gtcmtr_increment(); break; default: reply = FALSE; if (SS_NORMAL == status) { GET_LONG(status, curr_entry->clb_ptr->mbf); rts_error(VARLSTCNT(3) ERR_BADGTMNETMSG, 1, status); } break; } if (curr_entry) /* curr_entry can be NULL if went through gtcmtr_terminate */ { time(&curr_entry->lastact); /* curr_entry is used by gtcm_urgread_ast to determine if it needs to defer the interrupt message */ prev_curr_entry = curr_entry; if (CM_WRITE == reply) { /* if ast == gtcm_write_ast, let it worry */ curr_entry->clb_ptr->ast = gtcm_write_ast; curr_entry = EMPTY_QUEUE; cmi_write(prev_curr_entry->clb_ptr); } else { curr_entry = EMPTY_QUEUE; if (1 == (prev_curr_entry->int_cancel.laflag & 1)) { /* valid interrupt cancel msg, handle in gtcm_urgread_ast */ CMI_MUTEX_BLOCK; gtcm_int_unpack(prev_curr_entry); CMI_MUTEX_RESTORE; } else if (CM_READ == reply) { prev_curr_entry->clb_ptr->ast = gtcm_read_ast; cmi_read(prev_curr_entry->clb_ptr); } } } } else CMI_IDLE(CM_SERV_WAIT_FOR_INPUT); if (cm_timeout && (0 == gtcm_users)) start_timer((TID)&cm_shutdown, closewait, gtcm_shutdown_ast, 0, NULL); } return; } static void gtcm_gnp_trace(struct CLB *lnk, int sta, unsigned char *buf, size_t len) { gtcm_gnp_cpktdmp(gtcm_errfs, lnk, sta, buf, len, ""); } static void gtcm_gnp_trace_on(int sig) { trace_on = TRUE; } static void gtcm_gnp_trace_off(int sig) { trace_on = FALSE; } static void gtcm_gnp_switch_interrupt(int sig) { switch_log = TRUE; } #ifdef __osf__ #pragma pointer_size (save) #pragma pointer_size (long) #endif int main(int argc, char **argv, char **envp) #ifdef __osf__ #pragma pointer_size (restore) #endif { int4 timout; cmi_status_t status; int eof, arg_index, parse_ret; cmi_descriptor service_descr, log_path_descr; unsigned short service_len, log_path_len; char *ptr, service[512]; now_t now; /* for GET_CUR_TIME macro */ char time_str[CTIME_BEFORE_NL + 2], *time_ptr; /* for GET_CUR_TIME macro */ pid_t pid; struct sigaction act; DCL_THREADGBL_ACCESS; static boolean_t no_fork = FALSE; GTM_THREADGBL_INIT; set_blocksig(); gtm_imagetype_init(GTCM_GNP_SERVER_IMAGE); gtm_wcswidth_fnptr = gtm_wcswidth; gtm_env_init(); /* read in all environment variables */ gtmenvp = envp; getjobnum(); err_init(stop_image_conditional_core); assert(0 == offsetof(gv_key, top)); /* for integrity of CM_GET_GVCURRKEY */ assert(2 == offsetof(gv_key, end)); /* for integrity of CM_GET_GVCURRKEY */ assert(4 == offsetof(gv_key, prev)); /* for integrity of CM_GET_GVCURRKEY */ GTM_ICU_INIT_IF_NEEDED; /* Note: should be invoked after err_init (since it may error out) and before CLI parsing */ /* read comments in gtm.c for cli magic below */ cli_lex_setup(argc, argv); if (1 < argc) cli_gettoken(&eof); cli_token_buf[0] = '\0'; ptr = cli_lex_in_ptr->in_str; memmove(ptr + SIZEOF("GTCM_GNP_SERVER ") - 1, ptr, strlen(ptr) + 1); /* BYPASSOK */ MEMCPY_LIT(ptr, "GTCM_GNP_SERVER "); cli_lex_in_ptr->tp = cli_lex_in_ptr->in_str; parse_ret = parse_cmd(); if (parse_ret && (EOF != parse_ret)) rts_error(VARLSTCNT(4) parse_ret, 2, LEN_AND_STR(cli_err_str)); service_len = (unsigned short)SIZEOF(service); CMI_DESC_SET_POINTER(&service_descr, service); service[0] = '\0'; if (CLI_PRESENT == cli_present("SERVICE") && cli_get_str("SERVICE", CMI_DESC_POINTER(&service_descr), &service_len)) CMI_DESC_SET_LENGTH(&service_descr, service_len); else CMI_DESC_SET_LENGTH(&service_descr, 0); if (cli_get_int("TIMEOUT", &timout)) { cm_timeout = TRUE; if (timout > (1 << 21)) timout = (1 << 21); closewait = (timout << 10); /* s -> ms; approx */ } log_path_len = (unsigned short)SIZEOF(gtcm_gnp_server_log) - 1; CMI_DESC_SET_POINTER(&log_path_descr, gtcm_gnp_server_log); if (CLI_PRESENT != cli_present("LOG") || !cli_get_str("LOG", CMI_DESC_POINTER(&log_path_descr), &log_path_len)) log_path_len = 0; if (CLI_PRESENT == cli_present("TRACE")) trace_on = TRUE; gtcm_gnp_server_log[log_path_len] = '\0'; gtcm_open_cmerrlog(); assert(0 == EMPTY_QUEUE); get_page_size(); licensed = TRUE; stp_init(STP_INITSIZE); rts_stringpool = stringpool; getzdir(); sig_init(generic_signal_handler, null_handler, suspsigs_handler); /* should do be done before cmi_init */ /* Redefine handler for SIGHUP to switch log file */ memset(&act, 0, SIZEOF(act)); act.sa_handler = gtcm_gnp_switch_interrupt; sigaction(SIGHUP, &act, 0); act.sa_handler = gtcm_gnp_trace_on; sigaction(SIGUSR1, &act, 0); act.sa_handler = gtcm_gnp_trace_off; sigaction(SIGUSR2, &act, 0); procnum = 0; memset(proc_to_clb, 0, SIZEOF(proc_to_clb)); /* child continues here */ gtcm_connection = FALSE; if (!no_fork) { FORK_CLEAN(pid); if (0 > pid) { rts_error(VARLSTCNT(5) ERR_TEXT, 2, LEN_AND_LIT("Error forking gnp server into the background"), errno); exit(-1); } else if (0 < pid) exit(0); getjobnum(); (void) setpgrp(); } /* Write argv and the process id for ease of admin */ GET_CUR_TIME; util_out_print("!AD : ", FALSE, CTIME_BEFORE_NL, time_ptr); for (arg_index = 0; arg_index < argc; arg_index++) util_out_print("!AZ ", FALSE, argv[arg_index]); util_out_print("[pid : !UL]", TRUE, process_id); /* * the acc function pointer is NULL to prevent incoming connections * until we are ready. */ status = cmi_init(&service_descr, '\0', gtcm_neterr, NULL, gtcm_link_accept, gtcm_urgread_ast, CM_CLB_POOL_SIZE, SIZEOF(connection_struct), CM_MSG_BUF_SIZE + CM_BUFFER_OVERHEAD); if (CMI_ERROR(status)) { gtm_putmsg(VARLSTCNT(7) ERR_NETFAIL, 0, ERR_TEXT, 2, LEN_AND_LIT("Network interface initialization failed"), status); exit(status); } atexit(gtcm_exi_handler); INVOKE_INIT_SECSHR_ADDRS; initialize_pattern_table(); /* Pre-allocate some timer blocks. */ prealloc_gt_timers(); SET_LATCH_GLOBAL(&action_que.latch, LOCK_AVAILABLE); mu_gv_cur_reg_init(); cs_addrs = &FILE_INFO(gv_cur_region)->s_addrs; cs_data = cs_addrs->hdr; cs_addrs->nl = (node_local_ptr_t)malloc(SIZEOF(node_local)); memset((char *)cs_addrs->nl, 0, SIZEOF(node_local)); action_que_dummy_reg = gv_cur_region; /* ... now we are ready! */ ntd_root->crq = gtcm_init_ast; while (!cm_shutdown) { gtcm_gnp_server_actions(); } exit(SS_NORMAL); }