From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: From: Vladislav Shpilevoy Subject: [PATCH v2 08/11] evio: remove exceptions Date: Wed, 5 Dec 2018 00:28:55 +0300 Message-Id: <1a55a53f29375b5aacf448d8b21724f68bf49137.1543958698.git.v.shpilevoy@tarantool.org> In-Reply-To: References: In-Reply-To: References: To: tarantool-patches@freelists.org Cc: vdavydov.dev@gmail.com List-ID: Remove them to be able to convert evio to C - final step to make it usable in SWIM. Needed for #3234 --- src/box/iproto.cc | 8 +-- src/coio.cc | 13 ++-- src/evio.cc | 164 +++++++++++++++++++++++----------------------- src/evio.h | 12 ++-- 4 files changed, 99 insertions(+), 98 deletions(-) diff --git a/src/box/iproto.cc b/src/box/iproto.cc index f4051e791..0f64410a4 100644 --- a/src/box/iproto.cc +++ b/src/box/iproto.cc @@ -2031,10 +2031,10 @@ iproto_do_cfg_f(struct cbus_call_msg *m) case IPROTO_CFG_LISTEN: if (evio_service_is_active(&binary)) evio_service_stop(&binary); - if (cfg_msg->uri != NULL) { - evio_service_bind(&binary, cfg_msg->uri); - evio_service_listen(&binary); - } + if (cfg_msg->uri != NULL && + (evio_service_bind(&binary, cfg_msg->uri) != 0 || + evio_service_listen(&binary) != 0)) + diag_raise(); break; default: unreachable(); diff --git a/src/coio.cc b/src/coio.cc index 355c7a42e..82bf72e69 100644 --- a/src/coio.cc +++ b/src/coio.cc @@ -77,7 +77,8 @@ coio_connect_addr(struct ev_io *coio, struct sockaddr *addr, socklen_t len, ev_tstamp timeout) { ev_loop *loop = loop(); - evio_socket(coio, addr->sa_family, SOCK_STREAM, 0); + if (evio_socket(coio, addr->sa_family, SOCK_STREAM, 0) != 0) + diag_raise(); auto coio_guard = make_scoped_guard([=]{ evio_close(loop, coio); }); if (sio_connect(coio->fd, addr, len) == 0) { coio_guard.is_active = false; @@ -254,8 +255,9 @@ coio_accept(struct ev_io *coio, struct sockaddr *addr, * available */ int fd = sio_accept(coio->fd, addr, &addrlen); if (fd >= 0) { - evio_setsockopt_client(fd, addr->sa_family, - SOCK_STREAM); + if (evio_setsockopt_client(fd, addr->sa_family, + SOCK_STREAM) != 0) + diag_raise(); return fd; } if (sio_is_error_fatal(fd)) @@ -636,8 +638,9 @@ coio_service_init(struct coio_service *service, const char *name, void coio_service_start(struct evio_service *service, const char *uri) { - evio_service_bind(service, uri); - evio_service_listen(service); + if (evio_service_bind(service, uri) != 0 || + evio_service_listen(service) != 0) + diag_raise(); } void diff --git a/src/evio.cc b/src/evio.cc index 1d906db8e..a3d1d8a13 100644 --- a/src/evio.cc +++ b/src/evio.cc @@ -30,7 +30,6 @@ */ #include "evio.h" #include "uri.h" -#include "scoped_guard.h" #include #include #include @@ -41,9 +40,6 @@ #include #include "exception.h" -static void -evio_setsockopt_server(int fd, int family, int type); - /** Note: this function does not throw. */ void evio_close(ev_loop *loop, struct ev_io *evio) @@ -60,18 +56,18 @@ evio_close(ev_loop *loop, struct ev_io *evio) * Create an endpoint for communication. * Set socket as non-block and apply protocol specific options. */ -void +int evio_socket(struct ev_io *coio, int domain, int type, int protocol) { assert(coio->fd == -1); /* Don't leak fd if setsockopt fails. */ coio->fd = sio_socket(domain, type, protocol); if (coio->fd < 0) - diag_raise(); - evio_setsockopt_client(coio->fd, domain, type); + return -1; + return evio_setsockopt_client(coio->fd, domain, type); } -static void +static int evio_setsockopt_keepalive(int fd) { int on = 1; @@ -81,7 +77,7 @@ evio_setsockopt_keepalive(int fd) */ if (sio_setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on))) - diag_raise(); + return -1; #ifdef __linux__ /* * On Linux, we are able to fine-tune keepalive @@ -91,34 +87,36 @@ evio_setsockopt_keepalive(int fd) int keepcnt = 5; if (sio_setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, &keepcnt, sizeof(int))) - diag_raise(); + return -1; int keepidle = 30; if (sio_setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &keepidle, sizeof(int))) - diag_raise(); + return -1; int keepintvl = 60; if (sio_setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &keepintvl, sizeof(int))) - diag_raise(); + return -1; #endif + return 0; } /** Set common client socket options. */ -void +int evio_setsockopt_client(int fd, int family, int type) { int on = 1; /* In case this throws, the socket is not leaked. */ if (sio_setfl(fd, O_NONBLOCK, on)) - diag_raise(); + return -1; if (type == SOCK_STREAM && family != AF_UNIX) { /* * SO_KEEPALIVE to ensure connections don't hang * around for too long when a link goes away. */ - evio_setsockopt_keepalive(fd); + if (evio_setsockopt_keepalive(fd) != 0) + return -1; /* * Lower latency is more important than higher * bandwidth, and we usually write entire @@ -126,22 +124,23 @@ evio_setsockopt_client(int fd, int family, int type) */ if (sio_setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on))) - diag_raise(); + return -1; } + return 0; } /** Set options for server sockets. */ -static void +static int evio_setsockopt_server(int fd, int family, int type) { int on = 1; /* In case this throws, the socket is not leaked. */ if (sio_setfl(fd, O_NONBLOCK, on)) - diag_raise(); + return -1; /* Allow reuse local adresses. */ if (sio_setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on))) - diag_raise(); + return -1; /* Send all buffered messages on socket before take * control out from close(2) or shutdown(2). */ @@ -149,9 +148,11 @@ evio_setsockopt_server(int fd, int family, int type) if (sio_setsockopt(fd, SOL_SOCKET, SO_LINGER, &linger, sizeof(linger))) - diag_raise(); - if (type == SOCK_STREAM && family != AF_UNIX) - evio_setsockopt_keepalive(fd); + return -1; + if (type == SOCK_STREAM && family != AF_UNIX && + evio_setsockopt_keepalive(fd) != 0) + return -1; + return 0; } static inline const char * @@ -170,42 +171,33 @@ evio_service_accept_cb(ev_loop * /* loop */, ev_io *watcher, int /* revents */) { struct evio_service *service = (struct evio_service *) watcher->data; - + int fd; while (1) { /* * Accept all pending connections from backlog during event * loop iteration. Significally speed up acceptor with enabled * io_collect_interval. */ - int fd = -1; - try { - struct sockaddr_storage addr; - socklen_t addrlen = sizeof(addr); - fd = sio_accept(service->ev.fd, - (struct sockaddr *)&addr, &addrlen); - - if (fd < 0) { - if (sio_is_error_fatal(fd)) - diag_raise(); - return; - } - /* set common client socket options */ - evio_setsockopt_client(fd, service->addr.sa_family, SOCK_STREAM); - /* - * Invoke the callback and pass it the accepted - * socket. - */ - if (service->on_accept(service, fd, - (struct sockaddr *)&addr, - addrlen) != 0) - diag_raise(); - } catch (Exception *e) { - if (fd >= 0) - close(fd); - e->log(); + struct sockaddr_storage addr; + socklen_t addrlen = sizeof(addr); + fd = sio_accept(service->ev.fd, (struct sockaddr *)&addr, + &addrlen); + + if (fd < 0) { + if (sio_is_error_fatal(fd)) + break; return; } + if (evio_setsockopt_client(fd, service->addr.sa_family, + SOCK_STREAM) != 0) + break; + if (service->on_accept(service, fd, (struct sockaddr *)&addr, + addrlen) != 0) + break; } + if (fd >= 0) + close(fd); + diag_log(); } /* @@ -249,34 +241,34 @@ err: * * Throws an exception if error. */ -static void +static int 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 rc, fd = sio_socket(service->addr.sa_family, SOCK_STREAM, + IPPROTO_TCP); if (fd < 0) - diag_raise(); - - auto fd_guard = make_scoped_guard([=]{ close(fd); }); + return -1; - evio_setsockopt_server(fd, service->addr.sa_family, SOCK_STREAM); + if (evio_setsockopt_server(fd, service->addr.sa_family, + SOCK_STREAM) != 0) + goto error; - int rc = sio_bind(fd, &service->addr, service->addr_len); + rc = sio_bind(fd, &service->addr, service->addr_len); if (rc != 0) { if (sio_is_error_fatal(rc)) - diag_raise(); + goto error; if (evio_service_reuse_addr(service, fd)) - diag_raise(); + goto error; rc = sio_bind(fd, &service->addr, service->addr_len); if (rc != 0) { if (! sio_is_error_fatal(rc)) { diag_set(SocketError, sio_socketname(fd), "bind"); } - diag_raise(); + goto error; } } @@ -285,8 +277,10 @@ evio_service_bind_addr(struct evio_service *service) /* Register the socket in the event loop. */ ev_io_set(&service->ev, fd, EV_READ); - - fd_guard.is_active = false; + return 0; +error: + close(fd); + return -1; } /** @@ -294,7 +288,7 @@ evio_service_bind_addr(struct evio_service *service) * * @retval 0 for success */ -void +int evio_service_listen(struct evio_service *service) { say_debug("%s: listening on %s...", evio_service_name(service), @@ -302,8 +296,9 @@ evio_service_listen(struct evio_service *service) int fd = service->ev.fd; if (sio_listen(fd) != 0) - diag_raise(); + return -1; ev_io_start(service->loop, &service->ev); + return 0; } void @@ -329,13 +324,15 @@ evio_service_init(ev_loop *loop, struct evio_service *service, const char *name, /** * Try to bind. */ -void +int evio_service_bind(struct evio_service *service, const char *uri) { struct uri u; - if (uri_parse(&u, uri) || u.service == NULL) - tnt_raise(SocketError, sio_socketname(-1), - "invalid uri for bind: %s", uri); + if (uri_parse(&u, uri) || u.service == NULL) { + diag_set(SocketError, sio_socketname(-1), + "invalid uri for bind: %s", uri); + return -1; + } snprintf(service->serv, sizeof(service->serv), "%.*s", (int) u.service_len, u.service); @@ -365,26 +362,27 @@ evio_service_bind(struct evio_service *service, const char *uri) /* make no difference between empty string and NULL for host */ if (getaddrinfo(*service->host ? service->host : NULL, service->serv, - &hints, &res) != 0 || res == NULL) - tnt_raise(SocketError, sio_socketname(-1), - "can't resolve uri for bind"); - auto addrinfo_guard = make_scoped_guard([=]{ freeaddrinfo(res); }); - + &hints, &res) != 0 || res == NULL) { + diag_set(SocketError, sio_socketname(-1), + "can't resolve uri for bind"); + return -1; + } for (struct addrinfo *ai = res; ai != NULL; ai = ai->ai_next) { memcpy(&service->addr, ai->ai_addr, ai->ai_addrlen); service->addr_len = ai->ai_addrlen; - try { - return evio_service_bind_addr(service); - } catch (SocketError *e) { - say_error("%s: failed to bind on %s: %s", - evio_service_name(service), - sio_strfaddr(ai->ai_addr, ai->ai_addrlen), - e->get_errmsg()); - /* ignore */ + if (evio_service_bind_addr(service) == 0) { + freeaddrinfo(res); + return 0; } + say_error("%s: failed to bind on %s: %s", + evio_service_name(service), + sio_strfaddr(ai->ai_addr, ai->ai_addrlen), + diag_last_error(diag_get())->errmsg); } - tnt_raise(SocketError, sio_socketname(-1), "%s: failed to bind", - evio_service_name(service)); + freeaddrinfo(res); + diag_set(SocketError, sio_socketname(-1), "%s: failed to bind", + evio_service_name(service)); + return -1; } /** It's safe to stop a service which is not started yet. */ diff --git a/src/evio.h b/src/evio.h index e56e2b8a7..6c5e54ea4 100644 --- a/src/evio.h +++ b/src/evio.h @@ -39,8 +39,8 @@ #include "sio.h" #include "uri.h" /** - * Exception-aware way to add a listening socket to the event - * loop. Callbacks are invoked on bind and accept events. + * A way to add a listening socket to the event loop. Callbacks + * are invoked on bind and accept events. * * Coroutines/fibers are not used for port listeners * since listener's job is usually simple and only involves @@ -101,7 +101,7 @@ evio_service_init(ev_loop *loop, struct evio_service *service, const char *name, evio_accept_f on_accept, void *on_accept_param); /** Bind service to specified uri */ -void +int evio_service_bind(struct evio_service *service, const char *uri); /** @@ -109,14 +109,14 @@ evio_service_bind(struct evio_service *service, const char *uri); * * @retval 0 for success */ -void +int evio_service_listen(struct evio_service *service); /** If started, stop event flow and close the acceptor socket. */ void evio_service_stop(struct evio_service *service); -void +int evio_socket(struct ev_io *coio, int domain, int type, int protocol); void @@ -149,7 +149,7 @@ evio_timeout_update(ev_loop *loop, ev_tstamp start, ev_tstamp *delay) *delay = (elapsed >= *delay) ? 0 : *delay - elapsed; } -void +int evio_setsockopt_client(int fd, int family, int type); #endif /* TARANTOOL_EVIO_H_INCLUDED */ -- 2.17.2 (Apple Git-113)