Skip to content

Conversation

@saghul
Copy link
Member

@saghul saghul commented Jun 16, 2015

As per the LEP: libuv/leps#5

This is still WIP, I's just like a bit of early feedback.

ToDo:

  • Discuss / bikeshed on the naming
  • Windows
  • UDP
  • More tests
  • Add "versionadded" to the docs

R=@bnoordhuis

@bnoordhuis
Copy link
Member

I'd probably make the domain argument to uv_tcp_init_ex() a general purpose flags argument with the domain in the low bits.

There are only about 40-something address families and every platform I know of numbers them incrementally starting from zero, so you'd only need 6 bits to cover them all. Make it 8 or 10 bits to play it safe.

(Although that's wasting a lot of bits... AF_UNSPEC is always zero and AF_INET and AF_INET6 always < 32, AFAIK. But that aside.)

@saghul
Copy link
Member Author

saghul commented Jun 17, 2015

Can you elaborate a bit on why? Extensibility? FWIW, this is the first time that we modify some uv_*_init in years (if memory serves right), since they tend to basically do nothing, so I'm not really concerned about that.

@bnoordhuis
Copy link
Member

Extensibility, yes. Always leave an escape hatch if at all possible.

@saghul
Copy link
Member Author

saghul commented Jun 17, 2015

Let's assume there is some UV_NO_CLOEXEC flag which prevents the sockets from being created with O_CLOEXEC set. This API would then be used as follows:

uv_tcp_init_ex(loop, handle, AF_INET|UV_NO_CLOEXEC);

Is that right? Looks a bit weird to me :-S I can add a dummy flags thing if you really feel strong about it:

int uv_tcp_init_ex(uv_loop_t*, uv_tcp_t* handle, int domain, int flags);
uv_tcp_init_ex(loop, handle, AF_INET, UV_NO_CLOEXEC|UV_DO_AWESOME_STUFF);

WDYT?

@bnoordhuis
Copy link
Member

The three arg version looks alright to me and it's easier to remember, you can't accidentally swap the domain and the flags arguments. You can alias AF_INET as UV_AF_INET if using plain AF_INET bothers you.

@saghul
Copy link
Member Author

saghul commented Jun 17, 2015

@bnoordhuis is saghul@9e02f49 what you were suggesting?

@saghul saghul force-pushed the create_sockets_early branch 8 times, most recently from d59699b to 7eff28f Compare June 18, 2015 12:35
@saghul
Copy link
Member Author

saghul commented Jun 18, 2015

@bnoordhuis I'm chasing some failures on Windows, but can you PTAL the unix side?

@saghul saghul force-pushed the create_sockets_early branch from 7eff28f to 9f176e5 Compare June 18, 2015 14:08
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Femto-nit: the parens aren't necessary here.

@saghul saghul force-pushed the create_sockets_early branch from 9f176e5 to 6b4e0a0 Compare June 18, 2015 14:26
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sizeof(addr.sin_addr)?

@bnoordhuis
Copy link
Member

UNIX side LGTM minus some nits. Windows side looks okay to me too.

@saghul saghul force-pushed the create_sockets_early branch 2 times, most recently from 92d7f26 to fb63597 Compare June 18, 2015 14:48
@saghul
Copy link
Member Author

saghul commented Jun 18, 2015

@saghul saghul changed the title WIP: add ability to create sockets early Add ability to create sockets early Jun 18, 2015
@saghul saghul force-pushed the create_sockets_early branch from fb63597 to 388098f Compare June 18, 2015 15:09
@saghul
Copy link
Member Author

saghul commented Jun 18, 2015

Ok, addressed everything and the build is "green" (surprisingly we've been keeping it that way on Windows for a while \o/).

If nobody has any further comments I'll land this and the LEP later tonight.

Thanks again for the review Ben!

saghul added 2 commits June 19, 2015 09:37
Introduce two new APIs:

int uv_tcp_init_ex(uv_loop_t*, uv_tcp_t* handle, int flags)
int uv_udp_init_ex(uv_loop_t*, uv_udp_t* handle, int flags)

The lower 8 bits of the flags field are used for the socket domain.
AF_INET, AF_INET6 and AF_UNSPEC are supported. If AF_UNSPEC is specified
the socket is created lazily, just like uv_{tcp,udp}_init.

Some Windows notes:

getsockname fails with WSAEINVAL if the socket is not bound. This could
potentially be improved by detecting the socket family and filling
the sockaddr_in/6 struct manually.

bind returns WSAEFAULT if we try to bind a socket to the wrong family.
Unix returns EINVAL.

PR-URL: libuv#400
Reviewed-By: Ben Noordhuis <[email protected]>
@saghul saghul force-pushed the create_sockets_early branch from 388098f to f8f5982 Compare June 19, 2015 07:37
@saghul saghul merged commit f8f5982 into libuv:v1.x Jun 19, 2015
@saghul
Copy link
Member Author

saghul commented Jun 19, 2015

Landed!

@vavrusa
Copy link
Contributor

vavrusa commented Jun 25, 2015

Just a followup, can you do an API bump in the master/v1.x so I can #ifdef for the new version?

@saghul
Copy link
Member Author

saghul commented Jun 25, 2015

@vavrusa we bump the version when making a release (the tool does it), so you'll have to wait until we make a 1.7.0 release, sorry.

@vavrusa
Copy link
Contributor

vavrusa commented Jun 29, 2015

Okay, a small request then - could you make a macro in uv-version.h (basically UV_VERSION from version.c) so I could check for version instead of MAJOR > 1 || MAJOR == 1 && (MINOR > 6 && ... in preprocessor? I like both decimal 171 or hex 0x00010700 ways.

Example:

#if UV_VERSION >= 0x00107000
#define ENABLE_REUSEPORT
#endif

Decimal is neater, but it requires you must use 1 digit per minor release at most.

@saghul
Copy link
Member Author

saghul commented Jun 29, 2015

@vavrusa sounds ok to me, here is a PR: #412

@saghul
Copy link
Member Author

saghul commented Jun 29, 2015

@vavrusa you can now use UV_VERSION_HEX.

guworks pushed a commit to guworks/libuv that referenced this pull request Jul 9, 2015
guworks pushed a commit to guworks/libuv that referenced this pull request Jul 9, 2015
guworks pushed a commit to guworks/libuv that referenced this pull request Jul 9, 2015
Introduce two new APIs:

int uv_tcp_init_ex(uv_loop_t*, uv_tcp_t* handle, int flags)
int uv_udp_init_ex(uv_loop_t*, uv_udp_t* handle, int flags)

The lower 8 bits of the flags field are used for the socket domain.
AF_INET, AF_INET6 and AF_UNSPEC are supported. If AF_UNSPEC is specified
the socket is created lazily, just like uv_{tcp,udp}_init.

Some Windows notes:

getsockname fails with WSAEINVAL if the socket is not bound. This could
potentially be improved by detecting the socket family and filling
the sockaddr_in/6 struct manually.

bind returns WSAEFAULT if we try to bind a socket to the wrong family.
Unix returns EINVAL.

PR-URL: libuv#400
Reviewed-By: Ben Noordhuis <[email protected]>
skomski pushed a commit to skomski/libuv that referenced this pull request Aug 5, 2015
skomski pushed a commit to skomski/libuv that referenced this pull request Aug 5, 2015
skomski pushed a commit to skomski/libuv that referenced this pull request Aug 5, 2015
Introduce two new APIs:

int uv_tcp_init_ex(uv_loop_t*, uv_tcp_t* handle, int flags)
int uv_udp_init_ex(uv_loop_t*, uv_udp_t* handle, int flags)

The lower 8 bits of the flags field are used for the socket domain.
AF_INET, AF_INET6 and AF_UNSPEC are supported. If AF_UNSPEC is specified
the socket is created lazily, just like uv_{tcp,udp}_init.

Some Windows notes:

getsockname fails with WSAEINVAL if the socket is not bound. This could
potentially be improved by detecting the socket family and filling
the sockaddr_in/6 struct manually.

bind returns WSAEFAULT if we try to bind a socket to the wrong family.
Unix returns EINVAL.

PR-URL: libuv#400
Reviewed-By: Ben Noordhuis <[email protected]>
skomski pushed a commit to skomski/libuv that referenced this pull request Aug 5, 2015
skomski pushed a commit to skomski/libuv that referenced this pull request Aug 5, 2015
skomski pushed a commit to skomski/libuv that referenced this pull request Aug 5, 2015
Introduce two new APIs:

int uv_tcp_init_ex(uv_loop_t*, uv_tcp_t* handle, int flags)
int uv_udp_init_ex(uv_loop_t*, uv_udp_t* handle, int flags)

The lower 8 bits of the flags field are used for the socket domain.
AF_INET, AF_INET6 and AF_UNSPEC are supported. If AF_UNSPEC is specified
the socket is created lazily, just like uv_{tcp,udp}_init.

Some Windows notes:

getsockname fails with WSAEINVAL if the socket is not bound. This could
potentially be improved by detecting the socket family and filling
the sockaddr_in/6 struct manually.

bind returns WSAEFAULT if we try to bind a socket to the wrong family.
Unix returns EINVAL.

PR-URL: libuv#400
Reviewed-By: Ben Noordhuis <[email protected]>
@brimworks
Copy link
Contributor

BTW, the change to src/win/pipe.c in this change:

fb5df54

Is causing this problem:

luvit/luv#177

Removing this code from src/win/pipe.c:uv_set_pipe_handle() fixes the problem:

if (handle->handle != INVALID_HANDLE_VALUE)
return UV_EBUSY;

@brimworks
Copy link
Contributor

This error is triggered in this code path:

int uv_pipe_accept(uv_pipe_t* server, uv_stream_t* client) {
    ...
    if (server->ipc) {
        ...
    } else {
        ...
        if (!(server->flags & UV__HANDLE_CLOSING)) {
            uv_pipe_queue_accept(loop, server, req, FALSE);
        }
    }
}

static void uv_pipe_queue_accept(uv_loop_t* loop, uv_pipe_t* handle,
    uv_pipe_accept_t* req, BOOL firstInstance) {
    ...
    if (!firstInstance) {
        ...
        if (uv_set_pipe_handle(loop, handle, req->pipeHandle, -1, 0)) {
            ...
        }
    }
}

I could set server->handle = INVALID_HANDLE_VALUE; before uv_pipe_queue_accept() is called and fix this, but I don't know if that is the right thing to do.

@fippo
Copy link

fippo commented Jul 26, 2021

I just had a nice chat with @saghul about this which probably triggered a lot of memories for him :-)
Here is what I ended up with to manually do the setsockopt call, might be useful for someone:

  uv_udp_t* socket = new uv_udp_t;
  uv_udp_init_ex(Loop::GetLoop(), socket, UV_UDP_RECVMMSG | AF_INET);

  uv_os_fd_t fd;
  if (uv_fileno(reinterpret_cast<uv_handle_t*>(socket), &fd) == 0) {
    uint32_t yes = 1;
    int err = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, (char*)&yes, sizeof yes);
    printf("setsockopt SO_REUSEPORT err %d\n", err);
  }
  struct sockaddr_in recv_addr;
  uv_ip4_addr(listenIp.c_str(), listenPort, &recv_addr);
  uv_udp_bind(socket, (const struct sockaddr*)&recv_addr, UV_UDP_REUSEADDR);
  // ...

(for some implementations of Loop::GetLoop()

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants