/** * @brief * -DIS_tcp_wflush - flush tcp/dis write buffer * * @par Functionality: * Writes "committed" data in buffer to file discriptor, * packs remaining data (if any), resets pointers * * @return int * @retval 0 success * @retval -1 error * */ int DIS_tcp_wflush(int fd) { size_t ct; int i; int j; char *pb; struct tcpdisbuf *tp; struct pollfd pollfds[1]; pbs_tcp_errno = 0; tp = tcp_get_writebuf(fd); pb = tp->tdis_thebuf; ct = tp->tdis_trail; if (ct == 0) return 0; while ((i = CS_write(fd, pb, ct)) != ct) { if (i == CS_IO_FAIL) { if (errno == EINTR) { continue; } if (errno != EAGAIN) { /* fatal error on write, abort output */ pbs_tcp_errno = errno; return (-1); } /* write would have blocked (EAGAIN returned) */ /* poll for socket to be ready to accept, if */ /* not ready in TIMEOUT_SHORT seconds, fail */ /* redo the poll if EINTR */ do { pollfds[0].fd = fd; pollfds[0].events = POLLOUT; pollfds[0].revents = 0; j = poll(pollfds, 1, PBS_DIS_TCP_TIMEOUT_SHORT * 1000); } while ((j == -1) && (errno == EINTR)); if (j == 0) { /* never came ready, return error */ /* pbs_tcp_errno will add to log message */ pbs_tcp_errno = EAGAIN; return (-1); } else if (j == -1) { /* some other error - fatal */ pbs_tcp_errno = errno; return (-1); } continue; /* socket ready, retry write */ } /* write succeeded, do more if needed */ ct -= i; pb += i; } tp->tdis_eod = tp->tdis_lead; tcp_pack_buff(tp); return 0; }
int DIS_tcp_wflush( struct tcp_chan *chan) /* I */ { size_t ct; int i; char *pb = NULL; char *pbs_debug = NULL; int rc = PBSE_NONE; struct tcpdisbuf *tp; pbs_debug = getenv("PBSDEBUG"); tp = &chan->writebuf; pb = tp->tdis_thebuf; ct = tp->tdis_trailp - tp->tdis_thebuf; if (rc != PBSE_NONE) return(-1); while ((i = write(chan->sock, pb, ct)) != (ssize_t)ct) { if (i == -1) { if (errno == EINTR) { continue; } /* FAILURE */ if (pbs_debug != NULL) { fprintf(stderr, "TCP write of %d bytes (%.32s) [sock=%d] failed, errno=%d (%s)\n", (int)ct, pb, chan->sock, errno, strerror(errno)); } return(-1); } /* END if (i == -1) */ else { ct -= i; pb += i; } } /* END while (i) */ /* SUCCESS */ tp->tdis_eod = tp->tdis_leadp; tcp_pack_buff(tp); return(0); } /* END DIS_tcp_wflush() */
int tcp_read( struct tcp_chan *chan, long long *read_len, long long *avail_len, unsigned int timeout) { int rc = PBSE_NONE; unsigned long newsize; char *ptr; int tdis_buf_len = 0; int max_read_len = 0; char *new_data = NULL; struct tcpdisbuf *tp; int tmp_leadp = 0; int tmp_trailp = 0; int tmp_eod = 0; char err_msg[1024]; tp = &chan->readbuf; /* must compact any uncommitted data into bottom of buffer */ tcp_pack_buff(tp); chan->IsTimeout = 0; chan->SelectErrno = 0; chan->ReadErrno = 0; tdis_buf_len = tp->tdis_bufsize; max_read_len = tp->tdis_bufsize - (tp->tdis_eod - tp->tdis_thebuf); /* * we don't want to be locked out by an attack on the port to * deny service, so we time out the read, the network had better * deliver promptly */ if ((rc = socket_read(chan->sock, &new_data, read_len, timeout)) != PBSE_NONE) { switch (rc) { case PBSE_TIMEOUT: chan->IsTimeout = 1; break; default: chan->SelectErrno = rc; chan->ReadErrno = rc; break; } if (new_data != NULL) free(new_data); return(rc); } /* data read is less than buffer size */ else if (max_read_len > *read_len) { memcpy(tp->tdis_eod, new_data, *read_len); tp->tdis_eod += *read_len; *tp->tdis_eod = '\0'; *avail_len = tp->tdis_eod - tp->tdis_leadp; max_read_len = tp->tdis_eod - tp->tdis_thebuf; if (max_read_len > tdis_buf_len) { snprintf(err_msg, sizeof(err_msg), "eod ptr BEYOND end of buffer!! (fit) Remaining buffer = %d, read_len = %lld", max_read_len, *read_len); log_err(PBSE_INTERNAL,__func__,err_msg); } free(new_data); } /* data read is greater than buffer size */ else if (max_read_len <= *read_len) { newsize = (tdis_buf_len + *read_len) * 2; if ((ptr = (char *)calloc(1, newsize+1)) == NULL) { log_err(ENOMEM,__func__,"Could not allocate memory to read buffer"); rc = PBSE_MEM_MALLOC; free(new_data); return rc; } tmp_leadp = tp->tdis_leadp - tp->tdis_thebuf; tmp_trailp = tp->tdis_trailp - tp->tdis_thebuf; tmp_eod = tp->tdis_eod - tp->tdis_thebuf; snprintf(ptr, newsize, "%s%s", tp->tdis_thebuf, new_data); free(tp->tdis_thebuf); tp->tdis_thebuf = ptr; tp->tdis_bufsize = newsize; tp->tdis_eod = tp->tdis_thebuf + tmp_eod + *read_len; tp->tdis_trailp = tp->tdis_thebuf + tmp_trailp; tp->tdis_leadp = tp->tdis_thebuf + tmp_leadp; *avail_len = tp->tdis_eod - tp->tdis_leadp; max_read_len = tp->tdis_eod - tp->tdis_thebuf; tdis_buf_len = newsize; if (max_read_len > tdis_buf_len) { snprintf(err_msg, sizeof(err_msg), "eod ptr BEYOND end of buffer!!(expand) Remaining buffer = %d, read_len = %lld", max_read_len, *read_len); log_err(PBSE_INTERNAL,__func__,err_msg); } free(new_data); } return(rc); } /* END tcp_read() */
static int tcp_read(int fd) { int i; int try_decrypt_buf = 0; struct pollfd pollfds[1]; int timeout; struct tcpdisbuf *tp; char *tmcp; tp = tcp_get_readbuf(fd); #if defined(PBS_SECURITY) && (PBS_SECURITY == KCRYPT ) /* In a case where an intermediate decryption buffer * is being used (e.g. Kerberized PBS with encryption) the * "read" into our tcp buffer area is being satisfied outof * this internal buffer. For this situation reading begins * with any unread data residing in the CS library's internal * buffer area. Only if that data source is exhausted early * will the CS library code sequence to reading and decrypting * data from the socket, placing it in the intermediate * decryption buffer, from where it's subsequently "read". * * Because the CS library is organized in this manner a * real possibility exists to mistakenly wait for more data * to be present on the socket, when in fact all the data has * been collected and is available in the decryption buffer. * The clause that follows attempts to recognize this case. */ if (tp->tdis_eod && tp->tdis_eod == tp->tdis_bufsize) { /* don't wait, data probably in decryption buffer */ try_decrypt_buf = 1; } #endif /* compact (move to the front) the uncommitted data */ tcp_pack_buff(tp); if ((tp->tdis_bufsize - tp->tdis_eod) < 20) { /* no need to lock mutex here, this is per fd resize */ /* needing a larger buffer area for the data */ tp->tdis_bufsize += THE_BUF_SIZE; tmcp = (char *)realloc(tp->tdis_thebuf, sizeof(char)*tp->tdis_bufsize); if (tmcp != NULL) { tp->tdis_thebuf = tmcp; } else { /* realloc failed */ return -1; } } /* * we don't want to be locked out by an attack on the port to * deny service, so we time out the read, the network had better * deliver promptly */ do { if (try_decrypt_buf) timeout = 0; else timeout = pbs_tcp_timeout; pollfds[0].fd = fd; pollfds[0].events = POLLIN; pollfds[0].revents = 0; i = poll(pollfds, 1, timeout * 1000); if (pbs_tcp_interrupt) break; } while ((i == -1) && (errno == EINTR)); if ((i == 0 && try_decrypt_buf == 0) || (i < 0)) return i; while ((i = CS_read(fd, &tp->tdis_thebuf[tp->tdis_eod], tp->tdis_bufsize - tp->tdis_eod)) == CS_IO_FAIL) { if (errno != EINTR) break; } if (i > 0) tp->tdis_eod += i; return ((i == 0) ? -2 : i); }