Skip to content

Win32: evconnlistener_new_bind with LEV_OPT_REUSEABLE #1833

@adamws

Description

@adamws

I'm implementing server which initializes listener like this (err handling omitted):

struct event_base* base = event_base_new();
struct sockaddr_in sin;
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_port = htons(8444);
sin.sin_addr.s_addr = htonl(INADDR_ANY);
struct evconnlistener* listener = evconnlistener_new_bind(base, HandleAccept, ctx,
                                       LEV_OPT_REUSEABLE | LEV_OPT_CLOSE_ON_FREE,
                                       -1,
                                       (struct sockaddr*)&sin, sizeof(sin));
evconnlistener_set_error_cb(listener, HandleAcceptError);
event_base_dispatch(base);
evconnlistener_free(listener);
event_base_free(base);

I need to support both Linux & Windows. Server process might be killed abruptly at any moment and it should be possible to restart it quickly - hence LEV_OPT_REUSABLE (I think that details are not that important, we are using it in our test setup, server is started&killed by python).

On Linux this behaves as I expect, on Windows I'm getting 10048 (Only one usage of each socket address (protocol/network address/port) is normally permitted.) from evconnlistener_new_bind.

I've learned that SO_REUSEADDR on Unix and on Windows are different and tracked down my problem down to

libevent/evutil.c

Lines 480 to 493 in a994a52

int
evutil_make_listen_socket_reuseable(evutil_socket_t sock)
{
#if defined(SO_REUSEADDR) && !defined(_WIN32)
int one = 1;
/* REUSEADDR on Unix means, "don't hang on to this address after the
* listener is closed." On Windows, though, it means "don't keep other
* processes from binding to this address while we're using it. */
return setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void*) &one,
(ev_socklen_t)sizeof(one));
#else
return 0;
#endif
}

which causes the LEV_OPT_REUSEABLE to do nothing on Windows.

I assume this is intentional but:

  • this behavior could be documented better in
    /** Flag: Indicates that we should disable the timeout (if any) between when
    * this socket is closed and when we can listen again on the same port. */
    #define LEV_OPT_REUSEABLE (1u<<3)
  • perhaps dedicated flag which does set SO_REUSEADDR on Windows could be added so it is possible to use this nice utility function for both platforms - by all means, I'm not an expert, my main complaint here is about documentation - but giving user a choice seems reasonable here.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions