1*c43e99fdSEd Maste /* 2*c43e99fdSEd Maste * Copyright (c) 2009-2012 Niels Provos and Nick Mathewson 3*c43e99fdSEd Maste * 4*c43e99fdSEd Maste * Redistribution and use in source and binary forms, with or without 5*c43e99fdSEd Maste * modification, are permitted provided that the following conditions 6*c43e99fdSEd Maste * are met: 7*c43e99fdSEd Maste * 1. Redistributions of source code must retain the above copyright 8*c43e99fdSEd Maste * notice, this list of conditions and the following disclaimer. 9*c43e99fdSEd Maste * 2. Redistributions in binary form must reproduce the above copyright 10*c43e99fdSEd Maste * notice, this list of conditions and the following disclaimer in the 11*c43e99fdSEd Maste * documentation and/or other materials provided with the distribution. 12*c43e99fdSEd Maste * 3. The name of the author may not be used to endorse or promote products 13*c43e99fdSEd Maste * derived from this software without specific prior written permission. 14*c43e99fdSEd Maste * 15*c43e99fdSEd Maste * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16*c43e99fdSEd Maste * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17*c43e99fdSEd Maste * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18*c43e99fdSEd Maste * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19*c43e99fdSEd Maste * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20*c43e99fdSEd Maste * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21*c43e99fdSEd Maste * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22*c43e99fdSEd Maste * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23*c43e99fdSEd Maste * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24*c43e99fdSEd Maste * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25*c43e99fdSEd Maste */ 26*c43e99fdSEd Maste #include "../util-internal.h" 27*c43e99fdSEd Maste #include "event2/event-config.h" 28*c43e99fdSEd Maste 29*c43e99fdSEd Maste #ifdef _WIN32 30*c43e99fdSEd Maste #include <winsock2.h> 31*c43e99fdSEd Maste #endif 32*c43e99fdSEd Maste #include <sys/types.h> 33*c43e99fdSEd Maste #include <sys/stat.h> 34*c43e99fdSEd Maste #ifdef EVENT__HAVE_SYS_SOCKET_H 35*c43e99fdSEd Maste #include <sys/socket.h> 36*c43e99fdSEd Maste #endif 37*c43e99fdSEd Maste #include <fcntl.h> 38*c43e99fdSEd Maste #include <stdlib.h> 39*c43e99fdSEd Maste #include <stdio.h> 40*c43e99fdSEd Maste #include <string.h> 41*c43e99fdSEd Maste #ifndef _WIN32 42*c43e99fdSEd Maste #include <sys/time.h> 43*c43e99fdSEd Maste #include <unistd.h> 44*c43e99fdSEd Maste #endif 45*c43e99fdSEd Maste #include <errno.h> 46*c43e99fdSEd Maste 47*c43e99fdSEd Maste #include "event2/event.h" 48*c43e99fdSEd Maste #include "event2/util.h" 49*c43e99fdSEd Maste 50*c43e99fdSEd Maste #include "regress.h" 51*c43e99fdSEd Maste 52*c43e99fdSEd Maste static int was_et = 0; 53*c43e99fdSEd Maste 54*c43e99fdSEd Maste static void 55*c43e99fdSEd Maste read_cb(evutil_socket_t fd, short event, void *arg) 56*c43e99fdSEd Maste { 57*c43e99fdSEd Maste char buf; 58*c43e99fdSEd Maste int len; 59*c43e99fdSEd Maste 60*c43e99fdSEd Maste len = recv(fd, &buf, sizeof(buf), 0); 61*c43e99fdSEd Maste 62*c43e99fdSEd Maste called++; 63*c43e99fdSEd Maste if (event & EV_ET) 64*c43e99fdSEd Maste was_et = 1; 65*c43e99fdSEd Maste 66*c43e99fdSEd Maste if (!len) 67*c43e99fdSEd Maste event_del(arg); 68*c43e99fdSEd Maste } 69*c43e99fdSEd Maste 70*c43e99fdSEd Maste #ifdef _WIN32 71*c43e99fdSEd Maste #define LOCAL_SOCKETPAIR_AF AF_INET 72*c43e99fdSEd Maste #else 73*c43e99fdSEd Maste #define LOCAL_SOCKETPAIR_AF AF_UNIX 74*c43e99fdSEd Maste #endif 75*c43e99fdSEd Maste 76*c43e99fdSEd Maste static void 77*c43e99fdSEd Maste test_edgetriggered(void *et) 78*c43e99fdSEd Maste { 79*c43e99fdSEd Maste struct event *ev = NULL; 80*c43e99fdSEd Maste struct event_base *base = NULL; 81*c43e99fdSEd Maste const char *test = "test string"; 82*c43e99fdSEd Maste evutil_socket_t pair[2] = {-1,-1}; 83*c43e99fdSEd Maste int supports_et; 84*c43e99fdSEd Maste 85*c43e99fdSEd Maste /* On Linux 3.2.1 (at least, as patched by Fedora and tested by Nick), 86*c43e99fdSEd Maste * doing a "recv" on an AF_UNIX socket resets the readability of the 87*c43e99fdSEd Maste * socket, even though there is no state change, so we don't actually 88*c43e99fdSEd Maste * get edge-triggered behavior. Yuck! Linux 3.1.9 didn't have this 89*c43e99fdSEd Maste * problem. 90*c43e99fdSEd Maste */ 91*c43e99fdSEd Maste #ifdef __linux__ 92*c43e99fdSEd Maste if (evutil_ersatz_socketpair_(AF_INET, SOCK_STREAM, 0, pair) == -1) { 93*c43e99fdSEd Maste tt_abort_perror("socketpair"); 94*c43e99fdSEd Maste } 95*c43e99fdSEd Maste #else 96*c43e99fdSEd Maste if (evutil_socketpair(LOCAL_SOCKETPAIR_AF, SOCK_STREAM, 0, pair) == -1) { 97*c43e99fdSEd Maste tt_abort_perror("socketpair"); 98*c43e99fdSEd Maste } 99*c43e99fdSEd Maste #endif 100*c43e99fdSEd Maste 101*c43e99fdSEd Maste called = was_et = 0; 102*c43e99fdSEd Maste 103*c43e99fdSEd Maste tt_int_op(send(pair[0], test, (int)strlen(test)+1, 0), >, 0); 104*c43e99fdSEd Maste shutdown(pair[0], EVUTIL_SHUT_WR); 105*c43e99fdSEd Maste 106*c43e99fdSEd Maste /* Initalize the event library */ 107*c43e99fdSEd Maste base = event_base_new(); 108*c43e99fdSEd Maste 109*c43e99fdSEd Maste if (!strcmp(event_base_get_method(base), "epoll") || 110*c43e99fdSEd Maste !strcmp(event_base_get_method(base), "epoll (with changelist)") || 111*c43e99fdSEd Maste !strcmp(event_base_get_method(base), "kqueue")) 112*c43e99fdSEd Maste supports_et = 1; 113*c43e99fdSEd Maste else 114*c43e99fdSEd Maste supports_et = 0; 115*c43e99fdSEd Maste 116*c43e99fdSEd Maste TT_BLATHER(("Checking for edge-triggered events with %s, which should %s" 117*c43e99fdSEd Maste "support edge-triggering", event_base_get_method(base), 118*c43e99fdSEd Maste supports_et?"":"not ")); 119*c43e99fdSEd Maste 120*c43e99fdSEd Maste /* Initalize one event */ 121*c43e99fdSEd Maste ev = event_new(base, pair[1], EV_READ|EV_ET|EV_PERSIST, read_cb, &ev); 122*c43e99fdSEd Maste 123*c43e99fdSEd Maste event_add(ev, NULL); 124*c43e99fdSEd Maste 125*c43e99fdSEd Maste /* We're going to call the dispatch function twice. The first invocation 126*c43e99fdSEd Maste * will read a single byte from pair[1] in either case. If we're edge 127*c43e99fdSEd Maste * triggered, we'll only see the event once (since we only see transitions 128*c43e99fdSEd Maste * from no data to data), so the second invocation of event_base_loop will 129*c43e99fdSEd Maste * do nothing. If we're level triggered, the second invocation of 130*c43e99fdSEd Maste * event_base_loop will also activate the event (because there's still 131*c43e99fdSEd Maste * data to read). */ 132*c43e99fdSEd Maste event_base_loop(base,EVLOOP_NONBLOCK|EVLOOP_ONCE); 133*c43e99fdSEd Maste event_base_loop(base,EVLOOP_NONBLOCK|EVLOOP_ONCE); 134*c43e99fdSEd Maste 135*c43e99fdSEd Maste if (supports_et) { 136*c43e99fdSEd Maste tt_int_op(called, ==, 1); 137*c43e99fdSEd Maste tt_assert(was_et); 138*c43e99fdSEd Maste } else { 139*c43e99fdSEd Maste tt_int_op(called, ==, 2); 140*c43e99fdSEd Maste tt_assert(!was_et); 141*c43e99fdSEd Maste } 142*c43e99fdSEd Maste 143*c43e99fdSEd Maste end: 144*c43e99fdSEd Maste if (ev) { 145*c43e99fdSEd Maste event_del(ev); 146*c43e99fdSEd Maste event_free(ev); 147*c43e99fdSEd Maste } 148*c43e99fdSEd Maste if (base) 149*c43e99fdSEd Maste event_base_free(base); 150*c43e99fdSEd Maste evutil_closesocket(pair[0]); 151*c43e99fdSEd Maste evutil_closesocket(pair[1]); 152*c43e99fdSEd Maste } 153*c43e99fdSEd Maste 154*c43e99fdSEd Maste static void 155*c43e99fdSEd Maste test_edgetriggered_mix_error(void *data_) 156*c43e99fdSEd Maste { 157*c43e99fdSEd Maste struct basic_test_data *data = data_; 158*c43e99fdSEd Maste struct event_base *base = NULL; 159*c43e99fdSEd Maste struct event *ev_et=NULL, *ev_lt=NULL; 160*c43e99fdSEd Maste 161*c43e99fdSEd Maste #ifdef EVENT__DISABLE_DEBUG_MODE 162*c43e99fdSEd Maste if (1) 163*c43e99fdSEd Maste tt_skip(); 164*c43e99fdSEd Maste #endif 165*c43e99fdSEd Maste 166*c43e99fdSEd Maste if (!libevent_tests_running_in_debug_mode) 167*c43e99fdSEd Maste event_enable_debug_mode(); 168*c43e99fdSEd Maste 169*c43e99fdSEd Maste base = event_base_new(); 170*c43e99fdSEd Maste 171*c43e99fdSEd Maste /* try mixing edge-triggered and level-triggered to make sure it fails*/ 172*c43e99fdSEd Maste ev_et = event_new(base, data->pair[0], EV_READ|EV_ET, read_cb, ev_et); 173*c43e99fdSEd Maste tt_assert(ev_et); 174*c43e99fdSEd Maste ev_lt = event_new(base, data->pair[0], EV_READ, read_cb, ev_lt); 175*c43e99fdSEd Maste tt_assert(ev_lt); 176*c43e99fdSEd Maste 177*c43e99fdSEd Maste /* Add edge-triggered, then level-triggered. Get an error. */ 178*c43e99fdSEd Maste tt_int_op(0, ==, event_add(ev_et, NULL)); 179*c43e99fdSEd Maste tt_int_op(-1, ==, event_add(ev_lt, NULL)); 180*c43e99fdSEd Maste tt_int_op(EV_READ, ==, event_pending(ev_et, EV_READ, NULL)); 181*c43e99fdSEd Maste tt_int_op(0, ==, event_pending(ev_lt, EV_READ, NULL)); 182*c43e99fdSEd Maste 183*c43e99fdSEd Maste tt_int_op(0, ==, event_del(ev_et)); 184*c43e99fdSEd Maste /* Add level-triggered, then edge-triggered. Get an error. */ 185*c43e99fdSEd Maste tt_int_op(0, ==, event_add(ev_lt, NULL)); 186*c43e99fdSEd Maste tt_int_op(-1, ==, event_add(ev_et, NULL)); 187*c43e99fdSEd Maste tt_int_op(EV_READ, ==, event_pending(ev_lt, EV_READ, NULL)); 188*c43e99fdSEd Maste tt_int_op(0, ==, event_pending(ev_et, EV_READ, NULL)); 189*c43e99fdSEd Maste 190*c43e99fdSEd Maste end: 191*c43e99fdSEd Maste if (ev_et) 192*c43e99fdSEd Maste event_free(ev_et); 193*c43e99fdSEd Maste if (ev_lt) 194*c43e99fdSEd Maste event_free(ev_lt); 195*c43e99fdSEd Maste if (base) 196*c43e99fdSEd Maste event_base_free(base); 197*c43e99fdSEd Maste } 198*c43e99fdSEd Maste 199*c43e99fdSEd Maste struct testcase_t edgetriggered_testcases[] = { 200*c43e99fdSEd Maste { "et", test_edgetriggered, TT_FORK, NULL, NULL }, 201*c43e99fdSEd Maste { "et_mix_error", test_edgetriggered_mix_error, 202*c43e99fdSEd Maste TT_FORK|TT_NEED_SOCKETPAIR|TT_NO_LOGS, &basic_setup, NULL }, 203*c43e99fdSEd Maste END_OF_TESTCASES 204*c43e99fdSEd Maste }; 205