diff options
author | Murat Demirten <mdemirten@yh.com.tr> | 2018-06-04 16:43:34 +0300 |
---|---|---|
committer | Azat Khuzhin <a3at.mail@gmail.com> | 2018-10-26 07:24:29 +0300 |
commit | 387d91f9ab95df8ac3d7bb58493310ad4a377dcf (patch) | |
tree | 960a1f3e5bfbf51a0c85f92f11dec8b341752b9e | |
parent | b2667b76969c2ea382373f885062b45e82d0ac59 (diff) | |
download | libevent-387d91f9ab95df8ac3d7bb58493310ad4a377dcf.tar.gz |
listener: ipv6only socket bind support
According to RFC3493 and most Linux distributions, default value is to
work in IPv4-mapped mode. If there is a requirement to bind same port
on same ip addresses but different handlers for both IPv4 and IPv6,
it is required to set IPV6_V6ONLY socket option to be sure that the
code works as expected without affected by bindv6only sysctl setting
in system.
See an example working with this patch:
https://gist.github.com/demirten/023008a63cd966e48b0ebcf9af7fc113
Closes: #640 (cherry-pick)
-rw-r--r-- | evutil.c | 8 | ||||
-rw-r--r-- | include/event2/listener.h | 12 | ||||
-rw-r--r-- | include/event2/util.h | 12 | ||||
-rw-r--r-- | listener.c | 5 |
4 files changed, 37 insertions, 0 deletions
@@ -386,6 +386,14 @@ evutil_make_listen_socket_reuseable_port(evutil_socket_t sock) } int +evutil_make_listen_socket_ipv6only(evutil_socket_t sock) +{ + int one = 1; + return setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (void*) &one, + (ev_socklen_t)sizeof(one)); +} + +int evutil_make_tcp_listen_socket_deferred(evutil_socket_t sock) { #if defined(EVENT__HAVE_NETINET_TCP_H) && defined(TCP_DEFER_ACCEPT) diff --git a/include/event2/listener.h b/include/event2/listener.h index 84b4da05..789a27c2 100644 --- a/include/event2/listener.h +++ b/include/event2/listener.h @@ -97,6 +97,18 @@ typedef void (*evconnlistener_errorcb)(struct evconnlistener *, void *); * This is only available on Linux and kernel 3.9+ */ #define LEV_OPT_REUSEABLE_PORT (1u<<7) +/** Flag: Indicates that the listener wants to work only in IPv6 socket. + * + * According to RFC3493 and most Linux distributions, default value is to + * work in IPv4-mapped mode. If there is a requirement to bind same port + * on same ip addresses but different handlers for both IPv4 and IPv6, + * it is required to set IPV6_V6ONLY socket option to be sure that the + * code works as expected without affected by bindv6only sysctl setting in + * system. + * + * This socket option also supported by Windows. + */ +#define LEV_OPT_BIND_IPV6ONLY (1u<<8) /** Allocate a new evconnlistener object to listen for incoming TCP connections diff --git a/include/event2/util.h b/include/event2/util.h index 70aabb66..c0f5f80b 100644 --- a/include/event2/util.h +++ b/include/event2/util.h @@ -426,6 +426,18 @@ int evutil_make_listen_socket_reuseable(evutil_socket_t sock); EVENT2_EXPORT_SYMBOL int evutil_make_listen_socket_reuseable_port(evutil_socket_t sock); +/** Set ipv6 only bind socket option to make listener work only in ipv6 sockets. + + According to RFC3493 and most Linux distributions, default value for the + sockets is to work in IPv4-mapped mode. In IPv4-mapped mode, it is not possible + to bind same port from different IPv4 and IPv6 handlers. + + @param sock The socket to make in ipv6only working mode + @return 0 on success, -1 on failure + */ +EVENT2_EXPORT_SYMBOL +int evutil_make_listen_socket_ipv6only(evutil_socket_t sock); + /** Do platform-specific operations as needed to close a socket upon a successful execution of one of the exec*() functions. @@ -245,6 +245,11 @@ evconnlistener_new_bind(struct event_base *base, evconnlistener_cb cb, goto err; } + if (flags & LEV_OPT_BIND_IPV6ONLY) { + if (evutil_make_listen_socket_ipv6only(fd) < 0) + goto err; + } + if (sa) { if (bind(fd, sa, socklen)<0) goto err; |