Beispiel #1
0
/**************************************************************************
  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;
}
Beispiel #2
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);
    }
  }
}