int evcom_stream_pair (evcom_stream *a, evcom_stream *b) { int sv[2]; int old_errno; int r = socketpair(PF_UNIX, SOCK_STREAM, 0, sv); if (r < 0) return -1; r = set_nonblock(sv[0]); if (r < 0) goto set_nonblock_error; r = set_nonblock(sv[1]); if (r < 0) goto set_nonblock_error; evcom_stream_assign_fds(a, sv[0], sv[0]); evcom_stream_assign_fds(b, sv[1], sv[1]); return 0; set_nonblock_error: old_errno = errno; evcom_perror("set_nonblock()", errno); close(sv[0]); close(sv[1]); errno = old_errno; return -1; }
int pair_pingpong (int use_pipe) { a_got_close = 0; a_got_connect = 0; b_got_close = 0; b_got_connect = 0; pair_pingpong_cnt = 0; evcom_stream_init(&a); a.on_close = a_close; a.on_connect = a_connect; a.on_read = a_read; evcom_stream_reset_timeout(&a, PAIR_PINGPONG_TIMEOUT); #if EVCOM_HAVE_GNUTLS if (use_tls) anon_tls_client(&a); #endif evcom_stream_init(&b); b.on_close = b_close; b.on_connect = b_connect; b.on_read = b_read; evcom_stream_reset_timeout(&b, PAIR_PINGPONG_TIMEOUT); #if EVCOM_HAVE_GNUTLS if (use_tls) anon_tls_server(&b); #endif if (use_pipe) { int pipeA[2], pipeB[2]; assert(0 == pipe(pipeA)); assert(0 == pipe(pipeB)); evcom_stream_assign_fds(&a, pipeA[0], pipeB[1]); evcom_stream_assign_fds(&b, pipeB[0], pipeA[1]); } else { int r = evcom_stream_pair(&a, &b); assert(r == 0); } evcom_stream_attach(EV_DEFAULT_ &a); evcom_stream_attach(EV_DEFAULT_ &b); evcom_stream_write(&a, PING, strlen(PING)); ev_loop(EV_DEFAULT_ 0); assert(a_got_close); assert(a_got_connect); assert(b_got_close); assert(b_got_connect); assert(pair_pingpong_cnt == PAIR_PINGPONG_EXCHANGES); return 0; }
int evcom_stream_connect (evcom_stream *stream, struct sockaddr *address) { int fd = socket(address->sa_family, SOCK_STREAM, 0); if (fd < 0) { evcom_perror("socket()", errno); return -1; } int r = set_nonblock(fd); if (r < 0) { stream->errorno = errno; evcom_perror("set_nonblock()", errno); close(fd); return -1; } r = connect(fd, address, address_length(address)); if (r < 0 && errno != EINPROGRESS) { stream->errorno = errno; evcom_perror("connect", errno); close(fd); return -1; } evcom_stream_assign_fds(stream, fd, fd); stream->send_action = stream_send__wait_for_connection; stream->recv_action = NULL; return 0; }
/* Retruns evcom_stream if a connection could be accepted. * The returned stream is not yet attached to the event loop. * Otherwise NULL */ static evcom_stream* accept_connection (evcom_server *server) { struct sockaddr address; /* connector's address information */ socklen_t addr_len = sizeof(address); int fd = accept(server->fd, &address, &addr_len); if (fd < 0) { switch (errno) { case EMFILE: case ENFILE: too_many_connections = 1; server->flags |= EVCOM_TOO_MANY_CONN; evcom_server_detach(server); return NULL; case EINTR: case EAGAIN: return NULL; default: evcom_perror("accept()", errno); return NULL; } assert(0 && "no reach"); } evcom_stream *stream = NULL; if (server->on_connection) { stream = server->on_connection(server, &address); } if (stream == NULL) { close(fd); return NULL; } if (set_nonblock(fd) != 0) { evcom_perror("set_nonblock()", errno); return NULL; } stream->server = server; evcom_stream_assign_fds(stream, fd, fd); return stream; }