/* Stolen from Unix Network Programming by Stevens, Fenner, Rudoff p89 */ ssize_t tcp_read(int file_descriptor, void *vptr, size_t n, const struct timeval * ptv) { size_t nleft; ssize_t nread; char *ptr; //printf("NetRead attempt %d bytes Time:(%ld,%ld)\n",(int)n,ptv->tv_sec,ptv->tv_usec ) ; ptr = vptr; nleft = n; while (nleft > 0) { int rc; fd_set readset; struct timeval tv = { ptv->tv_sec, ptv->tv_usec, }; /* Initialize readset */ FD_ZERO(&readset); FD_SET(file_descriptor, &readset); /* Read if it doesn't timeout first */ rc = select(file_descriptor + 1, &readset, NULL, NULL, &tv); if (rc > 0) { /* Is there something to read? */ if (FD_ISSET(file_descriptor, &readset) == 0) { return -EIO; /* error */ } //update_max_delay(pn); if ((nread = read(file_descriptor, ptr, nleft)) < 0) { if (errno == EINTR) { errno = 0; // clear errno. We never use it anyway. nread = 0; /* and call read() again */ } else { ERROR_DATA("Network data read error\n"); return (-1); } } else if (nread == 0) { break; /* EOF */ } //Debug_Bytes( "NETREAD",ptr, nread ) ; nleft -= nread; ptr += nread; } else if (rc < 0) { /* select error */ if (errno == EINTR) { /* select() was interrupted, try again */ continue; } ERROR_DATA("Selection error (network)\n"); return -EINTR; } else { /* timed out */ LEVEL_CONNECT("TIMEOUT after %d bytes\n", n - nleft); return -EAGAIN; } } return (n - nleft); /* return >= 0 */ }
/* return < 0 if failure */ ZERO_OR_ERROR tcp_read(FILE_DESCRIPTOR_OR_ERROR file_descriptor, BYTE * buffer, size_t requested_size, const struct timeval * ptv, size_t * chars_in) { size_t to_be_read = requested_size ; if ( FILE_DESCRIPTOR_NOT_VALID( file_descriptor ) ) { return -EBADF ; } LEVEL_DEBUG("attempt %d bytes Time: "TVformat,(int)requested_size, TVvar(ptv) ) ; *chars_in = 0 ; while (to_be_read > 0) { int select_result; fd_set readset; struct timeval tv ; /* Initialize readset */ FD_ZERO(&readset); FD_SET(file_descriptor, &readset); /* Read if it doesn't timeout first */ timercpy( &tv, ptv ) ; select_result = select(file_descriptor + 1, &readset, NULL, NULL, &tv); if (select_result > 0) { ssize_t read_result; /* Is there something to read? */ if (FD_ISSET(file_descriptor, &readset) == 0) { LEVEL_DEBUG("tcp_error -- nothing avialable to read"); return -EBADF ; /* error */ } errno = 0 ; read_result = read(file_descriptor, &buffer[*chars_in], to_be_read) ; if ( read_result < 0 ) { if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK) { read_result = 0; /* and call read() again */ } else { LEVEL_DATA("Network data read error errno=%d %s", errno, strerror(errno)); STAT_ADD1(NET_read_errors); return -EBADF ; } } else if (read_result == 0) { break; /* EOF */ } TrafficInFD("NETREAD", &buffer[*chars_in], read_result, file_descriptor ) ; to_be_read -= read_result; *chars_in += read_result ; } else if (select_result < 0) { /* select error */ if (errno == EINTR) { /* select() was interrupted, try again */ continue; } ERROR_DATA("Select error"); return -EBADF; } else { /* timed out */ LEVEL_CONNECT("TIMEOUT after %d bytes", requested_size - to_be_read); return -EAGAIN; } } LEVEL_DEBUG("read: %d - %d = %d",(int)requested_size, (int) to_be_read, (int) (requested_size-to_be_read) ) ; return 0; }