uNetworking / uSockets

Miniscule cross-platform eventing, networking & crypto for async applications
Apache License 2.0
1.27k stars 261 forks source link

Adopting/transferring in a file descriptor #172

Closed abrownsword closed 8 months ago

abrownsword commented 2 years ago

For a project I've just been working on, I needed to be able to transfer in a socket that I created outside of uWebSockets/uSockets. I modified loop.c by moving the guts of the accept loop into a new function (us_socket_transfer) which is externally callable. The contents of the accept loop becomes just a call to this function, but if I create an accepted socket elsewhere in my program (transferred from another process, in my case) then I can call this function and the uWS::Loop "adopts" it. I haven't done extensive testing yet (and my code is just for an internal prototype so its not likely to become production code), but it seems to be working well. I thought I would suggest the change in case others might find it useful (I saw one issue mentioning inter-process socket transfers).

int us_socket_transfer(int client_fd, struct us_listen_socket_t *listen_socket, void *internal_addr)
{
    struct bsd_addr_t *addr = (struct bsd_addr_t*)internal_addr;
    struct bsd_addr_t bsd_addr;
    if (addr == NULL)
    {
        addr = &bsd_addr;
        if (bsd_remote_addr(client_fd, &bsd_addr) == -1)
            return -1;
    }

    struct us_poll_t *accepted_p = us_create_poll(us_socket_context(0, &listen_socket->s)->loop, 0, sizeof(struct us_socket_t) - sizeof(struct us_poll_t) + listen_socket->socket_ext_size);
    us_poll_init(accepted_p, client_fd, POLL_TYPE_SOCKET);
    us_poll_start(accepted_p, listen_socket->s.context->loop, LIBUS_SOCKET_READABLE);

    struct us_socket_t *s = (struct us_socket_t *) accepted_p;

    s->context = listen_socket->s.context;
    s->timeout = 0;
    s->low_prio_state = 0;

    /* We always use nodelay */
    bsd_socket_nodelay(client_fd, 1);

    us_internal_socket_context_link(listen_socket->s.context, s);

    listen_socket->s.context->on_open(s, 0, bsd_addr_get_ip(addr), bsd_addr_get_ip_length(addr));

    /* Exit accept loop if listen socket was closed in on_open handler */
    return us_socket_is_closed(0, &listen_socket->s);
}
ghost commented 2 years ago

Looks fine can you make it a PR?

abrownsword commented 1 year ago

https://github.com/uNetworking/uSockets/pull/175

uNetworkingAB commented 8 months ago

This is now possible and used in the uWS::LocalCluster you can look at HelloWorldThreaded