blob: b8af3cd8d7782df3711d2fa9eb3ab2004d454b9b [file] [log] [blame]
Benny Prijono5dcb38d2005-11-21 01:55:47 +00001/* $Id$ */
2/*
3 * Copyright (C)2003-2006 Benny Prijono <benny@prijono.org>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19#include <pjlib.h>
20#include "test.h"
21
22
23/**
24 * \page page_pjlib_sock_test Test: Socket
25 *
26 * This file provides implementation of \b sock_test(). It tests the
27 * various aspects of the socket API.
28 *
29 * \section sock_test_scope_sec Scope of the Test
30 *
31 * The scope of the test:
32 * - verify the validity of the address structs.
33 * - verify that address manipulation API works.
34 * - simple socket creation and destruction.
35 * - simple socket send/recv and sendto/recvfrom.
36 * - UDP connect()
37 * - send/recv big data.
38 * - all for both UDP and TCP.
39 *
40 * The APIs tested in this test:
41 * - pj_inet_aton()
42 * - pj_inet_ntoa()
43 * - pj_gethostname()
44 * - pj_sock_socket()
45 * - pj_sock_close()
46 * - pj_sock_send()
47 * - pj_sock_sendto()
48 * - pj_sock_recv()
49 * - pj_sock_recvfrom()
50 * - pj_sock_bind()
51 * - pj_sock_connect()
52 * - pj_sock_listen()
53 * - pj_sock_accept()
54 *
55 *
56 * This file is <b>pjlib-test/sock.c</b>
57 *
58 * \include pjlib-test/sock.c
59 */
60
61#if INCLUDE_SOCK_TEST
62
63#define UDP_PORT 51234
64#define TCP_PORT (UDP_PORT+10)
65#define BIG_DATA_LEN 9000
66
67static char bigdata[BIG_DATA_LEN];
68static char bigbuffer[BIG_DATA_LEN];
69
70static int format_test(void)
71{
72 pj_str_t s = pj_str("127.0.0.1");
73 char *p;
74 pj_in_addr addr;
75 const pj_str_t *hostname;
76
77 PJ_LOG(3,("test", "...format_test()"));
78
79 /* pj_inet_aton() */
80 if (pj_inet_aton(&s, &addr) != 1)
81 return -10;
82
83 /* Check the result. */
84 p = (char*)&addr;
85 if (p[0]!=127 || p[1]!=0 || p[2]!=0 || p[3]!=1)
86 return -15;
87
88 /* pj_inet_ntoa() */
89 p = pj_inet_ntoa(addr);
90 if (!p)
91 return -20;
92
93 if (pj_strcmp2(&s, p) != 0)
94 return -30;
95
96 /* pj_gethostname() */
97 hostname = pj_gethostname();
98 if (!hostname || !hostname->ptr || !hostname->slen)
99 return -40;
100
101 /* pj_gethostaddr() */
102
103 return 0;
104}
105
106static int simple_sock_test(void)
107{
108 int types[2];
109 pj_sock_t sock;
110 int i;
111 pj_status_t rc = PJ_SUCCESS;
112
113 types[0] = PJ_SOCK_STREAM;
114 types[1] = PJ_SOCK_DGRAM;
115
116 PJ_LOG(3,("test", "...simple_sock_test()"));
117
118 for (i=0; i<sizeof(types)/sizeof(types[0]); ++i) {
119
120 rc = pj_sock_socket(PJ_AF_INET, types[i], 0, &sock);
121 if (rc != PJ_SUCCESS) {
122 app_perror("...error: unable to create socket type %d", rc);
123 break;
124 } else {
125 rc = pj_sock_close(sock);
126 if (rc != 0) {
127 app_perror("...error: close socket", rc);
128 break;
129 }
130 }
131 }
132 return rc;
133}
134
135
136static int send_recv_test(int sock_type,
137 pj_sock_t ss, pj_sock_t cs,
138 pj_sockaddr_in *dstaddr, pj_sockaddr_in *srcaddr,
139 int addrlen)
140{
141 enum { DATA_LEN = 16 };
142 char senddata[DATA_LEN+4], recvdata[DATA_LEN+4];
143 pj_ssize_t sent, received, total_received;
144 pj_status_t rc;
145
146 TRACE_(("test", "....create_random_string()"));
147 pj_create_random_string(senddata, DATA_LEN);
148 senddata[DATA_LEN-1] = '\0';
149
150 /*
151 * Test send/recv small data.
152 */
153 TRACE_(("test", "....sendto()"));
154 if (dstaddr) {
155 sent = DATA_LEN;
156 rc = pj_sock_sendto(cs, senddata, &sent, 0, dstaddr, addrlen);
157 if (rc != PJ_SUCCESS || sent != DATA_LEN) {
158 app_perror("...sendto error", rc);
159 rc = -140; goto on_error;
160 }
161 } else {
162 sent = DATA_LEN;
163 rc = pj_sock_send(cs, senddata, &sent, 0);
164 if (rc != PJ_SUCCESS || sent != DATA_LEN) {
165 app_perror("...send error", rc);
166 rc = -145; goto on_error;
167 }
168 }
169
170 TRACE_(("test", "....recv()"));
171 if (srcaddr) {
172 pj_sockaddr_in addr;
173 int srclen = sizeof(addr);
174
175 pj_memset(&addr, 0, sizeof(addr));
176
177 received = DATA_LEN;
178 rc = pj_sock_recvfrom(ss, recvdata, &received, 0, &addr, &srclen);
179 if (rc != PJ_SUCCESS || received != DATA_LEN) {
180 app_perror("...recvfrom error", rc);
181 rc = -150; goto on_error;
182 }
183 if (srclen != addrlen)
184 return -151;
185 if (pj_memcmp(&addr, srcaddr, srclen) != 0) {
186 char srcaddr_str[32], addr_str[32];
187 strcpy(srcaddr_str, pj_inet_ntoa(srcaddr->sin_addr));
188 strcpy(addr_str, pj_inet_ntoa(addr.sin_addr));
189 PJ_LOG(3,("test", "...error: src address mismatch (original=%s, "
190 "recvfrom addr=%s)",
191 srcaddr_str, addr_str));
192 return -152;
193 }
194
195 } else {
196 /* Repeat recv() until all data is received.
197 * This applies only for non-UDP of course, since for UDP
198 * we would expect all data to be received in one packet.
199 */
200 total_received = 0;
201 do {
202 received = DATA_LEN-total_received;
203 rc = pj_sock_recv(ss, recvdata+total_received, &received, 0);
204 if (rc != PJ_SUCCESS) {
205 app_perror("...recv error", rc);
206 rc = -155; goto on_error;
207 }
208 if (received <= 0) {
209 PJ_LOG(3,("", "...error: socket has closed! (received=%d)",
210 received));
211 rc = -156; goto on_error;
212 }
213 if (received != DATA_LEN-total_received) {
214 if (sock_type != PJ_SOCK_STREAM) {
215 PJ_LOG(3,("", "...error: expecting %u bytes, got %u bytes",
216 DATA_LEN-total_received, received));
217 rc = -157; goto on_error;
218 }
219 }
220 total_received += received;
221 } while (total_received < DATA_LEN);
222 }
223
224 TRACE_(("test", "....memcmp()"));
225 if (pj_memcmp(senddata, recvdata, DATA_LEN) != 0) {
226 PJ_LOG(3,("","...error: received data mismatch "
227 "(got:'%s' expecting:'%s'",
228 recvdata, senddata));
229 rc = -160; goto on_error;
230 }
231
232 /*
233 * Test send/recv big data.
234 */
235 TRACE_(("test", "....sendto()"));
236 if (dstaddr) {
237 sent = BIG_DATA_LEN;
238 rc = pj_sock_sendto(cs, bigdata, &sent, 0, dstaddr, addrlen);
239 if (rc != PJ_SUCCESS || sent != BIG_DATA_LEN) {
240 app_perror("...sendto error", rc);
241 rc = -161; goto on_error;
242 }
243 } else {
244 sent = BIG_DATA_LEN;
245 rc = pj_sock_send(cs, bigdata, &sent, 0);
246 if (rc != PJ_SUCCESS || sent != BIG_DATA_LEN) {
247 app_perror("...send error", rc);
248 rc = -165; goto on_error;
249 }
250 }
251
252 TRACE_(("test", "....recv()"));
253
254 /* Repeat recv() until all data is received.
255 * This applies only for non-UDP of course, since for UDP
256 * we would expect all data to be received in one packet.
257 */
258 total_received = 0;
259 do {
260 received = BIG_DATA_LEN-total_received;
261 rc = pj_sock_recv(ss, bigbuffer+total_received, &received, 0);
262 if (rc != PJ_SUCCESS) {
263 app_perror("...recv error", rc);
264 rc = -170; goto on_error;
265 }
266 if (received <= 0) {
267 PJ_LOG(3,("", "...error: socket has closed! (received=%d)",
268 received));
269 rc = -173; goto on_error;
270 }
271 if (received != BIG_DATA_LEN-total_received) {
272 if (sock_type != PJ_SOCK_STREAM) {
273 PJ_LOG(3,("", "...error: expecting %u bytes, got %u bytes",
274 BIG_DATA_LEN-total_received, received));
275 rc = -176; goto on_error;
276 }
277 }
278 total_received += received;
279 } while (total_received < BIG_DATA_LEN);
280
281 TRACE_(("test", "....memcmp()"));
282 if (pj_memcmp(bigdata, bigbuffer, BIG_DATA_LEN) != 0) {
283 PJ_LOG(3,("", "...error: received data has been altered!"));
284 rc = -180; goto on_error;
285 }
286
287 rc = 0;
288
289on_error:
290 return rc;
291}
292
293static int udp_test(void)
294{
295 pj_sock_t cs = PJ_INVALID_SOCKET, ss = PJ_INVALID_SOCKET;
296 pj_sockaddr_in dstaddr, srcaddr;
297 pj_str_t s;
298 pj_status_t rc = 0, retval;
299
300 PJ_LOG(3,("test", "...udp_test()"));
301
302 rc = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &ss);
303 if (rc != 0) {
304 app_perror("...error: unable to create socket", rc);
305 return -100;
306 }
307
308 rc = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &cs);
309 if (rc != 0)
310 return -110;
311
312 /* Bind server socket. */
313 pj_memset(&dstaddr, 0, sizeof(dstaddr));
314 dstaddr.sin_family = PJ_AF_INET;
315 dstaddr.sin_port = pj_htons(UDP_PORT);
316 dstaddr.sin_addr = pj_inet_addr(pj_cstr(&s, "127.0.0.1"));
317
318 if ((rc=pj_sock_bind(ss, &dstaddr, sizeof(dstaddr))) != 0) {
319 app_perror("...bind error", rc);
320 rc = -120; goto on_error;
321 }
322
323 /* Bind client socket. */
324 pj_memset(&srcaddr, 0, sizeof(srcaddr));
325 srcaddr.sin_family = PJ_AF_INET;
326 srcaddr.sin_port = pj_htons(UDP_PORT-1);
327 srcaddr.sin_addr = pj_inet_addr(pj_cstr(&s, "127.0.0.1"));
328
329 if ((rc=pj_sock_bind(cs, &srcaddr, sizeof(srcaddr))) != 0) {
330 app_perror("...bind error", rc);
331 rc = -121; goto on_error;
332 }
333
334 /* Test send/recv, with sendto */
335 rc = send_recv_test(PJ_SOCK_DGRAM, ss, cs, &dstaddr, NULL,
336 sizeof(dstaddr));
337 if (rc != 0)
338 goto on_error;
339
340 /* Test send/recv, with sendto and recvfrom */
341 rc = send_recv_test(PJ_SOCK_DGRAM, ss, cs, &dstaddr,
342 &srcaddr, sizeof(dstaddr));
343 if (rc != 0)
344 goto on_error;
345
346 /* connect() the sockets. */
347 rc = pj_sock_connect(cs, &dstaddr, sizeof(dstaddr));
348 if (rc != 0) {
349 app_perror("...connect() error", rc);
350 rc = -122; goto on_error;
351 }
352
353 /* Test send/recv with send() */
354 rc = send_recv_test(PJ_SOCK_DGRAM, ss, cs, NULL, NULL, 0);
355 if (rc != 0)
356 goto on_error;
357
358 /* Test send/recv with send() and recvfrom */
359 rc = send_recv_test(PJ_SOCK_DGRAM, ss, cs, NULL, &srcaddr,
360 sizeof(srcaddr));
361 if (rc != 0)
362 goto on_error;
363
364on_error:
365 retval = rc;
366 if (cs != PJ_INVALID_SOCKET) {
367 rc = pj_sock_close(cs);
368 if (rc != PJ_SUCCESS) {
369 app_perror("...error in closing socket", rc);
370 return -1000;
371 }
372 }
373 if (ss != PJ_INVALID_SOCKET) {
374 rc = pj_sock_close(ss);
375 if (rc != PJ_SUCCESS) {
376 app_perror("...error in closing socket", rc);
377 return -1010;
378 }
379 }
380
381 return retval;
382}
383
384static int tcp_test(void)
385{
386 pj_sock_t cs, ss;
387 pj_status_t rc = 0, retval;
388
389 PJ_LOG(3,("test", "...tcp_test()"));
390
391 rc = app_socketpair(PJ_AF_INET, PJ_SOCK_STREAM, 0, &ss, &cs);
392 if (rc != PJ_SUCCESS) {
393 app_perror("...error: app_socketpair():", rc);
394 return -2000;
395 }
396
397 /* Test send/recv with send() and recv() */
398 retval = send_recv_test(PJ_SOCK_STREAM, ss, cs, NULL, NULL, 0);
399
400 rc = pj_sock_close(cs);
401 if (rc != PJ_SUCCESS) {
402 app_perror("...error in closing socket", rc);
403 return -2000;
404 }
405
406 rc = pj_sock_close(ss);
407 if (rc != PJ_SUCCESS) {
408 app_perror("...error in closing socket", rc);
409 return -2010;
410 }
411
412 return retval;
413}
414
415static int ioctl_test(void)
416{
417 return 0;
418}
419
420int sock_test()
421{
422 int rc;
423
424 pj_create_random_string(bigdata, BIG_DATA_LEN);
425
426 rc = format_test();
427 if (rc != 0)
428 return rc;
429
430 rc = simple_sock_test();
431 if (rc != 0)
432 return rc;
433
434 rc = ioctl_test();
435 if (rc != 0)
436 return rc;
437
438 rc = udp_test();
439 if (rc != 0)
440 return rc;
441
442 rc = tcp_test();
443 if (rc != 0)
444 return rc;
445
446 return 0;
447}
448
449
450#else
451/* To prevent warning about "translation unit is empty"
452 * when this test is disabled.
453 */
454int dummy_sock_test;
455#endif /* INCLUDE_SOCK_TEST */
456