/************************************************************************** write wrapper function -vasc **************************************************************************/ static int write_socket_data(struct connection *pc, struct socket_packet_buffer *buf, int limit) { int start, nput, nblock; if (is_server() && pc->server.is_closing) { return 0; } for (start=0; buf->ndata-start>limit;) { fd_set writefs, exceptfs; struct timeval tv; FC_FD_ZERO(&writefs); FC_FD_ZERO(&exceptfs); FD_SET(pc->sock, &writefs); FD_SET(pc->sock, &exceptfs); tv.tv_sec = 0; tv.tv_usec = 0; if (fc_select(pc->sock+1, NULL, &writefs, &exceptfs, &tv) <= 0) { if (errno != EINTR) { break; } else { /* EINTR can happen sometimes, especially when compiling with -pg. * Generally we just want to run select again. */ continue; } } if (FD_ISSET(pc->sock, &exceptfs)) { connection_close(pc, _("network exception")); return -1; } if (FD_ISSET(pc->sock, &writefs)) { nblock=MIN(buf->ndata-start, MAX_LEN_PACKET); log_debug("trying to write %d limit=%d", nblock, limit); if((nput=fc_writesocket(pc->sock, (const char *)buf->data+start, nblock)) == -1) { #ifdef NONBLOCKING_SOCKETS if (errno == EWOULDBLOCK || errno == EAGAIN) { break; } #endif connection_close(pc, _("lagging connection")); return -1; } start += nput; } } if (start > 0) { buf->ndata -= start; memmove(buf->data, buf->data+start, buf->ndata); pc->last_write = timer_renew(pc->last_write, TIMER_USER, TIMER_ACTIVE); timer_start(pc->last_write); } return 0; }
/**************************************************************************** A wrapper around read_socket_data() which also handles the case the socket becomes writeable and there is still data which should be sent to the server. Returns: -1 : an error occurred - you should close the socket -2 : the connection was closed >0 : number of bytes read =0 : no data read, would block ****************************************************************************/ static int read_from_connection(struct connection *pc, bool block) { for (;;) { fd_set readfs, writefs, exceptfs; int socket_fd = pc->sock; bool have_data_for_server = (pc->used && pc->send_buffer && 0 < pc->send_buffer->ndata); int n; struct timeval tv; tv.tv_sec = 0; tv.tv_usec = 0; FC_FD_ZERO(&readfs); FD_SET(socket_fd, &readfs); FC_FD_ZERO(&exceptfs); FD_SET(socket_fd, &exceptfs); if (have_data_for_server) { FC_FD_ZERO(&writefs); FD_SET(socket_fd, &writefs); n = fc_select(socket_fd + 1, &readfs, &writefs, &exceptfs, block ? NULL : &tv); } else { n = fc_select(socket_fd + 1, &readfs, NULL, &exceptfs, block ? NULL : &tv); } /* the socket is neither readable, writeable nor got an * exception */ if (n == 0) { return 0; } if (n == -1) { if (errno == EINTR) { /* EINTR can happen sometimes, especially when compiling with -pg. * Generally we just want to run select again. */ log_debug("select() returned EINTR"); continue; } log_error("select() return=%d errno=%d (%s)", n, errno, fc_strerror(fc_get_errno())); return -1; } if (FD_ISSET(socket_fd, &exceptfs)) { return -1; } if (have_data_for_server && FD_ISSET(socket_fd, &writefs)) { flush_connection_send_buffer_all(pc); } if (FD_ISSET(socket_fd, &readfs)) { return read_socket_data(socket_fd, pc->buffer); } } }