/* Internal version of start_timer that does not protect itself, assuming this has already been done. * Otherwise does as explained above in start_timer. */ STATICFNDEF void start_timer_int(TID tid, int4 time_to_expir, void (*handler)(), int4 hdata_len, void *hdata) { ABS_TIME at; assert(0 != time_to_expir); sys_get_curr_time(&at); if (first_timeset) { init_timers(); first_timeset = FALSE; } /* We expect no timer with id=<tid> to exist in the timer queue currently. This is asserted in "add_timer" call below. * In pro though, we'll be safe and remove any tids that exist before adding a new entry with the same tid - 2009/10. * If a few years pass without the assert failing, it might be safe then to remove the PRO_ONLY code below. */ # ifndef DEBUG if (timeroot && (timeroot->tid == tid)) sys_canc_timer(); remove_timer(tid); /* Remove timer from chain */ # endif /* Check if # of free timer slots is less than minimum threshold. If so, allocate more of those while it is safe to do so */ if ((GT_TIMER_EXPAND_TRIGGER > num_timers_free) && (1 > timer_stack_count)) gt_timers_alloc(); add_timer(&at, tid, time_to_expir, handler, hdata_len, hdata); /* Link new timer into timer chain */ if ((timeroot->tid == tid) || !timer_active) start_first_timer(&at); }
void gtcml_chkreg(void) { cm_lckblkreg *reg, *reg1; sys_get_curr_time(&chkreg_time); /* just once per pass */ reg1 = reg = blkdlist; while (reg) { gv_cur_region = reg->region->reg; if (reg->region->refcnt == 0) { gtcml_chklck(reg,FALSE); assert (reg->lock == 0); } else if (reg->region->wakeup < ((mlk_ctldata *)FILE_INFO(gv_cur_region)->s_addrs.lock_addrs[0])->wakeups) { gtcml_chklck(reg,FALSE); reg->region->wakeup = ((mlk_ctldata *)FILE_INFO(gv_cur_region)->s_addrs.lock_addrs[0])->wakeups; reg->pass = CM_BLKPASS; } else if (--reg->pass == 0) { gtcml_chklck(reg,TRUE); reg->pass = CM_BLKPASS; } if (reg->lock == 0) { if (reg == blkdlist) { blkdlist = reg->next; free(reg); reg = reg1 = blkdlist; } else { reg1->next = reg->next; free(reg); reg = reg1->next; } } else { reg1 = reg; reg = reg->next; } } }
/* Cancel timer. * Arguments: tid - timer id */ void cancel_timer(TID tid) { ABS_TIME at; sigset_t savemask; sigprocmask(SIG_BLOCK, &blockalrm, &savemask); /* block SIGALRM signal */ sys_get_curr_time(&at); if (tid == 0) { assert(process_exiting || IS_GTMSECSHR_IMAGE); /* wcs_phase2_commit_wait relies on this flag being set BEFORE * cancelling all timers. But secshr doesn't have it. */ cancel_all_timers(); uninit_all_timers(); timer_stack_count = 0; sigprocmask(SIG_SETMASK, &savemask, NULL); return; } if (timeroot && (timeroot->tid == tid)) /* if this is the first timer in the chain, stop it */ sys_canc_timer(); remove_timer(tid); /* remove it from the chain */ start_first_timer(&at); /* start the first timer in the chain */ sigprocmask(SIG_SETMASK, &savemask, NULL); }
boolean_t iosocket_wait(io_desc *iod, int4 timepar) { struct timeval utimeout; ABS_TIME cur_time, end_time; struct sockaddr_storage peer; /* socket address + port */ fd_set tcp_fd; d_socket_struct *dsocketptr; socket_struct *socketptr, *newsocketptr; socket_interrupt *sockintr; char *errptr; int4 errlen, ii, msec_timeout; int rv, max_fd, len; GTM_SOCKLEN_TYPE size; boolean_t zint_restart; mv_stent *mv_zintdev; int retry_num; struct sockaddr *peer_sa_ptr; char port_buffer[NI_MAXSERV], ipaddr[SA_MAXLEN + 1]; int errcode; /* check for validity */ assert(iod->type == gtmsocket); dsocketptr = (d_socket_struct *)iod->dev_sp; sockintr = &dsocketptr->sock_save_state; peer_sa_ptr = ((struct sockaddr *)(&peer)); /* Check for restart */ if (!dsocketptr->mupintr) /* Simple path, no worries*/ zint_restart = FALSE; else { /* We have a pending wait restart of some sort - check we aren't recursing on this device */ if (sockwhich_invalid == sockintr->who_saved) GTMASSERT; /* Interrupt should never have an invalid save state */ if (dollar_zininterrupt) rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_ZINTRECURSEIO); if (sockwhich_wait != sockintr->who_saved) GTMASSERT; /* ZINTRECURSEIO should have caught */ DBGSOCK((stdout, "socwait: *#*#*#*#*#*#*# Restarted interrupted wait\n")); mv_zintdev = io_find_mvstent(iod, FALSE); if (mv_zintdev) { if (sockintr->end_time_valid) /* Restore end_time for timeout */ end_time = sockintr->end_time; /* Done with this mv_stent. Pop it off if we can, else mark it inactive. */ if (mv_chain == mv_zintdev) POP_MV_STENT(); /* pop if top of stack */ else { /* else mark it unused */ mv_zintdev->mv_st_cont.mvs_zintdev.buffer_valid = FALSE; mv_zintdev->mv_st_cont.mvs_zintdev.io_ptr = NULL; } zint_restart = TRUE; DBGSOCK((stdout, "socwait: mv_stent found - endtime: %d/%d\n", end_time.at_sec, end_time.at_usec)); } else DBGSOCK((stdout, "socwait: no mv_stent found !!\n")); dsocketptr->mupintr = FALSE; sockintr->who_saved = sockwhich_invalid; } /* check for events */ FD_ZERO(&tcp_fd); while (TRUE) { max_fd = 0; for (ii = 0; ii < dsocketptr->n_socket; ii++) { socketptr = dsocketptr->socket[ii]; if ((socket_listening == socketptr->state) || (socket_connected == socketptr->state)) { FD_SET(socketptr->sd, &tcp_fd); max_fd = MAX(max_fd, socketptr->sd); } } utimeout.tv_sec = timepar; utimeout.tv_usec = 0; msec_timeout = timeout2msec(timepar); sys_get_curr_time(&cur_time); if (!zint_restart || !sockintr->end_time_valid) add_int_to_abs_time(&cur_time, msec_timeout, &end_time); else { /* end_time taken from restart data. Compute what msec_timeout should be so timeout timer gets set correctly below. */ DBGSOCK((stdout, "socwait: Taking timeout end time from wait restart data\n")); cur_time = sub_abs_time(&end_time, &cur_time); if (0 > cur_time.at_sec) { msec_timeout = -1; utimeout.tv_sec = 0; utimeout.tv_usec = 0; } else { msec_timeout = (int4)(cur_time.at_sec * 1000 + cur_time.at_usec / 1000); utimeout.tv_sec = cur_time.at_sec; utimeout.tv_usec = (gtm_tv_usec_t)cur_time.at_usec; } } sockintr->end_time_valid = FALSE; for ( ; ; ) { rv = select(max_fd + 1, (void *)&tcp_fd, (void *)0, (void *)0, (timepar == NO_M_TIMEOUT ? (struct timeval *)0 : &utimeout)); if (0 > rv && EINTR == errno) { if (0 != outofband) { DBGSOCK((stdout, "socwait: outofband interrupt received (%d) -- " "queueing mv_stent for wait intr\n", outofband)); PUSH_MV_STENT(MVST_ZINTDEV); mv_chain->mv_st_cont.mvs_zintdev.io_ptr = iod; mv_chain->mv_st_cont.mvs_zintdev.buffer_valid = FALSE; sockintr->who_saved = sockwhich_wait; sockintr->end_time = end_time; sockintr->end_time_valid = TRUE; dsocketptr->mupintr = TRUE; socketus_interruptus++; DBGSOCK((stdout, "socwait: mv_stent queued - endtime: %d/%d interrupts: %d\n", end_time.at_sec, end_time.at_usec, socketus_interruptus)); outofband_action(FALSE); GTMASSERT; /* Should *never* return from outofband_action */ return FALSE; /* For the compiler.. */ } sys_get_curr_time(&cur_time); cur_time = sub_abs_time(&end_time, &cur_time); if (0 > cur_time.at_sec) { rv = 0; /* time out */ break; } utimeout.tv_sec = cur_time.at_sec; utimeout.tv_usec = (gtm_tv_usec_t)cur_time.at_usec; } else break; /* either other error or done */ } if (rv == 0) { iod->dollar.key[0] = '\0'; return FALSE; } else if (rv < 0) { errptr = (char *)STRERROR(errno); errlen = STRLEN(errptr); rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_SOCKWAIT, 0, ERR_TEXT, 2, errlen, errptr); return FALSE; } /* find out which socket is ready */ for (ii = 0; ii < dsocketptr->n_socket; ii++) { socketptr = dsocketptr->socket[ii]; if (0 != FD_ISSET(socketptr->sd, &tcp_fd)) break; } assert(ii < dsocketptr->n_socket); if (socket_listening == socketptr->state) { if (gtm_max_sockets <= dsocketptr->n_socket) { rts_error_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_SOCKMAX, 1, gtm_max_sockets); return FALSE; } size = SIZEOF(struct sockaddr_storage); rv = tcp_routines.aa_accept(socketptr->sd, peer_sa_ptr, &size); if (-1 == rv) { # ifdef __hpux if (ENOBUFS == errno) continue; /* On HP-UX, ENOBUFS may indicate a transient condition; retry */ # endif errptr = (char *)STRERROR(errno); errlen = STRLEN(errptr); rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_SOCKACPT, 0, ERR_TEXT, 2, errlen, errptr); return FALSE; } SOCKET_DUP(socketptr, newsocketptr); newsocketptr->sd = rv; SOCKET_ADDR_COPY(newsocketptr->remote, peer_sa_ptr, size); /* translate internal address to numeric ip address */ GETNAMEINFO(peer_sa_ptr, size, ipaddr, SA_MAXLEN, NULL, 0, NI_NUMERICHOST, errcode); if (0 != errcode) { SOCKET_FREE(newsocketptr); RTS_ERROR_ADDRINFO(NULL, ERR_GETNAMEINFO, errcode); return FALSE; } if (NULL != newsocketptr->remote.saddr_ip) free(newsocketptr->remote.saddr_ip); STRNDUP(ipaddr, SA_MAXLEN, newsocketptr->remote.saddr_ip); /* translate internal address to port number*/ GETNAMEINFO(peer_sa_ptr, size, NULL, 0, port_buffer, NI_MAXSERV, NI_NUMERICSERV, errcode); if (0 != errcode) { SOCKET_FREE(newsocketptr); RTS_ERROR_ADDRINFO(NULL, ERR_GETNAMEINFO, errcode); return FALSE; } newsocketptr->remote.port = ATOI(port_buffer); newsocketptr->state = socket_connected; newsocketptr->passive = FALSE; newsocketptr->first_read = newsocketptr->first_write = TRUE; /* put the new-born socket to the list and create a handle for it */ iosocket_handle(newsocketptr->handle, &newsocketptr->handle_len, TRUE, dsocketptr); dsocketptr->socket[dsocketptr->n_socket++] = newsocketptr; dsocketptr->current_socket = dsocketptr->n_socket - 1; len = SIZEOF(CONNECTED) - 1; memcpy(&iod->dollar.key[0], CONNECTED, len); iod->dollar.key[len++] = '|'; memcpy(&iod->dollar.key[len], newsocketptr->handle, newsocketptr->handle_len); len += newsocketptr->handle_len; iod->dollar.key[len++] = '|'; strncpy(&iod->dollar.key[len], newsocketptr->remote.saddr_ip, DD_BUFLEN - 1 - len); iod->dollar.key[DD_BUFLEN-1] = '\0'; /* In case we fill the buffer */ } else { assert(socket_connected == socketptr->state); dsocketptr->current_socket = ii; len = SIZEOF(READ) - 1; memcpy(&iod->dollar.key[0], READ, len); iod->dollar.key[len++] = '|'; memcpy(&iod->dollar.key[len], socketptr->handle, socketptr->handle_len); len += socketptr->handle_len; iod->dollar.key[len++] = '|'; if (NULL != socketptr->remote.saddr_ip) { strncpy(&iod->dollar.key[len], socketptr->remote.saddr_ip, DD_BUFLEN - 1 - len); iod->dollar.key[DD_BUFLEN-1] = '\0'; } else iod->dollar.key[len] = '\0'; } break; }
/* * ----------------------------------------------- * Maintain in parallel with op_zalloc2 * Arguments: * timeout - max. time to wait for locks before giving up * laflag - passed to gvcmx* routines as "laflag" argument; * originally indicated the request was a Lock or * zAllocate request (hence the name "laflag"), but * now capable of holding more values signifying * additional information * * Return: * 1 - if not timeout specified * if timeout specified: * != 0 - all the locks int the list obtained, or * 0 - blocked * The return result is suited to be placed directly into * the $T variable by the caller if timeout is specified. * ----------------------------------------------- */ int op_lock2(int4 timeout, unsigned char laflag) /* timeout is in seconds */ { boolean_t blocked, timer_on; signed char gotit; unsigned short locks_bckout, locks_done; int4 msec_timeout; /* timeout in milliseconds */ mlk_pvtblk *pvt_ptr1, *pvt_ptr2, **prior; unsigned char action; ABS_TIME cur_time, end_time, remain_time; mv_stent *mv_zintcmd; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; gotit = -1; cm_action = laflag; out_of_time = FALSE; if (timeout < 0) timeout = 0; else if (TREF(tpnotacidtime) < timeout) TPNOTACID_CHECK(LOCKTIMESTR); if (!(timer_on = (NO_M_TIMEOUT != timeout))) /* NOTE assignment */ msec_timeout = NO_M_TIMEOUT; else { msec_timeout = timeout2msec(timeout); if (0 == msec_timeout) { out_of_time = TRUE; timer_on = FALSE; } else { mv_zintcmd = find_mvstent_cmd(ZINTCMD_LOCK, restart_pc, restart_ctxt, FALSE); if (mv_zintcmd) { remain_time = mv_zintcmd->mv_st_cont.mvs_zintcmd.end_or_remain; if (0 <= remain_time.at_sec) msec_timeout = (int4)(remain_time.at_sec * 1000 + remain_time.at_usec / 1000); else msec_timeout = 0; TAREF1(zintcmd_active, ZINTCMD_LOCK).restart_pc_last = mv_zintcmd->mv_st_cont.mvs_zintcmd.restart_pc_prior; TAREF1(zintcmd_active, ZINTCMD_LOCK).restart_ctxt_last = mv_zintcmd->mv_st_cont.mvs_zintcmd.restart_ctxt_prior; TAREF1(zintcmd_active, ZINTCMD_LOCK).count--; assert(0 <= TAREF1(zintcmd_active, ZINTCMD_LOCK).count); if (mv_chain == mv_zintcmd) POP_MV_STENT(); /* just pop if top of stack */ else { /* flag as not active */ mv_zintcmd->mv_st_cont.mvs_zintcmd.command = ZINTCMD_NOOP; mv_zintcmd->mv_st_cont.mvs_zintcmd.restart_pc_check = NULL; } } if (0 < msec_timeout) { sys_get_curr_time(&cur_time); add_int_to_abs_time(&cur_time, msec_timeout, &end_time); start_timer((TID)&timer_on, msec_timeout, wake_alarm, 0, NULL); } else { out_of_time = TRUE; timer_on = FALSE; } } } lckclr(); for (blocked = FALSE; !blocked;) { /* if this is a request for a remote node */ if (remlkreq) { if (gotit >= 0) gotit = gvcmx_resremlk(cm_action); else gotit = gvcmx_reqremlk(cm_action, msec_timeout); /* REQIMMED if 2nd arg == 0 */ if (!gotit) { /* only REQIMMED returns false */ blocked = TRUE; break; } } for (pvt_ptr1 = mlk_pvt_root, locks_done = 0; locks_done < lks_this_cmd; pvt_ptr1 = pvt_ptr1->next, locks_done++) { /* Go thru the list of all locks to be obtained attempting to lock * each one. If any lock could not be obtained, break out of the loop */ if (!mlk_lock(pvt_ptr1, 0, TRUE)) { /* If lock is obtained */ pvt_ptr1->granted = TRUE; switch (laflag) { case CM_LOCKS: pvt_ptr1->level = 1; break; case INCREMENTAL: if (pvt_ptr1->level < 511) /* The same lock can not be incremented more than 511 times. */ pvt_ptr1->level += pvt_ptr1->translev; else level_err(pvt_ptr1); break; default: GTMASSERT; break; } } else { blocked = TRUE; break; } } /* If we did not get blocked, we are all done */ if (!blocked) break; /* We got blocked and need to keep retrying after some time interval */ if (remlkreq) gvcmx_susremlk(cm_action); switch (cm_action) { case CM_LOCKS: action = LOCKED; break; case INCREMENTAL: action = INCREMENTAL; break; default: GTMASSERT; break; } for (pvt_ptr2 = mlk_pvt_root, locks_bckout = 0; locks_bckout < locks_done; pvt_ptr2 = pvt_ptr2->next, locks_bckout++) { assert(pvt_ptr2->granted && (pvt_ptr2 != pvt_ptr1)); mlk_bckout(pvt_ptr2, action); } if (dollar_tlevel && (CDB_STAGNATE <= t_tries)) { /* upper TPNOTACID_CHECK conditioned on no short timeout; this one rel_crits to avoid potential deadlock */ assert(TREF(tpnotacidtime) >= timeout); TPNOTACID_CHECK(LOCKTIMESTR); } for (;;) { if (out_of_time || outofband) { /* if time expired || control-c, tptimeout, or jobinterrupt encountered */ if (outofband || !lk_check_own(pvt_ptr1)) { /* If CTL-C, check lock owner */ if (pvt_ptr1->nodptr) /* Get off pending list to be sent a wake */ mlk_unpend(pvt_ptr1); /* Cancel all remote locks obtained so far */ if (remlkreq) { gvcmx_canremlk(); gvcmz_clrlkreq(); remlkreq = FALSE; } if (outofband) { if (timer_on && !out_of_time) { cancel_timer((TID)&timer_on); timer_on = FALSE; } if (!out_of_time && (NO_M_TIMEOUT != timeout)) { /* get remain = end_time - cur_time */ sys_get_curr_time(&cur_time); remain_time = sub_abs_time(&end_time, &cur_time); if (0 <= remain_time.at_sec) msec_timeout = (int4)(remain_time.at_sec * 1000 + remain_time.at_usec / 1000); else msec_timeout = 0; /* treat as out_of_time */ if (0 >= msec_timeout) { out_of_time = TRUE; timer_on = FALSE; /* as if LOCK :0 */ break; } PUSH_MV_STENT(MVST_ZINTCMD); mv_chain->mv_st_cont.mvs_zintcmd.end_or_remain = remain_time; mv_chain->mv_st_cont.mvs_zintcmd.restart_ctxt_check = restart_ctxt; mv_chain->mv_st_cont.mvs_zintcmd.restart_pc_check = restart_pc; /* save current information from zintcmd_active */ mv_chain->mv_st_cont.mvs_zintcmd.restart_ctxt_prior = TAREF1(zintcmd_active, ZINTCMD_LOCK).restart_ctxt_last; mv_chain->mv_st_cont.mvs_zintcmd.restart_pc_prior = TAREF1(zintcmd_active, ZINTCMD_LOCK).restart_pc_last; TAREF1(zintcmd_active, ZINTCMD_LOCK).restart_pc_last = restart_pc; TAREF1(zintcmd_active, ZINTCMD_LOCK).restart_ctxt_last = restart_ctxt; TAREF1(zintcmd_active, ZINTCMD_LOCK).count++; mv_chain->mv_st_cont.mvs_zintcmd.command = ZINTCMD_LOCK; outofband_action(FALSE); /* no return */ } } break; } } if (!mlk_lock(pvt_ptr1, 0, FALSE)) { /* If we got the lock, break out of timer loop */ blocked = FALSE; if (pvt_ptr1 != mlk_pvt_root) { rel_quant(); /* attempt to get a full timeslice for maximum chance to get all */ mlk_unlock(pvt_ptr1); } break; } if (pvt_ptr1->nodptr) lk_check_own(pvt_ptr1); /* clear an abandoned owner */ hiber_start_wait_any(LOCK_SELF_WAKE); } if (blocked && out_of_time) break; } if (remlkreq) { gvcmz_clrlkreq(); remlkreq = FALSE; } if (NO_M_TIMEOUT != timeout) { /* was timed or immediate */ if (timer_on && !out_of_time) cancel_timer((TID)&timer_on); if (blocked) { for (prior = &mlk_pvt_root; *prior;) { if (!(*prior)->granted) { /* if entry was never granted, delete list entry */ mlk_pvtblk_delete(prior); } else prior = &((*prior)->next); } mlk_stats.n_user_locks_fail++; return (FALSE); } } mlk_stats.n_user_locks_success++; return (TRUE); }
short iott_readfl (mval *v, int4 length, int4 timeout) /* timeout in seconds */ { boolean_t ret, nonzerotimeout, timed; uint4 mask; unsigned char inchar, *temp; #ifdef __MVS__ unsigned char asc_inchar; #endif int dx, msk_in, msk_num, outlen, rdlen, save_errno, selstat, status, width; int4 msec_timeout; /* timeout in milliseconds */ io_desc *io_ptr; d_tt_struct *tt_ptr; io_terminator outofbands; io_termmask mask_term; unsigned char *zb_ptr, *zb_top; ABS_TIME cur_time, end_time; fd_set input_fd; struct timeval input_timeval; struct timeval save_input_timeval; error_def(ERR_CTRAP); error_def(ERR_IOEOF); error_def(ERR_NOPRINCIO); assert(stringpool.free >= stringpool.base); assert(stringpool.free <= stringpool.top); io_ptr = io_curr_device.in; tt_ptr = (d_tt_struct *)(io_ptr->dev_sp); assert(dev_open == io_ptr->state); iott_flush(io_curr_device.out); width = io_ptr->width; if (stringpool.free + length > stringpool.top) stp_gcol (length); outlen = 0; /* --------------------------------------------------------- * zb_ptr is be used to fill-in the value of $zb as we go * If we drop-out with error or otherwise permaturely, * consider $zb to be null. * --------------------------------------------------------- */ zb_ptr = io_ptr->dollar.zb; zb_top = zb_ptr + sizeof(io_ptr->dollar.zb) - 1; *zb_ptr = 0; io_ptr->esc_state = START; io_ptr->dollar.za = 0; io_ptr->dollar.zeof = FALSE; v->str.len = 0; dx = (int)io_ptr->dollar.x; ret = TRUE; temp = stringpool.free; mask = tt_ptr->term_ctrl; mask_term = tt_ptr->mask_term; if (mask & TRM_NOTYPEAHD) TCFLUSH(tt_ptr->fildes, TCIFLUSH, status); if (mask & TRM_READSYNC) { DOWRITERC(tt_ptr->fildes, &dc1, 1, status); if (0 != status) { io_ptr->dollar.za = 9; rts_error(VARLSTCNT(1) status); } } nonzerotimeout = FALSE; if (NO_M_TIMEOUT == timeout) { timed = FALSE; input_timeval.tv_sec = 100; msec_timeout = NO_M_TIMEOUT; } else { timed = TRUE; input_timeval.tv_sec = timeout; msec_timeout = timeout2msec(timeout); if (!msec_timeout) iott_mterm(io_ptr); else { nonzerotimeout = TRUE; sys_get_curr_time(&cur_time); add_int_to_abs_time(&cur_time, msec_timeout, &end_time); } } input_timeval.tv_usec = 0; do { if (outofband) { outlen = 0; if (!msec_timeout) iott_rterm(io_ptr); outofband_action(FALSE); break; } errno = 0; FD_ZERO(&input_fd); FD_SET(tt_ptr->fildes, &input_fd); assert(0 != FD_ISSET(tt_ptr->fildes, &input_fd)); /* the checks for EINTR below are valid and should not be converted to EINTR * wrapper macros, since the select/read is not retried on EINTR. */ save_input_timeval = input_timeval; /* take a copy and pass it because select() below might change it */ selstat = select(tt_ptr->fildes + 1, (void *)&input_fd, (void *)NULL, (void *)NULL, &save_input_timeval); if (selstat < 0) { if (EINTR != errno) goto term_error; } else if (0 == selstat) { if (timed) { ret = FALSE; break; } continue; /* select() timeout; keep going */ } else if (0 < (rdlen = read(tt_ptr->fildes, &inchar, 1))) /* This read is protected */ { assert(0 != FD_ISSET(tt_ptr->fildes, &input_fd)); /* -------------------------------------------------- * set prin_in_dev_failure to FALSE to indicate that * input device is working now. * -------------------------------------------------- */ prin_in_dev_failure = FALSE; if (tt_ptr->canonical) { if (0 == inchar) { /* -------------------------------------- * This means that the device has hungup * -------------------------------------- */ io_ptr->dollar.zeof = TRUE; io_ptr->dollar.x = 0; io_ptr->dollar.za = 9; io_ptr->dollar.y++; if (io_ptr->error_handler.len > 0) rts_error(VARLSTCNT(1) ERR_IOEOF); break; } else io_ptr->dollar.zeof = FALSE; } if (mask & TRM_CONVERT) NATIVE_CVT2UPPER(inchar, inchar); GETASCII(asc_inchar,inchar); if ((dx >= width) && io_ptr->wrap && !(mask & TRM_NOECHO)) { DOWRITE(tt_ptr->fildes, NATIVE_TTEOL, strlen(NATIVE_TTEOL)); dx = 0; } if ((' ' > INPUT_CHAR) && (tt_ptr->enbld_outofbands.mask & (1 << INPUT_CHAR))) { outlen = 0; io_ptr->dollar.za = 9; std_dev_outbndset(INPUT_CHAR); /* it needs ASCII? */ outofband = 0; if (!msec_timeout) iott_rterm(io_ptr); rts_error(VARLSTCNT(3) ERR_CTRAP, 1, ctrap_action_is); break; } if ((0 != (mask & TRM_ESCAPE)) && ((NATIVE_ESC == inchar) || (START != io_ptr->esc_state))) { if (zb_ptr >= zb_top) { /* $zb overflow */ io_ptr->dollar.za = 2; break; } *zb_ptr++ = inchar; iott_escape(zb_ptr - 1, zb_ptr, io_ptr); *(zb_ptr - 1) = INPUT_CHAR; /* need to store ASCII value */ if (FINI == io_ptr->esc_state) break; if (BADESC == io_ptr->esc_state) { /* Escape sequence failed parse */ io_ptr->dollar.za = 2; break; } /* -------------------------------------------------------------------- * In escape sequence...do not process further, but get next character * -------------------------------------------------------------------- */ } else { /* SIMPLIFY THIS! */ msk_num = (uint4)INPUT_CHAR / NUM_BITS_IN_INT4; msk_in = (1 << ((uint4)INPUT_CHAR % NUM_BITS_IN_INT4)); if (msk_in & mask_term.mask[msk_num]) { *zb_ptr++ = INPUT_CHAR; break; } if (((int)inchar == tt_ptr->ttio_struct->c_cc[VERASE]) && !(mask & TRM_PASTHRU)) { if ((0< outlen) && (0 < dx)) { outlen--; dx--; *temp--; if (!(mask & TRM_NOECHO)) { DOWRITERC(tt_ptr->fildes, eraser, sizeof(eraser), status); if (0 != status) goto term_error; } } } else { if (!(mask & TRM_NOECHO)) { DOWRITERC(tt_ptr->fildes, &inchar, 1, status); if (0 != status) goto term_error; } *temp++ = inchar; outlen++; dx++; } } } else if (0 == rdlen) { if (0 < selstat) { /* this should be the only possibility */ io_ptr->dollar.zeof = TRUE; io_ptr->dollar.x = 0; io_ptr->dollar.za = 0; io_ptr->dollar.y++; if (io_curr_device.in == io_std_device.in) { if (!prin_in_dev_failure) prin_in_dev_failure = TRUE; else { send_msg(VARLSTCNT(1) ERR_NOPRINCIO); stop_image_no_core(); } } if (io_ptr->dollar.zeof) { io_ptr->dollar.za = 9; rts_error(VARLSTCNT(1) ERR_IOEOF); } else { io_ptr->dollar.zeof = TRUE; io_ptr->dollar.za = 0; if (0 < io_ptr->error_handler.len) rts_error(VARLSTCNT(1) ERR_IOEOF); } break; } if (0 == errno) { /* eof */ io_ptr->dollar.zeof = TRUE; io_ptr->dollar.x = 0; io_ptr->dollar.za = 0; io_ptr->dollar.y++; if (0 < io_ptr->error_handler.len) rts_error(VARLSTCNT(1) ERR_IOEOF); break; } } else if (EINTR != errno) /* rdlen < 0 */ goto term_error; if (nonzerotimeout) { sys_get_curr_time(&cur_time); cur_time = sub_abs_time(&end_time, &cur_time); if (0 > cur_time.at_sec) { ret = FALSE; break; } input_timeval.tv_sec = cur_time.at_sec; input_timeval.tv_usec = cur_time.at_usec; } } while (outlen < length); *zb_ptr++ = 0; if (!msec_timeout) { iott_rterm(io_ptr); if (0 == outlen) ret = FALSE; } if (mask & TRM_READSYNC) { DOWRITERC(tt_ptr->fildes, &dc3, 1, status); if (0 != status) { io_ptr->dollar.za = 9; rts_error(VARLSTCNT(1) status); } } if (outofband) { v->str.len = 0; io_ptr->dollar.za = 9; return(FALSE); } v->str.len = outlen; v->str.addr = (char *)stringpool.free; if (!(mask & TRM_NOECHO)) { if ((io_ptr->dollar.x += v->str.len) >= io_ptr->width && io_ptr->wrap) { io_ptr->dollar.y += (io_ptr->dollar.x / io_ptr->width); if (io_ptr->length) io_ptr->dollar.y %= io_ptr->length; io_ptr->dollar.x %= io_ptr->width; if (0 == io_ptr->dollar.x) DOWRITE(tt_ptr->fildes, NATIVE_TTEOL, strlen(NATIVE_TTEOL)); } } return ((short)ret); term_error: save_errno = errno; io_ptr->dollar.za = 9; if (!msec_timeout) iott_rterm(io_ptr); rts_error(VARLSTCNT(1) save_errno); return FALSE; }
/* * ------------------------------------------ * Hang the process for a specified time. * * Goes to sleep for a positive value. * Any caught signal will terminate the sleep * following the execution of that signal's catching routine. * * Arguments: * num - time to sleep * * Return: * none * ------------------------------------------ */ void op_hang(mval* num) { int ms; mv_stent *mv_zintcmd; ABS_TIME cur_time, end_time; # ifdef VMS uint4 time[2]; int4 efn_mask, status; # endif DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; ms = 0; MV_FORCE_NUM(num); if (num->mvtype & MV_INT) { if (0 < num->m[1]) { assert(MV_BIAS >= 1000); /* if formats change overflow may need attention */ ms = num->m[1] * (1000 / MV_BIAS); } } else if (0 == num->sgn) /* if sign is not 0 it means num is negative */ ms = mval2i(num) * 1000; /* too big to care about fractional amounts */ if (ms) { if (TREF(tpnotacidtime) * 1000 < ms) TPNOTACID_CHECK(HANGSTR); # if defined(DEBUG) && defined(UNIX) if (gtm_white_box_test_case_enabled && (WBTEST_DEFERRED_TIMERS == gtm_white_box_test_case_number) && (3 > gtm_white_box_test_case_count) && (123000 == ms)) { DEFER_INTERRUPTS(INTRPT_NO_TIMER_EVENTS); DBGFPF((stderr, "OP_HANG: will sleep for 20 seconds\n")); LONG_SLEEP(20); DBGFPF((stderr, "OP_HANG: done sleeping\n")); ENABLE_INTERRUPTS(INTRPT_NO_TIMER_EVENTS); return; } if (gtm_white_box_test_case_enabled && (WBTEST_BREAKMPC == gtm_white_box_test_case_number) && (0 == gtm_white_box_test_case_count) && (999 == ms)) { frame_pointer->old_frame_pointer->mpc = (unsigned char *)GTM64_ONLY(0xdeadbeef12345678) NON_GTM64_ONLY(0xdead1234); return; } /* Upon seeing a .999s hang this white-box test launches a timer that pops with a period of UTIL_OUT_SYSLOG_INTERVAL * and prints a long message via util_out_ptr. */ if (gtm_white_box_test_case_enabled && (WBTEST_UTIL_OUT_BUFFER_PROTECTION == gtm_white_box_test_case_number) && (0 == gtm_white_box_test_case_count) && (999 == ms)) { start_timer((TID)&util_out_syslog_dump, UTIL_OUT_SYSLOG_INTERVAL, util_out_syslog_dump, 0, NULL); return; } # endif sys_get_curr_time(&cur_time); mv_zintcmd = find_mvstent_cmd(ZINTCMD_HANG, restart_pc, restart_ctxt, FALSE); if (!mv_zintcmd) add_int_to_abs_time(&cur_time, ms, &end_time); else { end_time = mv_zintcmd->mv_st_cont.mvs_zintcmd.end_or_remain; cur_time = sub_abs_time(&end_time, &cur_time); /* get remaing time to sleep */ if (0 <= cur_time.at_sec) ms = (int4)(cur_time.at_sec * 1000 + cur_time.at_usec / 1000); else ms = 0; /* all done */ /* restore/pop previous zintcmd_active[ZINTCMD_HANG] hints */ TAREF1(zintcmd_active, ZINTCMD_HANG).restart_pc_last = mv_zintcmd->mv_st_cont.mvs_zintcmd.restart_pc_prior; TAREF1(zintcmd_active, ZINTCMD_HANG).restart_ctxt_last = mv_zintcmd->mv_st_cont.mvs_zintcmd.restart_ctxt_prior; TAREF1(zintcmd_active, ZINTCMD_HANG).count--; assert(0 <= TAREF1(zintcmd_active, ZINTCMD_HANG).count); if (mv_chain == mv_zintcmd) POP_MV_STENT(); /* just pop if top of stack */ else { /* flag as not active */ mv_zintcmd->mv_st_cont.mvs_zintcmd.command = ZINTCMD_NOOP; mv_zintcmd->mv_st_cont.mvs_zintcmd.restart_pc_check = NULL; } if (0 == ms) return; /* done HANGing */ } UNIX_ONLY(hiber_start(ms);) VMS_ONLY( time[0] = -time_low_ms(ms); time[1] = -time_high_ms(ms) - 1; efn_mask = (1 << efn_outofband | 1 << efn_timer); if (SS$_NORMAL != (status = sys$setimr(efn_timer, &time, NULL, &time, 0))) rts_error(VARLSTCNT(8) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("$setimr"), CALLFROM, status); if (SS$_NORMAL != (status = sys$wflor(efn_outofband, efn_mask))) rts_error(VARLSTCNT(8) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("$wflor"), CALLFROM, status); ) if (outofband)
/* * ------------------------------------------ * Hang the process for a specified time. * * Goes to sleep for a positive value. * Any caught signal will terminate the sleep * following the execution of that signal's catching routine. * * The actual hang duration should be NO LESS than the specified * duration for specified durations greater than .001 seconds. * Certain applications depend on this assumption. * * Arguments: * num - time to sleep * * Return: * none * ------------------------------------------ */ void op_hang(mval* num) { int ms; double tmp; mv_stent *mv_zintcmd; ABS_TIME cur_time, end_time; # ifdef VMS uint4 time[2]; int4 efn_mask, status; # endif DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; ms = 0; MV_FORCE_NUM(num); if (num->mvtype & MV_INT) { if (0 < num->m[1]) { assert(MV_BIAS >= 1000); /* if formats change overflow may need attention */ ms = num->m[1] * (1000 / MV_BIAS); } } else if (0 == num->sgn) /* if sign is not 0 it means num is negative */ { tmp = mval2double(num) * (double)1000; ms = ((double)MAXPOSINT4 >= tmp) ? (int)tmp : (int)MAXPOSINT4; } if (ms) { if (TREF(tpnotacidtime) * 1000 < ms) TPNOTACID_CHECK(HANGSTR); # if defined(DEBUG) && defined(UNIX) if (WBTEST_ENABLED(WBTEST_DEFERRED_TIMERS) && (3 > gtm_white_box_test_case_count) && (123000 == ms)) { DEFER_INTERRUPTS(INTRPT_NO_TIMER_EVENTS); DBGFPF((stderr, "OP_HANG: will sleep for 20 seconds\n")); LONG_SLEEP(20); DBGFPF((stderr, "OP_HANG: done sleeping\n")); ENABLE_INTERRUPTS(INTRPT_NO_TIMER_EVENTS); return; } if (WBTEST_ENABLED(WBTEST_BREAKMPC)&& (0 == gtm_white_box_test_case_count) && (999 == ms)) { frame_pointer->old_frame_pointer->mpc = (unsigned char *)GTM64_ONLY(0xdeadbeef12345678) NON_GTM64_ONLY(0xdead1234); return; } if (WBTEST_ENABLED(WBTEST_UTIL_OUT_BUFFER_PROTECTION) && (0 == gtm_white_box_test_case_count) && (999 == ms)) { /* Upon seeing a .999s hang this white-box test launches a timer that pops with a period of * UTIL_OUT_SYSLOG_INTERVAL and prints a long message via util_out_ptr. */ start_timer((TID)&util_out_syslog_dump, UTIL_OUT_SYSLOG_INTERVAL, util_out_syslog_dump, 0, NULL); return; } # endif sys_get_curr_time(&cur_time); mv_zintcmd = find_mvstent_cmd(ZINTCMD_HANG, restart_pc, restart_ctxt, FALSE); if (!mv_zintcmd) add_int_to_abs_time(&cur_time, ms, &end_time); else { end_time = mv_zintcmd->mv_st_cont.mvs_zintcmd.end_or_remain; cur_time = sub_abs_time(&end_time, &cur_time); /* get remaing time to sleep */ if (0 <= cur_time.at_sec) ms = (int4)(cur_time.at_sec * 1000 + cur_time.at_usec / 1000); else ms = 0; /* all done */ /* restore/pop previous zintcmd_active[ZINTCMD_HANG] hints */ TAREF1(zintcmd_active, ZINTCMD_HANG).restart_pc_last = mv_zintcmd->mv_st_cont.mvs_zintcmd.restart_pc_prior; TAREF1(zintcmd_active, ZINTCMD_HANG).restart_ctxt_last = mv_zintcmd->mv_st_cont.mvs_zintcmd.restart_ctxt_prior; TAREF1(zintcmd_active, ZINTCMD_HANG).count--; assert(0 <= TAREF1(zintcmd_active, ZINTCMD_HANG).count); if (mv_chain == mv_zintcmd) POP_MV_STENT(); /* just pop if top of stack */ else { /* flag as not active */ mv_zintcmd->mv_st_cont.mvs_zintcmd.command = ZINTCMD_NOOP; mv_zintcmd->mv_st_cont.mvs_zintcmd.restart_pc_check = NULL; } if (0 == ms) return; /* done HANGing */ } # ifdef UNIX if (ms < 10) SLEEP_USEC(ms * 1000, TRUE); /* Finish the sleep if it is less than 10ms. */ else hiber_start(ms); # elif defined(VMS) time[0] = -time_low_ms(ms); time[1] = -time_high_ms(ms) - 1; efn_mask = (1 << efn_outofband | 1 << efn_timer); if (SS$_NORMAL != (status = sys$setimr(efn_timer, &time, NULL, &time, 0))) rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("$setimr"), CALLFROM, status); if (SS$_NORMAL != (status = sys$wflor(efn_outofband, efn_mask))) rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("$wflor"), CALLFROM, status); if (outofband) { if (SS$_WASCLR == (status = sys$readef(efn_timer, &efn_mask))) { if (SS$_NORMAL != (status = sys$cantim(&time, 0))) rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("$cantim"), CALLFROM, status); } else assertpro(SS$_WASSET == status); } # endif } else rel_quant(); if (outofband) { PUSH_MV_STENT(MVST_ZINTCMD); mv_chain->mv_st_cont.mvs_zintcmd.end_or_remain = end_time; mv_chain->mv_st_cont.mvs_zintcmd.restart_ctxt_check = restart_ctxt; mv_chain->mv_st_cont.mvs_zintcmd.restart_pc_check = restart_pc; /* save current information from zintcmd_active */ mv_chain->mv_st_cont.mvs_zintcmd.restart_ctxt_prior = TAREF1(zintcmd_active, ZINTCMD_HANG).restart_ctxt_last; mv_chain->mv_st_cont.mvs_zintcmd.restart_pc_prior = TAREF1(zintcmd_active, ZINTCMD_HANG).restart_pc_last; TAREF1(zintcmd_active, ZINTCMD_HANG).restart_pc_last = restart_pc; TAREF1(zintcmd_active, ZINTCMD_HANG).restart_ctxt_last = restart_ctxt; TAREF1(zintcmd_active, ZINTCMD_HANG).count++; mv_chain->mv_st_cont.mvs_zintcmd.command = ZINTCMD_HANG; outofband_action(FALSE); } return; }
void iosocket_tls(mval *optionmval, int4 timeoutarg, mval *tlsid, mval *password, mval *extraarg) { /* note extraarg is not currently used */ int4 length, flags, timeout, msec_timeout, status, status2, len, errlen, devlen, tls_errno, save_errno; io_desc *iod; d_socket_struct *dsocketptr; socket_struct *socketptr; char optionstr[MAX_TLSOPTION], idstr[MAX_TLSID_LEN], passwordstr[GTM_PASSPHRASE_MAX_ASCII + 1]; const char *errp; tls_option option; gtm_tls_socket_t *tlssocket; ABS_TIME cur_time, end_time; # ifdef USE_POLL struct pollfd fds; # else fd_set fds, *readfds, *writefds; struct timeval timeout_spec, *timeout_ptr; # endif iod = io_curr_device.out; assert(gtmsocket == iod->type); dsocketptr = (d_socket_struct *)iod->dev_sp; if (0 >= dsocketptr->n_socket) { rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_NOSOCKETINDEV); return; } if (dsocketptr->n_socket <= dsocketptr->current_socket) { rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_CURRSOCKOFR, 2, dsocketptr->current_socket, dsocketptr->n_socket); return; } if (dsocketptr->mupintr) rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_ZINTRECURSEIO); socketptr = dsocketptr->socket[dsocketptr->current_socket]; ENSURE_DATA_SOCKET(socketptr); if (socket_tcpip != socketptr->protocol) { rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_TLSPARAM, 4, RTS_ERROR_MVAL(optionmval), LEN_AND_LIT("but socket is not TCP")); return; } if (socket_connected != socketptr->state) { rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_TLSPARAM, 4, LEN_AND_LIT("/TLS"), LEN_AND_LIT("but socket not connected")); return; } if (NULL != tlsid) { length = tlsid->str.len; if (MAX_TLSID_LEN < (length + 1)) /* for null */ { rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_TLSPARAM, 4, LEN_AND_LIT("TLSID"), LEN_AND_LIT("too long")); return; } STRNCPY_STR(idstr, tlsid->str.addr, length); idstr[length] = '\0'; } else idstr[0] = '\0'; if (NULL != password) { length = password->str.len; if (GTM_PASSPHRASE_MAX_ASCII < length) { rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_TLSPARAM, 4, LEN_AND_LIT("passphrase"), LEN_AND_LIT("too long")); return; } STRNCPY_STR(passwordstr, password->str.addr, length); passwordstr[length] = '\0'; } else passwordstr[0] = '\0'; length = MIN(MAX_TLSOPTION, optionmval->str.len); lower_to_upper((uchar_ptr_t)optionstr, (uchar_ptr_t)optionmval->str.addr, length); if (0 == memcmp(optionstr, "CLIENT", length)) option = tlsopt_client; else if (0 == memcmp(optionstr, "SERVER", length)) option = tlsopt_server; else if (0 == memcmp(optionstr, "RENEGOTIATE", length)) option = tlsopt_renegotiate; else option = tlsopt_invalid; memcpy(iod->dollar.device, "0", SIZEOF("0")); if (NO_M_TIMEOUT != timeoutarg) { msec_timeout = timeout2msec(timeoutarg); sys_get_curr_time(&cur_time); add_int_to_abs_time(&cur_time, msec_timeout, &end_time); } else msec_timeout = -1; if ((tlsopt_client == option) || (tlsopt_server == option)) { /* most of the setup is common */ if (socketptr->tlsenabled) { rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_TLSPARAM, 4, LEN_AND_STR(optionstr), LEN_AND_LIT("but TLS already enabled")); return; } assertpro((0 >= socketptr->buffered_length) && (0 >= socketptr->obuffer_length)); if (NULL == tls_ctx) { /* first use of TLS */ if (-1 == gtm_tls_loadlibrary()) { rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_TLSDLLNOOPEN, 0, ERR_TEXT, 2, LEN_AND_STR(dl_err)); return; } if (NULL == (tls_ctx = (gtm_tls_init(GTM_TLS_API_VERSION, GTMTLS_OP_INTERACTIVE_MODE)))) { errp = gtm_tls_get_error(); len = SIZEOF(ONE_COMMA) - 1; memcpy(iod->dollar.device, ONE_COMMA, len); errlen = STRLEN(errp); devlen = MIN((SIZEOF(iod->dollar.device) - len - 1), errlen); memcpy(&iod->dollar.device[len], errp, devlen + 1); if (devlen < errlen) iod->dollar.device[SIZEOF(iod->dollar.device) - 1] = '\0'; if (socketptr->ioerror) rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_TLSINIT, 0, ERR_TEXT, 2, errlen, errp); if (NO_M_TIMEOUT != timeoutarg) dollar_truth = FALSE; return; } } socketptr->tlsenabled = TRUE; flags = GTMTLS_OP_SOCKET_DEV | ((tlsopt_client == option) ? GTMTLS_OP_CLIENT_MODE : 0); socketptr->tlssocket = gtm_tls_socket(tls_ctx, NULL, socketptr->sd, idstr, flags); if (NULL == socketptr->tlssocket) { socketptr->tlsenabled = FALSE; errp = gtm_tls_get_error(); len = SIZEOF(ONE_COMMA) - 1; memcpy(iod->dollar.device, ONE_COMMA, len); errlen = STRLEN(errp); devlen = MIN((SIZEOF(iod->dollar.device) - len - 1), errlen); memcpy(&iod->dollar.device[len], errp, devlen + 1); if (devlen < errlen) iod->dollar.device[SIZEOF(iod->dollar.device) - 1] = '\0'; if (socketptr->ioerror) rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_TLSCONVSOCK, 0, ERR_TEXT, 2, errlen, errp); if (NO_M_TIMEOUT != timeoutarg) dollar_truth = FALSE; return; } status = 0; # ifndef USE_POLL if (NO_M_TIMEOUT == timeoutarg) timeout_ptr = NULL; else { timeout_spec.tv_sec = msec_timeout / 1000; timeout_spec.tv_usec = (msec_timeout % 1000) * 1000; /* remainder in millsecs to microsecs */ timeout_ptr = &timeout_spec; } # endif do { status2 = 0; if (0 != status) { # ifdef USE_POLL fds.fd = socketptr->sd; fds.events = (GTMTLS_WANT_READ == status) ? POLLIN : POLLOUT; # else readfds = writefds = NULL; assertpro(FD_SETSIZE > socketptr->sd); FD_ZERO(&fds); FD_SET(socketptr->sd, &fds); writefds = (GTMTLS_WANT_WRITE == status) ? &fds : NULL; readfds = (GTMTLS_WANT_READ == status) ? &fds : NULL; # endif POLL_ONLY(if (-1 == (status2 = poll(&fds, 1, msec_timeout)))) SELECT_ONLY(if (-1 == (status2 = select(socketptr->sd + 1, readfds, writefds, NULL, timeout_ptr)))) { save_errno = errno; if (EAGAIN == save_errno) { rel_quant(); /* allow resources to become available */ status2 = 0; /* treat as timeout */ } else if (EINTR == save_errno) status2 = 0; } } else status2 = 1; /* do accept/connect first time */ if (0 < status2) { if (tlsopt_server == option) status = gtm_tls_accept((gtm_tls_socket_t *)socketptr->tlssocket); else status = gtm_tls_connect((gtm_tls_socket_t *)socketptr->tlssocket); } if ((0 > status2) || ((status != 0) && ((GTMTLS_WANT_READ != status) && (GTMTLS_WANT_WRITE != status)))) { if (0 != status) { tls_errno = gtm_tls_errno(); if (0 > tls_errno) errp = gtm_tls_get_error(); else errp = STRERROR(tls_errno); } else errp = STRERROR(save_errno); socketptr->tlsenabled = FALSE; len = SIZEOF(ONE_COMMA) - 1; memcpy(iod->dollar.device, ONE_COMMA, len); errlen = STRLEN(errp); devlen = MIN((SIZEOF(iod->dollar.device) - len - 1), errlen); memcpy(&iod->dollar.device[len], errp, devlen + 1); if (devlen < errlen) iod->dollar.device[SIZEOF(iod->dollar.device) - 1] = '\0'; if (socketptr->ioerror) rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_TLSHANDSHAKE, 0, ERR_TEXT, 2, errlen, errp); return; } if ((0 != status) && (0 <= status2)) /* not accepted/connected and not error */ { /* check for timeout if not error or want read or write */ if ((0 != timeoutarg) && (NO_M_TIMEOUT != timeoutarg)) { sys_get_curr_time(&cur_time); cur_time = sub_abs_time(&end_time, &cur_time); if (0 >= cur_time.at_sec) { /* no more time */ gtm_tls_session_close((gtm_tls_socket_t **)&socketptr->tlssocket); socketptr->tlsenabled = FALSE; dollar_truth = FALSE; return; } else { /* adjust msec_timeout for poll/select */ # ifdef USE_POLL msec_timeout = (cur_time.at_sec * 1000) + (cur_time.at_usec / 1000); # else timeout_spec.tv_sec = cur_time.at_sec; timeout_spec.tv_usec = (gtm_tv_usec_t)cur_time.at_usec; # endif } } else if (0 == timeoutarg) { /* only one chance */ gtm_tls_session_close((gtm_tls_socket_t **)&socketptr->tlssocket); socketptr->tlsenabled = FALSE; dollar_truth = FALSE; return; } continue; } } while ((GTMTLS_WANT_READ == status) || (GTMTLS_WANT_WRITE == status)); /* turn on output buffering */ if (0 == socketptr->obuffer_size) socketptr->obuffer_size = socketptr->buffer_size; socketptr->obuffer_length = socketptr->obuffer_offset = 0; socketptr->obuffer_wait_time = DEFAULT_WRITE_WAIT; socketptr->obuffer_flush_time = DEFAULT_WRITE_WAIT * 2; /* until add device parameter */ socketptr->obuffer = malloc(socketptr->obuffer_size); } else if (tlsopt_renegotiate == option)
boolean_t iosocket_connect(socket_struct *socketptr, int4 timepar, boolean_t update_bufsiz) { int temp_1 = 1; char *errptr; int4 errlen, msec_timeout, real_errno; boolean_t no_time_left = FALSE; short len; d_socket_struct *dsocketptr; ABS_TIME cur_time, end_time; error_def(ERR_SOCKINIT); error_def(ERR_OPENCONN); error_def(ERR_TEXT); error_def(ERR_GETSOCKOPTERR); error_def(ERR_SETSOCKOPTERR); dsocketptr = socketptr->dev; assert(NULL != dsocketptr); dsocketptr->dollar_key[0] = '\0'; if (timepar != NO_M_TIMEOUT) { msec_timeout = timeout2msec(timepar); sys_get_curr_time(&cur_time); add_int_to_abs_time(&cur_time, msec_timeout, &end_time); } do { if (1 != temp_1) { tcp_routines.aa_close(socketptr->sd); } if (-1 == (socketptr->sd = tcp_routines.aa_socket(AF_INET, SOCK_STREAM, 0))) { errptr = (char *)STRERROR(errno); errlen = strlen(errptr); rts_error(VARLSTCNT(5) ERR_SOCKINIT, 3, errno, errlen, errptr); return FALSE; } temp_1 = 1; if (-1 == tcp_routines.aa_setsockopt(socketptr->sd, SOL_SOCKET, SO_REUSEADDR, &temp_1, sizeof(temp_1))) { errptr = (char *)STRERROR(errno); errlen = strlen(errptr); rts_error(VARLSTCNT(7) ERR_SETSOCKOPTERR, 5, RTS_ERROR_LITERAL("SO_REUSEADDR"), errno, errlen, errptr); return FALSE; } #ifdef TCP_NODELAY temp_1 = socketptr->nodelay ? 1 : 0; if (-1 == tcp_routines.aa_setsockopt(socketptr->sd, IPPROTO_TCP, TCP_NODELAY, &temp_1, sizeof(temp_1))) { errptr = (char *)STRERROR(errno); errlen = strlen(errptr); rts_error(VARLSTCNT(7) ERR_SETSOCKOPTERR, 5, RTS_ERROR_LITERAL("TCP_NODELAY"), errno, errlen, errptr); return FALSE; } #endif if (update_bufsiz) { if (-1 == tcp_routines.aa_setsockopt(socketptr->sd, SOL_SOCKET, SO_RCVBUF, &socketptr->bufsiz, sizeof(socketptr->bufsiz))) { errptr = (char *)STRERROR(errno); errlen = strlen(errptr); rts_error(VARLSTCNT(7) ERR_SETSOCKOPTERR, 5, RTS_ERROR_LITERAL("SO_RCVBUF"), errno, errlen, errptr); return FALSE; } } else { temp_1 = sizeof(socketptr->bufsiz); if (-1 == tcp_routines.aa_getsockopt(socketptr->sd, SOL_SOCKET, SO_RCVBUF, &socketptr->bufsiz, &temp_1)) { errptr = (char *)STRERROR(errno); errlen = strlen(errptr); rts_error(VARLSTCNT(7) ERR_GETSOCKOPTERR, 5, RTS_ERROR_LITERAL("SO_RCVBUF"), errno, errlen, errptr); return FALSE; } } temp_1 = tcp_routines.aa_connect(socketptr->sd, (struct sockaddr *)&socketptr->remote.sin, sizeof(socketptr->remote.sin)); if (temp_1 < 0) { real_errno = errno; no_time_left = TRUE; switch (real_errno) { case ETIMEDOUT : /* the other side bound but not listening */ case ECONNREFUSED : if (NO_M_TIMEOUT != timepar) { sys_get_curr_time(&cur_time); cur_time = sub_abs_time(&end_time, &cur_time); if (cur_time.at_sec > 0) no_time_left = FALSE; } break; case EINTR : break; default: errptr = (char *)STRERROR(real_errno); errlen = strlen(errptr); rts_error(VARLSTCNT(6) ERR_OPENCONN, 0, ERR_TEXT, 2, errlen, errptr); break; } if (no_time_left) { return FALSE; } hiber_start(100); } } while (temp_1 < 0); /* handle the local information later. SPRINTF(socketptr->local.saddr_ip, "%s", tcp_routines.aa_inet_ntoa(socketptr->remote.sin.sin_addr)); socketptr->local.port = GTM_NTOHS(socketptr->remote.sin.sin_port); */ socketptr->state = socket_connected; /* update dollar_key */ len = sizeof(ESTABLISHED) - 1; memcpy(&dsocketptr->dollar_key[0], ESTABLISHED, len); dsocketptr->dollar_key[len++] = '|'; memcpy(&dsocketptr->dollar_key[len], socketptr->handle, socketptr->handle_len); len += socketptr->handle_len; dsocketptr->dollar_key[len++] = '|'; memcpy(&dsocketptr->dollar_key[len], socketptr->remote.saddr_ip, strlen(socketptr->remote.saddr_ip)); len += strlen(socketptr->remote.saddr_ip); dsocketptr->dollar_key[len] = '\0'; return TRUE; }
short iotcp_open(io_log_name *dev, mval *pp, int file_des, mval *mspace, int4 timeout) { boolean_t no_time_left = FALSE, timed; char addr[SA_MAXLEN+1], *errptr, sockaddr[SA_MAXLEN+1], temp_addr[SA_MAXLEN+1], temp_ch; unsigned char ch, len; int4 length, width; unsigned short port; int4 errlen, msec_timeout; int ii, status, size, on = 1, p_offset = 0, temp_1 = -2; TID timer_id; ABS_TIME cur_time, end_time, time_for_read, save_time_for_read; d_tcp_struct *tcpptr, newtcp; io_desc *ioptr; struct sockaddr_in peer; /* socket address + port */ fd_set tcp_fd; int lsock; error_def(ERR_DEVPARMNEG); error_def(ERR_INVADDRSPEC); error_def(ERR_INVPORTSPEC); error_def(ERR_IPADDRREQ); error_def(ERR_OPENCONN); error_def(ERR_SOCKACPT); error_def(ERR_SOCKINIT); error_def(ERR_SOCKPARMREQ); error_def(ERR_SOCKWAIT); error_def(ERR_TEXT); #ifdef DEBUG_TCP PRINTF("iotcp_open.c >>> tt = %d\n", t); #endif ioptr = dev->iod; assert((params) *(pp->str.addr + p_offset) < (unsigned char)n_iops); assert(0 != ioptr); assert(ioptr->state >= 0 && ioptr->state < n_io_dev_states); assert(tcp == ioptr->type); if (dev_never_opened == ioptr->state) { ioptr->dev_sp = (void *)malloc(sizeof(d_tcp_struct)); memset(ioptr->dev_sp, 0, sizeof(d_tcp_struct)); } tcpptr = (d_tcp_struct *)ioptr->dev_sp; if (dev_never_opened == ioptr->state) { ioptr->state = dev_closed; ioptr->width = TCPDEF_WIDTH; ioptr->length = TCPDEF_LENGTH; ioptr->wrap = TRUE; if (-1 == iotcp_fillroutine()) assert(FALSE); } ioptr->dollar.zeof = FALSE; newtcp = *tcpptr; memcpy(newtcp.dollar_device, LITZERO, sizeof(LITZERO)); newtcp.passive = FALSE; while (iop_eol != *(pp->str.addr + p_offset)) { switch (ch = *(pp->str.addr + p_offset++)) { case iop_width: GET_LONG(width, pp->str.addr + p_offset); if (0 == width) newtcp.width = TCPDEF_WIDTH; else if (width > 0) newtcp.width = width; else rts_error(VARLSTCNT(1) ERR_DEVPARMNEG); break; case iop_length: GET_LONG(length, pp->str.addr + p_offset); if (0 == length) newtcp.length = TCPDEF_LENGTH; else if (length > 0) newtcp.length = length; else rts_error(VARLSTCNT(1) ERR_DEVPARMNEG); break; case iop_listen: newtcp.passive = TRUE; break; case iop_socket: len = *(pp->str.addr + p_offset); memset(sockaddr, 0, SA_MAXLEN+1); memcpy(sockaddr, pp->str.addr + p_offset + 1, (len <= SA_MAXLEN) ? len : SA_MAXLEN); *temp_addr = '\0'; *addr = '\0'; port = 0; if (SSCANF(sockaddr, "%[^,], %hu", temp_addr, &port) < 2) { newtcp.sin.sin_addr.s_addr = INADDR_ANY; if (SSCANF(sockaddr, ",%hu", &port) < 1) { rts_error(VARLSTCNT(1) ERR_INVPORTSPEC); return FALSE; } } else { ii = 0; temp_ch = temp_addr[0]; while(ISDIGIT(temp_ch) || ('.' == temp_ch)) { ii++; temp_ch = temp_addr[ii]; } if ('\0' != temp_ch) SPRINTF(addr, "%s", iotcp_name2ip(temp_addr)); else SPRINTF(addr, "%s", temp_addr); if ((in_addr_t)-1 == (newtcp.sin.sin_addr.s_addr = tcp_routines.aa_inet_addr(addr))) { rts_error(VARLSTCNT(1) ERR_INVADDRSPEC); return FALSE; } } newtcp.sin.sin_port = GTM_HTONS(port); newtcp.sin.sin_family = AF_INET; break; case iop_exception: ioptr->error_handler.len = *(pp->str.addr + p_offset); ioptr->error_handler.addr = (char *)(pp->str.addr + p_offset + 1); s2pool(&ioptr->error_handler); break; default: break; } p_offset += ((IOP_VAR_SIZE == io_params_size[ch]) ? (unsigned char)*(pp->str.addr + p_offset) + 1 : io_params_size[ch]); } if ((0 == newtcp.sin.sin_port) && (0 == newtcp.sin.sin_addr.s_addr)) { rts_error(VARLSTCNT(1) ERR_SOCKPARMREQ); return FALSE; } /* active connection must have a complete address specification */ if ((INADDR_ANY == newtcp.sin.sin_addr.s_addr) && !newtcp.passive) { rts_error(VARLSTCNT(1) ERR_IPADDRREQ); return FALSE; } if (dev_closed == ioptr->state) { if (newtcp.passive) /* passive connection */ { /* no listening socket for this addr? make one. */ memcpy(ioptr->dev_sp, &newtcp, sizeof(d_tcp_struct)); if (!(lsock = iotcp_getlsock(dev))) return FALSE; /* could not create listening socket */ timer_id = (TID)iotcp_open; out_of_time = FALSE; time_for_read.at_sec = ((NO_M_TIMEOUT == timeout) ? 0 : 1); time_for_read.at_usec = 0; if (NO_M_TIMEOUT == timeout) { timed = FALSE; msec_timeout = NO_M_TIMEOUT; } else { timed = TRUE; msec_timeout = timeout2msec(timeout); if (msec_timeout > 0) { /* there is time to wait */ sys_get_curr_time(&cur_time); add_int_to_abs_time(&cur_time, msec_timeout, &end_time); start_timer(timer_id, msec_timeout, wake_alarm, 0, NULL); } else out_of_time = TRUE; } for (status = 0; 0 == status; ) { FD_ZERO(&tcp_fd); FD_SET(lsock, &tcp_fd); /* * Note: the check for EINTR from the select below should remain, as aa_select is a * function, and not all callers of aa_select behave the same when EINTR is returned. */ save_time_for_read = time_for_read; status = tcp_routines.aa_select(lsock + 1, (void *)&tcp_fd, (void *)0, (void *)0, &time_for_read); time_for_read = save_time_for_read; if (0 > status) { if (EINTR == errno && FALSE == out_of_time) /* interrupted by a signal which is not OUR timer */ status = 0; else break; } if (outofband) break; if (timed) { if (msec_timeout > 0) { sys_get_curr_time(&cur_time); cur_time = sub_abs_time(&end_time, &cur_time); if (cur_time.at_sec <= 0) { out_of_time = TRUE; cancel_timer(timer_id); break; } } else break; } #ifdef __linux__ time_for_read.at_sec = ((NO_M_TIMEOUT == timeout) ? 0 : 1); time_for_read.at_usec = 0; #endif } if (timed) { if (0 != msec_timeout) { cancel_timer(timer_id); if (out_of_time || outofband) return FALSE; /*if (outofband) outofband_action(FALSE);*/ } } if (0 > status) { errptr = (char *)STRERROR(errno); errlen = strlen(errptr); iotcp_rmlsock((io_desc *)dev->iod); rts_error(VARLSTCNT(6) ERR_SOCKWAIT, 0, ERR_TEXT, 2, errlen, errptr); return FALSE; } size = sizeof(struct sockaddr_in); status = tcp_routines.aa_accept(lsock, &peer, &size); if (-1 == status) { errptr = (char *)STRERROR(errno); errlen = strlen(errptr); iotcp_rmlsock((io_desc *)dev->iod); rts_error(VARLSTCNT(6) ERR_SOCKACPT, 0, ERR_TEXT, 2, errlen, errptr); return FALSE; } SPRINTF(newtcp.saddr, "%s,%d", tcp_routines.aa_inet_ntoa(peer.sin_addr), GTM_NTOHS(newtcp.sin.sin_port)); newtcp.socket = status; } else /* active connection */ { if (NO_M_TIMEOUT != timeout) { msec_timeout = timeout2msec(timeout); sys_get_curr_time(&cur_time); add_int_to_abs_time(&cur_time, msec_timeout, &end_time); } no_time_left = FALSE; temp_1 = 1; do { if(1 != temp_1) tcp_routines.aa_close(newtcp.socket); newtcp.socket = tcp_routines.aa_socket(AF_INET, SOCK_STREAM, 0); if (-1 == newtcp.socket) { errptr = (char *)STRERROR(errno); errlen = strlen(errptr); rts_error(VARLSTCNT(5) ERR_SOCKINIT, 3, errno, errlen, errptr); return FALSE; } /* allow multiple connections to the same IP address */ if (-1 == tcp_routines.aa_setsockopt(newtcp.socket, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on))) { (void)tcp_routines.aa_close(newtcp.socket); errptr = (char *)STRERROR(errno); errlen = strlen(errptr); rts_error(VARLSTCNT(5) ERR_SOCKINIT, 3, errno, errlen, errptr); return FALSE; } size=sizeof(newtcp.bufsiz); if (-1 == tcp_routines.aa_getsockopt(newtcp.socket, SOL_SOCKET, SO_RCVBUF, &newtcp.bufsiz, &size)) { (void)tcp_routines.aa_close(newtcp.socket); errptr = (char *)STRERROR(errno); errlen = strlen(errptr); rts_error(VARLSTCNT(5) ERR_SOCKINIT, 3, errno, errlen, errptr); return FALSE; } /* * Note: the check for EINTR from the connect need not be converted to an EINTR wrapper macro, * since the connect is not retried on EINTR. */ temp_1 = tcp_routines.aa_connect(newtcp.socket, (struct sockaddr *)&newtcp.sin, sizeof(newtcp.sin)); if ((temp_1 < 0) && (ECONNREFUSED != errno) && (EINTR != errno)) { (void)tcp_routines.aa_close(newtcp.socket); errptr = (char *)STRERROR(errno); errlen = strlen(errptr); rts_error(VARLSTCNT(6) ERR_OPENCONN, 0, ERR_TEXT, 2, errlen, errptr); return FALSE; } if ((temp_1 < 0) && (EINTR == errno)) { (void)tcp_routines.aa_close(newtcp.socket); return FALSE; } if ((temp_1 < 0) && (NO_M_TIMEOUT != timeout)) { sys_get_curr_time(&cur_time); cur_time = sub_abs_time(&end_time, &cur_time); if (cur_time.at_sec <= 0) no_time_left = TRUE; } SHORT_SLEEP(100); /* Sleep for 100 ms */ } while ((TRUE != no_time_left) && (temp_1 < 0)); if (temp_1 < 0) /* out of time */ { tcp_routines.aa_close(newtcp.socket); return FALSE; } #ifdef ntohs /* if it's a macro, use it instead of tcp_routines.aa_ntohs */ SPRINTF(newtcp.saddr, "%s,%d", tcp_routines.aa_inet_ntoa(newtcp.sin.sin_addr), ntohs(newtcp.sin.sin_port)); #else SPRINTF(newtcp.saddr, "%s,%d", tcp_routines.aa_inet_ntoa(newtcp.sin.sin_addr), tcp_routines.aa_ntohs(newtcp.sin.sin_port)); #endif } memcpy(ioptr->dev_sp, &newtcp, sizeof(d_tcp_struct)); ioptr->state = dev_open; } #ifdef DEBUG_TCP PRINTF("%s (%d) <<<\n", __FILE__, tcpptr->socket); #endif return TRUE; }
bool io_open_try(io_log_name *naml, io_log_name *tl, mval *pp, int4 timeout, mval *mspace) { char buf1[MAX_TRANS_NAME_LEN]; /* buffer to hold translated name */ char dev_type[MAX_DEV_TYPE_LEN]; int n; mstr tn; /* translated name */ uint4 stat; /* status */ int p_offset; unsigned char ch; ABS_TIME cur_time, end_time; bool out_of_time = FALSE; if (0 == naml->iod) { if (0 == tl->iod) { tl->iod = (io_desc *)malloc(SIZEOF(io_desc)); memset((char*)tl->iod, 0, SIZEOF(io_desc)); tl->iod->pair.in = tl->iod; tl->iod->pair.out = tl->iod; tl->iod->trans_name = tl; p_offset = 0; while (iop_eol != *(pp->str.addr + p_offset)) { if ((iop_tmpmbx == (ch = *(pp->str.addr + p_offset++))) || (iop_prmmbx == ch)) tl->iod->type = mb; else if (iop_nl == ch) tl->iod->type = nl; p_offset += ((IOP_VAR_SIZE == io_params_size[ch]) ? (unsigned char)*(pp->str.addr + p_offset) + 1 : io_params_size[ch]); } if (!tl->iod->type && mspace && mspace->str.len) { lower_to_upper(dev_type, mspace->str.addr, mspace->str.len); if (((SIZEOF("SOCKET") - 1) == mspace->str.len) && (0 == memcmp(dev_type, LIT_AND_LEN("SOCKET")))) tl->iod->type = gtmsocket; else tl->iod->type = us; } if (!tl->iod->type) { tn.len = tl->len; tn.addr = &tl->dollar_io; tl->iod->type = io_type(&tn); } } naml->iod = tl->iod; } tl->iod->disp_ptr = &io_dev_dispatch[tl->iod->type]; assert(0 != naml->iod); active_device = naml->iod; if (dev_never_opened == naml->iod->state) { naml->iod->wrap = DEFAULT_IOD_WRAP; naml->iod->width = DEFAULT_IOD_WIDTH; naml->iod->length = DEFAULT_IOD_LENGTH; naml->iod->write_filter = write_filter; } if (dev_open != naml->iod->state) { naml->iod->dollar.x = 0; naml->iod->dollar.y = 0; naml->iod->dollar.za = 0; naml->iod->dollar.zb[0] = 0; naml->iod->dollar.zeof = FALSE; } if (0 == timeout) stat = (naml->iod->disp_ptr->open)(naml, pp, -1, mspace, timeout); /* ZY: add a parameter timeout */ else if (NO_M_TIMEOUT == timeout) { while (FALSE == (stat = (naml->iod->disp_ptr->open)(naml, pp, -1, mspace, timeout))) /* ZY: add timeout */ { hiber_start(1000); /* 1 second */ if (outofband) outofband_action(FALSE); } } else { sys_get_curr_time(&cur_time); add_int_to_abs_time(&cur_time, timeout * 1000, &end_time); while (FALSE == (stat = (naml->iod->disp_ptr->open)(naml, pp, -1, mspace, timeout)) /* ZY: add timeout */ && (!out_of_time)) { hiber_start(1000); /* 1 second */ if (outofband) outofband_action(FALSE); sys_get_curr_time(&cur_time); if (abs_time_comp(&end_time, &cur_time) <= 0) out_of_time = TRUE; } } if (TRUE == stat) { naml->iod->state = dev_open; if (27 == naml->iod->trans_name->dollar_io[0]) { tn.addr = &naml->iod->trans_name->dollar_io[4]; n = naml->iod->trans_name->len - 4; if (n < 0) n = 0; tn.len = n; naml->iod->trans_name = get_log_name(&tn, INSERT); naml->iod->trans_name->iod = naml->iod; } } else { if (dev_open == naml->iod->state && (gtmsocket != naml->iod->type)) naml->iod->state = dev_closed; else if ((gtmsocket == naml->iod->type) && naml->iod->newly_created) { assert(naml->iod->state != dev_open); iosocket_destroy(naml->iod); } } active_device = 0; if ((NO_M_TIMEOUT != timeout) && IS_MCODE_RUNNING) return (stat); return FALSE; }
int tcp_open(char *host, unsigned short port, int4 timeout, boolean_t passive) /* host needs to be NULL terminated */ { boolean_t no_time_left = FALSE, error_given = FALSE; char temp_addr[SA_MAXLEN + 1], addr[SA_MAXLEN + 1]; char *from, *to, *errptr, *temp_ch; char ipname[SA_MAXLEN]; int match, sock, sendbufsize, ii, on = 1, temp_1 = -2; GTM_SOCKLEN_TYPE size; int4 rv, msec_timeout; struct addrinfo *ai_ptr = NULL, *remote_ai_ptr = NULL, *remote_ai_head, hints; char port_buffer[NI_MAXSERV], *brack_pos; int host_len, addr_len, port_len; char msg_buffer[1024]; mstr msg_string; ABS_TIME cur_time, end_time; fd_set tcp_fd; struct sockaddr_storage peer; short retry_num; int save_errno, errlen; const char *terrptr; int errcode; boolean_t af; msg_string.len = SIZEOF(msg_buffer); msg_string.addr = msg_buffer; /* ============================= initialize structures ============================== */ if (NULL != host) { host_len = strlen(host); if ('[' == host[0]) { brack_pos = memchr(host, ']', SA_MAXLEN); if (NULL == brack_pos || (&host[1] == brack_pos)) { rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_INVADDRSPEC); return -1; } addr_len = brack_pos - &(host[1]); memcpy(addr, &host[1], addr_len); if ('\0' != *(brack_pos + 1)) { /* not allowed to have special symbols other than [ and ] */ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_INVADDRSPEC); return -1; } } else { /* IPv4 address only */ addr_len = strlen(host); if (0 == addr_len) { rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_INVADDRSPEC); return -1; } memcpy(addr, &host[0], addr_len); } addr[addr_len] = '\0'; CLIENT_HINTS(hints); port_len = 0; I2A(port_buffer, port_len, port); port_buffer[port_len]='\0'; if (0 != (errcode = getaddrinfo(addr, port_buffer, &hints, &remote_ai_head))) { RTS_ERROR_ADDRINFO(NULL, ERR_GETADDRINFO, errcode); return -1; } } /* ============================== do the connection ============================== */ if (passive) { struct timeval utimeout, save_utimeout; int lsock; af = ((GTM_IPV6_SUPPORTED && !ipv4_only) ? AF_INET6 : AF_INET); lsock = socket(af, SOCK_STREAM, IPPROTO_TCP); if (-1 == lsock) { af = AF_INET; if (-1 == (lsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP))) { save_errno = errno; errptr = (char *)STRERROR(save_errno); errlen = STRLEN(errptr); gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_SOCKINIT, 3, save_errno, errlen, errptr); assert(FALSE); return -1; } } SERVER_HINTS(hints, af); /* We can only listen on our own system */ port_len = 0; I2A(port_buffer, port_len, port); port_buffer[port_len]='\0'; if (0 != (errcode = getaddrinfo(NULL, port_buffer, &hints, &ai_ptr))) { RTS_ERROR_ADDRINFO(NULL, ERR_GETADDRINFO, errcode); return -1; } /* allow multiple connections to the same IP address */ if (-1 == setsockopt(lsock, SOL_SOCKET, SO_REUSEADDR, &on, SIZEOF(on))) { save_errno = errno; (void)close(lsock); errptr = (char *)STRERROR(save_errno); errlen = STRLEN(errptr); gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_SETSOCKOPTERR, 5, LEN_AND_LIT("SO_REUSEADDR"), save_errno, errlen, errptr); assert(FALSE); return -1; } if (-1 == bind(lsock, ai_ptr->ai_addr, ai_ptr->ai_addrlen)) { save_errno = errno; (void)close(lsock); gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("bind()"), CALLFROM, save_errno); return -1; } freeaddrinfo(ai_ptr); /* establish a queue of length MAX_CONN_PENDING for incoming connections */ if (-1 == listen(lsock, MAX_CONN_PENDING)) { save_errno = errno; (void)close(lsock); errptr = (char *)STRERROR(save_errno); errlen = STRLEN(errptr); gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_SOCKLISTEN, 0, ERR_TEXT, 2, errlen, errptr); assert(FALSE); return -1; } if (NO_M_TIMEOUT != timeout) { msec_timeout = timeout2msec(timeout); sys_get_curr_time(&cur_time); add_int_to_abs_time(&cur_time, msec_timeout, &end_time); utimeout.tv_sec = timeout; utimeout.tv_usec = 0; } assertpro(FD_SETSIZE > lsock); FD_ZERO(&tcp_fd); while (TRUE) { while (TRUE) { /* The check for EINTR below is valid and should not be converted to an EINTR wrapper macro * since it might be a timeout. */ FD_SET(lsock, &tcp_fd); save_utimeout = utimeout; rv = select(lsock + 1, (void *)&tcp_fd, (void *)0, (void *)0, (NO_M_TIMEOUT == timeout) ? (struct timeval *)0 : &utimeout); save_errno = errno; utimeout = save_utimeout; if ((0 <= rv) || (EINTR != save_errno)) break; if (NO_M_TIMEOUT != timeout) { sys_get_curr_time(&cur_time); cur_time = sub_abs_time(&end_time, &cur_time); if (0 >= (utimeout.tv_sec = cur_time.at_sec)) { rv = 0; break; } } } if (0 == rv) { (void)close(lsock); util_out_print("Listening timed out.\n", TRUE); assert(FALSE); return -1; } else if (0 > rv) { (void)close(lsock); gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("select()"), CALLFROM, save_errno); assert(FALSE); return -1; } size = SIZEOF(struct sockaddr_storage); ACCEPT_SOCKET(lsock, (struct sockaddr*)(&peer), &size, sock); if (FD_INVALID == sock) { save_errno = errno; # ifdef __hpux if (ENOBUFS == save_errno) continue; # endif (void)close(lsock); errptr = (char *)STRERROR(save_errno); errlen = STRLEN(errptr); gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_SOCKACPT, 0, ERR_TEXT, 2, errlen, errptr); assert(FALSE); return -1; } GETNAMEINFO((struct sockaddr*)(&peer), size, temp_addr, SA_MAXLEN + 1, NULL, 0, NI_NUMERICHOST, errcode); if (0 != errcode) { RTS_ERROR_ADDRINFO(NULL, ERR_GETNAMEINFO, errcode); return -1; } # ifdef DEBUG_ONLINE PRINTF("Connection is from : %s\n", &temp_addr[0]); # endif break; /* previously there is following check here * if ((0 == temp_sin_addr) || (0 == memcmp(&addr[0], &temp_addr[0], strlen(addr)))) * However, temp_sin_addr is always 0 on server side, and addr(local address) shoud not equal to * temp_addr(remote address), so the entire check should be removed */ } (void)close(lsock); } else { /* client side (connection side) */ if (NO_M_TIMEOUT != timeout)
boolean_t iosocket_wait(io_desc *iod, int4 timepar) { struct timeval utimeout; ABS_TIME cur_time, end_time; struct sockaddr_in peer; /* socket address + port */ fd_set tcp_fd; d_socket_struct *dsocketptr; socket_struct *socketptr, *newsocketptr; char *errptr; int4 errlen, ii, msec_timeout; int rv, size, max_fd; short len; error_def(ERR_SOCKACPT); error_def(ERR_SOCKWAIT); error_def(ERR_TEXT); /* check for validity */ assert(iod->type == gtmsocket); dsocketptr = (d_socket_struct *)iod->dev_sp; /* check for events */ max_fd = 0; FD_ZERO(&tcp_fd); for (ii = 0; ii < dsocketptr->n_socket; ii++) { socketptr = dsocketptr->socket[ii]; if ((socket_listening == socketptr->state) || (socket_connected == socketptr->state)) { FD_SET(socketptr->sd, &tcp_fd); max_fd = MAX(max_fd, socketptr->sd); } } utimeout.tv_sec = timepar; utimeout.tv_usec = 0; msec_timeout = timeout2msec(timepar); sys_get_curr_time(&cur_time); add_int_to_abs_time(&cur_time, msec_timeout, &end_time); for ( ; ; ) { rv = tcp_routines.aa_select(max_fd + 1, (void *)&tcp_fd, (void *)0, (void *)0, (timepar == NO_M_TIMEOUT ? (struct timeval *)0 : &utimeout)); if (0 > rv && EINTR == errno) { if (OUTOFBANDNOW(outofband)) { rv = 0; /* treat as time out */ break; } sys_get_curr_time(&cur_time); cur_time = sub_abs_time(&end_time, &cur_time); if (0 > cur_time.at_sec) { rv = 0; /* time out */ break; } utimeout.tv_sec = cur_time.at_sec; utimeout.tv_usec = cur_time.at_usec; } else break; /* either other error or done */ } if (rv == 0) { dsocketptr->dollar_key[0] = '\0'; return FALSE; } else if (rv < 0) { errptr = (char *)STRERROR(errno); errlen = strlen(errptr); rts_error(VARLSTCNT(6) ERR_SOCKWAIT, 0, ERR_TEXT, 2, errlen, errptr); return FALSE; } /* find out which socket is ready */ for (ii = 0; ii < dsocketptr->n_socket; ii++) { socketptr = dsocketptr->socket[ii]; if (0 != FD_ISSET(socketptr->sd, &tcp_fd)) break; } assert(ii < dsocketptr->n_socket); if (socket_listening == socketptr->state) { size = sizeof(struct sockaddr_in); rv = tcp_routines.aa_accept(socketptr->sd, &peer, &size); if (rv == -1) { errptr = (char *)STRERROR(errno); errlen = strlen(errptr); rts_error(VARLSTCNT(6) ERR_SOCKACPT, 0, ERR_TEXT, 2, errlen, errptr); return FALSE; } /* got the connection, create a new socket in the device socket list */ newsocketptr = (socket_struct *)malloc(sizeof(socket_struct)); *newsocketptr = *socketptr; newsocketptr->sd = rv; memcpy(&newsocketptr->remote.sin, &peer, sizeof(struct sockaddr_in)); SPRINTF(newsocketptr->remote.saddr_ip, "%s", tcp_routines.aa_inet_ntoa(peer.sin_addr)); newsocketptr->remote.port = GTM_NTOHS(peer.sin_port); newsocketptr->state = socket_connected; newsocketptr->passive = FALSE; for (ii = 0; ii < newsocketptr->n_delimiter; ii++) { newsocketptr->delimiter[ii].addr = (char *)malloc(socketptr->delimiter[ii].len); memcpy(newsocketptr->delimiter[ii].addr, socketptr->delimiter[ii].addr, socketptr->delimiter[ii].len); } newsocketptr->buffer = (char *)malloc(socketptr->buffer_size); newsocketptr->buffer_size = socketptr->buffer_size; newsocketptr->buffered_length = socketptr->buffered_offset = 0; /* put the new-born socket to the list and create a handle for it */ iosocket_handle(newsocketptr->handle, &newsocketptr->handle_len, TRUE, dsocketptr); dsocketptr->socket[dsocketptr->n_socket++] = newsocketptr; dsocketptr->current_socket = dsocketptr->n_socket - 1; len = sizeof(CONNECTED) - 1; memcpy(&dsocketptr->dollar_key[0], CONNECTED, len); dsocketptr->dollar_key[len++] = '|'; memcpy(&dsocketptr->dollar_key[len], newsocketptr->handle, newsocketptr->handle_len); len += newsocketptr->handle_len; dsocketptr->dollar_key[len++] = '|'; memcpy(&dsocketptr->dollar_key[len], newsocketptr->remote.saddr_ip, strlen(newsocketptr->remote.saddr_ip)); len += strlen(newsocketptr->remote.saddr_ip); dsocketptr->dollar_key[len] = '\0'; } else { assert(socket_connected == socketptr->state); dsocketptr->current_socket = ii; len = sizeof(READ) - 1; memcpy(&dsocketptr->dollar_key[0], READ, len); dsocketptr->dollar_key[len++] = '|'; memcpy(&dsocketptr->dollar_key[len], socketptr->handle, socketptr->handle_len); len += socketptr->handle_len; dsocketptr->dollar_key[len++] = '|'; memcpy(&dsocketptr->dollar_key[len], socketptr->remote.saddr_ip, strlen(socketptr->remote.saddr_ip)); len += strlen(socketptr->remote.saddr_ip); dsocketptr->dollar_key[len] = '\0'; } return TRUE; }
int tcp_open(char *host, unsigned short port, int4 timeout, boolean_t passive) /* host needs to be NULL terminated */ { boolean_t no_time_left = FALSE, error_given = FALSE; char temp_addr[SA_MAXLEN + 1], addr[SA_MAXLEN + 1]; char *from, *to, *errptr, *temp_ch; int match, sock, sendbufsize, size, ii, on = 1, temp_1 = -2; int4 errlen, rv, msec_timeout; struct sockaddr_in sin; in_addr_t temp_sin_addr; char msg_buffer[1024]; mstr msg_string; ABS_TIME cur_time, end_time; fd_set tcp_fd; struct sockaddr_in peer; error_def(ERR_INVADDRSPEC); temp_sin_addr = 0; msg_string.len = sizeof(msg_buffer); msg_string.addr = msg_buffer; memset((char *)&sin, 0, sizeof(struct sockaddr_in)); /* ============================= initialize structures ============================== */ if (NULL != host) { temp_ch = host; while(ISDIGIT(*temp_ch) || ('.' == *temp_ch)) temp_ch++; if ('\0' != *temp_ch) SPRINTF(addr, "%s", iotcp_name2ip(host)); else SPRINTF(addr, "%s", host); if (-1 == (temp_sin_addr = tcp_routines.aa_inet_addr(addr))) { gtm_getmsg(ERR_INVADDRSPEC, &msg_string); util_out_print(msg_string.addr, TRUE, ERR_INVADDRSPEC); return -1; } } if (passive) /* We can only listen on our own system */ sin.sin_addr.s_addr = INADDR_ANY; else { if (0 == temp_sin_addr) { /* If no address was specified */ util_out_print("An address has to be specified for an active connection.", TRUE); return -1; } /* Set where to send the connection attempt */ sin.sin_addr.s_addr = temp_sin_addr; } sin.sin_port = GTM_HTONS(port); sin.sin_family = AF_INET; /* ============================== do the connection ============================== */ if (passive) { struct timeval utimeout, save_utimeout; int lsock; lsock = tcp_routines.aa_socket(AF_INET, SOCK_STREAM, 0); if (-1 == lsock) { errptr = (char *)STRERROR(errno); errlen = strlen(errptr); util_out_print(errptr, TRUE, errno); return -1; } /* allow multiple connections to the same IP address */ if (-1 == tcp_routines.aa_setsockopt(lsock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on))) { errptr = (char *)STRERROR(errno); errlen = strlen(errptr); (void)tcp_routines.aa_close(lsock); util_out_print(errptr, TRUE, errno); return -1; } if (-1 == tcp_routines.aa_bind(lsock, (struct sockaddr *)&sin, sizeof(struct sockaddr))) { errptr = (char *)STRERROR(errno); errlen = strlen(errptr); (void)tcp_routines.aa_close(lsock); util_out_print(errptr, TRUE, errno); return -1; } /* establish a queue of length MAX_CONN_PENDING for incoming connections */ if (-1 == tcp_routines.aa_listen(lsock, MAX_CONN_PENDING)) { errptr = (char *)STRERROR(errno); errlen = strlen(errptr); (void)tcp_routines.aa_close(lsock); util_out_print(errptr, TRUE, errno); return -1; } if (NO_M_TIMEOUT != timeout) { msec_timeout = timeout2msec(timeout); sys_get_curr_time(&cur_time); add_int_to_abs_time(&cur_time, msec_timeout, &end_time); utimeout.tv_sec = timeout; utimeout.tv_usec = 0; } while(1) { while(1) { /* * the check for EINTR below is valid and should not be converted to an EINTR * wrapper macro, since it might be a timeout. */ FD_ZERO(&tcp_fd); FD_SET(lsock, &tcp_fd); save_utimeout = utimeout; rv = tcp_routines.aa_select(lsock + 1, (void *)&tcp_fd, (void *)0, (void *)0, (NO_M_TIMEOUT == timeout) ? (struct timeval *)0 : &utimeout); utimeout = save_utimeout; if ((0 <= rv) || (EINTR != errno)) break; if (NO_M_TIMEOUT != timeout) { sys_get_curr_time(&cur_time); cur_time = sub_abs_time(&end_time, &cur_time); if (0 >= (utimeout.tv_sec = cur_time.at_sec)) { rv = 0; break; } } } if (0 == rv) { util_out_print("Listening timed out.\n", TRUE); (void)tcp_routines.aa_close(lsock); return -1; } else if (0 > rv) { errptr = (char *)STRERROR(errno); errlen = strlen(errptr); util_out_print(errptr, TRUE, errno); (void)tcp_routines.aa_close(lsock); return -1; } size = sizeof(struct sockaddr_in); sock = tcp_routines.aa_accept(lsock, &peer, &size); if (-1 == sock) { errptr = (char *)STRERROR(errno); errlen = strlen(errptr); util_out_print(errptr, TRUE, errno); (void)tcp_routines.aa_close(lsock); return -1; } SPRINTF(&temp_addr[0], "%s", tcp_routines.aa_inet_ntoa(peer.sin_addr)); #ifdef DEBUG_ONLINE PRINTF("Connection is from : %s\n", &temp_addr[0]); #endif /* Check if connection is from whom we want it to be from. Note that this is not a robust check (potential for multiple IP addrs for a resolved name but workarounds for this exist so not a lot of effort has been expended here at this time. Especially since the check is easily spoofed with raw sockets anyway. It is more for the accidental "oops" type check than serious security.. */ if ((0 == temp_sin_addr) || (0 == memcmp(&addr[0], &temp_addr[0], strlen(addr)))) break; else { /* Connection not from expected host */ (void)tcp_routines.aa_close(sock); if (NO_M_TIMEOUT != timeout) { sys_get_curr_time(&cur_time); cur_time = sub_abs_time(&end_time, &cur_time); utimeout.tv_sec = ((cur_time.at_sec > 0) ? cur_time.at_sec : 0); } if (!error_given) { util_out_print("Connection from !AD rejected and ignored", TRUE, LEN_AND_STR(&temp_addr[0])); error_given = TRUE; } } } (void)tcp_routines.aa_close(lsock); } else { if (NO_M_TIMEOUT != timeout) { msec_timeout = timeout2msec(timeout); sys_get_curr_time(&cur_time); add_int_to_abs_time(&cur_time, msec_timeout, &end_time); } no_time_left = FALSE; temp_1 = 1; do { if (1 != temp_1) tcp_routines.aa_close(sock); sock = tcp_routines.aa_socket(AF_INET, SOCK_STREAM, 0); if (-1 == sock) { errptr = (char *)STRERROR(errno); errlen = strlen(errptr); util_out_print(errptr, TRUE, errno); return -1; } /* allow multiple connections to the same IP address */ if (-1 == tcp_routines.aa_setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on))) { (void)tcp_routines.aa_close(sock); errptr = (char *)STRERROR(errno); errlen = strlen(errptr); util_out_print(errptr, TRUE, errno); return -1; } temp_1 = tcp_routines.aa_connect(sock, (struct sockaddr *)(&sin), sizeof(sin)); /* * the check for EINTR below is valid and should not be converted to an EINTR * wrapper macro, because other error conditions are checked, and a retry is not * immediately performed. */ if ((0 > temp_1) && (ECONNREFUSED != errno) && (EINTR != errno)) { (void)tcp_routines.aa_close(sock); errptr = (char *)STRERROR(errno); errlen = strlen(errptr); util_out_print(errptr, TRUE, errno); return -1; } if ((0 > temp_1) && (EINTR == errno)) { (void)tcp_routines.aa_close(sock); util_out_print("Interrupted.", TRUE); return -1; } if ((temp_1 < 0) && (NO_M_TIMEOUT != timeout)) { sys_get_curr_time(&cur_time); cur_time = sub_abs_time(&end_time, &cur_time); if (cur_time.at_sec <= 0) no_time_left = TRUE; } SHORT_SLEEP(NAP_LENGTH); /* Sleep for NAP_LENGTH ms */ } while ((FALSE == no_time_left) && (0 > temp_1)); if (0 > temp_1) /* out of time */ { tcp_routines.aa_close(sock); util_out_print("Connection timed out.", TRUE); return -1; } } return sock; }
boolean_t iosocket_bind(socket_struct *socketptr, int4 timepar, boolean_t update_bufsiz) { int temp_1 = 1; char *errptr; int4 errlen, msec_timeout, real_errno; short len; in_port_t actual_port; boolean_t no_time_left = FALSE; d_socket_struct *dsocketptr; struct addrinfo *ai_ptr; char port_buffer[NI_MAXSERV]; int errcode; ABS_TIME cur_time, end_time; GTM_SOCKLEN_TYPE addrlen; GTM_SOCKLEN_TYPE sockbuflen; dsocketptr = socketptr->dev; ai_ptr = (struct addrinfo*)(&socketptr->local.ai); assert(NULL != dsocketptr); dsocketptr->iod->dollar.key[0] = '\0'; if (FD_INVALID != socketptr->temp_sd) { socketptr->sd = socketptr->temp_sd; socketptr->temp_sd = FD_INVALID; } if (timepar != NO_M_TIMEOUT) { msec_timeout = timeout2msec(timepar); sys_get_curr_time(&cur_time); add_int_to_abs_time(&cur_time, msec_timeout, &end_time); } do { temp_1 = 1; if (-1 == tcp_routines.aa_setsockopt(socketptr->sd, SOL_SOCKET, SO_REUSEADDR, &temp_1, SIZEOF(temp_1))) { real_errno = errno; errptr = (char *)STRERROR(real_errno); errlen = STRLEN(errptr); SOCKET_FREE(socketptr); rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_SETSOCKOPTERR, 5, RTS_ERROR_LITERAL("SO_REUSEADDR"), real_errno, errlen, errptr); return FALSE; } #ifdef TCP_NODELAY temp_1 = socketptr->nodelay ? 1 : 0; if (-1 == tcp_routines.aa_setsockopt(socketptr->sd, IPPROTO_TCP, TCP_NODELAY, &temp_1, SIZEOF(temp_1))) { real_errno = errno; errptr = (char *)STRERROR(real_errno); errlen = STRLEN(errptr); SOCKET_FREE(socketptr); rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_SETSOCKOPTERR, 5, RTS_ERROR_LITERAL("TCP_NODELAY"), real_errno, errlen, errptr); return FALSE; } #endif if (update_bufsiz) { if (-1 == tcp_routines.aa_setsockopt(socketptr->sd, SOL_SOCKET, SO_RCVBUF, &socketptr->bufsiz, SIZEOF(socketptr->bufsiz))) { real_errno = errno; errptr = (char *)STRERROR(real_errno); errlen = STRLEN(errptr); SOCKET_FREE(socketptr); rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_SETSOCKOPTERR, 5, RTS_ERROR_LITERAL("SO_RCVBUF"), real_errno, errlen, errptr); return FALSE; } } else { sockbuflen = SIZEOF(socketptr->bufsiz); if (-1 == tcp_routines.aa_getsockopt(socketptr->sd, SOL_SOCKET, SO_RCVBUF, &socketptr->bufsiz, &sockbuflen)) { real_errno = errno; errptr = (char *)STRERROR(real_errno); errlen = STRLEN(errptr); SOCKET_FREE(socketptr); rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_GETSOCKOPTERR, 5, RTS_ERROR_LITERAL("SO_RCVBUF"), real_errno, errlen, errptr); return FALSE; } } temp_1 = tcp_routines.aa_bind(socketptr->sd, SOCKET_LOCAL_ADDR(socketptr), ai_ptr->ai_addrlen); if (temp_1 < 0) { real_errno = errno; no_time_left = TRUE; switch (real_errno) { case EADDRINUSE: if (NO_M_TIMEOUT != timepar) { sys_get_curr_time(&cur_time); cur_time = sub_abs_time(&end_time, &cur_time); if (cur_time.at_sec > 0) no_time_left = FALSE; } break; case EINTR: break; default: SOCKET_FREE(socketptr); rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_SOCKBIND, 0, real_errno, 0); break; } if (no_time_left) return FALSE; hiber_start(100); tcp_routines.aa_close(socketptr->sd); if (-1 == (socketptr->sd = tcp_routines.aa_socket(ai_ptr->ai_family,ai_ptr->ai_socktype, ai_ptr->ai_protocol))) { real_errno = errno; errptr = (char *)STRERROR(real_errno); errlen = STRLEN(errptr); SOCKET_FREE(socketptr); rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_SOCKINIT, 3, real_errno, errlen, errptr); return FALSE; } } } while (temp_1 < 0); /* obtain actual port from the bound address if port 0 was specified */ addrlen = SOCKET_ADDRLEN(socketptr, ai_ptr, local); if (-1 == tcp_routines.aa_getsockname(socketptr->sd, SOCKET_LOCAL_ADDR(socketptr), &addrlen)) { real_errno = errno; errptr = (char *)STRERROR(real_errno); errlen = STRLEN(errptr); rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_GETSOCKNAMERR, 3, real_errno, errlen, errptr); return FALSE; } assert(ai_ptr->ai_addrlen == addrlen); GETNAMEINFO(SOCKET_LOCAL_ADDR(socketptr), addrlen, NULL, 0, port_buffer, NI_MAXSERV, NI_NUMERICSERV, errcode); if (0 != errcode) { SOCKET_FREE(socketptr); RTS_ERROR_ADDRINFO(NULL, ERR_GETNAMEINFO, errcode); return FALSE; } actual_port = ATOI(port_buffer); if (0 == socketptr->local.port) socketptr->local.port = actual_port; assert(socketptr->local.port == actual_port); socketptr->state = socket_bound; len = SIZEOF(BOUND) - 1; memcpy(&dsocketptr->iod->dollar.key[0], BOUND, len); dsocketptr->iod->dollar.key[len++] = '|'; memcpy(&dsocketptr->iod->dollar.key[len], socketptr->handle, socketptr->handle_len); len += socketptr->handle_len; dsocketptr->iod->dollar.key[len++] = '|'; SPRINTF(&dsocketptr->iod->dollar.key[len], "%d", socketptr->local.port); return TRUE; }
/* Timer handler. This is the main handler routine that is being called by the kernel upon receipt * of timer signal. It dispatches to the user handler routine, and removes first timer in a timer * queue. If the queue is not empty, it starts the first timer in the queue. The why parameter is a * no-op in our case, but is required to maintain compatibility with the system type of __sighandler_t, * which is (void*)(int). */ STATICFNDEF void timer_handler(int why) { int4 cmp; GT_TIMER *tpop, *tpop_prev = NULL; ABS_TIME at; sigset_t savemask; int save_errno, timer_defer_cnt, offset; TID *deferred_tid; boolean_t tid_found; char *save_util_outptr; va_list save_last_va_list_ptr; boolean_t util_copy_saved = FALSE; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; # ifdef DEBUG if (IS_GTM_IMAGE) { tpop = find_timer((TID)heartbeat_timer_ptr, &tpop); assert(process_exiting || (((NULL != tpop) && heartbeat_started) || ((NULL == tpop) && !heartbeat_started))); } # endif if (0 < timer_stack_count) return; timer_stack_count++; deferred_timers_check_needed = FALSE; save_errno = errno; timer_active = FALSE; /* timer has popped; system timer not active anymore */ sys_get_curr_time(&at); tpop = (GT_TIMER *)timeroot; timer_defer_cnt = 0; /* reset the deferred timer count, since we are in timer_handler */ SAVE_UTIL_OUT_BUFFER(save_util_outptr, save_last_va_list_ptr, util_copy_saved); while (tpop) /* fire all handlers that expired */ { cmp = abs_time_comp(&at, (ABS_TIME *)&tpop->expir_time); if (cmp < 0) break; /* A timer might pop while we are in the non-zero intrpt_ok_state zone, which could cause collisions. Instead, * we will defer timer events and drive them once the deferral is removed, unless the timer is safe. */ if ((INTRPT_OK_TO_INTERRUPT == intrpt_ok_state) && (FALSE == process_exiting) || tpop->safe) { if (NULL != tpop_prev) tpop_prev->next = tpop->next; else timeroot = tpop->next; if (tpop->safe) { safe_timer_cnt--; assert(0 <= safe_timer_cnt); } if (NULL != tpop->handler) /* if there is a handler, call it */ { # ifdef DEBUG if (gtm_white_box_test_case_enabled && (WBTEST_DEFERRED_TIMERS == gtm_white_box_test_case_number) && ((void *)tpop->handler != (void*)heartbeat_timer_ptr)) { DBGFPF((stderr, "TIMER_HANDLER: handled a timer\n")); timer_pop_cnt++; } # endif timer_in_handler = TRUE; (*tpop->handler)(tpop->tid, tpop->hd_len, tpop->hd_data); timer_in_handler = FALSE; if (!tpop->safe) /* if safe, avoid a system call */ sys_get_curr_time(&at); /* refresh current time if called a handler */ } tpop->next = (GT_TIMER *)timefree; /* put timer block on the free chain */ timefree = tpop; if (NULL != tpop_prev) tpop = tpop_prev->next; else tpop = (GT_TIMER *)timeroot; num_timers_free++; assert(0 < num_timers_free); } else { timer_defer_cnt++; # ifdef DEBUG if (gtm_white_box_test_case_enabled && (WBTEST_DEFERRED_TIMERS == gtm_white_box_test_case_number)) { if (!deferred_tids) { deferred_tids = (TID *)malloc(SIZEOF(TID) * 2); *deferred_tids = tpop->tid; *(deferred_tids + 1) = -1; DBGFPF((stderr, "TIMER_HANDLER: deferred a timer\n")); } else { tid_found = FALSE; deferred_tid = deferred_tids; while (-1 != *deferred_tid) { if (*deferred_tid == tpop->tid) { tid_found = TRUE; break; } deferred_tid++; } if (!tid_found) { offset = deferred_tid - deferred_tids; deferred_tid = (TID *)malloc((offset + 2) * SIZEOF(TID)); memcpy(deferred_tid, deferred_tids, offset * SIZEOF(TID)); free(deferred_tids); deferred_tids = deferred_tid; *(deferred_tids + offset++) = tpop->tid; *(deferred_tids + offset) = -1; DBGFPF((stderr, "TIMER_HANDLER: deferred a timer\n")); } } } # endif tpop_prev = tpop; tpop = tpop->next; if (0 == safe_timer_cnt) /* no more safe timers left, so quit */ break; } } RESTORE_UTIL_OUT_BUFFER(save_util_outptr, save_last_va_list_ptr, util_copy_saved); if (((FALSE == process_exiting) && (INTRPT_OK_TO_INTERRUPT == intrpt_ok_state)) || (0 < safe_timer_cnt)) start_first_timer(&at); else if ((NULL != timeroot) || (0 < timer_defer_cnt)) deferred_timers_check_needed = TRUE; errno = save_errno; /* restore mainline errno */ timer_stack_count--; }
int iotcp_readfl(mval *v, int4 width, int4 timeout) /* 0 == width is a flag that the caller is read and the length is not actually fixed */ /* timeout in seconds */ { /* VMS uses the UCX interface; should support others that emulate it */ boolean_t ret, timed, vari; int flags, len, real_errno, save_errno; int i; io_desc *io_ptr; d_tcp_struct *tcpptr; int4 status; int4 msec_timeout; /* timeout in milliseconds */ TID timer_id; ABS_TIME cur_time, end_time, time_for_read, lcl_time_for_read, zero; fd_set tcp_fd; char *errptr; int4 errlen; error_def(ERR_IOEOF); error_def(ERR_TEXT); error_def(ERR_GETSOCKOPTERR); error_def(ERR_SETSOCKOPTERR); #ifdef DEBUG_TCP PRINTF("%s >>>\n", __FILE__); #endif assert(stringpool.free >= stringpool.base); assert(stringpool.free <= stringpool.top); if (0 == width) { /* op_readfl won't do this; must be a call from iotcp_read */ vari = TRUE; width = MAX_READLEN; } else { vari = FALSE; width = (width < MAX_READLEN) ? width : MAX_READLEN; } if (stringpool.free + width > stringpool.top) stp_gcol(width); io_ptr = io_curr_device.in; assert(dev_open == io_ptr->state); tcpptr = (d_tcp_struct *)(io_ptr->dev_sp); if (io_ptr->dollar.x && (TCP_WRITE == tcpptr->lastop)) { /* switching from write to read */ #ifdef C9A06001531 /* pending change request C9A06-001531 */ if (!io_ptr->dollar.za) iotcp_wteol(1, io_ptr); #endif io_ptr->dollar.x = 0; } tcpptr->lastop = TCP_READ; ret = TRUE; timer_id = (TID)iotcp_readfl; out_of_time = FALSE; time_for_read.at_sec = ((0 == timeout) ? 0 : 1); time_for_read.at_usec = 0; if (NO_M_TIMEOUT == timeout) { timed = FALSE; msec_timeout = NO_M_TIMEOUT; } else { timed = TRUE; msec_timeout = timeout2msec(timeout); if (msec_timeout > 0) { /* there is time to wait */ #ifdef UNIX /* set blocking I/O */ FCNTL2(tcpptr->socket, F_GETFL, flags); if (flags < 0) { save_errno = errno; errptr = (char *)STRERROR(errno); rts_error(VARLSTCNT(7) ERR_GETSOCKOPTERR, 5, LEN_AND_LIT("F_GETFL FOR NON BLOCKING I/O"), save_errno, LEN_AND_STR(errptr)); } FCNTL3(tcpptr->socket, F_SETFL, flags & (~(O_NDELAY | O_NONBLOCK)), fcntl_res); if (fcntl_res < 0) { save_errno = errno; errptr = (char *)STRERROR(errno); rts_error(VARLSTCNT(7) ERR_SETSOCKOPTERR, 5, LEN_AND_LIT("F_SETFL FOR NON BLOCKING I/O"), save_errno, LEN_AND_STR(errptr)); } #endif sys_get_curr_time(&cur_time); add_int_to_abs_time(&cur_time, msec_timeout, &end_time); start_timer(timer_id, msec_timeout, wake_alarm, 0, NULL); } else out_of_time = TRUE; } for (i = 0, status = 0; status >= 0; ) { FD_ZERO(&tcp_fd); FD_SET(tcpptr->socket, &tcp_fd); assert(0 != FD_ISSET(tcpptr->socket, &tcp_fd)); assert(((1 == time_for_read.at_sec) || (0 == time_for_read.at_sec)) && (0 == time_for_read.at_usec)); /* * the check for EINTR below is valid and should not be converted to an EINTR * wrapper macro, since it might be a timeout. */ lcl_time_for_read = time_for_read; status = tcp_routines.aa_select(tcpptr->socket + 1, (void *)(&tcp_fd), (void *)0, (void *)0, &lcl_time_for_read); if (status > 0) { status = tcp_routines.aa_recv(tcpptr->socket, (char *)(stringpool.free + i), width - i, 0); if ((0 == status) || ((-1 == status) && (ECONNRESET == errno || EPIPE == errno || EINVAL == errno))) { /* lost connection. */ if (0 == status) errno = ECONNRESET; real_errno = errno; status = -2; break; } } if (status < 0) { if (EINTR == errno && FALSE == out_of_time) { /* interrupted by a signal which is not OUR timer, continue looping */ status = 0; } else real_errno = errno; } else real_errno = 0; if (outofband) break; if (timed) { if (msec_timeout > 0) { sys_get_curr_time(&cur_time); cur_time = sub_abs_time(&end_time, &cur_time); if (cur_time.at_sec <= 0) { out_of_time = TRUE; cancel_timer(timer_id); if (status > 0) i += status; break; } } else { if (status > 0) i += status; break; } } if (0 > status) break; i += status; if ((vari && (0 != i)) || (i >= width)) break; } if (EINTR == real_errno) status = 0; /* don't treat a <CTRL-C> or timeout as an error */ if (timed) { if (0 == msec_timeout) { if (0 == status) ret = FALSE; } else { #ifdef UNIX real_errno = errno; FCNTL3(tcpptr->socket, F_SETFL, flags, fcntl_res); if (fcntl_res < 0) { save_errno = errno; errptr = (char *)STRERROR(errno); rts_error(VARLSTCNT(7) ERR_SETSOCKOPTERR, 5, LEN_AND_LIT("F_SETFL FOR RESTORING SOCKET OPTIONS"), save_errno, LEN_AND_STR(errptr)); } errno = real_errno; #endif if (out_of_time && (i < width)) ret = FALSE; else cancel_timer(timer_id); } } if (i > 0) { /* there's somthing to return */ v->str.len = i; v->str.addr = (char *)stringpool.free; if (((io_ptr->dollar.x += i) >= io_ptr->width) && (TRUE == io_ptr->wrap)) { io_ptr->dollar.y += (io_ptr->dollar.x / io_ptr->width); if (0 != io_ptr->length) io_ptr->dollar.y %= io_ptr->length; io_ptr->dollar.x %= io_ptr->width; } } else v->str.len = 0; #ifdef DEBUG_TCP PRINTF("%s <<<\n", __FILE__); #endif len = sizeof("1,") - 1; if (status >= 0) { /* no real problems */ io_ptr->dollar.za = 0; /* the handling of urgent data doesn't work and never has, the design should be changed to use a /URGENT controlnmemonic * because there is really only one character available at a time zero.at_sec = zero.at_usec = 0; FD_ZERO(&tcp_fd); FD_SET(tcpptr->socket, &tcp_fd); if (tcp_routines.aa_select(tcpptr->socket + 1, (void *)(tcpptr->urgent ? &tcp_fd : 0), (void *)0, (void *)(tcpptr->urgent ? 0 : &tcp_fd), &zero) > 0) { memcpy(tcpptr->dollar_device, "1,", len); if (tcpptr->urgent) { memcpy(&tcpptr->dollar_device[len], "No ",sizeof("No ")); len += sizeof("No ") - 1; } memcpy(&tcpptr->dollar_device[len], "Urgent Data", sizeof("Urgent Data")); } else */ memcpy(tcpptr->dollar_device, "0", sizeof("0")); } else { /* there's a significant problem */ if (0 == i) io_ptr->dollar.x = 0; io_ptr->dollar.za = 9; memcpy(tcpptr->dollar_device, "1,", len); errptr = (char *)STRERROR(errno); errlen = STRLEN(errptr); memcpy(&tcpptr->dollar_device[len], errptr, errlen); if (io_ptr->dollar.zeof || -1 == status || 0 < io_ptr->error_handler.len) { io_ptr->dollar.zeof = TRUE; rts_error(VARLSTCNT(6) ERR_IOEOF, 0, ERR_TEXT, 2, errlen, errptr); } else io_ptr->dollar.zeof = TRUE; } return (ret); }