summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMurat Demirten <mdemirten@yh.com.tr>2018-06-04 16:43:34 +0300
committerAzat Khuzhin <a3at.mail@gmail.com>2018-10-26 07:24:29 +0300
commit387d91f9ab95df8ac3d7bb58493310ad4a377dcf (patch)
tree960a1f3e5bfbf51a0c85f92f11dec8b341752b9e
parentb2667b76969c2ea382373f885062b45e82d0ac59 (diff)
downloadlibevent-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.c8
-rw-r--r--include/event2/listener.h12
-rw-r--r--include/event2/util.h12
-rw-r--r--listener.c5
4 files changed, 37 insertions, 0 deletions
diff --git a/evutil.c b/evutil.c
index d93eff5f..5d385bdc 100644
--- a/evutil.c
+++ b/evutil.c
@@ -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.
diff --git a/listener.c b/listener.c
index 2835df17..e803bed1 100644
--- a/listener.c
+++ b/listener.c
@@ -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;