void iott_close(io_desc *v, mval *pp) { d_tt_struct *ttptr; params ch; int status; int p_offset; boolean_t ch_set; assert(v->type == tt); if (v->state != dev_open) return; ESTABLISH_GTMIO_CH(&v->pair, ch_set); iott_flush(v); if (v->pair.in != v) assert(v->pair.out == v); ttptr = (d_tt_struct *)v->dev_sp; if (v->pair.out != v) assert(v->pair.in == v); v->state = dev_closed; resetterm(v); p_offset = 0; while (*(pp->str.addr + p_offset) != iop_eol) { if ((ch = *(pp->str.addr + p_offset++)) == iop_exception) { v->error_handler.len = *(pp->str.addr + p_offset); v->error_handler.addr = (char *)(pp->str.addr + p_offset + 1); s2pool(&v->error_handler); } p_offset += ((IOP_VAR_SIZE == io_params_size[ch]) ? (unsigned char)*(pp->str.addr + p_offset) + 1 : io_params_size[ch]); } if (v == io_std_device.in || (v == io_std_device.out)) { REVERT_GTMIO_CH(&v->pair, ch_set); return; } CLOSEFILE_RESET(ttptr->fildes, status); /* resets "ttptr->fildes" to FD_INVALID */ if (0 != status) { assert(status == errno); rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("iott_close(CLOSEFILE)"), CALLFROM, status); } if (ttptr->recall_buff.addr) { free(ttptr->recall_buff.addr); ttptr->recall_buff.addr = NULL; } REVERT_GTMIO_CH(&v->pair, ch_set); return; }
/* write ASCII characters converting to UTF16 if needed * returns bytes written */ int iorm_write_utf_ascii(io_desc *iod, char *string, int len) { int outlen, mblen, status; wint_t utf_code; unsigned char *outstart, *out, *top, *outptr, *nextoutptr, *outptrtop, *nextmb; d_rm_struct *rm_ptr; boolean_t ch_set; ESTABLISH_RET_GTMIO_CH(&iod->pair, -1, ch_set); rm_ptr = (d_rm_struct *)iod->dev_sp; assert(NULL != rm_ptr); if (CHSET_UTF8 != iod->ochset) { outstart = outptr = &rm_ptr->outbuf[rm_ptr->out_bytes]; outptrtop = rm_ptr->outbuf + rm_ptr->recordsize; /* buffer is larger than recordsize to allow for EOL */ assert(len <= (&rm_ptr->outbuf[rm_ptr->outbufsize] - outstart)); for (out = (unsigned char*)string, top = out + len, outlen = 0; out < top && outptr <= outptrtop; out = nextmb, outptr = nextoutptr) { nextmb = UTF8_MBTOWC(out, top, utf_code); assert(nextmb == (out + 1)); if (WEOF == utf_code) { iod->dollar.za = 9; UTF8_BADCHAR((int)(nextmb - out), out, top, 0, NULL); } if (CHSET_UTF16BE == iod->ochset) nextoutptr = UTF16BE_WCTOMB(utf_code, outptr); else nextoutptr = UTF16LE_WCTOMB(utf_code, outptr); if (nextoutptr == outptr) { /* invalid codepoint */ iod->dollar.za = 9; UTF8_BADCHAR((int)(nextmb - out), out, top, chset_names[iod->ochset].len, chset_names[iod->ochset].addr); } mblen = (int)(nextoutptr - outptr); outlen += mblen; } } else { outstart = (unsigned char *)string; outlen = len; } if (0 < outlen) { if (rm_ptr->output_encrypted) { REALLOC_CRYPTBUF_IF_NEEDED(outlen); WRITE_ENCRYPTED_DATA(rm_ptr, iod->trans_name, outstart, outlen, pvt_crypt_buf.addr); outptr = (unsigned char *)pvt_crypt_buf.addr; } else outptr = outstart; DOWRITERC_RM(rm_ptr, outptr, outlen, status); ISSUE_NOPRINCIO_IF_NEEDED_RM(status, ==, iod); rm_ptr->write_occurred = TRUE; rm_ptr->out_bytes += outlen; } REVERT_GTMIO_CH(&iod->pair, ch_set); return outlen; }
void iott_use(io_desc *iod, mval *pp) { boolean_t flush_input; char dc1, *ttab; d_tt_struct *temp_ptr, *tt_ptr; int p_offset, fil_type, save_errno, status; int4 length, width; io_desc *d_in, *d_out; io_termmask mask_term; struct sigaction act; struct termios t; uint4 mask_in; unsigned char ch, len; boolean_t ch_set; p_offset = 0; assert(iod->state == dev_open); ESTABLISH_GTMIO_CH(&iod->pair, ch_set); iott_flush(iod); tt_ptr = (d_tt_struct *)iod->dev_sp; if (*(pp->str.addr + p_offset) != iop_eol) { if (tt_ptr->mupintr) if (dollar_zininterrupt) rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_ZINTRECURSEIO); else { /* The interrupted read was not properly resumed so clear it now */ tt_ptr->mupintr = FALSE; tt_ptr->tt_state_save.who_saved = ttwhichinvalid; io_find_mvstent(iod, TRUE); } status = tcgetattr(tt_ptr->fildes, &t); if (0 != status) { save_errno = errno; ISSUE_NOPRINCIO_IF_NEEDED_TT(io_curr_device.out); rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_TCGETATTR, 1, tt_ptr->fildes, save_errno); } flush_input = FALSE; d_in = iod->pair.in; d_out = iod->pair.out; temp_ptr = (d_tt_struct *)d_in->dev_sp; mask_in = temp_ptr->term_ctrl; mask_term = temp_ptr->mask_term; while (*(pp->str.addr + p_offset) != iop_eol) { switch (ch = *(pp->str.addr + p_offset++)) { case iop_canonical: tt_ptr->canonical = TRUE; t.c_lflag |= ICANON; break; case iop_nocanonical: tt_ptr->canonical = FALSE; t.c_lflag &= ~(ICANON); break; case iop_empterm: tt_ptr->ext_cap |= TT_EMPTERM; break; case iop_noempterm: tt_ptr->ext_cap &= ~TT_EMPTERM; break; case iop_cenable: if (!ctrlc_on) { /* if it's already cenable, no need to change */ temp_ptr = (d_tt_struct *)io_std_device.in->dev_sp; if (tt_ptr->fildes == temp_ptr->fildes) { /* if this is $PRINCIPAL make sure the ctrlc_handler is enabled */ sigemptyset(&act.sa_mask); act.sa_flags = 0; act.sa_handler = ctrlc_handler_ptr; sigaction(SIGINT, &act, 0); ctrlc_on = TRUE; } } break; case iop_nocenable: if (ctrlc_on) { /* if it's already nocenable, no need to change */ temp_ptr = (d_tt_struct *)io_std_device.in->dev_sp; if (tt_ptr->fildes == temp_ptr->fildes) { /* if this is $PRINCIPAL may disable the ctrlc_handler */ if (0 == (CTRLC_MSK & tt_ptr->enbld_outofbands.mask)) { /* but only if ctrap=$c(3) is not active */ sigemptyset(&act.sa_mask); act.sa_flags = 0; act.sa_handler = SIG_IGN; sigaction(SIGINT, &act, 0); } ctrlc_on = FALSE; } } break; case iop_clearscreen: if (NULL != CLR_EOS) gtm_tputs(CLR_EOS, 1, outc); break; case iop_convert: mask_in |= TRM_CONVERT; break; case iop_noconvert: mask_in &= ~TRM_CONVERT; break; case iop_ctrap: GET_LONG(tt_ptr->enbld_outofbands.mask, pp->str.addr + p_offset); if (!ctrlc_on) { /* if cenable, ctrlc_handler active anyway, otherwise, depends on ctrap=$c(3) */ sigemptyset(&act.sa_mask); act.sa_flags = 0; act.sa_handler = (CTRLC_MSK & tt_ptr->enbld_outofbands.mask) ? ctrlc_handler_ptr : SIG_IGN; sigaction(SIGINT, &act, 0); } break; case iop_downscroll: if (d_out->dollar.y > 0) { d_out->dollar.y--; if (NULL != CURSOR_ADDRESS) gtm_tputs(gtm_tparm(CURSOR_ADDRESS, d_out->dollar.y, d_out->dollar.x), 1, outc); } break; case iop_echo: mask_in &= (~TRM_NOECHO); break; case iop_noecho: mask_in |= TRM_NOECHO; break; case iop_editing: if (io_curr_device.in == io_std_device.in) { /* $PRINCIPAL only */ tt_ptr->ext_cap |= TT_EDITING; if (!tt_ptr->recall_buff.addr) { assert(tt_ptr->in_buf_sz); tt_ptr->recall_buff.addr = malloc(tt_ptr->in_buf_sz); tt_ptr->recall_size = tt_ptr->in_buf_sz; tt_ptr->recall_buff.len = 0; /* nothing in buffer */ } } break; case iop_noediting: if (io_curr_device.in == io_std_device.in) tt_ptr->ext_cap &= ~TT_EDITING; /* $PRINCIPAL only */ break; case iop_escape: mask_in |= TRM_ESCAPE; break; case iop_noescape: mask_in &= (~TRM_ESCAPE); default: break; case iop_eraseline: if (NULL != CLR_EOL) gtm_tputs(CLR_EOL, 1, outc); break; case iop_exception: iod->error_handler.len = *(pp->str.addr + p_offset); iod->error_handler.addr = (char *)(pp->str.addr + p_offset + 1); s2pool(&iod->error_handler); break; case iop_filter: len = *(pp->str.addr + p_offset); ttab = pp->str.addr + p_offset + 1; if ((fil_type = namelook(filter_index, filter_names, ttab, len)) < 0) { rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_TTINVFILTER); return; } switch (fil_type) { case 0: iod->write_filter |= CHAR_FILTER; break; case 1: iod->write_filter |= ESC1; break; case 2: iod->write_filter &= ~CHAR_FILTER; break; case 3: iod->write_filter &= ~ESC1; break; } break; case iop_nofilter: iod->write_filter = 0; break; case iop_flush: flush_input = TRUE; break; case iop_hostsync: t.c_iflag |= IXOFF; break; case iop_nohostsync: t.c_iflag &= ~IXOFF; break; case iop_insert: if (io_curr_device.in == io_std_device.in) tt_ptr->ext_cap &= ~TT_NOINSERT; /* $PRINCIPAL only */ break; case iop_noinsert: if (io_curr_device.in == io_std_device.in) tt_ptr->ext_cap |= TT_NOINSERT; /* $PRINCIPAL only */ break; case iop_length: GET_LONG(length, pp->str.addr + p_offset); if (0 > length) rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_DEVPARMNEG); d_out->length = length; break; case iop_pasthru: mask_in |= TRM_PASTHRU; break; case iop_nopasthru: mask_in &= (~TRM_PASTHRU); break; case iop_readsync: mask_in |= TRM_READSYNC; break; case iop_noreadsync: dc1 = (char)17; temp_ptr = (d_tt_struct *)io_std_device.in->dev_sp; DOWRITERC(temp_ptr->fildes, &dc1, 1, status); if (0 != status) rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) status); mask_in &= (~TRM_READSYNC); break; case iop_terminator: memcpy(&mask_term.mask[0], (pp->str.addr + p_offset), SIZEOF(io_termmask)); temp_ptr = (d_tt_struct *)d_in->dev_sp; if (mask_term.mask[0] == NUL && mask_term.mask[1] == NUL && mask_term.mask[2] == NUL && mask_term.mask[3] == NUL && mask_term.mask[4] == NUL && mask_term.mask[5] == NUL && mask_term.mask[6] == NUL && mask_term.mask[7] == NUL) { temp_ptr->default_mask_term = TRUE; if (CHSET_UTF8 == d_in->ichset) { mask_term.mask[0] = TERM_MSK_UTF8_0; mask_term.mask[4] = TERM_MSK_UTF8_4; } else mask_term.mask[0] = TERM_MSK; } else temp_ptr->default_mask_term = FALSE; break; case iop_noterminator: temp_ptr = (d_tt_struct *)d_in->dev_sp; temp_ptr->default_mask_term = FALSE; memset(&mask_term.mask[0], 0, SIZEOF(io_termmask)); break; case iop_ttsync: t.c_iflag |= IXON; break; case iop_nottsync: t.c_iflag &= ~IXON; break; case iop_typeahead: mask_in &= (~TRM_NOTYPEAHD); break; case iop_notypeahead: mask_in |= TRM_NOTYPEAHD; break; case iop_upscroll: d_out->dollar.y++; if (d_out->length) d_out->dollar.y %= d_out->length; if (NULL != CURSOR_ADDRESS) gtm_tputs(gtm_tparm(CURSOR_ADDRESS, d_out->dollar.y, d_out->dollar.x), 1, outc); break; case iop_width: GET_LONG(width, pp->str.addr + p_offset); if (0 > width) rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_DEVPARMNEG); /* Do not allow a WIDTH of 1 if UTF mode (ICHSET or OCHSET is not M) */ if ((1 == width) && ((CHSET_M != d_in->ochset) || (CHSET_M != d_in->ichset))) rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_WIDTHTOOSMALL); if (0 == width) { d_out->wrap = FALSE; d_out->width = TTDEF_PG_WIDTH; } else { d_out->width = width; d_out->wrap = TRUE; } break; case iop_wrap: d_out->wrap = TRUE; break; case iop_nowrap: d_out->wrap = FALSE; break; case iop_x: GET_LONG(d_out->dollar.x, pp->str.addr + p_offset); if (0 > (int4)d_out->dollar.x) d_out->dollar.x = 0; if (d_out->dollar.x > d_out->width && d_out->wrap) { d_out->dollar.y += (d_out->dollar.x / d_out->width); if (d_out->length) d_out->dollar.y %= d_out->length; d_out->dollar.x %= d_out->width; } if (NULL != CURSOR_ADDRESS) gtm_tputs(gtm_tparm(CURSOR_ADDRESS, d_out->dollar.y, d_out->dollar.x), 1, outc); break; case iop_y: GET_LONG(d_out->dollar.y, pp->str.addr + p_offset); if (0 > (int4)d_out->dollar.y) d_out->dollar.y = 0; if (d_out->length) d_out->dollar.y %= d_out->length; if (NULL != CURSOR_ADDRESS) gtm_tputs(gtm_tparm(CURSOR_ADDRESS, d_out->dollar.y, d_out->dollar.x), 1, outc); break; case iop_ipchset: { # ifdef KEEP_zOS_EBCDIC if ( (iconv_t)0 != iod->input_conv_cd ) { ICONV_CLOSE_CD(iod->input_conv_cd); } SET_CODE_SET(iod->in_code_set, (char *)(pp->str.addr + p_offset + 1)); if (DEFAULT_CODE_SET != iod->in_code_set) ICONV_OPEN_CD(iod->input_conv_cd, (char *)(pp->str.addr + p_offset + 1), INSIDE_CH_SET); # endif break; } case iop_opchset: { # ifdef KEEP_zOS_EBCDIC if ( (iconv_t)0 != iod->output_conv_cd) { ICONV_CLOSE_CD(iod->output_conv_cd); } SET_CODE_SET(iod->out_code_set, (char *)(pp->str.addr + p_offset + 1)); if (DEFAULT_CODE_SET != iod->out_code_set) ICONV_OPEN_CD(iod->output_conv_cd, INSIDE_CH_SET, (char *)(pp->str.addr + p_offset + 1)); # endif break; } } p_offset += ((IOP_VAR_SIZE == io_params_size[ch]) ? (unsigned char)*(pp->str.addr + p_offset) + 1 : io_params_size[ch]); } temp_ptr = (d_tt_struct *)d_in->dev_sp; Tcsetattr(tt_ptr->fildes, TCSANOW, &t, status, save_errno); if (0 != status) rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_TCSETATTR, 1, tt_ptr->fildes, save_errno); temp_ptr->term_ctrl = mask_in; memcpy(&temp_ptr->mask_term, &mask_term, SIZEOF(io_termmask)); if (flush_input) { TCFLUSH(tt_ptr->fildes, TCIFLUSH, status); if (0 != status) rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, LIT_AND_LEN("tcflush input"), CALLFROM, errno); } } else if (tt_ptr->mupintr && !dollar_zininterrupt) { /* The interrupted read was not properly resumed so clear it now */ tt_ptr->mupintr = FALSE; tt_ptr->tt_state_save.who_saved = ttwhichinvalid; io_find_mvstent(iod, TRUE); /* clear mv stack entry */ } REVERT_GTMIO_CH(&iod->pair, ch_set); return; }
void iorm_write_utf(mstr *v) { int4 inchars, char_count; /* in characters */ int4 inlen, outbytes, mblen; /* in bytes */ int4 availwidth, usedwidth, mbwidth; /* in display columns */ int status, padsize,fstat_res,save_errno; wint_t utf_code; io_desc *iod; d_rm_struct *rm_ptr; unsigned char *inptr, *top, *nextmb, *outptr, *nextoutptr, *outstart, temppad, temppadarray[2]; char *out_ptr; boolean_t utf8_active = TRUE; /* needed by GTM_IO_WCWIDTH macro */ boolean_t stream, wrap; struct stat statbuf; boolean_t ch_set; iod = io_curr_device.out; ESTABLISH_GTMIO_CH(&io_curr_device, ch_set); rm_ptr = (d_rm_struct *)iod->dev_sp; assert(NULL != rm_ptr); inptr = (unsigned char *)v->addr; inlen = v->len; top = inptr + inlen; if (!rm_ptr->fixed && 0 == iod->dollar.x) rm_ptr->out_bytes = 0; /* user reset $X */ inchars = UTF8_LEN_STRICT(v->addr, v->len); /* validate and get good char count */ if (0 >= inchars) { REVERT_GTMIO_CH(&io_curr_device, ch_set); return; } usedwidth = 0; stream = rm_ptr->stream; wrap = iod->wrap; if (stream && !wrap) { /* For STREAM and NOWRAP, allow the entire record to be written without any record truncations/terminations */ availwidth = inlen; /* calculate worst case requirement of width (in chars) to write out input bytes */ rm_ptr->out_bytes = 0; } else availwidth = iod->width - iod->dollar.x; outbytes = 0; if (CHSET_UTF8 != iod->ochset) { outstart = nextoutptr = outptr = &rm_ptr->outbuf[rm_ptr->out_bytes]; if (!rm_ptr->done_1st_write) { /* get the file size */ FSTAT_FILE(rm_ptr->fildes, &statbuf, fstat_res); if (-1 == fstat_res) { save_errno = errno; rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("fstat"), CALLFROM, save_errno); } if (CHSET_UTF16 == iod->ochset) { /* Write BOM but do not count it towards the bytes in the current record */ /* write BOM if file is empty */ if (0 == statbuf.st_size) { memcpy(outptr, UTF16BE_BOM, UTF16BE_BOM_LEN); outbytes = UTF16BE_BOM_LEN; if (rm_ptr->output_encrypted) { REALLOC_CRYPTBUF_IF_NEEDED(outbytes); WRITE_ENCRYPTED_DATA(rm_ptr, iod->trans_name, outstart, outbytes, pvt_crypt_buf.addr); out_ptr = pvt_crypt_buf.addr; } else out_ptr = (char *)outstart; DOWRITERC_RM(rm_ptr, out_ptr, outbytes, status); ISSUE_NOPRINCIO_IF_NEEDED_RM(status, ==, iod); rm_ptr->write_occurred = TRUE; outptr = outstart; rm_ptr->out_bytes = outbytes = 0; /* save UTF16BE_BOM_LEN in bom_num_bytes until bom is checked, but don't indicate that bom has been checked - which still needs to be done for reading the exception is if the file was opened WRITEONLY */ rm_ptr->bom_num_bytes = UTF16BE_BOM_LEN; if (rm_ptr->write_only) rm_ptr->bom_checked = TRUE; } iod->ochset = CHSET_UTF16BE; get_chset_desc(&chset_names[iod->ochset]); }
void iosocket_tls(mval *optionmval, int4 timeoutarg, mval *tlsid, mval *password, mval *extraarg) { 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; char *extrastr, *extraptr; 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 boolean_t ch_set; 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]; ESTABLISH_GTMIO_CH(&iod->pair, ch_set); ENSURE_DATA_SOCKET(socketptr); if (socket_tcpip != socketptr->protocol) { rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_TLSPARAM, 4, LEN_AND_LIT("/TLS"), 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 (('\0' != idstr[0]) && (NULL != password)) { /* password only usable if tlsid provided - iosocket_iocontrol checks */ 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 if (NULL != password) { rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_TLSPARAM, 4, LEN_AND_LIT("passphrase"), LEN_AND_LIT("requires TLSID")); return; } else passwordstr[0] = '\0'; length = MIN((SIZEOF(optionstr) - 1), optionmval->str.len); lower_to_upper((uchar_ptr_t)optionstr, (uchar_ptr_t)optionmval->str.addr, length); optionstr[length] = '\0'; 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 in process */ 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; REVERT_GTMIO_CH(&iod->pair, ch_set); return; } } socketptr->tlsenabled = TRUE; flags = GTMTLS_OP_SOCKET_DEV | ((tlsopt_client == option) ? GTMTLS_OP_CLIENT_MODE : 0); if (NULL != extraarg) { if ('\0' == idstr[0]) { rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_TLSPARAM, 4, LEN_AND_STR(optionstr), LEN_AND_LIT("TLSID required for configuration string")); return; } length = extraarg->str.len; extrastr = malloc(length + 1 + SIZEOF(TLSLABEL) - 1 + tlsid->str.len + SIZEOF(COLONBRACKET) - 1 + SIZEOF(BRACKETSSEMIS) - 1); STRNCPY_LIT(extrastr, TLSLABEL); extraptr = extrastr + SIZEOF(TLSLABEL) - 1; memcpy(extraptr, tlsid->str.addr, tlsid->str.len); extraptr += tlsid->str.len; STRNCPY_LIT(extraptr, COLONBRACKET); extraptr = extraptr + SIZEOF(COLONBRACKET) - 1; STRNCPY_STR(extraptr, extraarg->str.addr, length); extraptr += length; STRNCPY_LIT(extraptr, BRACKETSSEMIS); extraptr += SIZEOF(BRACKETSSEMIS) - 1; *extraptr = '\0'; if (0 > gtm_tls_add_config(tls_ctx, idstr, extrastr)) { /* error string available */ socketptr->tlsenabled = FALSE; free(extrastr); 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'; rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_TLSCONVSOCK, 0, ERR_TEXT, 2, errlen, errp); return; } else free(extrastr); } if ('\0' != passwordstr[0]) { if ('\0' == idstr[0]) { rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_TLSPARAM, 4, LEN_AND_STR(optionstr), LEN_AND_LIT("TLSID required for passphrase")); return; } if (0 > gtm_tls_store_passwd(tls_ctx, idstr, passwordstr)) { /* error string available */ 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'; rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_TLSCONVSOCK, 0, ERR_TEXT, 2, errlen, errp); return; } } 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; REVERT_GTMIO_CH(&iod->pair, ch_set); return; } status = 0; # ifndef USE_POLL if (NO_M_TIMEOUT == timeoutarg) timeout_ptr = NULL; else { timeout_spec.tv_sec = msec_timeout / MILLISECS_IN_SEC; /* remainder in millsecs to microsecs */ timeout_spec.tv_usec = (msec_timeout % MILLISECS_IN_SEC) * MICROSECS_IN_MSEC; 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); if (NO_M_TIMEOUT != timeoutarg) dollar_truth = FALSE; REVERT_GTMIO_CH(&iod->pair, ch_set); 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; REVERT_GTMIO_CH(&iod->pair, ch_set); return; } else { /* adjust msec_timeout for poll/select */ # ifdef USE_POLL msec_timeout = (cur_time.at_sec * MILLISECS_IN_SEC) + DIVIDE_ROUND_UP(cur_time.at_usec, MICROSECS_IN_MSEC); # 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; REVERT_GTMIO_CH(&iod->pair, ch_set); 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)