short iorm_read (mval *v, int4 timeout) /* timeout in seconds */ { boolean_t ret, timed; int4 msec_timeout; /* timeout in milliseconds */ uint4 width; char inchar, *temp; int flags; int fcntl_res; int4 i; io_desc *io_ptr; d_rm_struct *rm_ptr; int4 status; TID timer_id; error_def(ERR_IOEOF); assert(stringpool.free >= stringpool.base); assert(stringpool.free <= stringpool.top); io_ptr = io_curr_device.in; assert (io_ptr->state == dev_open); rm_ptr = (d_rm_struct*) (io_ptr->dev_sp); if (io_ptr->dollar.x && rm_ptr->lastop == RM_WRITE) { if (!io_ptr->dollar.za) iorm_wteol(1, io_ptr); io_ptr->dollar.x = 0; } rm_ptr->lastop = RM_READ; timer_id = (TID) iorm_read; width = io_ptr->width; if (stringpool.free + width > stringpool.top) stp_gcol (width); i = 0; ret = TRUE; temp = (char*) stringpool.free; out_of_time = FALSE; if (timeout == NO_M_TIMEOUT) { timed = FALSE; msec_timeout = NO_M_TIMEOUT; } else { timed = TRUE; msec_timeout = timeout2msec(timeout); if (msec_timeout > 0) { start_timer(timer_id, msec_timeout, wake_alarm, 0, NULL); } else { out_of_time = TRUE; FCNTL2(rm_ptr->fildes, F_GETFL, flags); FCNTL3(rm_ptr->fildes, F_SETFL, (flags | O_NDELAY), fcntl_res); } } errno = 0; if (rm_ptr->fixed) { /* * the check for EINTR below is valid and should not be converted to an EINTR * wrapper macro, since it might be a timeout. */ DOREADRLTO(rm_ptr->fildes, temp, width, out_of_time, status); if (0 > status) { i = 0; if (errno == EINTR && out_of_time) status = -2; } else i = status; } else { do { if ((status = getc (rm_ptr->filstr)) != EOF) { inchar = (unsigned char) status; if (inchar == NATIVE_NL) break; *temp++ = inchar; i++; } else { inchar = 0; if (errno == 0) status = 0; else if (errno == EINTR) { if (out_of_time) status = -2; else continue; /* Ignore interruption if wasn't our timeout */ } break; } } while (i < width); } if (status == EOF && errno != EINTR) { io_ptr->dollar.za = 9; v->str.len = 0; if ((timed) && (!out_of_time)) cancel_timer(timer_id); rts_error(VARLSTCNT(1) errno); } if (timed) { if (msec_timeout == 0) { FCNTL3(rm_ptr->fildes, F_SETFL, flags, fcntl_res); if (rm_ptr->fifo && status == 0) ret = FALSE; } else { if (out_of_time) ret = FALSE; else cancel_timer(timer_id); } } if (status == 0 && i == 0 && !rm_ptr->fifo) { v->str.len = 0; if (io_ptr->dollar.zeof == TRUE) { io_ptr->dollar.za = 9; rts_error(VARLSTCNT(1) ERR_IOEOF); } io_ptr->dollar.zeof = TRUE; io_ptr->dollar.x = 0; io_ptr->dollar.za = 0; io_ptr->dollar.y++; if (io_ptr->error_handler.len > 0) { rts_error(VARLSTCNT(1) ERR_IOEOF); } } else { v->str.len = i; v->str.addr = (char *) stringpool.free; if (!rm_ptr->fixed && inchar == NATIVE_NL) { io_ptr->dollar.x = 0; io_ptr->dollar.y++; } else if ((io_ptr->dollar.x += i) >= 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; } } io_ptr->dollar.za = 0; return((short) ret); }
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); }