1 /*
2 * Copyright (C) 2011, 2012 Internet Systems Consortium, Inc. ("ISC")
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
9 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
10 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
11 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
12 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
13 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
14 * PERFORMANCE OF THIS SOFTWARE.
15 */
16
17 /* $Id$ */
18
19 /*! \file */
20
21 #include <config.h>
22
23 #include <atf-c.h>
24
25 #include <unistd.h>
26 #include <time.h>
27
28 #include <isc/socket.h>
29
30 #include "../task_p.h"
31 #include "isctest.h"
32
33 /*
34 * Helper functions
35 */
36 typedef struct {
37 isc_boolean_t done;
38 isc_result_t result;
39 } completion_t;
40
41 static void
completion_init(completion_t * completion)42 completion_init(completion_t *completion) {
43 completion->done = ISC_FALSE;
44 }
45
46 static void
event_done(isc_task_t * task,isc_event_t * event)47 event_done(isc_task_t *task, isc_event_t *event) {
48 isc_socketevent_t *dev;
49 completion_t *completion = event->ev_arg;
50
51 UNUSED(task);
52
53 dev = (isc_socketevent_t *) event;
54 completion->result = dev->result;
55 completion->done = ISC_TRUE;
56 isc_event_free(&event);
57 }
58
59 static isc_result_t
waitfor(completion_t * completion)60 waitfor(completion_t *completion) {
61 int i = 0;
62 while (!completion->done && i++ < 5000) {
63 #ifndef ISC_PLATFORM_USETHREADS
64 while (isc__taskmgr_ready(taskmgr))
65 isc__taskmgr_dispatch(taskmgr);
66 #endif
67 isc_test_nap(1000);
68 }
69 if (completion->done)
70 return (ISC_R_SUCCESS);
71 return (ISC_R_FAILURE);
72 }
73
74 /*
75 * Individual unit tests
76 */
77
78 /* Test UDP sendto/recv (IPv4) */
79 ATF_TC(udp_sendto);
ATF_TC_HEAD(udp_sendto,tc)80 ATF_TC_HEAD(udp_sendto, tc) {
81 atf_tc_set_md_var(tc, "descr", "UDP sendto/recv");
82 }
ATF_TC_BODY(udp_sendto,tc)83 ATF_TC_BODY(udp_sendto, tc) {
84 isc_result_t result;
85 isc_sockaddr_t addr1, addr2;
86 struct in_addr in;
87 isc_socket_t *s1 = NULL, *s2 = NULL;
88 isc_task_t *task = NULL;
89 char sendbuf[BUFSIZ], recvbuf[BUFSIZ];
90 completion_t completion;
91 isc_region_t r;
92
93 UNUSED(tc);
94
95 result = isc_test_begin(NULL, ISC_TRUE);
96 ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
97
98 /*
99 * Create two sockets: 127.0.0.1/5444 and 127.0.0.1/5445, talking to
100 * each other.
101 */
102 in.s_addr = inet_addr("127.0.0.1");
103 isc_sockaddr_fromin(&addr1, &in, 5444);
104 isc_sockaddr_fromin(&addr2, &in, 5445);
105
106 result = isc_socket_create(socketmgr, PF_INET, isc_sockettype_udp, &s1);
107 ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
108 result = isc_socket_bind(s1, &addr1, ISC_SOCKET_REUSEADDRESS);
109 ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
110
111 result = isc_socket_create(socketmgr, PF_INET, isc_sockettype_udp, &s2);
112 ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
113 result = isc_socket_bind(s2, &addr2, ISC_SOCKET_REUSEADDRESS);
114 ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
115
116 result = isc_task_create(taskmgr, 0, &task);
117 ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
118
119 strcpy(sendbuf, "Hello");
120 r.base = (void *) sendbuf;
121 r.length = strlen(sendbuf) + 1;
122
123 completion_init(&completion);
124 result = isc_socket_sendto(s1, &r, task, event_done, &completion,
125 &addr2, NULL);
126 ATF_CHECK_EQ(result, ISC_R_SUCCESS);
127 waitfor(&completion);
128 ATF_CHECK(completion.done);
129 ATF_CHECK_EQ(completion.result, ISC_R_SUCCESS);
130
131 r.base = (void *) recvbuf;
132 r.length = BUFSIZ;
133 completion_init(&completion);
134 result = isc_socket_recv(s2, &r, 1, task, event_done, &completion);
135 ATF_CHECK_EQ(result, ISC_R_SUCCESS);
136 waitfor(&completion);
137 ATF_CHECK(completion.done);
138 ATF_CHECK_EQ(completion.result, ISC_R_SUCCESS);
139 ATF_CHECK_STREQ(recvbuf, "Hello");
140
141 isc_task_detach(&task);
142
143 isc_socket_detach(&s1);
144 isc_socket_detach(&s2);
145
146 isc_test_end();
147 }
148
149 /* Test UDP sendto/recv with duplicated socket */
150 ATF_TC(udp_dup);
ATF_TC_HEAD(udp_dup,tc)151 ATF_TC_HEAD(udp_dup, tc) {
152 atf_tc_set_md_var(tc, "descr", "duplicated socket sendto/recv");
153 }
ATF_TC_BODY(udp_dup,tc)154 ATF_TC_BODY(udp_dup, tc) {
155 isc_result_t result;
156 isc_sockaddr_t addr1, addr2;
157 struct in_addr in;
158 isc_socket_t *s1 = NULL, *s2 = NULL, *s3 = NULL;
159 isc_task_t *task = NULL;
160 char sendbuf[BUFSIZ], recvbuf[BUFSIZ];
161 completion_t completion;
162 isc_region_t r;
163
164 UNUSED(tc);
165
166 result = isc_test_begin(NULL, ISC_TRUE);
167 ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
168
169 /*
170 * Create two sockets: 127.0.0.1/5444 and 127.0.0.1/5445, talking to
171 * each other.
172 */
173 in.s_addr = inet_addr("127.0.0.1");
174 isc_sockaddr_fromin(&addr1, &in, 5444);
175 isc_sockaddr_fromin(&addr2, &in, 5445);
176
177 result = isc_socket_create(socketmgr, PF_INET, isc_sockettype_udp, &s1);
178 ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
179 result = isc_socket_bind(s1, &addr1, ISC_SOCKET_REUSEADDRESS);
180 ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
181
182 result = isc_socket_create(socketmgr, PF_INET, isc_sockettype_udp, &s2);
183 ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
184 result = isc_socket_bind(s2, &addr2, ISC_SOCKET_REUSEADDRESS);
185 ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
186
187 result = isc_socket_dup(s2, &s3);
188 ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
189
190 result = isc_task_create(taskmgr, 0, &task);
191 ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
192
193 strcpy(sendbuf, "Hello");
194 r.base = (void *) sendbuf;
195 r.length = strlen(sendbuf) + 1;
196
197 completion_init(&completion);
198 result = isc_socket_sendto(s1, &r, task, event_done, &completion,
199 &addr2, NULL);
200 ATF_CHECK_EQ(result, ISC_R_SUCCESS);
201 waitfor(&completion);
202 ATF_CHECK(completion.done);
203 ATF_CHECK_EQ(completion.result, ISC_R_SUCCESS);
204
205 strcpy(sendbuf, "World");
206 r.base = (void *) sendbuf;
207 r.length = strlen(sendbuf) + 1;
208
209 completion_init(&completion);
210 result = isc_socket_sendto(s1, &r, task, event_done, &completion,
211 &addr2, NULL);
212 ATF_CHECK_EQ(result, ISC_R_SUCCESS);
213 waitfor(&completion);
214 ATF_CHECK(completion.done);
215 ATF_CHECK_EQ(completion.result, ISC_R_SUCCESS);
216
217 r.base = (void *) recvbuf;
218 r.length = BUFSIZ;
219 completion_init(&completion);
220 result = isc_socket_recv(s2, &r, 1, task, event_done, &completion);
221 ATF_CHECK_EQ(result, ISC_R_SUCCESS);
222 waitfor(&completion);
223 ATF_CHECK(completion.done);
224 ATF_CHECK_EQ(completion.result, ISC_R_SUCCESS);
225 ATF_CHECK_STREQ(recvbuf, "Hello");
226
227 r.base = (void *) recvbuf;
228 r.length = BUFSIZ;
229 completion_init(&completion);
230 result = isc_socket_recv(s3, &r, 1, task, event_done, &completion);
231 ATF_CHECK_EQ(result, ISC_R_SUCCESS);
232 waitfor(&completion);
233 ATF_CHECK(completion.done);
234 ATF_CHECK_EQ(completion.result, ISC_R_SUCCESS);
235 ATF_CHECK_STREQ(recvbuf, "World");
236
237 isc_task_detach(&task);
238
239 isc_socket_detach(&s1);
240 isc_socket_detach(&s2);
241 isc_socket_detach(&s3);
242
243 isc_test_end();
244 }
245
246 /*
247 * Main
248 */
ATF_TP_ADD_TCS(tp)249 ATF_TP_ADD_TCS(tp) {
250 ATF_TP_ADD_TC(tp, udp_sendto);
251 ATF_TP_ADD_TC(tp, udp_dup);
252
253 return (atf_no_error());
254 }
255
256