Пример #1
0
bool new_pipe(int fd[2], bool r_nonblocking, bool w_nonblocking)
{
    if( ::pipe(fd) == -1 )
        return false;

    bool ret = false;
    do
    {
        if( r_nonblocking && make_nonblocking(fd[0])==-1 )
            break;

        if( w_nonblocking && make_nonblocking(fd[1])==-1 )
            break;

        ret = true;
    }while(0);

    if(!ret)
    {
        ::close(fd[0]);
        ::close(fd[1]);
    }

    return ret;
}
Пример #2
0
static error_code
try_port (RELAYLIB_INFO* rli, u_short port, char *if_name, char *relay_ip)
{
    struct hostent *he;
    struct sockaddr_in local;

    rli->m_listensock = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
    if (rli->m_listensock == SOCKET_ERROR) {
	debug_printf ("try_port(%d) failed socket() call\n", port);
        return SR_ERROR_SOCK_BASE;
    }
    make_nonblocking(rli->m_listensock);

    if ('\0' == *relay_ip) {
	if (read_interface(if_name,&local.sin_addr.s_addr) != 0)
	    local.sin_addr.s_addr = htonl(INADDR_ANY);
    } else {
	he = gethostbyname(relay_ip);
	memcpy(&local.sin_addr, he->h_addr_list[0], he->h_length);
    }

    local.sin_family = AF_INET;
    local.sin_port = htons(port);

#ifndef WIN32
    {
        // Prevent port error when restarting quickly after a previous exit
        int opt = 1;
        setsockopt(rli->m_listensock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
    }
#endif
                        
    if (bind(rli->m_listensock, (struct sockaddr *)&local, sizeof(local)) == SOCKET_ERROR)
    {
	debug_printf ("try_port(%d) failed bind() call\n", port);
        closesocket(rli->m_listensock);
        rli->m_listensock = SOCKET_ERROR;
        return SR_ERROR_CANT_BIND_ON_PORT;
    }
        
    if (listen(rli->m_listensock, 1) == SOCKET_ERROR)
    {
	debug_printf ("try_port(%d) failed listen() call\n", port);
        closesocket(rli->m_listensock);
        rli->m_listensock = SOCKET_ERROR;
        return SR_ERROR_SOCK_BASE;
    }

    debug_printf ("try_port(%d) succeeded\n", port);
    return SR_SUCCESS;
}
Пример #3
0
bool
make_info_slave(void)
{
  int socks[2];
  pid_t child;
  int n;

  if (info_slave_state != INFO_SLAVE_DOWN) {
    if (info_slave_pid > 0)
      kill_info_slave();
    info_slave_state = INFO_SLAVE_DOWN;
  }

  if (startup_attempts == 0)
    time(&startup_window);

  startup_attempts += 1;

  if (startup_attempts > MAX_ATTEMPTS) {
    time_t now;

    time(&now);
    if (difftime(now, startup_window) <= 60.0) {
      /* Too many failed attempts to start info_slave in 1 minute */
      do_rawlog(LT_ERR, "Disabling info_slave due to too many errors.");
      info_slave_halted = true;
      return false;
    } else {
      /* Reset counter */
      startup_window = now;
      startup_attempts = 0;
    }
  }
#ifndef AF_LOCAL
  /* Use Posix.1g names. */
#define AF_LOCAL AF_UNIX
#endif

#ifdef HAVE_SOCKETPAIR
  if (socketpair(AF_LOCAL, SOCK_DGRAM, 0, socks) < 0) {
    penn_perror("creating slave datagram socketpair");
    return false;
  }
  if (socks[0] >= maxd)
    maxd = socks[0] + 1;
  if (socks[1] >= maxd)
    maxd = socks[1] + 1;
#endif

  child = fork();
  if (child < 0) {
    penn_perror("forking info slave");
#ifdef HAVE_SOCKETPAIR
    closesocket(socks[0]);
    closesocket(socks[1]);
#endif
    return false;
  } else if (child > 0) {
    info_slave_state = INFO_SLAVE_READY;
    info_slave_pid = child;
#ifdef HAVE_SOCKETPAIR
    info_slave = socks[0];
    closesocket(socks[1]);
    do_rawlog(LT_ERR,
              "Spawning info slave, communicating using socketpair, pid %d.",
              child);
#endif
    make_nonblocking(info_slave);
  } else {
    int errfd = fileno(stderr);
    int dupfd;

    /* Close unneeded fds and sockets: Everything but stderr and the
       socket used to talk to the mush */
    for (n = 0; n < maxd; n++) {
      if (n == errfd)
        continue;
#ifdef HAVE_SOCKETPAIR
      if (n == socks[1])
        continue;
#endif
      close(n);
    }
    /* Reuse stdin and stdout for talking to the slave */
    dupfd = dup2(socks[1], 0);
    if (dupfd < 0) {
      penn_perror("dup2() of stdin in info_slave");
      exit(1);
    }

    dupfd = dup2(socks[1], 1);
    if (dupfd < 0) {
      penn_perror("dup2() of stdout in info_slave");
      exit(1);
    }

    close(socks[1]);

    execl("./info_slave", "info_slave", "for", MUDNAME, (char *) NULL);
    penn_perror("execing info slave");
    exit(1);
  }

  if (info_slave >= maxd)
    maxd = info_slave + 1;

  lower_priority_by(info_slave_pid, 4);

  for (n = 0; n < maxd; n++)
    if (FD_ISSET(n, &info_pending))
      query_info_slave(n);

  return true;
}
Пример #4
0
void run(void)
{
    int listener;
    struct fd_state *state[FD_SETSIZE];
    struct sockaddr_in sin;
    int i, maxfd;
    fd_set readset, writeset, exset;

    sin.sin_family = AF_INET;
    sin.sin_addr.s_addr = 0;
    sin.sin_port = htons(8081);

    for (i = 0; i < FD_SETSIZE; ++i)
        state[i] = NULL;

    listener = socket(AF_INET, SOCK_STREAM, 0);
    make_nonblocking(listener);

    if (bind(listener, (struct sockaddr*)&sin, sizeof(sin)) < 0) {
        perror("bind");
        return;
    }

    if (listen(listener, 16)<0) {
        perror("listen");
        return;
    }

    FD_ZERO(&readset);
    FD_ZERO(&writeset);
    FD_ZERO(&exset);

    while (1) {
        maxfd = listener;

        FD_ZERO(&readset);
        FD_ZERO(&writeset);
        FD_ZERO(&exset);

        FD_SET(listener, &readset);

        for (i=0; i < FD_SETSIZE; ++i) {
            if (state[i]) {
                if (i > maxfd)
                    maxfd = i;
                FD_SET(i, &readset);
                if (state[i]->writing) {
                    FD_SET(i, &writeset);
                }
            }
        }

        if (select(maxfd+1, &readset, &writeset, &exset, NULL) < 0) {
            perror("select");
            return;
        }

        if (FD_ISSET(listener, &readset)) {
            struct sockaddr_storage ss;
            socklen_t slen = sizeof(ss);
            int fd = accept(listener, (struct sockaddr*)&ss, &slen);
            if (fd < 0) {
                perror("accept");
            } else if (fd > FD_SETSIZE) {
                close(fd);
            } else {
                make_nonblocking(fd);
                state[fd] = alloc_fd_state();

                char send_buf[1024] = "Connected";
                send(fd, send_buf, 1024, 0);

                assert(state[fd]);/*XXX*/
            }
        }

        for (i=0; i < maxfd+1; ++i) {
            int r = 0;
            if (i == listener)
                continue;

            if (FD_ISSET(i, &readset)) {
                r = do_read(i, state[i]);
            }
            if (r == 0 && FD_ISSET(i, &writeset)) {
                r = do_write(i, state[i]);
            }
            if (r) {
                free_fd_state(state[i]);
                state[i] = NULL;
                close(i);
            }
        }
    }
}
Пример #5
0
/* Copies data from stdin to PTY and from PTY to stdout until no
   more data can be read or written. */
static void
relay (int pty, int dead_child_fd) 
{
  struct pipe 
    {
      int in, out;
      char buf[BUFSIZ];
      size_t size, ofs;
      bool active;
    };
  struct pipe pipes[2];

  /* Make PTY, stdin, and stdout non-blocking. */
  make_nonblocking (pty, true);
  make_nonblocking (STDIN_FILENO, true);
  make_nonblocking (STDOUT_FILENO, true);

  /* Configure noncanonical mode on PTY and stdin to avoid
     waiting for end-of-line.  We want to minimize context
     switching on PTY (for efficiency) and minimize latency on
     stdin to avoid a laggy user experience. */
  make_noncanon (pty, 16, 1);
  make_noncanon (STDIN_FILENO, 1, 0);

  memset (pipes, 0, sizeof pipes);
  pipes[0].in = STDIN_FILENO;
  pipes[0].out = pty;
  pipes[1].in = pty;
  pipes[1].out = STDOUT_FILENO;
  
  while (pipes[0].in != -1 || pipes[1].in != -1)
    {
      fd_set read_fds, write_fds;
      int retval;
      int i;

      FD_ZERO (&read_fds);
      FD_ZERO (&write_fds);
      for (i = 0; i < 2; i++)
        {
          struct pipe *p = &pipes[i];

          /* Don't do anything with the stdin->pty pipe until we
             have some data for the pty->stdout pipe.  If we get
             too eager, Bochs will throw away our input. */
          if (i == 0 && !pipes[1].active)
            continue;
          
          if (p->in != -1 && p->size + p->ofs < sizeof p->buf)
            FD_SET (p->in, &read_fds);
          if (p->out != -1 && p->size > 0)
            FD_SET (p->out, &write_fds); 
        }
      FD_SET (dead_child_fd, &read_fds);

      do 
        {
          retval = select (FD_SETSIZE, &read_fds, &write_fds, NULL, NULL); 
        }
      while (retval < 0 && errno == EINTR);
      if (retval < 0) 
        fail_io ("select");

      if (FD_ISSET (dead_child_fd, &read_fds))
        {
          /* Child died.  Do final relaying. */
          struct pipe *p = &pipes[1];
          if (p->out == -1)
            return;
          make_nonblocking (STDOUT_FILENO, false);
          for (;;) 
            {
              ssize_t n;
                  
              /* Write buffer. */
              while (p->size > 0) 
                {
                  n = write (p->out, p->buf + p->ofs, p->size);
                  if (n < 0)
                    fail_io ("write");
                  else if (n == 0)
                    fail_io ("zero-length write");
                  p->ofs += n;
                  p->size -= n;
                }
              p->ofs = 0;

              p->size = n = read (p->in, p->buf, sizeof p->buf);
              if (n <= 0)
                return;
            }
        }

      for (i = 0; i < 2; i++) 
        {
          struct pipe *p = &pipes[i];
          if (p->in != -1 && FD_ISSET (p->in, &read_fds))
            {
              ssize_t n = read (p->in, p->buf + p->ofs + p->size,
                                sizeof p->buf - p->ofs - p->size);
              if (n > 0) 
                {
                  p->active = true;
                  p->size += n;
                  if (p->size == BUFSIZ && p->ofs != 0)
                    {
                      memmove (p->buf, p->buf + p->ofs, p->size);
                      p->ofs = 0;
                    }
                }
              else if (!handle_error (n, &p->in, p->in == pty, "read"))
                return;
            }
          if (p->out != -1 && FD_ISSET (p->out, &write_fds)) 
            {
              ssize_t n = write (p->out, p->buf + p->ofs, p->size);
              if (n > 0) 
                {
                  p->ofs += n;
                  p->size -= n;
                  if (p->size == 0)
                    p->ofs = 0;
                }
              else if (!handle_error (n, &p->out, p->out == pty, "write"))
                return;
            }
        }
    }
}
Пример #6
0
const char *
get_username(long a, int prt, int myprt)
{
    int fd, len, result;
    struct sockaddr_in addr;
    char *ptr, *ptr2;
    static char buf[1024];
    int lasterr;
    int timeout = IDENTD_TIMEOUT;

    if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
        perror("resolver ident socket");
        return(0);
    }

    make_nonblocking(fd);

    len = sizeof(addr);
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = a;
    addr.sin_port = htons((short)113);

    do {
	result = connect(fd, (struct sockaddr *) &addr, len);
	lasterr = errno;
        if (result < 0) {
            if (!timeout--) break;
            sleep(1);
        }
    } while (result < 0 && lasterr == EINPROGRESS);
    if (result < 0 && lasterr != EISCONN) {
        goto bad;
    }

    sprintf(buf, "%d,%d\n", prt, myprt);
    do {
	result = write(fd ,buf, strlen(buf));
	lasterr = errno;
	if (result < 0) {
	    if (!timeout--) break;
	    sleep(1);
	}
    } while (result < 0 && lasterr == EAGAIN);
    if (result < 0) goto bad;

    do {
	result = read(fd, buf, sizeof(buf));
	lasterr = errno;
	if (result < 0) {
	    if (!timeout--) break;
	    sleep(1);
	}
    } while (result < 0 && lasterr == EAGAIN);
    if (result < 0) goto bad;

    ptr = index(buf, ':');
    if (!ptr) goto bad;
    ptr++;
    if (*ptr) ptr++;
    if(strncmp(ptr, "USERID", 6)) goto bad;

    ptr = index(ptr, ':');
    if (!ptr) goto bad;
    ptr = index(ptr + 1, ':');
    if (!ptr) goto bad;
    ptr++;
    /* if (*ptr) ptr++; */

    close(fd);
    if ((ptr2 = index(ptr, '\r'))) *ptr2 = '\0';
    if (!*ptr) return(0);
    return ptr;

bad:
    close(fd);
    return(0);
}
Пример #7
0
int main() {

	int l_socket_fd = -1;
	int c_socket_fd = -1;
	fd_set fds;

	l_socket_fd = android_get_control_socket(SOCKET_NAME);

	if (l_socket_fd < 0 ){
		ALOGE("Unable to open inputdevinfo_socket (%s)\n", strerror(errno));
		return -1;
	}

	if (make_nonblocking (l_socket_fd)) {
		ALOGE("Unable to modify inputdevinfo_socket flags. (%s)\n", strerror(errno));
	}

	if (listen (l_socket_fd, 0) < 0) {
		ALOGE("Unable to open inputdevinfo_socket (%s)\n", strerror(errno));
		return -1;
	}

	while(1){
		FD_ZERO(&fds);
		FD_SET(l_socket_fd, &fds);

		if (c_socket_fd >= 0 ) {
			// &&  fcntl(c_socket_fd, F_GETFD) >= 0 ? 
			FD_SET(c_socket_fd, &fds);
		}

		int retval = select(get_max(c_socket_fd, l_socket_fd) + 1, &fds, NULL, NULL, NULL);

		if(retval <= 0){
			ALOGI("Error\n");
			// Should I check for EBADR?
			break;
		} 

		if(FD_ISSET(l_socket_fd, &fds)) {
			ALOGI("Connection attempt\n");
			if(c_socket_fd < 0) {
				c_socket_fd = accept(l_socket_fd, NULL, NULL);
			}

			if (make_nonblocking (c_socket_fd)) {
				ALOGE("Unable to modify socket flags. (%s)\n", strerror(errno));
			}
			
		} 

		if(c_socket_fd >= 0 && FD_ISSET(c_socket_fd, &fds)){

			int unread_bytes_count;
			if (ioctl(c_socket_fd, FIONREAD, &unread_bytes_count)){
				ALOGE("Attempt to check if client socket is closed resulted in error.\n");
			} else if(unread_bytes_count == 0) {
				//TODO: Check return code?				
				close(c_socket_fd);
				c_socket_fd = -1;
			} else {
				process_cmds(c_socket_fd, MAX_COMMAND_LENGTH);
				close(c_socket_fd);
				c_socket_fd = -1;
			}
		}

	}

return 0;

}
Пример #8
0
int main(int argc, char *argv[])
{
    //======= insert unit test
    //    test();
    //=======
    
    
    if (argc < 2) {
        fprintf(stderr,"ERROR, no port provided\n");
        exit(1);
    }
    
    int portno = atoi(argv[1]);
    
    struct sigaction sa;          // for signal SIGCHLD
    /****** Kill Zombie Processes ******/
    sa.sa_handler = sigchld_handler; // reap all dead processes
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = SA_RESTART;
    if (sigaction(SIGCHLD, &sa, NULL) == -1) {
        perror("sigaction");
        exit(1);
    }
    /*********************************/
    
    
    
    struct sockaddr_in myaddr;	/* our address */
	struct sockaddr_in remaddr;	/* remote address */
	int fd;				/* our socket */
    
    
	/* create a UDP socket */
    
	if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
		perror("cannot create socket\n");
		return 0;
	}
    
	/* bind the socket to any valid IP address and a specific port */
    
	memset((char *)&myaddr, 0, sizeof(myaddr));
	myaddr.sin_family = AF_INET;
	myaddr.sin_addr.s_addr = htonl(INADDR_ANY);
	myaddr.sin_port = htons(portno);
    
	if (bind(fd, (struct sockaddr *)&myaddr, sizeof(myaddr)) < 0) {
		perror("bind failed");
		return 0;
	}
    
    make_nonblocking(fd);
    
    if (argc == 5) {
        //set window size... maybe validate?
        WINDOW_SIZE = atoi(argv[2]);
        LOSS_PROBABILITY = atof(argv[3]);
        CORRUPTION_PROBABILITY = atof(argv[4]);
        Server server(portno, fd, myaddr, remaddr, WINDOW_SIZE, LOSS_PROBABILITY, CORRUPTION_PROBABILITY);
        server.startListening();
    } else {
        Server server(portno, fd, myaddr, remaddr);
        server.startListening();
    }
    
}
Пример #9
0
void
thread_accept (void* arg)
{
    int ret;
    int newsock;
    BOOL good;
    struct sockaddr_in client;
    socklen_t iAddrSize = sizeof(client);
    RELAY_LIST* newhostsock;
    int icy_metadata;
    char* client_http_header;
    RIP_MANAGER_INFO* rmi = (RIP_MANAGER_INFO*) arg;
    RELAYLIB_INFO* rli = &rmi->relaylib_info;
    STREAM_PREFS* prefs = rmi->prefs;
    int have_metadata;

    if (rmi->http_info.meta_interval == NO_META_INTERVAL) {
	have_metadata = 0;
    } else {
	have_metadata = 1;
    }

    debug_printf("thread_accept:start\n");

    while (rli->m_running)
    {
        fd_set fds;
        struct timeval tv;

        // this event will keep use from accepting while we 
	//   have a connection active
        // when a connection gets dropped, or when streamripper shuts down
        //   this event will get signaled
	debug_printf("thread_accept:waiting on m_sem_not_connected\n");
        threadlib_waitfor_sem (&rli->m_sem_not_connected);
        if (!rli->m_running) {
	    debug_printf("thread_accept:exit (no longer m_running)\n");
            break;
	}

        // Poll once per second, instead of blocking forever in 
	// accept(), so that we can regain control if relaylib_stop() 
	// called
        FD_ZERO (&fds);
        while (rli->m_listensock != SOCKET_ERROR && rli->m_running)
        {
            FD_SET (rli->m_listensock, &fds);
            tv.tv_sec = 1;
            tv.tv_usec = 0;
	    debug_printf("thread_accept:calling select()\n");
            ret = select (rli->m_listensock + 1, &fds, NULL, NULL, &tv);
	    debug_printf("thread_accept:select() returned %d\n", ret);
            if (ret == 1) {
                unsigned long num_connected;
                /* If connections are full, do nothing.  Note that 
                    m_max_connections is 0 for infinite connections allowed. */
                threadlib_waitfor_sem (&rmi->relay_list_sem);
                num_connected = rmi->relay_list_len;
                threadlib_signal_sem (&rmi->relay_list_sem);
                if (prefs->max_connections > 0 && num_connected >= (unsigned long) prefs->max_connections) {
                    continue;
                }
                /* Check for connections */
		debug_printf ("Calling accept()\n");
                newsock = accept (rli->m_listensock, (struct sockaddr *)&client, &iAddrSize);
                if (newsock != SOCKET_ERROR) {
                    // Got successful accept

                    debug_printf ("Relay: Client %d new from %s:%hu\n", newsock,
                                  inet_ntoa(client.sin_addr), ntohs(client.sin_port));

                    // Socket is new and its buffer had better have 
		    // room to hold the entire HTTP header!
                    good = FALSE;
                    if (header_receive (newsock, &icy_metadata) == 0 && rmi->cbuf2.buf != NULL) {
			int header_len;
			make_nonblocking (newsock);
			client_http_header = client_relay_header_generate (rmi, icy_metadata);
			header_len = strlen (client_http_header);
			ret = send (newsock, client_http_header, strlen(client_http_header), 0);
			debug_printf ("Relay: Sent response header to client %d (%d)\n", 
			    ret, header_len);
			client_relay_header_release (client_http_header);
			if (ret == header_len) {
                            newhostsock = malloc (sizeof(RELAY_LIST));
                            if (newhostsock != NULL) {
                                // Add new client to list (headfirst)
                                threadlib_waitfor_sem (&rmi->relay_list_sem);
                                newhostsock->m_is_new = 1;
                                newhostsock->m_sock = newsock;
                                newhostsock->m_next = rmi->relay_list;
				if (have_metadata) {
                                    newhostsock->m_icy_metadata = icy_metadata;
				} else {
                                    newhostsock->m_icy_metadata = 0;
				}

                                rmi->relay_list = newhostsock;
                                rmi->relay_list_len++;
                                threadlib_signal_sem (&rmi->relay_list_sem);
                                good = TRUE;
                            }
                        }
                    }

                    if (!good)
                    {
                        closesocket (newsock);
                        debug_printf ("Relay: Client %d disconnected (Unable to receive HTTP header) or cbuf2.buf is NULL\n", newsock);
			//if (rmi->cbuf2.buf == NULL) {
			  //  debug_printf ("In fact, cbuf2.buf is NULL\n");
			//}
                    }
                }
            }
            else if (ret == SOCKET_ERROR)
            {
                /* Something went wrong with select */
                break;
            }
        }
        threadlib_signal_sem (&rli->m_sem_not_connected);
	/* loop back up to select */
    }
    rli->m_running_accept = FALSE;
    rli->m_running = FALSE;
}
Пример #10
0
static int forward(pid_t pid, int *sigchld_fd, int stdin_pipe[2], int stdout_pipe[2], int stderr_pipe[2], void *socket)
{
	int rc = -1;

	if (close(stdin_pipe[0]) == -1)
		TRACE_ERRNO("close(%i) failed", stdin_pipe[0]);
	stdin_pipe[0] = -1;

	if (close(stdout_pipe[1]) == -1)
		TRACE_ERRNO("close(%i) failed", stdout_pipe[1]);
	stdout_pipe[1] = -1;

	if (close(stderr_pipe[1]) == -1)
		TRACE_ERRNO("close(%i) failed", stderr_pipe[1]);
	stderr_pipe[1] = -1;

	zmq_msg_t stdin_msg;
	size_t stdin_msg_pos = 0;
	zmq_msg_t stdout_msg;
	int stdout_msg_valid = 0;
	zmq_msg_t stderr_msg;
	int stderr_msg_valid = 0;

	if (make_nonblocking(stdin_pipe[1]) == -1)
		goto _out;
	if (make_nonblocking(stdout_pipe[0]) == -1)
		goto _out;
	if (make_nonblocking(stderr_pipe[0]) == -1)
		goto _out;
	TRACE("made nonblocking: %i, %i, %i", stdin_pipe[1], stdout_pipe[0], stderr_pipe[0]);

	while (1) {
		zmq_pollitem_t items[5];
		zmq_pollitem_t *item = items;

		zmq_pollitem_t *stdin_item = NULL;
		if (stdin_pipe[1] != -1 && stdin_msg_pos) {
			stdin_item = item++;
			stdin_item->socket = NULL;
			stdin_item->fd = stdin_pipe[1];
			stdin_item->events = ZMQ_POLLOUT | ZMQ_POLLERR;
		}

		zmq_pollitem_t *stdout_item = NULL;
		if (stdout_pipe[0] != -1 && !stdout_msg_valid) {
			stdout_item = item++;
			stdout_item->socket = NULL;
			stdout_item->fd = stdout_pipe[0];
			stdout_item->events = ZMQ_POLLIN | ZMQ_POLLERR;
		}

		zmq_pollitem_t *stderr_item = NULL;
		if (stderr_pipe[0] != -1 && !stderr_msg_valid) {
			stderr_item = item++;
			stderr_item->socket = NULL;
			stderr_item->fd = stderr_pipe[0];
			stderr_item->events = ZMQ_POLLIN | ZMQ_POLLERR;
		}

		zmq_pollitem_t *socket_item = NULL;
		short socket_events = ((stdout_msg_valid || stderr_msg_valid) ? ZMQ_POLLOUT : 0) |
		                      ((stdin_pipe[1] == -1 || stdin_msg_pos) ? 0 : ZMQ_POLLIN);
		if (socket_events) {
			socket_item = item++;
			socket_item->socket = socket;
			socket_item->fd = -1;
			socket_item->events = socket_events;
		}

		zmq_pollitem_t *sigchld_item = NULL;
		if (*sigchld_fd != -1) {
			sigchld_item = item++;
			sigchld_item->socket = NULL;
			sigchld_item->fd = *sigchld_fd;
			sigchld_item->events = ZMQ_POLLIN | ZMQ_POLLERR;
		}

		if (item == items) {
			TRACE("nothing to poll, exiting");
			break;
		}

		TRACE("polling:%s%s%s%s%s", stdin_item ? " stdin" : "",
		                            stdout_item ? " stdout" : "",
		                            stderr_item ? " stderr" : "",
		                            socket_item ? " socket" : "",
		                            sigchld_item ? " sigchld" : "");

		while (1) {
			if (zmq_poll(items, item - items, -1) == -1) {
				if (errno == EINTR)
					continue;
				TRACE_ERRNO("zmq_poll() failed");
				goto _out;
			}
			break;
		}

		if (stdin_item && (stdin_item->revents & (ZMQ_POLLOUT | ZMQ_POLLERR)))
			if (fd_write(&stdin_pipe[1], &stdin_msg, &stdin_msg_pos) == -1)
				goto _out;
		if (socket_item && (socket_item->revents & ZMQ_POLLOUT)) {
			if (socket_write(socket, &stdout_msg, &stdout_msg_valid) == -1)
				goto _out;
			if (socket_write(socket, &stderr_msg, &stderr_msg_valid) == -1)
				goto _out;
		}
		if (stdout_item && (stdout_item->revents & (ZMQ_POLLIN | ZMQ_POLLERR)))
			if (on_fd_readable(&stdout_pipe[0], socket, &stdout_msg, &stdout_msg_valid, msg_type_stdout) == -1)
				goto _out;
		if (stderr_item && (stderr_item->revents & (ZMQ_POLLIN | ZMQ_POLLERR)))
			if (on_fd_readable(&stderr_pipe[0], socket, &stderr_msg, &stderr_msg_valid, msg_type_stderr) == -1)
				goto _out;
		if (socket_item && (socket_item->revents & ZMQ_POLLIN))
			if (on_socket_readable(socket, &stdin_pipe[1], &stdin_msg, &stdin_msg_pos) == -1)
				goto _out;
		if (sigchld_item && (sigchld_item->revents & (ZMQ_POLLIN | ZMQ_POLLERR)))
			if (on_sigchld(sigchld_fd, pid, &stdin_pipe[1]) == -1)
				goto _out;
	}

	rc = 0;

_out:
	if (stdin_msg_pos && zmq_msg_close(&stdin_msg) == -1)
		TRACE_ERRNO("zmq_msg_close() failed");
	if (stdout_msg_valid && zmq_msg_close(&stdout_msg) == -1)
		TRACE_ERRNO("zmq_msg_close() failed");
	if (stderr_msg_valid && zmq_msg_close(&stderr_msg) == -1)
		TRACE_ERRNO("zmq_msg_close() failed");
	return rc;
}