2 * Copyright (c) 2009-2012 Niels Provos and Nick Mathewson
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. The name of the author may not be used to endorse or promote products
13 * derived from this software without specific prior written permission.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 #include <sys/types.h>
35 #include <sys/socket.h>
36 #include <netinet/in.h>
37 # ifdef _XOPEN_SOURCE_EXTENDED
38 # include <arpa/inet.h>
45 #include "event2/listener.h"
46 #include "event2/event.h"
47 #include "event2/util.h"
51 #include "tinytest_macros.h"
52 #include "util-internal.h"
55 acceptcb(struct evconnlistener
*listener
, evutil_socket_t fd
,
56 struct sockaddr
*addr
, int socklen
, void *arg
)
60 TT_BLATHER(("Got one for %p", ptr
));
61 evutil_closesocket(fd
);
64 evconnlistener_disable(listener
);
68 regress_pick_a_port(void *arg
)
70 struct basic_test_data
*data
= arg
;
71 struct event_base
*base
= data
->base
;
72 struct evconnlistener
*listener1
= NULL
, *listener2
= NULL
;
73 struct sockaddr_in sin
;
74 int count1
= 2, count2
= 1;
75 struct sockaddr_storage ss1
, ss2
;
76 struct sockaddr_in
*sin1
, *sin2
;
77 ev_socklen_t slen1
= sizeof(ss1
), slen2
= sizeof(ss2
);
79 LEV_OPT_CLOSE_ON_FREE
|LEV_OPT_REUSEABLE
|LEV_OPT_CLOSE_ON_EXEC
;
81 evutil_socket_t fd1
= -1, fd2
= -1, fd3
= -1;
83 if (data
->setup_data
&& strstr((char*)data
->setup_data
, "ts")) {
84 flags
|= LEV_OPT_THREADSAFE
;
87 memset(&sin
, 0, sizeof(sin
));
88 sin
.sin_family
= AF_INET
;
89 sin
.sin_addr
.s_addr
= htonl(0x7f000001); /* 127.0.0.1 */
90 sin
.sin_port
= 0; /* "You pick!" */
92 listener1
= evconnlistener_new_bind(base
, acceptcb
, &count1
,
93 flags
, -1, (struct sockaddr
*)&sin
, sizeof(sin
));
95 listener2
= evconnlistener_new_bind(base
, acceptcb
, &count2
,
96 flags
, -1, (struct sockaddr
*)&sin
, sizeof(sin
));
99 tt_int_op(evconnlistener_get_fd(listener1
), >=, 0);
100 tt_int_op(evconnlistener_get_fd(listener2
), >=, 0);
101 tt_assert(getsockname(evconnlistener_get_fd(listener1
),
102 (struct sockaddr
*)&ss1
, &slen1
) == 0);
103 tt_assert(getsockname(evconnlistener_get_fd(listener2
),
104 (struct sockaddr
*)&ss2
, &slen2
) == 0);
105 tt_int_op(ss1
.ss_family
, ==, AF_INET
);
106 tt_int_op(ss2
.ss_family
, ==, AF_INET
);
108 sin1
= (struct sockaddr_in
*)&ss1
;
109 sin2
= (struct sockaddr_in
*)&ss2
;
110 tt_int_op(ntohl(sin1
->sin_addr
.s_addr
), ==, 0x7f000001);
111 tt_int_op(ntohl(sin2
->sin_addr
.s_addr
), ==, 0x7f000001);
112 tt_int_op(sin1
->sin_port
, !=, sin2
->sin_port
);
114 tt_ptr_op(evconnlistener_get_base(listener1
), ==, base
);
115 tt_ptr_op(evconnlistener_get_base(listener2
), ==, base
);
117 fd1
= fd2
= fd3
= -1;
118 evutil_socket_connect(&fd1
, (struct sockaddr
*)&ss1
, slen1
);
119 evutil_socket_connect(&fd2
, (struct sockaddr
*)&ss1
, slen1
);
120 evutil_socket_connect(&fd3
, (struct sockaddr
*)&ss2
, slen2
);
123 Sleep(100); /* XXXX this is a stupid stopgap. */
125 event_base_dispatch(base
);
127 tt_int_op(count1
, ==, 0);
128 tt_int_op(count2
, ==, 0);
132 EVUTIL_CLOSESOCKET(fd1
);
134 EVUTIL_CLOSESOCKET(fd2
);
136 EVUTIL_CLOSESOCKET(fd3
);
138 evconnlistener_free(listener1
);
140 evconnlistener_free(listener2
);
144 errorcb(struct evconnlistener
*lis
, void *data_
)
148 evconnlistener_disable(lis
);
152 regress_listener_error(void *arg
)
154 struct basic_test_data
*data
= arg
;
155 struct event_base
*base
= data
->base
;
156 struct evconnlistener
*listener
= NULL
;
158 unsigned int flags
= LEV_OPT_CLOSE_ON_FREE
|LEV_OPT_REUSEABLE
;
160 if (data
->setup_data
&& strstr((char*)data
->setup_data
, "ts")) {
161 flags
|= LEV_OPT_THREADSAFE
;
164 /* send, so that pair[0] will look 'readable'*/
165 tt_int_op(send(data
->pair
[1], "hello", 5, 0), >, 0);
167 /* Start a listener with a bogus socket. */
168 listener
= evconnlistener_new(base
, acceptcb
, &count
,
173 evconnlistener_set_error_cb(listener
, errorcb
);
177 event_base_dispatch(base
);
178 tt_int_op(count
,==,1000); /* set by error cb */
182 evconnlistener_free(listener
);
185 struct testcase_t listener_testcases
[] = {
187 { "randport", regress_pick_a_port
, TT_FORK
|TT_NEED_BASE
,
190 { "randport_ts", regress_pick_a_port
, TT_FORK
|TT_NEED_BASE
,
191 &basic_setup
, (char*)"ts"},
193 { "error", regress_listener_error
,
194 TT_FORK
|TT_NEED_BASE
|TT_NEED_SOCKETPAIR
,
197 { "error_ts", regress_listener_error
,
198 TT_FORK
|TT_NEED_BASE
|TT_NEED_SOCKETPAIR
,
199 &basic_setup
, (char*)"ts"},
204 struct testcase_t listener_iocp_testcases
[] = {
205 { "randport", regress_pick_a_port
,
206 TT_FORK
|TT_NEED_BASE
|TT_ENABLE_IOCP
,
209 { "error", regress_listener_error
,
210 TT_FORK
|TT_NEED_BASE
|TT_NEED_SOCKETPAIR
|TT_ENABLE_IOCP
,