[PATCH v2 08/11] evio: remove exceptions
Vladislav Shpilevoy
v.shpilevoy at tarantool.org
Wed Dec 5 00:28:55 MSK 2018
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 <stdio.h>
#include <sys/socket.h>
#include <sys/un.h>
@@ -41,9 +40,6 @@
#include <trivia/util.h>
#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)
More information about the Tarantool-patches
mailing list