From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: From: Vladislav Shpilevoy Subject: [PATCH 1/1] evio: allow not only SOCK_STREAM servers Date: Mon, 17 Dec 2018 14:55:44 +0300 Message-Id: <0c0e2a63433e75e652153031d6b6b171845bdff6.1545047633.git.v.shpilevoy@tarantool.org> To: tarantool-patches@freelists.org Cc: vdavydov.dev@gmail.com List-ID: evio is a useful tool for creating servers. Evio sets all necessary flags, retries bind, parses URI. But it does not work with SOCK_DGRAM sockets - SOCK_STREAM is hardcoded. SWIM is going to use SOCK_DGRAM, and this patch makes it possible to bind datagram sockets. Needed for #3234 --- https://github.com/tarantool/tarantool/tree/gerold103/gh-3234-swim-second-preparation https://github.com/tarantool/tarantool/issues/3234 src/box/iproto.cc | 4 ++-- src/coio.cc | 4 ++-- src/evio.c | 48 +++++++++++++++++++++++++++++++++++------------ src/evio.h | 19 ++++++++++++++++--- 4 files changed, 56 insertions(+), 19 deletions(-) diff --git a/src/box/iproto.cc b/src/box/iproto.cc index 223469f22..157789384 100644 --- a/src/box/iproto.cc +++ b/src/box/iproto.cc @@ -1873,8 +1873,8 @@ net_cord_f(va_list /* ap */) mempool_create(&iproto_connection_pool, &cord()->slabc, sizeof(struct iproto_connection)); - evio_service_init(loop(), &binary, "binary", - iproto_on_accept, NULL); + evio_service_init_tcp(loop(), &binary, "binary", iproto_on_accept, + NULL); /* Init statistics counter */ diff --git a/src/coio.cc b/src/coio.cc index 6b94cf2a6..30d18ab3c 100644 --- a/src/coio.cc +++ b/src/coio.cc @@ -632,8 +632,8 @@ void coio_service_init(struct coio_service *service, const char *name, fiber_func handler, void *handler_param) { - evio_service_init(loop(), &service->evio_service, name, - coio_service_on_accept, service); + evio_service_init_tcp(loop(), &service->evio_service, name, + coio_service_on_accept, service); service->handler = handler; service->handler_param = handler_param; } diff --git a/src/evio.c b/src/evio.c index 9ca14c45c..c16fc99db 100644 --- a/src/evio.c +++ b/src/evio.c @@ -209,7 +209,8 @@ evio_service_accept_cb(ev_loop *loop, ev_io *watcher, int events) static int evio_service_reuse_addr(struct evio_service *service, int fd) { - if ((service->addr.sa_family != AF_UNIX) || (errno != EADDRINUSE)) { + if (service->addr.sa_family != AF_UNIX || errno != EADDRINUSE || + service->sock_type != SOCK_STREAM) { diag_set(SocketError, sio_socketname(fd), "evio_service_reuse_addr"); return -1; @@ -248,13 +249,13 @@ evio_service_bind_addr(struct evio_service *service) say_debug("%s: binding to %s...", evio_service_name(service), sio_strfaddr(&service->addr, service->addr_len)); /* Create a socket. */ - int fd = sio_socket(service->addr.sa_family, - SOCK_STREAM, IPPROTO_TCP); + int fd = sio_socket(service->addr.sa_family, service->sock_type, + service->sock_protocol); if (fd < 0) return -1; if (evio_setsockopt_server(fd, service->addr.sa_family, - SOCK_STREAM) != 0) + service->sock_type) != 0) goto error; if (sio_bind(fd, &service->addr, service->addr_len)) { @@ -282,6 +283,12 @@ error: return -1; } +void +evio_service_start(struct evio_service *service) +{ + ev_io_start(service->loop, &service->ev); +} + /** * Listen on bounded port. * @@ -306,30 +313,47 @@ evio_service_listen(struct evio_service *service) } return -1; } - ev_io_start(service->loop, &service->ev); + evio_service_start(service); return 0; } -void +static void evio_service_init(ev_loop *loop, struct evio_service *service, const char *name, - evio_accept_f on_accept, void *on_accept_param) + int sock_type, int sock_protocol) { memset(service, 0, sizeof(struct evio_service)); snprintf(service->name, sizeof(service->name), "%s", name); service->loop = loop; - - service->on_accept = on_accept; - service->on_accept_param = on_accept_param; + service->sock_type = sock_type; + service->sock_protocol = sock_protocol; /* * Initialize libev objects to be able to detect if they * are active or not in evio_service_stop(). */ - ev_init(&service->ev, evio_service_accept_cb); ev_io_set(&service->ev, -1, 0); service->ev.data = service; } +void +evio_service_init_udp(ev_loop *loop, struct evio_service *service, + const char *name, evio_input_f on_input) +{ + evio_service_init(loop, service, name, SOCK_DGRAM, IPPROTO_UDP); + ev_init(&service->ev, on_input); +} + +void +evio_service_init_tcp(ev_loop *loop, struct evio_service *service, + const char *name, evio_accept_f on_accept, + void *on_accept_param) +{ + evio_service_init(loop, service, name, SOCK_STREAM, IPPROTO_TCP); + service->on_accept = on_accept; + service->on_accept_param = on_accept_param; + ev_init(&service->ev, evio_service_accept_cb); +} + /** * Try to bind. */ @@ -366,7 +390,7 @@ evio_service_bind(struct evio_service *service, const char *uri) struct addrinfo hints, *res; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; + hints.ai_socktype = service->sock_type; hints.ai_flags = AI_PASSIVE|AI_ADDRCONFIG; /* make no difference between empty string and NULL for host */ diff --git a/src/evio.h b/src/evio.h index 69d641a60..826b6bb31 100644 --- a/src/evio.h +++ b/src/evio.h @@ -72,6 +72,8 @@ struct evio_service; typedef int (*evio_accept_f)(struct evio_service *, int, struct sockaddr *, socklen_t); +typedef void (*evio_input_f)(struct ev_loop *, struct ev_io *, int); + struct evio_service { /** Service name. E.g. 'primary', 'secondary', etc. */ @@ -86,7 +88,9 @@ struct evio_service struct sockaddr_storage addrstorage; }; socklen_t addr_len; - + /** Socket type (STREAM/DGRAM) and protocol (TCP/UDP). */ + int sock_type; + int sock_protocol; /** * A callback invoked on every accepted client socket. * If a callback returned != 0, the accepted socket is @@ -102,8 +106,13 @@ struct evio_service /** Initialize the service. Don't bind to the port yet. */ void -evio_service_init(ev_loop *loop, struct evio_service *service, const char *name, - evio_accept_f on_accept, void *on_accept_param); +evio_service_init_tcp(ev_loop *loop, struct evio_service *service, + const char *name, evio_accept_f on_accept, + void *on_accept_param); + +void +evio_service_init_udp(ev_loop *loop, struct evio_service *service, + const char *name, evio_input_f on_input); /** Bind service to specified uri */ int @@ -117,6 +126,10 @@ evio_service_bind(struct evio_service *service, const char *uri); int evio_service_listen(struct evio_service *service); +/** Run IO event loop. */ +void +evio_service_start(struct evio_service *service); + /** If started, stop event flow and close the acceptor socket. */ void evio_service_stop(struct evio_service *service); -- 2.17.2 (Apple Git-113)