rem: debug_v(("entering with timeout=%d:%d select() ...", delayer.tv_sec, delayer.tv_usec));
context: int core_readwrite(nc_sock_t *nc_main, nc_sock_t *nc_slave){  int fd_stdin, fd_stdout, fd_sock, fd_max;  int read_ret, write_ret;  unsigned char buf[1024];  bool inloop = TRUE;  fd_set ins, outs;  struct timeval delayer;  assert(nc_main && nc_slave);  debug_v(("core_readwrite(nc_main=%p, nc_slave=%p)", (void *)nc_main,	  (void *)nc_slave));  /* set the actual input and output fds and find out the max fd + 1 */  fd_sock = nc_main->fd;  assert(fd_sock >= 0);  /* if the domain is unspecified, it means that this is the standard I/O */  if (nc_slave->domain == PF_UNSPEC) {    fd_stdin = STDIN_FILENO;    fd_stdout = STDOUT_FILENO;  }  else {    fd_stdin = fd_stdout = nc_slave->fd;    assert(fd_stdin >= 0);  }  fd_max = 1 + (fd_stdin > fd_sock ? fd_stdin : fd_sock);  delayer.tv_sec = 0;  delayer.tv_usec = 0;  /* use the internal signal handler */  signal_handler = FALSE;  while (inloop) {    bool call_select = TRUE;    struct sockaddr_in recv_addr;	/* only used by UDP proto */    unsigned int recv_len = sizeof(recv_addr);    /* if we received an interrupt signal break this function */    if (got_sigint) {      got_sigint = FALSE;      break;    }    /* if we received a terminating signal we must terminate */    if (got_sigterm)      break;    /* reset the ins and outs events watch because some changes could happen */    FD_ZERO(&ins);    FD_ZERO(&outs);    /* if the receiving queue is not empty it means that something bad is       happening (for example the target sending queue is delaying the output       and so requires some more time to free up. */    if (nc_main->recvq.len == 0) {      debug_v(("watching main sock for incoming data (recvq is empty)"));      FD_SET(fd_sock, &ins);    }    else      call_select = FALSE;    /* same thing for the other socket */    if (nc_slave->recvq.len == 0) { /* FIXME: call_select = false but could call it	anyway and one of them could be set.. so what happens? */      debug_v(("watching slave sock for incoming data (recvq is empty)"));      if (use_stdin || (netcat_mode == NETCAT_TUNNEL))        FD_SET(fd_stdin, &ins);    }    else      call_select = FALSE;    /* now the send queue. There are two cases in which the main sendq is not       empty.  The first one is when we have a delayed output (-i), in which       case the delayer is not null, and the socket is writable.  The second       case is when the socket buffer is full, so the socket is not writable       and the delayer is either null or set, depending on the opt_interval       variable. */    if (nc_main->sendq.len > 0) {      if ((delayer.tv_sec == 0) && (delayer.tv_usec == 0)) {	debug_v(("watching main sock for outgoing availability (there is pending data)"));	FD_SET(fd_sock, &outs);	call_select = TRUE;      }    }    if (call_select || delayer.tv_sec || delayer.tv_usec) {      int ret;      debug_v(("entering with timeout=%d:%d select() ...", delayer.tv_sec, delayer.tv_usec));      ret = select(fd_max, &ins, &outs, NULL,		   (delayer.tv_sec || delayer.tv_usec ? &delayer : NULL));      if (ret < 0) {	if (errno == EINTR)	  goto handle_signal;	perror("select(core_readwrite)");	exit(EXIT_FAILURE);      }      call_select = TRUE;    }    /* reading from stdin the incoming data.  The data is currently in the       kernel's receiving queue, and in this session we move that data to our       own receiving queue, located in the socket object.  We can be sure that       this queue is empty now because otherwise this fd wouldn't have been       watched. */    if (call_select && FD_ISSET(fd_stdin, &ins)) {      read_ret = read(fd_stdin, buf, sizeof(buf));      debug_dv(("read(stdin) = %d", read_ret));      if (read_ret < 0) {	perror("read(stdin)");	exit(EXIT_FAILURE);      }      else if (read_ret == 0) {	/* when we receive EOF and this is a tunnel say goodbye, otherwise	   it means that stdin has finished its input. */	if ((netcat_mode == NETCAT_TUNNEL) || opt_eofclose) {	  debug_v(("EOF Received from stdin! (exiting from loop..)"));	  inloop = FALSE;	}	else {	  debug_v(("EOF Received from stdin! (removing from lookups..)"));	  use_stdin = FALSE;	}      }      else {	/* we can overwrite safely since if the receive queue is busy this fd	   is not watched at all. */        nc_slave->recvq.len = read_ret;        nc_slave->recvq.head = NULL;        nc_slave->recvq.pos = buf;      }    }    /* for optimization reasons we have a common buffer for both receiving       queues, because of this, handle the data now so the buffer is available       for the other socket events. */    if (nc_slave->recvq.len > 0) {      nc_buffer_t *my_recvq = &nc_slave->recvq;      nc_buffer_t *rem_sendq = &nc_main->sendq;      debug_v(("there are %d data bytes in slave->recvq", my_recvq->len));      /* if the remote send queue is empty, move there the entire data block */      if (rem_sendq->len == 0) {	debug_v(("  moved %d data bytes from slave->recvq to main->sendq", my_recvq->len));	memcpy(rem_sendq, my_recvq, sizeof(*rem_sendq));	memset(my_recvq, 0, sizeof(*my_recvq));      }      else if (!my_recvq->head) {	/* move the data block in a dedicated allocated space */	debug_v(("  reallocating %d data bytes in slave->recvq", my_recvq->len));	my_recvq->head = malloc(my_recvq->len);	memcpy(my_recvq->head, my_recvq->pos, my_recvq->len);	my_recvq->pos = my_recvq->head;      }    }    /* now handle the nc_slave sendq because of the same reason as above. There       could be a common buffer that moves around the queues, so if this is the case       handle it so that it can be reused. If we must delay it some more, copy it       in a dynamically allocated space. */    if (nc_main->sendq.len > 0) {      unsigned char *data = nc_main->sendq.pos;      int data_len = nc_main->sendq.len;      nc_buffer_t *my_sendq = &nc_main->sendq;      debug_v(("there are %d data bytes in main->sendq", my_sendq->len));      /* we have a delayed output, but at this point we might have the         send queue pointing to a stack buffer.  In this case, allocate a         new buffer and copy the data there for the buffered output. */      if (opt_interval) {	int i = 0;	if (delayer.tv_sec || delayer.tv_usec)	  goto skip_sect;		/* the delay is not yet over! */	/* find the newline character.  We are going to output the first line	   immediately while we allocate and safe the rest of the data for a	   later output. */	while (i < data_len)	  if (data[i++] == '\n')	    break;	data_len = i;	delayer.tv_sec = opt_interval;      }      write_ret = write(fd_sock, data, data_len);      if (write_ret < 0) {	if (errno == EAGAIN)	  write_ret = 0;	/* write would block, append it to select */	else {	  perror("write(net)");	  exit(EXIT_FAILURE);	}      }      /* FIXME: fix the below unhandled exception, and find a way to delay the       * tries to call write(2) in case of EAGAIN, i think 100ms would be fine       * for most systems. A too high value would not use all the bandwidth on       * bigger installations, while a too small value would eat cpu with       * kernel overhead. */      bytes_sent += write_ret;		/* update statistics */      debug_dv(("write(net) = %d (buf=%p)", write_ret, (void *)data));      if (write_ret < data_len) {	debug_v(("Damn! I wanted to send to sock %d bytes but it only sent %d",		data_len, write_ret));	data_len = write_ret;      }      /* if the option is set, hexdump the sent data */      if (opt_hexdump) {#ifndef USE_OLD_HEXDUMP	fprintf(output_fp, "Sent %u bytes to the socket\n", write_ret);#endif	netcat_fhexdump(output_fp, '>', data, data_len);      }      /* update the queue */      my_sendq->len -= data_len;      my_sendq->pos += data_len; skip_sect:      debug_v(("there are %d data bytes left in the queue", my_sendq->len));      if (my_sendq->len == 0) {	free(my_sendq->head);	memset(my_sendq, 0, sizeof(*my_sendq));      }      else if (!my_sendq->head) {	my_sendq->head = malloc(my_sendq->len);	memcpy(my_sendq->head, my_sendq->pos, my_sendq->len);	my_sendq->pos = my_sendq->head;      }    }				/* end of reading from stdin section */    /* reading from the socket (net). */    if (call_select && FD_ISSET(fd_sock, &ins)) {      if ((nc_main->proto == NETCAT_PROTO_UDP) && opt_zero) {	memset(&recv_addr, 0, sizeof(recv_addr));	/* this allows us to fetch packets from different addresses */	read_ret = recvfrom(fd_sock, buf, sizeof(buf), 0,			    (struct sockaddr *)&recv_addr, &recv_len);	/* when recvfrom() call fails, recv_addr remains untouched */	debug_dv(("recvfrom(net) = %d (address=%s:%d)", read_ret,		netcat_inet_ntop(&recv_addr.sin_addr), ntohs(recv_addr.sin_port)));      }      else {	/* common file read fallback */	read_ret = read(fd_sock, buf, sizeof(buf));	debug_dv(("read(net) = %d", read_ret));      }      if (read_ret < 0) {	perror("read(net)");	exit(EXIT_FAILURE);      }      else if (read_ret == 0) {	debug_v(("EOF Received from the net"));	inloop = FALSE;      }      else {	nc_main->recvq.len = read_ret;	nc_main->recvq.head = NULL;	nc_main->recvq.pos = buf;      }    }    /* handle net receiving queue */    if (nc_main->recvq.len > 0) {      nc_buffer_t *my_recvq = &nc_main->recvq;      nc_buffer_t *rem_sendq = &nc_slave->sendq;      /* check for telnet codes (if enabled).  Note that the buffered output         interval does NOT apply to telnet code answers */      if (opt_telnet)	netcat_telnet_parse(nc_main);      /* the telnet parsing could have returned 0 chars! */      if (my_recvq->len > 0) {	/* if the remote send queue is empty, move there the entire data block */	if (rem_sendq->len == 0) {	  memcpy(rem_sendq, my_recvq, sizeof(*rem_sendq));	  memset(my_recvq, 0, sizeof(*my_recvq));	}	else if (!my_recvq->head) {	  /* move the data block in a dedicated allocated space */	  my_recvq->head = malloc(my_recvq->len);	  memcpy(my_recvq->head, my_recvq->pos, my_recvq->len);	  my_recvq->pos = my_recvq->head;	}      }    }    if (nc_slave->sendq.len > 0) {      unsigned char *data = nc_slave->sendq.pos;      int data_len = nc_slave->sendq.len;      nc_buffer_t *my_sendq = &nc_slave->sendq;      write_ret = write(fd_stdout, data, data_len);      bytes_recv += write_ret;		/* update statistics */      debug_dv(("write(stdout) = %d", write_ret));      if (write_ret < 0) {	perror("write(stdout)");	exit(EXIT_FAILURE);      }      /* FIXME: unhandled exception */      assert((write_ret > 0) && (write_ret <= data_len));      if (write_ret < data_len) {	debug_v(("Damn! I wanted to send to stdout %d bytes but it only sent %d",		data_len, write_ret));	data_len = write_ret;      }      /* if option is set, hexdump the received data */      if (opt_hexdump) {#ifndef USE_OLD_HEXDUMP	if ((nc_main->proto == NETCAT_PROTO_UDP) && opt_zero)	  fprintf(output_fp, "Received %d bytes from %s:%d\n", write_ret,		  netcat_inet_ntop(&recv_addr.sin_addr), ntohs(recv_addr.sin_port));	else	  fprintf(output_fp, "Received %d bytes from the socket\n", write_ret);#endif	netcat_fhexdump(output_fp, '<', data, write_ret);      }      /* update the queue */      my_sendq->len -= data_len;      my_sendq->pos += data_len;      debug_v(("there are %d data bytes left in the queue", my_sendq->len));      if (my_sendq->len == 0) {	free(my_sendq->head);	memset(my_sendq, 0, sizeof(*my_sendq));      }      else if (!my_sendq->head) {	my_sendq->head = malloc(my_sendq->len);	memcpy(my_sendq->head, my_sendq->pos, my_sendq->len);	my_sendq->pos = my_sendq->head;      }    }				/* end of reading from the socket section */ handle_signal:			/* FIXME: i'm not sure this is the right place */    if (got_sigusr1) {      debug_v(("LOCAL printstats!"));      netcat_printstats(TRUE);      got_sigusr1 = FALSE;    }    continue;  }				/* end of while (inloop) */  /* we've got an EOF from the net, close the sockets */  shutdown(fd_sock, SHUT_RDWR);  close(fd_sock);  nc_main->fd = -1;  /* close the slave socket only if it wasn't a simulation */  if (nc_slave->domain != PF_UNSPEC) {    shutdown(fd_stdin, SHUT_RDWR);    close(fd_stdin);    nc_slave->fd = -1;  }  /* restore the extarnal signal handler */  signal_handler = TRUE;  return 0;}				/* end of core_readwrite() */