static void accept_cb(struct ev_loop *loop, ev_uinet *w, int revents) { struct passive_context *passive = w->data; struct uinet_socket *newso = NULL; struct uinet_socket *newpeerso = NULL; struct connection_context *conn = NULL; struct connection_context *peerconn = NULL; int error; int batch_limit = 32; int processed = 0; while ((processed < batch_limit) && (UINET_EWOULDBLOCK != (error = uinet_soaccept(w->so, NULL, &newso)))) { processed++; if (0 == error) { newpeerso = NULL; conn = NULL; peerconn = NULL; if (passive->verbose) printf("accept succeeded\n"); conn = create_conn(passive, newso, 1); if (NULL == conn) goto fail; newpeerso = uinet_sogetpassivepeer(newso); peerconn = create_conn(passive, newpeerso, 0); if (NULL == peerconn) goto fail; conn->peer = peerconn; peerconn->peer = conn; ev_uinet_start(loop, &conn->watcher); if (!passive->extract) ev_uinet_start(loop, &peerconn->watcher); passive->interface->num_sockets += 2; continue; fail: if (conn) destroy_conn(conn); if (newso) uinet_soclose(newso); if (newpeerso) uinet_soclose(newpeerso); } } if (processed > passive->interface->max_accept_batch) passive->interface->max_accept_batch = processed; }
static void echo_accept_cb(struct ev_loop *loop, ev_uinet *w, int revents) { struct uinet_demo_echo *echo = w->data; struct uinet_socket *newso = NULL; struct ev_uinet_ctx *soctx = NULL; struct echo_connection *conn = NULL; int error; if (0 != (error = uinet_soaccept(w->so, NULL, &newso))) { printf("%s: Accept failed (%d)\n", echo->cfg.name, error); } else { if (echo->cfg.verbose) printf("%s: Accept succeeded\n", echo->cfg.name); soctx = ev_uinet_attach(newso); if (NULL == soctx) { printf("%s: Failed to alloc libev context for new connection\n", echo->cfg.name); goto fail; } conn = malloc(sizeof(*conn)); if (NULL == conn) { printf("%s: Failed to alloc new connection context\n", echo->cfg.name); goto fail; } conn->echo = echo; conn->id = echo->next_id++; conn->verbose = echo->cfg.verbose; ev_init(&conn->connected_watcher, echo_connected_cb); ev_uinet_set(&conn->connected_watcher, soctx, EV_WRITE); conn->connected_watcher.data = conn; if (conn->verbose || (echo->cfg.copy_mode & UINET_IP_COPY_MODE_MAYBE)) ev_uinet_start(loop, &conn->connected_watcher); ev_init(&conn->watcher, echo_cb); ev_uinet_set(&conn->watcher, soctx, EV_READ); conn->watcher.data = conn; ev_uinet_start(loop, &conn->watcher); } return; fail: if (conn) free(conn); if (soctx) ev_uinet_detach(soctx); if (newso) uinet_soclose(newso); }
static void nproxy_writable_cb(struct ev_loop *loop, ev_uinet *w, int revents) { struct nproxy_connection *conn = w->data; struct nproxy_connection *other_side_conn = conn->other_side; /* restart the other side's copy watcher */ ev_uinet_start(loop, &other_side_conn->copy_watcher); /* stop this watcher until the other side's copy watcher needs it again */ ev_uinet_stop(loop, w); }
static void nproxy_outbound_connected_cb(struct ev_loop *loop, ev_uinet *w, int revents) { struct nproxy_splice *splice = w->data; struct uinet_demo_nproxy *nproxy = splice->nproxy; struct uinet_sockaddr_in *sin1, *sin2; char buf1[32], buf2[32]; ev_uinet_stop(loop, w); if (splice->verbose) { uinet_sogetsockaddr(w->so, (struct uinet_sockaddr **)&sin1); uinet_sogetpeeraddr(w->so, (struct uinet_sockaddr **)&sin2); printf("%s: splice %llu: outbound connection established (local=%s:%u foreign=%s:%u)\n", nproxy->cfg.name, (unsigned long long)splice->id, uinet_inet_ntoa(sin1->sin_addr, buf1, sizeof(buf1)), ntohs(sin1->sin_port), uinet_inet_ntoa(sin2->sin_addr, buf2, sizeof(buf2)), ntohs(sin2->sin_port)); uinet_free_sockaddr((struct uinet_sockaddr *)sin1); uinet_free_sockaddr((struct uinet_sockaddr *)sin2); } ev_uinet_start(loop, &splice->inbound.copy_watcher); ev_uinet_start(loop, &splice->outbound.copy_watcher); }
static void accept_cb(struct ev_loop *loop, ev_uinet *w, int revents) { struct echo_context *echo = w->data; struct uinet_socket *newso = NULL; struct connection_context *conn = NULL; struct ev_uinet_ctx *soctx = NULL; int error; if (0 != (error = uinet_soaccept(w->so, NULL, &newso))) { printf("accept failed (%d)\n", error); } else { printf("accept succeeded\n"); soctx = ev_uinet_attach(newso); if (NULL == soctx) { printf("Failed to alloc libev context for new connection socket\n"); goto fail; } conn = malloc(sizeof(*conn)); if (NULL == conn) { printf("Failed to alloc connection context for new connection\n"); goto fail; } ev_init(&conn->watcher, echo_cb); ev_uinet_set(&conn->watcher, soctx, EV_READ); conn->watcher.data = conn; ev_uinet_start(loop, &conn->watcher); } return; fail: if (conn) free(conn); if (soctx) ev_uinet_detach(soctx); if (newso) uinet_soclose(newso); }
static void echo_cb(struct ev_loop *loop, ev_uinet *w, int revents) { struct echo_connection *conn = w->data; struct uinet_demo_echo *echo = conn->echo; struct uinet_iovec iov; struct uinet_uio uio; int max_read; int max_write; int read_size; int error; #define BUFFER_SIZE (64*1024) char buffer[BUFFER_SIZE]; max_read = uinet_soreadable(w->so, 0); if (max_read <= 0) { /* the watcher should never be invoked if there is no error and there no bytes to be read */ assert(max_read != 0); if (conn->verbose) printf("%s: connection %llu: can't read, closing\n", echo->cfg.name, (unsigned long long)conn->id); goto err; } else { max_write = echo->sink ? max_read : uinet_sowritable(w->so, 0); if (-1 == max_write) { if (conn->verbose) printf("%s: connection %llu: can't write, closing\n", echo->cfg.name, (unsigned long long)conn->id); goto err; } else { read_size = imin(imin(max_read, max_write), BUFFER_SIZE); uio.uio_iov = &iov; iov.iov_base = buffer; iov.iov_len = read_size; uio.uio_iovcnt = 1; uio.uio_offset = 0; uio.uio_resid = read_size; error = uinet_soreceive(w->so, NULL, &uio, NULL); if (0 != error) { printf("%s: connection %llu: read error (%d), closing\n", echo->cfg.name, (unsigned long long)conn->id, error); goto err; } assert(uio.uio_resid == 0); if (!echo->sink) { uio.uio_iov = &iov; iov.iov_base = buffer; iov.iov_len = read_size; uio.uio_iovcnt = 1; uio.uio_offset = 0; uio.uio_resid = read_size; error = uinet_sosend(w->so, NULL, &uio, 0); if (0 != error) { printf("%s: connection %llu: write error (%d), closing\n", echo->cfg.name, (unsigned long long)conn->id, error); goto err; } } if (max_write < max_read) { /* limited by write space, so change to a * write watch on the socket, if we aren't * already one. */ if (w->events & EV_READ) { ev_uinet_stop(loop, w); w->events = EV_WRITE; ev_uinet_start(loop, w); } /* else, continue as a write watch */ } else if (!(w->events & EV_READ)) { /* write space wasn't a limitation this * time, so switch back to waiting on * EV_READ */ ev_uinet_stop(loop, w); w->events = EV_READ; ev_uinet_start(loop, w); } /* else, continue as a read watcher */ } } return; err: ev_uinet_stop(loop, w); ev_uinet_detach(w->ctx); uinet_soclose(w->so); free(conn); }
static int echo_start(struct uinet_demo_config *cfg, uinet_instance_t uinst, struct ev_loop *loop) { struct uinet_demo_echo *echo = (struct uinet_demo_echo *)cfg; struct uinet_socket *listen_socket = NULL; struct ev_uinet_ctx *soctx = NULL; struct uinet_in_addr addr; int optlen, optval; int error; struct uinet_sockaddr_in sin; if (uinet_inet_pton(UINET_AF_INET, echo->listen_addr, &addr) <= 0) { printf("%s: Malformed address %s\n", echo->cfg.name, echo->listen_addr); error = UINET_EINVAL; goto fail; } error = uinet_socreate(echo->cfg.uinst, UINET_PF_INET, &listen_socket, UINET_SOCK_STREAM, 0); if (0 != error) { printf("%s: Listen socket creation failed (%d)\n", echo->cfg.name, error); goto fail; } soctx = ev_uinet_attach(listen_socket); if (NULL == soctx) { printf("%s: Failed to alloc libev socket context\n", echo->cfg.name); error = UINET_ENOMEM; goto fail; } if (echo->promisc) { if ((error = uinet_make_socket_promiscuous(listen_socket, NULL))) { printf("%s: Failed to make listen socket promiscuous (%d)\n", echo->cfg.name, error); goto fail; } } if (cfg->copy_mode) { if ((error = uinet_sosetcopymode(listen_socket, cfg->copy_mode, cfg->copy_limit, cfg->copy_uif))) { printf("%s: Failed to set copy mode (%d)\n", echo->cfg.name, error); goto fail; } } /* * Socket needs to be non-blocking to work with the event system */ uinet_sosetnonblocking(listen_socket, 1); /* Set NODELAY on the listen socket so it will be set on all * accepted sockets via inheritance. */ optlen = sizeof(optval); optval = 1; if ((error = uinet_sosetsockopt(listen_socket, UINET_IPPROTO_TCP, UINET_TCP_NODELAY, &optval, optlen))) { printf("%s: Failed to set TCP_NODELAY (%d)\n", echo->cfg.name, error); goto fail; } /* Listen on all VLANs */ if ((error = uinet_setl2info2(listen_socket, NULL, NULL, UINET_INL2I_TAG_ANY, NULL))) { printf("%s: Listen socket L2 info set failed (%d)\n", echo->cfg.name, error); goto fail; } echo->listen_socket = listen_socket; memset(&sin, 0, sizeof(struct uinet_sockaddr_in)); sin.sin_len = sizeof(struct uinet_sockaddr_in); sin.sin_family = UINET_AF_INET; sin.sin_addr = addr; sin.sin_port = htons(echo->listen_port); error = uinet_sobind(listen_socket, (struct uinet_sockaddr *)&sin); if (0 != error) { printf("%s: Bind to %s:%u failed\n", echo->cfg.name, echo->listen_addr, echo->listen_port); goto fail; } error = uinet_solisten(echo->listen_socket, -1); if (0 != error) { printf("%s: Listen on %s:%u failed\n", echo->cfg.name, echo->listen_addr, echo->listen_port); goto fail; } if (echo->cfg.verbose) printf("%s: Listening on %s:%u\n", echo->cfg.name, echo->listen_addr, echo->listen_port); /* * Set up a read watcher to accept new connections */ ev_init(&echo->listen_watcher, echo_accept_cb); ev_uinet_set(&echo->listen_watcher, soctx, EV_READ); echo->listen_watcher.data = echo; ev_uinet_start(echo->cfg.loop, &echo->listen_watcher); return (0); fail: if (soctx) ev_uinet_detach(soctx); if (listen_socket) uinet_soclose(listen_socket); return (error); }
static struct passive_context * create_passive(struct ev_loop *loop, struct server_config *cfg) { struct passive_context *passive = NULL; struct uinet_socket *listener = NULL; struct ev_uinet_ctx *soctx = NULL; struct uinet_in_addr addr; int optlen, optval; int error; struct uinet_sockaddr_in sin; if (uinet_inet_pton(UINET_AF_INET, cfg->listen_addr, &addr) <= 0) { printf("Malformed address %s\n", cfg->listen_addr); goto fail; } error = uinet_socreate(UINET_PF_INET, &listener, UINET_SOCK_STREAM, 0); if (0 != error) { printf("Listen socket creation failed (%d)\n", error); goto fail; } soctx = ev_uinet_attach(listener); if (NULL == soctx) { printf("Failed to alloc libev socket context\n"); goto fail; } if ((error = uinet_make_socket_passive(listener))) { printf("Failed to make listen socket passive (%d)\n", error); goto fail; } if (cfg->interface->promisc) { if ((error = uinet_make_socket_promiscuous(listener, cfg->interface->cdom))) { printf("Failed to make listen socket promiscuous (%d)\n", error); goto fail; } } /* * The following settings will be inherited by all sockets created * by this listen socket. */ /* * Need to be non-blocking to work with the event system. */ uinet_sosetnonblocking(listener, 1); /* Wait 5 seconds for connections to complete */ optlen = sizeof(optval); optval = 5; if ((error = uinet_sosetsockopt(listener, UINET_IPPROTO_TCP, UINET_TCP_KEEPINIT, &optval, optlen))) goto fail; /* Begin counting down to close after 10 seconds of idle */ optlen = sizeof(optval); optval = 10; if ((error = uinet_sosetsockopt(listener, UINET_IPPROTO_TCP, UINET_TCP_KEEPIDLE, &optval, optlen))) goto fail; /* Count down to close once per second */ optlen = sizeof(optval); optval = 1; if ((error = uinet_sosetsockopt(listener, UINET_IPPROTO_TCP, UINET_TCP_KEEPINTVL, &optval, optlen))) goto fail; /* Close after idle for 3 counts */ optlen = sizeof(optval); optval = 3; if ((error = uinet_sosetsockopt(listener, UINET_IPPROTO_TCP, UINET_TCP_KEEPCNT, &optval, optlen))) goto fail; /* Wait 100 milliseconds for missing TCP segments */ optlen = sizeof(optval); optval = 100; if ((error = uinet_sosetsockopt(listener, UINET_IPPROTO_TCP, UINET_TCP_REASSDL, &optval, optlen))) goto fail; passive = calloc(1, sizeof(struct passive_context)); if (NULL == passive) { goto fail; } passive->loop = loop; passive->listener = listener; passive->verbose = cfg->verbose; passive->interface = cfg->interface; passive->extract = cfg->extract; memcpy(passive->content_types, cfg->content_types, sizeof(passive->content_types)); memset(&sin, 0, sizeof(struct uinet_sockaddr_in)); sin.sin_len = sizeof(struct uinet_sockaddr_in); sin.sin_family = UINET_AF_INET; sin.sin_addr = addr; sin.sin_port = htons(cfg->listen_port); error = uinet_sobind(listener, (struct uinet_sockaddr *)&sin); if (0 != error) { printf("bind failed\n"); goto fail; } error = uinet_solisten(passive->listener, -1); if (0 != error) goto fail; if (passive->verbose) { char buf[32]; printf("Listening on %s:%u\n", uinet_inet_ntoa(addr, buf, sizeof(buf)), cfg->listen_port); } ev_init(&passive->listen_watcher, accept_cb); ev_uinet_set(&passive->listen_watcher, soctx, EV_READ); passive->listen_watcher.data = passive; ev_uinet_start(loop, &passive->listen_watcher); return (passive); fail: if (soctx) ev_uinet_detach(soctx); if (listener) uinet_soclose(listener); if (passive) free(passive); return (NULL); }
/* * The passive http extraction code works by alternately parsing the * passively reconstructed request and response streams. The same callback * (below) is used to drive the parsing of each stream. Parsing begins with * the request stream, and once a complete request has been parsed, the * parser and read watcher for the request stream are paused and the parser * and read watcher for the response stream are activated. Once an entire * response is parsed, the parser and read watcher for the response stream * are paused, and the parser and read watcher for the request stream are * activated. Along the way, response bodies that match the supplied list * of content types are extracted to files. * * This is example code whose purpose is to demonstrate upper layer protocol * processing using libuinet passive sockets functionality. Little to no * attempt is made to deal with a number of ugly realities involved in * robustly parsing http streams in the wild. */ static void passive_extract_cb(struct ev_loop *loop, ev_uinet *w, int revents) { struct connection_context *conn = (struct connection_context *)w->data; struct uinet_iovec iov; struct uinet_uio uio; int max_read; int read_size; int bytes_read; int error; int flags; size_t nparsed; max_read = uinet_soreadable(w->so, 0); if (max_read <= 0) { /* the watcher should never be invoked if there is no error and there no bytes to be read */ assert(max_read != 0); /* * There are no more complete requests/responses to be had, shut everything down. */ if (conn->verbose) printf("%s: can't read, closing\n", conn->label); goto err; } else { read_size = imin(max_read, conn->buffer_size - conn->buffer_index); uio.uio_iov = &iov; iov.iov_base = &conn->buffer[conn->buffer_index]; iov.iov_len = read_size; uio.uio_iovcnt = 1; uio.uio_offset = 0; uio.uio_resid = read_size; flags = UINET_MSG_HOLE_BREAK; error = uinet_soreceive(w->so, NULL, &uio, &flags); if (0 != error) { printf("%s: read error (%d), closing\n", conn->label, error); goto err; } if (flags & UINET_MSG_HOLE_BREAK) { printf("%s: hole in data, closing connections\n", conn->label); goto err; } bytes_read = read_size - uio.uio_resid; conn->buffer_count += bytes_read; conn->bytes_read += bytes_read; do { passive_extract_parse_buffer(conn); if (HTTP_PARSER_ERRNO(conn->parser) != HPE_OK) { if (HTTP_PARSER_ERRNO(conn->parser) == HPE_PAUSED) { if (conn->verbose > 1) printf("%s: completed parsing request or response\n", conn->label); http_parser_pause(conn->peer->parser, 0); passive_extract_parse_buffer(conn->peer); if (HTTP_PARSER_ERRNO(conn->peer->parser) == HPE_OK) { if (conn->verbose > 1) printf("%s: peer needs more data\n", conn->label); /* Peer parser needs more data */ ev_uinet_stop(conn->server->loop, &conn->watcher); ev_uinet_start(conn->server->loop, &conn->peer->watcher); break; } else if (HTTP_PARSER_ERRNO(conn->peer->parser) != HPE_PAUSED) { printf("Peer parse failure %s, closing connections\n", http_errno_name(HTTP_PARSER_ERRNO(conn->peer->parser))); goto err; } else { if (conn->verbose > 1) printf("%s: peer completed parsing request or response\n", conn->label); /* * The other parser has paused, so it's time for us to continue * parsing/receiving. */ http_parser_pause(conn->parser, 0); } } else { printf("Parse failure %s, closing connections\n", http_errno_name(HTTP_PARSER_ERRNO(conn->parser))); goto err; } } } while (conn->buffer_count); } return; err: /* * Deliver EOS to each parser. If a parser is paused or otherwise * in an error state, no work will be done. The main reason for * doing this is to correctly handle the case where response parsing * requires an EOS to complete. Under such circumstances, one of * the calls below will complete the work. */ http_parser_execute(conn->parser, conn->parser_settings, NULL, 0); http_parser_execute(conn->peer->parser, conn->peer->parser_settings, NULL, 0); destroy_conn(conn->peer); destroy_conn(conn); }
static int passive_start(struct uinet_demo_config *cfg, uinet_instance_t uinst, struct ev_loop *loop) { struct uinet_demo_passive *passive = (struct uinet_demo_passive *)cfg; struct uinet_socket *listen_socket = NULL; struct ev_uinet_ctx *soctx = NULL; struct uinet_in_addr addr; int optlen, optval; int error; struct uinet_sockaddr_in sin; if (uinet_inet_pton(UINET_AF_INET, passive->listen_addr, &addr) <= 0) { printf("%s: Malformed address %s\n", passive->cfg.name, passive->listen_addr); error = UINET_EINVAL; goto fail; } error = uinet_socreate(passive->cfg.uinst, UINET_PF_INET, &listen_socket, UINET_SOCK_STREAM, 0); if (0 != error) { printf("%s: Listen socket creation failed (%d)\n", passive->cfg.name, error); goto fail; } soctx = ev_uinet_attach(listen_socket); if (NULL == soctx) { printf("%s: Failed to alloc libev socket context\n", passive->cfg.name); error = UINET_ENOMEM; goto fail; } if ((error = uinet_make_socket_passive(listen_socket))) { printf("%s: Failed to make listen socket passive (%d)\n", passive->cfg.name, error); goto fail; } if (passive->promisc) { if ((error = uinet_make_socket_promiscuous(listen_socket, NULL))) { printf("%s: Failed to make listen socket promiscuous (%d)\n", passive->cfg.name, error); goto fail; } } /* * The following settings will be inherited by all sockets created * by this listen socket. */ /* * Need to be non-blocking to work with the event system. */ uinet_sosetnonblocking(listen_socket, 1); /* Wait 5 seconds for connections to complete */ optlen = sizeof(optval); optval = 5; if ((error = uinet_sosetsockopt(listen_socket, UINET_IPPROTO_TCP, UINET_TCP_KEEPINIT, &optval, optlen))) { printf("%s: Failed to set TCP_KEEPINIT (%d)\n", passive->cfg.name, error); goto fail; } /* Begin counting down to close after 10 seconds of idle */ optlen = sizeof(optval); optval = 10; if ((error = uinet_sosetsockopt(listen_socket, UINET_IPPROTO_TCP, UINET_TCP_KEEPIDLE, &optval, optlen))) { printf("%s: Failed to set TCP_KEEPIDLE (%d)\n", passive->cfg.name, error); goto fail; } /* Count down to close once per second */ optlen = sizeof(optval); optval = 1; if ((error = uinet_sosetsockopt(listen_socket, UINET_IPPROTO_TCP, UINET_TCP_KEEPINTVL, &optval, optlen))) { printf("%s: Failed to set TCP_KEEPINTVL (%d)\n", passive->cfg.name, error); goto fail; } /* Close after idle for 3 counts */ optlen = sizeof(optval); optval = 3; if ((error = uinet_sosetsockopt(listen_socket, UINET_IPPROTO_TCP, UINET_TCP_KEEPCNT, &optval, optlen))) { printf("%s: Failed to set TCP_KEEPCNT (%d)\n", passive->cfg.name, error); goto fail; } /* Wait 100 milliseconds for missing TCP segments */ optlen = sizeof(optval); optval = 100; if ((error = uinet_sosetsockopt(listen_socket, UINET_IPPROTO_TCP, UINET_TCP_REASSDL, &optval, optlen))) { printf("%s: Failed to set TCP_REASSDL (%d)\n", passive->cfg.name, error); goto fail; } passive->listen_socket = listen_socket; memset(&sin, 0, sizeof(struct uinet_sockaddr_in)); sin.sin_len = sizeof(struct uinet_sockaddr_in); sin.sin_family = UINET_AF_INET; sin.sin_addr = addr; sin.sin_port = htons(passive->listen_port); error = uinet_sobind(listen_socket, (struct uinet_sockaddr *)&sin); if (0 != error) { printf("%s: Bind to %s:%u failed\n", passive->cfg.name, passive->listen_addr, passive->listen_port); goto fail; } error = uinet_solisten(passive->listen_socket, -1); if (0 != error) { printf("%s: Listen on %s:%u failed\n", passive->cfg.name, passive->listen_addr, passive->listen_port); goto fail; } if (passive->cfg.verbose) printf("%s: Listening on %s:%u\n", passive->cfg.name, passive->listen_addr, passive->listen_port); ev_init(&passive->listen_watcher, passive_accept_cb); ev_uinet_set(&passive->listen_watcher, soctx, EV_READ); passive->listen_watcher.data = passive; ev_uinet_start(loop, &passive->listen_watcher); return (0); fail: if (soctx) ev_uinet_detach(soctx); if (listen_socket) uinet_soclose(listen_socket); return (error); }
static void passive_accept_cb(struct ev_loop *loop, ev_uinet *w, int revents) { struct uinet_demo_passive *passive = w->data; struct uinet_socket *newso = NULL; struct uinet_socket *newpeerso = NULL; struct passive_connection *conn = NULL; struct passive_connection *peerconn = NULL; int error; unsigned int batch_limit = 32; unsigned int processed = 0; while ((processed < batch_limit) && (UINET_EWOULDBLOCK != (error = uinet_soaccept(w->so, NULL, &newso)))) { processed++; if (0 == error) { newpeerso = NULL; conn = NULL; peerconn = NULL; if (passive->cfg.verbose) printf("%s: Accept succeeded\n", passive->cfg.name); conn = create_conn(passive, newso, 1); if (NULL == conn) { printf("%s: Failed to alloc new connection context\n", passive->cfg.name); goto fail; } newpeerso = uinet_sogetpassivepeer(newso); peerconn = create_conn(passive, newpeerso, 0); if (NULL == peerconn) { printf("%s: Failed to alloc new peer connection context\n", passive->cfg.name); goto fail; } conn->peer = peerconn; peerconn->peer = conn; ev_uinet_start(loop, &conn->watcher); ev_uinet_start(loop, &peerconn->watcher); if (conn->verbose || (passive->cfg.copy_mode & UINET_IP_COPY_MODE_MAYBE)) ev_uinet_start(loop, &conn->connected_watcher); if (peerconn->verbose || (passive->cfg.copy_mode & UINET_IP_COPY_MODE_MAYBE)) ev_uinet_start(loop, &peerconn->connected_watcher); passive->num_sockets += 2; continue; fail: if (conn) destroy_conn(conn); if (newso) uinet_soclose(newso); if (newpeerso) uinet_soclose(newpeerso); } } if (processed > passive->max_accept_batch) passive->max_accept_batch = processed; }
static struct echo_context * create_echo(struct ev_loop *loop, struct server_config *cfg) { struct echo_context *echo = NULL; struct uinet_socket *listener = NULL; struct ev_uinet_ctx *soctx = NULL; struct uinet_in_addr addr; int optlen, optval; int error; struct uinet_sockaddr_in sin; if (uinet_inet_pton(UINET_AF_INET, cfg->listen_addr, &addr) <= 0) { printf("Malformed address %s\n", cfg->listen_addr); goto fail; } error = uinet_socreate(UINET_PF_INET, &listener, UINET_SOCK_STREAM, 0); if (0 != error) { printf("Listen socket creation failed (%d)\n", error); goto fail; } soctx = ev_uinet_attach(listener); if (NULL == soctx) { printf("Failed to alloc libev socket context\n"); goto fail; } if (cfg->interface->promisc) { if ((error = uinet_make_socket_promiscuous(listener, cfg->interface->cdom))) { printf("Failed to make listen socket promiscuous (%d)\n", error); goto fail; } } uinet_sosetnonblocking(listener, 1); /* Set NODELAY on the listen socket so it will be set on all * accepted sockets via inheritance. */ optlen = sizeof(optval); optval = 1; if ((error = uinet_sosetsockopt(listener, UINET_IPPROTO_TCP, UINET_TCP_NODELAY, &optval, optlen))) goto fail; echo = malloc(sizeof(struct echo_context)); if (NULL == echo) { goto fail; } /* Listen on all VLANs */ if ((error = uinet_setl2info2(listener, NULL, NULL, UINET_INL2I_TAG_ANY, NULL))) { printf("Listen socket L2 info set failed (%d)\n", error); goto fail; } echo->loop = loop; echo->listener = listener; echo->verbose = cfg->verbose; echo->listen_cdom = cfg->interface->cdom; memset(&sin, 0, sizeof(struct uinet_sockaddr_in)); sin.sin_len = sizeof(struct uinet_sockaddr_in); sin.sin_family = UINET_AF_INET; sin.sin_addr = addr; sin.sin_port = htons(cfg->listen_port); error = uinet_sobind(listener, (struct uinet_sockaddr *)&sin); if (0 != error) { printf("bind failed\n"); goto fail; } error = uinet_solisten(echo->listener, -1); if (0 != error) goto fail; if (echo->verbose) { char buf[32]; printf("Listening on %s:%u\n", uinet_inet_ntoa(addr, buf, sizeof(buf)), cfg->listen_port); } ev_init(&echo->listen_watcher, accept_cb); ev_uinet_set(&echo->listen_watcher, soctx, EV_READ); echo->listen_watcher.data = echo; ev_uinet_start(loop, &echo->listen_watcher); return (echo); fail: if (soctx) ev_uinet_detach(soctx); if (listener) uinet_soclose(listener); if (echo) free(echo); return (NULL); }
static void nproxy_accept_cb(struct ev_loop *loop, ev_uinet *w, int revents) { struct uinet_demo_nproxy *nproxy = w->data; struct uinet_socket *newso = NULL; struct ev_uinet_ctx *soctx = NULL; struct nproxy_splice *splice = NULL; int error; if (0 != (error = uinet_soaccept(w->so, NULL, &newso))) { printf("%s: Accept failed (%d)\n", nproxy->cfg.name, error); } else { if (nproxy->cfg.verbose) printf("%s: Accept succeeded\n", nproxy->cfg.name); soctx = ev_uinet_attach(newso); if (NULL == soctx) { printf("%s: Failed to alloc libev context for new splice\n", nproxy->cfg.name); goto fail; } splice = malloc(sizeof(*splice)); if (NULL == splice) { printf("%s: Failed to alloc new splice context\n", nproxy->cfg.name); goto fail; } splice->nproxy = nproxy; splice->id = nproxy->next_id++; splice->verbose = nproxy->cfg.verbose; splice->inbound.name = "inbound"; splice->inbound.splice = splice; splice->inbound.other_side = &splice->outbound; splice->outbound.name = "outbound"; splice->outbound.splice = splice; splice->outbound.other_side = &splice->inbound; ev_init(&splice->inbound.connected_watcher, nproxy_inbound_connected_cb); ev_uinet_set(&splice->inbound.connected_watcher, soctx, EV_WRITE); splice->inbound.connected_watcher.data = splice; ev_uinet_start(loop, &splice->inbound.connected_watcher); ev_init(&splice->inbound.writable_watcher, nproxy_writable_cb); ev_uinet_set(&splice->inbound.writable_watcher, soctx, EV_WRITE); splice->inbound.writable_watcher.data = &splice->inbound; /* will be started as necessary by the outbound copy watcher */ ev_init(&splice->inbound.copy_watcher, nproxy_copy_cb); ev_uinet_set(&splice->inbound.copy_watcher, soctx, EV_READ); splice->inbound.copy_watcher.data = &splice->inbound; /* will be started when the outbound connection is established */ } return; fail: if (splice) free(splice); if (soctx) ev_uinet_detach(soctx); if (newso) uinet_soclose(newso); }
static void nproxy_inbound_connected_cb(struct ev_loop *loop, ev_uinet *w, int revents) { struct nproxy_splice *splice = w->data; struct uinet_demo_nproxy *nproxy = splice->nproxy; struct uinet_sockaddr_in *sin_local, *sin_foreign; struct uinet_socket *outbound_socket = NULL; struct ev_uinet_ctx *soctx = NULL; struct uinet_in_l2info l2i; char buf1[32], buf2[32]; int optlen, optval; int error; uinet_sogetsockaddr(w->so, (struct uinet_sockaddr **)&sin_local); uinet_sogetpeeraddr(w->so, (struct uinet_sockaddr **)&sin_foreign); if (splice->verbose) printf("%s: splice %llu: inbound connection established (local=%s:%u foreign=%s:%u)\n", nproxy->cfg.name, (unsigned long long)splice->id, uinet_inet_ntoa(sin_local->sin_addr, buf1, sizeof(buf1)), ntohs(sin_local->sin_port), uinet_inet_ntoa(sin_foreign->sin_addr, buf2, sizeof(buf2)), ntohs(sin_foreign->sin_port)); if ((nproxy->cfg.copy_mode & UINET_IP_COPY_MODE_MAYBE) && ((uinet_sogetserialno(w->so) % nproxy->cfg.copy_every) == 0)){ if ((error = uinet_sosetcopymode(w->so, UINET_IP_COPY_MODE_RX|UINET_IP_COPY_MODE_ON, nproxy->cfg.copy_limit, nproxy->cfg.copy_uif))) printf("%s: splice %llu: Failed to set copy mode (%d)\n", nproxy->cfg.name, (unsigned long long)splice->id, error); } /* don't need this watcher anymore */ ev_uinet_stop(loop, w); /* Create the outbound connection */ error = uinet_socreate(nproxy->cfg.uinst, UINET_PF_INET, &outbound_socket, UINET_SOCK_STREAM, 0); if (error != 0) { printf("%s: splice %llu: outbound socket creation failed (%d)\n", nproxy->cfg.name, (unsigned long long)splice->id, error); goto fail; } if ((error = uinet_make_socket_promiscuous(outbound_socket, nproxy->outbound_if))) { printf("%s: splice %llu: failed to make outbound socket promiscuous (%d)\n", nproxy->cfg.name, (unsigned long long)splice->id, error); goto fail; } /* * Socket needs to be non-blocking to work with the event system */ uinet_sosetnonblocking(outbound_socket, 1); optlen = sizeof(optval); optval = 1; error = uinet_sosetsockopt(outbound_socket, UINET_IPPROTO_TCP, UINET_TCP_NODELAY, &optval, optlen); if (error != 0) { printf("%s: splice %llu: failed to set TCP_NODELAY on outbound socket (%d)\n", nproxy->cfg.name, (unsigned long long)splice->id, error); goto fail; } /* Bind to the foreign address of the inbound connection */ error = uinet_sobind(outbound_socket, (struct uinet_sockaddr *)sin_foreign); if (error != 0) { printf("%s: splice %llu: outbound socket bind failed (%d)\n", nproxy->cfg.name, (unsigned long long)splice->id, error); goto fail; } /* * Use the same MAC addrs and VLAN tag stack as the inbound * connection, which requires swapping the local and foreign MAC * addrs. */ error = uinet_getl2info(w->so, &l2i); if (error != 0) { printf("%s: splice %llu: unable to get l2info from inbound socket (%d)\n", nproxy->cfg.name, (unsigned long long)splice->id, error); goto fail; } error = uinet_setl2info2(outbound_socket, l2i.inl2i_foreign_addr, l2i.inl2i_local_addr, l2i.inl2i_flags, &l2i.inl2i_tagstack); if (error != 0) { printf("%s: splice %llu: unable to set l2info for outbound socket (%d)\n", nproxy->cfg.name, (unsigned long long)splice->id, error); goto fail; } soctx = ev_uinet_attach(outbound_socket); if (NULL == soctx) { printf("%s: splice %llu: failed to alloc libev context for outbound socket\n", nproxy->cfg.name, (unsigned long long)splice->id); goto fail; } /* The connection target is the local address of the inbound connection */ error = uinet_soconnect(outbound_socket, (struct uinet_sockaddr *)sin_local); if ((error != 0) && (error != UINET_EINPROGRESS)) { printf("%s: splice %llu: outbound socket connect failed (%d)\n", nproxy->cfg.name, (unsigned long long)splice->id, error); goto fail; } uinet_free_sockaddr((struct uinet_sockaddr *)sin_local); uinet_free_sockaddr((struct uinet_sockaddr *)sin_foreign); ev_init(&splice->outbound.connected_watcher, nproxy_outbound_connected_cb); ev_uinet_set(&splice->outbound.connected_watcher, soctx, EV_WRITE); splice->outbound.connected_watcher.data = splice; ev_uinet_start(loop, &splice->outbound.connected_watcher); ev_init(&splice->outbound.writable_watcher, nproxy_writable_cb); ev_uinet_set(&splice->outbound.writable_watcher, soctx, EV_WRITE); splice->outbound.writable_watcher.data = &splice->outbound; /* will be started as necessary by the inbound copy watcher */ ev_init(&splice->outbound.copy_watcher, nproxy_copy_cb); ev_uinet_set(&splice->outbound.copy_watcher, soctx, EV_READ); splice->outbound.copy_watcher.data = &splice->outbound; /* will be started when the outbound connection is established */ return; fail: uinet_free_sockaddr((struct uinet_sockaddr *)sin_local); uinet_free_sockaddr((struct uinet_sockaddr *)sin_foreign); if (soctx) ev_uinet_detach(soctx); if (outbound_socket) uinet_soclose(outbound_socket); free(splice); }
static void nproxy_copy_cb(struct ev_loop *loop, ev_uinet *w, int revents) { struct nproxy_connection *conn = w->data; struct nproxy_connection *other_side_conn = conn->other_side; struct nproxy_splice *splice = conn->splice; struct uinet_demo_nproxy *nproxy = splice->nproxy; struct uinet_socket *other_side_so = conn->other_side->copy_watcher.so; struct uinet_iovec iov; struct uinet_uio uio; int max_read; int max_write; int read_size; int error; #define BUFFER_SIZE (64*1024) char buffer[BUFFER_SIZE]; max_read = uinet_soreadable(w->so, 0); if (max_read <= 0) { /* the watcher should never be invoked if there is no error and there no bytes to be read */ assert(max_read != 0); if (splice->verbose) printf("%s: splice %llu: %s: can't read, closing splice\n", nproxy->cfg.name, (unsigned long long)splice->id, conn->name); goto err; } else { max_write = uinet_sowritable(other_side_so, 0); if (-1 == max_write) { if (splice->verbose) printf("%s: splice %llu: %s: can't write, closing splice\n", nproxy->cfg.name, (unsigned long long)splice->id, other_side_conn->name); goto err; } else { read_size = imin(imin(max_read, max_write), BUFFER_SIZE); /* read_size == 0 should only happen when max_write is 0 */ if (read_size > 0) { uio.uio_iov = &iov; iov.iov_base = buffer; iov.iov_len = read_size; uio.uio_iovcnt = 1; uio.uio_offset = 0; uio.uio_resid = read_size; error = uinet_soreceive(w->so, NULL, &uio, NULL); if (0 != error) { printf("%s: splice %llu: %s: read error (%d), closing splice\n", nproxy->cfg.name, (unsigned long long)splice->id, conn->name, error); goto err; } assert(uio.uio_resid == 0); uio.uio_iov = &iov; iov.iov_base = buffer; iov.iov_len = read_size; uio.uio_iovcnt = 1; uio.uio_offset = 0; uio.uio_resid = read_size; error = uinet_sosend(other_side_so, NULL, &uio, 0); if (0 != error) { printf("%s: splice %llu: %s: write error (%d), closing splice\n", nproxy->cfg.name, (unsigned long long)splice->id, other_side_conn->name, error); goto err; } } if (max_write < max_read) { /* * Limited by write space, so deactivate us * and activate the write watcher for the * other side, which will reactivate us when * it fires. */ ev_uinet_stop(loop, w); ev_uinet_start(loop, &other_side_conn->writable_watcher); } } } return; err: nproxy_splice_destroy(loop, splice); }