[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

Re: [Libevent-users] Stop listening on http server when accept() returns Too Many Open Files



Thanks a lot for your reply!

On 2010-09-20 12:29, Nick Mathewson wrote:
> One possibility is that, when a non-retriable error occurs, the
> callback is invoked with fd set to -1, and errno (LastSocketError) set
> to the appropriate error.  This behavior would break programs that
> don't expect listeners to ever call the listener callback with a bad
> fd, so it would have to be off by default, and enabled via an
> LEV_OPT_* option.
> 
> Another possibility is to allow code to register a separate error
> callback for each listener that would get invoked when an error
> occurred.  This seems a little cleaner to me.

I'd be fine with both, but I would also prefer the second option. A
separate callback for errors is how the rest of libevent already works.

Would the attached patch work?

Simon
-- 
NAT64/DNS64 open-source --> http://ecdysis.viagenie.ca
STUN/TURN server        --> http://numb.viagenie.ca
vCard 4.0               --> http://www.vcarddav.org
From 0a5e1a39692dad552b08f7d4d133c5f220b639ff Mon Sep 17 00:00:00 2001
From: Simon Perreault <simon.perreault@xxxxxxxxxxx>
Date: Mon, 20 Sep 2010 12:47:39 -0400
Subject: [PATCH] Add error callback to evconnlistener

---
 include/event2/listener.h |   12 ++++++++++++
 listener.c                |   12 +++++++++++-
 2 files changed, 23 insertions(+), 1 deletions(-)

diff --git a/include/event2/listener.h b/include/event2/listener.h
index 98ee886..5f34ff4 100644
--- a/include/event2/listener.h
+++ b/include/event2/listener.h
@@ -49,6 +49,14 @@ struct evconnlistener;
  */
 typedef void (*evconnlistener_cb)(struct evconnlistener *, evutil_socket_t, struct sockaddr *, int socklen, void *);
 
+/**
+   A callback that we invoke when a listener encounters a non-retriable error.
+
+   @param listener The evconnlistener
+   @param user_arg the pointer passed to evconnlistener_new()
+ */
+typedef void (*evconnlistener_ecb)(struct evconnlistener *, void *);
+
 /** Flag: Indicates that we should not make incoming sockets nonblocking
  * before passing them to the callback. */
 #define LEV_OPT_LEAVE_SOCKETS_BLOCKING	(1u<<0)
@@ -114,6 +122,10 @@ struct event_base *evconnlistener_get_base(struct evconnlistener *lev);
 /** Return the socket that an evconnlistner is listening on. */
 evutil_socket_t evconnlistener_get_fd(struct evconnlistener *lev);
 
+/** Set an evconnlistener's error callback. */
+void evconnlistner_set_error_cb(struct evconnlistener *lev,
+    evconnlistener_ecb ecb);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/listener.c b/listener.c
index 1b42281..ac56033 100644
--- a/listener.c
+++ b/listener.c
@@ -70,6 +70,7 @@ struct evconnlistener_ops {
 struct evconnlistener {
 	const struct evconnlistener_ops *ops;
 	evconnlistener_cb cb;
+	evconnlistener_ecb ecb;
 	void *user_data;
 	unsigned flags;
 };
@@ -281,6 +282,12 @@ event_listener_getbase(struct evconnlistener *lev)
 	return event_get_base(&lev_e->listener);
 }
 
+void evconnlistner_set_error_cb(struct evconnlistener *lev,
+    evconnlistener_ecb ecb)
+{
+	lev->ecb = ecb;
+}
+
 static void
 listener_read_cb(evutil_socket_t fd, short what, void *p)
 {
@@ -303,7 +310,10 @@ listener_read_cb(evutil_socket_t fd, short what, void *p)
 	err = evutil_socket_geterror(fd);
 	if (EVUTIL_ERR_ACCEPT_RETRIABLE(err))
 		return;
-	event_sock_warn(fd, "Error from accept() call");
+	if (lev->ecb != NULL)
+		lev->ecb(lev, lev->user_data);
+	else
+		event_sock_warn(fd, "Error from accept() call");
 }
 
 #ifdef WIN32
-- 
1.7.1