]> granicus.if.org Git - libevent/commitdiff
Add test for behavior on remote socket close
authorNick Mathewson <nickm@torproject.org>
Thu, 3 Jun 2010 15:25:54 +0000 (11:25 -0400)
committerNick Mathewson <nickm@torproject.org>
Thu, 3 Jun 2010 15:25:54 +0000 (11:25 -0400)
On all the backends on this little mac laptop, that behavior is to
report a remote socket close as both EV_READ and EV_WRITE.
Historically, we had problem for some of these behaviors on some
backends, so let's make sure that such behaviors don't come back.

test/regress.c

index 51719a15cf4a5f774959a0998ba7da67493934ce..3d4404eea19fda723637e5c1d9c629f2d4d26281 100644 (file)
@@ -62,6 +62,7 @@
 #include "event2/buffer_compat.h"
 #include "event2/util.h"
 #include "event-internal.h"
+#include "util-internal.h"
 #include "log-internal.h"
 
 #include "regress.h"
@@ -370,6 +371,112 @@ test_simpleread_multiple(void)
        cleanup_test();
 }
 
+static int have_closed = 0;
+static int premature_event = 0;
+static void
+simpleclose_close_fd_cb(evutil_socket_t s, short what, void *ptr)
+{
+       evutil_socket_t **fds = ptr;
+       TT_BLATHER(("Closing"));
+       evutil_closesocket(*fds[0]);
+       evutil_closesocket(*fds[1]);
+       *fds[0] = -1;
+       *fds[1] = -1;
+       have_closed = 1;
+}
+
+static void
+record_event_cb(evutil_socket_t s, short what, void *ptr)
+{
+       short *whatp = ptr;
+       if (!have_closed)
+               premature_event = 1;
+       *whatp = what;
+       TT_BLATHER(("Recorded %d on socket %d", (int)what, (int)s));
+}
+
+static void
+test_simpleclose(void *ptr)
+{
+       /* Test that a close of FD is detected as a read and as a write. */
+       struct event_base *base = event_base_new();
+       evutil_socket_t pair1[2]={-1,-1}, pair2[2] = {-1, -1};
+       evutil_socket_t *to_close[2];
+       struct event *rev=NULL, *wev=NULL, *closeev=NULL;
+       struct timeval tv;
+       short got_read_on_close = 0, got_write_on_close = 0;
+       char buf[1024];
+       memset(buf, 99, sizeof(buf));
+#ifdef WIN32
+#define LOCAL_SOCKETPAIR_AF AF_INET
+#else
+#define LOCAL_SOCKETPAIR_AF AF_UNIX
+#endif
+       if (evutil_socketpair(LOCAL_SOCKETPAIR_AF, SOCK_STREAM, 0, pair1)<0)
+               TT_DIE(("socketpair: %s", strerror(errno)));
+       if (evutil_socketpair(LOCAL_SOCKETPAIR_AF, SOCK_STREAM, 0, pair2)<0)
+               TT_DIE(("socketpair: %s", strerror(errno)));
+       if (evutil_make_socket_nonblocking(pair1[1]) < 0)
+               TT_DIE(("make_socket_nonblocking"));
+       if (evutil_make_socket_nonblocking(pair2[1]) < 0)
+               TT_DIE(("make_socket_nonblocking"));
+
+       /** Stuff pair2[1] full of data, until write fails */
+       while (1) {
+               int r = write(pair2[1], buf, sizeof(buf));
+               if (r<0) {
+                       int err = evutil_socket_geterror(pair2[1]);
+                       if (! EVUTIL_ERR_RW_RETRIABLE(err))
+                               TT_DIE(("write failed strangely: %s",
+                                       evutil_socket_error_to_string(err)));
+                       break;
+               }
+       }
+       to_close[0] = &pair1[0];
+       to_close[1] = &pair2[0];
+
+       closeev = event_new(base, -1, EV_TIMEOUT, simpleclose_close_fd_cb,
+           to_close);
+       rev = event_new(base, pair1[1], EV_READ, record_event_cb,
+           &got_read_on_close);
+       TT_BLATHER(("Waiting for read on %d", (int)pair1[1]));
+       wev = event_new(base, pair2[1], EV_WRITE, record_event_cb,
+           &got_write_on_close);
+       TT_BLATHER(("Waiting for write on %d", (int)pair2[1]));
+       tv.tv_sec = 0;
+       tv.tv_usec = 100*1000; /* Close pair1[0] after a little while, and make
+                              * sure we get a read event. */
+       event_add(closeev, &tv);
+       event_add(rev, NULL);
+       event_add(wev, NULL);
+       /* Don't let the test go on too long. */
+       tv.tv_sec = 0;
+       tv.tv_usec = 200*1000;
+       event_base_loopexit(base, &tv);
+       event_base_loop(base, 0);
+
+       tt_int_op(got_read_on_close, ==, EV_READ);
+       tt_int_op(got_write_on_close, ==, EV_WRITE);
+       tt_int_op(premature_event, ==, 0);
+
+end:
+       if (pair1[0] >= 0)
+               evutil_closesocket(pair1[0]);
+       if (pair1[1] >= 0)
+               evutil_closesocket(pair1[1]);
+       if (pair2[0] >= 0)
+               evutil_closesocket(pair2[0]);
+       if (pair2[1] >= 0)
+               evutil_closesocket(pair2[1]);
+       if (rev)
+               event_free(rev);
+       if (closeev)
+               event_free(closeev);
+       if (base)
+               event_base_free(base);
+}
+
+
 static void
 test_multiple(void)
 {
@@ -2087,6 +2194,8 @@ struct testcase_t main_testcases[] = {
        LEGACY(simpleread, TT_ISOLATED),
        LEGACY(simpleread_multiple, TT_ISOLATED),
        LEGACY(simplewrite, TT_ISOLATED),
+       { "simpleclose", test_simpleclose, TT_FORK, &basic_setup,
+         NULL },
        LEGACY(multiple, TT_ISOLATED),
        LEGACY(persistent, TT_ISOLATED),
        LEGACY(combined, TT_ISOLATED),