Tarantool development patches archive
 help / color / mirror / Atom feed
From: Vladislav Shpilevoy <v.shpilevoy@tarantool.org>
To: tarantool-patches@freelists.org
Cc: vdavydov.dev@gmail.com
Subject: [PATCH v2 08/11] evio: remove exceptions
Date: Wed,  5 Dec 2018 00:28:55 +0300	[thread overview]
Message-ID: <1a55a53f29375b5aacf448d8b21724f68bf49137.1543958698.git.v.shpilevoy@tarantool.org> (raw)
In-Reply-To: <cover.1543958698.git.v.shpilevoy@tarantool.org>
In-Reply-To: <cover.1543958698.git.v.shpilevoy@tarantool.org>

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)

  parent reply	other threads:[~2018-12-04 21:28 UTC|newest]

Thread overview: 23+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-12-04 21:28 [PATCH v2 00/11] SWIM preparation Vladislav Shpilevoy
2018-12-04 21:28 ` [PATCH v2 01/11] sio: remove unused functions Vladislav Shpilevoy
2018-12-09 12:10   ` Vladimir Davydov
2018-12-04 21:28 ` [PATCH v2 10/11] evio: make code C compatible Vladislav Shpilevoy
2018-12-05  8:56   ` Vladimir Davydov
2018-12-05 20:07     ` [tarantool-patches] " Vladislav Shpilevoy
2018-12-04 21:28 ` [PATCH v2 11/11] evio: turn nto c Vladislav Shpilevoy
2018-12-04 21:28 ` [PATCH v2 02/11] sio: treat EADDRINUSE in sio_listen as error Vladislav Shpilevoy
2018-12-09 12:57   ` Vladimir Davydov
2018-12-10 15:36     ` [tarantool-patches] " Vladislav Shpilevoy
2018-12-04 21:28 ` [PATCH v2 03/11] sio: remove exceptions Vladislav Shpilevoy
2018-12-09 12:54   ` Vladimir Davydov
2018-12-10 15:37     ` [tarantool-patches] " Vladislav Shpilevoy
2018-12-11  8:44       ` Vladimir Davydov
2018-12-04 21:28 ` [PATCH v2 04/11] sio: make code compatible with C Vladislav Shpilevoy
2018-12-05  8:57   ` Vladimir Davydov
2018-12-05 20:07     ` [tarantool-patches] " Vladislav Shpilevoy
2018-12-04 21:28 ` [PATCH v2 05/11] sio: turn into C Vladislav Shpilevoy
2018-12-04 21:28 ` [PATCH v2 06/11] evio: make on_accept be nothrow Vladislav Shpilevoy
2018-12-04 21:28 ` [PATCH v2 07/11] coio: fix double close of a file descriptor Vladislav Shpilevoy
2018-12-04 21:28 ` Vladislav Shpilevoy [this message]
2018-12-04 21:28 ` [PATCH v2 09/11] coio: fix file descriptor leak on accept Vladislav Shpilevoy
2018-12-11  8:47 ` [PATCH v2 00/11] SWIM preparation Vladimir Davydov

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1a55a53f29375b5aacf448d8b21724f68bf49137.1543958698.git.v.shpilevoy@tarantool.org \
    --to=v.shpilevoy@tarantool.org \
    --cc=tarantool-patches@freelists.org \
    --cc=vdavydov.dev@gmail.com \
    --subject='Re: [PATCH v2 08/11] evio: remove exceptions' \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox