blob: 0cac52857efae68b1d204f5ea94ca1d39657504a [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
Benny Prijono42c5b9e2006-05-10 19:24:40 +000066#define ADDRESS "127.0.0.1"
67#define A0 127
68#define A1 0
69#define A2 0
70#define A3 1
71
Benny Prijono5dcb38d2005-11-21 01:55:47 +000072
73static char bigdata[BIG_DATA_LEN];
74static char bigbuffer[BIG_DATA_LEN];
75
76static int format_test(void)
77{
Benny Prijono42c5b9e2006-05-10 19:24:40 +000078 pj_str_t s = pj_str(ADDRESS);
79 unsigned char *p;
Benny Prijono5dcb38d2005-11-21 01:55:47 +000080 pj_in_addr addr;
Benny Prijono0e25e7c2006-06-28 11:10:02 +000081 char zero[64];
82 pj_sockaddr_in addr2;
Benny Prijono5dcb38d2005-11-21 01:55:47 +000083 const pj_str_t *hostname;
84
85 PJ_LOG(3,("test", "...format_test()"));
86
87 /* pj_inet_aton() */
88 if (pj_inet_aton(&s, &addr) != 1)
89 return -10;
90
91 /* Check the result. */
Benny Prijono42c5b9e2006-05-10 19:24:40 +000092 p = (unsigned char*)&addr;
93 if (p[0]!=A0 || p[1]!=A1 || p[2]!=A2 || p[3]!=A3) {
94 PJ_LOG(3,("test", " error: mismatched address. p0=%d, p1=%d, "
95 "p2=%d, p3=%d", p[0] & 0xFF, p[1] & 0xFF,
96 p[2] & 0xFF, p[3] & 0xFF));
Benny Prijono5dcb38d2005-11-21 01:55:47 +000097 return -15;
Benny Prijono42c5b9e2006-05-10 19:24:40 +000098 }
Benny Prijono5dcb38d2005-11-21 01:55:47 +000099
100 /* pj_inet_ntoa() */
Benny Prijonod8410532006-06-15 11:04:33 +0000101 p = (unsigned char*) pj_inet_ntoa(addr);
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000102 if (!p)
103 return -20;
104
Benny Prijonod8410532006-06-15 11:04:33 +0000105 if (pj_strcmp2(&s, (char*)p) != 0)
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000106 return -30;
107
Benny Prijono0e25e7c2006-06-28 11:10:02 +0000108 /* Test that pj_sockaddr_in_init() initialize the whole structure,
109 * including sin_zero.
110 */
111 pj_sockaddr_in_init(&addr2, 0, 1000);
Benny Prijonoac623b32006-07-03 15:19:31 +0000112 pj_bzero(zero, sizeof(zero));
Benny Prijono0e25e7c2006-06-28 11:10:02 +0000113 if (pj_memcmp(addr2.sin_zero, zero, sizeof(addr2.sin_zero)) != 0)
114 return -35;
115
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000116 /* pj_gethostname() */
117 hostname = pj_gethostname();
118 if (!hostname || !hostname->ptr || !hostname->slen)
119 return -40;
120
Benny Prijono42c5b9e2006-05-10 19:24:40 +0000121 PJ_LOG(3,("test", "....hostname is %.*s",
122 (int)hostname->slen, hostname->ptr));
123
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000124 /* pj_gethostaddr() */
125
Benny Prijono0e25e7c2006-06-28 11:10:02 +0000126
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000127 return 0;
128}
129
130static int simple_sock_test(void)
131{
132 int types[2];
133 pj_sock_t sock;
134 int i;
135 pj_status_t rc = PJ_SUCCESS;
136
137 types[0] = PJ_SOCK_STREAM;
138 types[1] = PJ_SOCK_DGRAM;
139
140 PJ_LOG(3,("test", "...simple_sock_test()"));
141
142 for (i=0; i<sizeof(types)/sizeof(types[0]); ++i) {
143
144 rc = pj_sock_socket(PJ_AF_INET, types[i], 0, &sock);
145 if (rc != PJ_SUCCESS) {
146 app_perror("...error: unable to create socket type %d", rc);
147 break;
148 } else {
149 rc = pj_sock_close(sock);
150 if (rc != 0) {
151 app_perror("...error: close socket", rc);
152 break;
153 }
154 }
155 }
156 return rc;
157}
158
159
160static int send_recv_test(int sock_type,
161 pj_sock_t ss, pj_sock_t cs,
162 pj_sockaddr_in *dstaddr, pj_sockaddr_in *srcaddr,
163 int addrlen)
164{
165 enum { DATA_LEN = 16 };
166 char senddata[DATA_LEN+4], recvdata[DATA_LEN+4];
167 pj_ssize_t sent, received, total_received;
168 pj_status_t rc;
169
170 TRACE_(("test", "....create_random_string()"));
171 pj_create_random_string(senddata, DATA_LEN);
172 senddata[DATA_LEN-1] = '\0';
173
174 /*
175 * Test send/recv small data.
176 */
177 TRACE_(("test", "....sendto()"));
178 if (dstaddr) {
179 sent = DATA_LEN;
180 rc = pj_sock_sendto(cs, senddata, &sent, 0, dstaddr, addrlen);
181 if (rc != PJ_SUCCESS || sent != DATA_LEN) {
182 app_perror("...sendto error", rc);
183 rc = -140; goto on_error;
184 }
185 } else {
186 sent = DATA_LEN;
187 rc = pj_sock_send(cs, senddata, &sent, 0);
188 if (rc != PJ_SUCCESS || sent != DATA_LEN) {
189 app_perror("...send error", rc);
190 rc = -145; goto on_error;
191 }
192 }
193
194 TRACE_(("test", "....recv()"));
195 if (srcaddr) {
196 pj_sockaddr_in addr;
197 int srclen = sizeof(addr);
198
Benny Prijonoac623b32006-07-03 15:19:31 +0000199 pj_bzero(&addr, sizeof(addr));
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000200
201 received = DATA_LEN;
202 rc = pj_sock_recvfrom(ss, recvdata, &received, 0, &addr, &srclen);
203 if (rc != PJ_SUCCESS || received != DATA_LEN) {
204 app_perror("...recvfrom error", rc);
205 rc = -150; goto on_error;
206 }
207 if (srclen != addrlen)
208 return -151;
209 if (pj_memcmp(&addr, srcaddr, srclen) != 0) {
210 char srcaddr_str[32], addr_str[32];
211 strcpy(srcaddr_str, pj_inet_ntoa(srcaddr->sin_addr));
212 strcpy(addr_str, pj_inet_ntoa(addr.sin_addr));
213 PJ_LOG(3,("test", "...error: src address mismatch (original=%s, "
214 "recvfrom addr=%s)",
215 srcaddr_str, addr_str));
216 return -152;
217 }
218
219 } else {
220 /* Repeat recv() until all data is received.
221 * This applies only for non-UDP of course, since for UDP
222 * we would expect all data to be received in one packet.
223 */
224 total_received = 0;
225 do {
226 received = DATA_LEN-total_received;
227 rc = pj_sock_recv(ss, recvdata+total_received, &received, 0);
228 if (rc != PJ_SUCCESS) {
229 app_perror("...recv error", rc);
230 rc = -155; goto on_error;
231 }
232 if (received <= 0) {
233 PJ_LOG(3,("", "...error: socket has closed! (received=%d)",
234 received));
235 rc = -156; goto on_error;
236 }
237 if (received != DATA_LEN-total_received) {
238 if (sock_type != PJ_SOCK_STREAM) {
239 PJ_LOG(3,("", "...error: expecting %u bytes, got %u bytes",
240 DATA_LEN-total_received, received));
241 rc = -157; goto on_error;
242 }
243 }
244 total_received += received;
245 } while (total_received < DATA_LEN);
246 }
247
248 TRACE_(("test", "....memcmp()"));
249 if (pj_memcmp(senddata, recvdata, DATA_LEN) != 0) {
250 PJ_LOG(3,("","...error: received data mismatch "
251 "(got:'%s' expecting:'%s'",
252 recvdata, senddata));
253 rc = -160; goto on_error;
254 }
255
256 /*
257 * Test send/recv big data.
258 */
259 TRACE_(("test", "....sendto()"));
260 if (dstaddr) {
261 sent = BIG_DATA_LEN;
262 rc = pj_sock_sendto(cs, bigdata, &sent, 0, dstaddr, addrlen);
263 if (rc != PJ_SUCCESS || sent != BIG_DATA_LEN) {
264 app_perror("...sendto error", rc);
265 rc = -161; goto on_error;
266 }
267 } else {
268 sent = BIG_DATA_LEN;
269 rc = pj_sock_send(cs, bigdata, &sent, 0);
270 if (rc != PJ_SUCCESS || sent != BIG_DATA_LEN) {
271 app_perror("...send error", rc);
272 rc = -165; goto on_error;
273 }
274 }
275
276 TRACE_(("test", "....recv()"));
277
278 /* Repeat recv() until all data is received.
279 * This applies only for non-UDP of course, since for UDP
280 * we would expect all data to be received in one packet.
281 */
282 total_received = 0;
283 do {
284 received = BIG_DATA_LEN-total_received;
285 rc = pj_sock_recv(ss, bigbuffer+total_received, &received, 0);
286 if (rc != PJ_SUCCESS) {
287 app_perror("...recv error", rc);
288 rc = -170; goto on_error;
289 }
290 if (received <= 0) {
291 PJ_LOG(3,("", "...error: socket has closed! (received=%d)",
292 received));
293 rc = -173; goto on_error;
294 }
295 if (received != BIG_DATA_LEN-total_received) {
296 if (sock_type != PJ_SOCK_STREAM) {
297 PJ_LOG(3,("", "...error: expecting %u bytes, got %u bytes",
298 BIG_DATA_LEN-total_received, received));
299 rc = -176; goto on_error;
300 }
301 }
302 total_received += received;
303 } while (total_received < BIG_DATA_LEN);
304
305 TRACE_(("test", "....memcmp()"));
306 if (pj_memcmp(bigdata, bigbuffer, BIG_DATA_LEN) != 0) {
307 PJ_LOG(3,("", "...error: received data has been altered!"));
308 rc = -180; goto on_error;
309 }
310
311 rc = 0;
312
313on_error:
314 return rc;
315}
316
317static int udp_test(void)
318{
319 pj_sock_t cs = PJ_INVALID_SOCKET, ss = PJ_INVALID_SOCKET;
320 pj_sockaddr_in dstaddr, srcaddr;
321 pj_str_t s;
322 pj_status_t rc = 0, retval;
323
324 PJ_LOG(3,("test", "...udp_test()"));
325
326 rc = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &ss);
327 if (rc != 0) {
328 app_perror("...error: unable to create socket", rc);
329 return -100;
330 }
331
332 rc = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &cs);
333 if (rc != 0)
334 return -110;
335
336 /* Bind server socket. */
Benny Prijonoac623b32006-07-03 15:19:31 +0000337 pj_bzero(&dstaddr, sizeof(dstaddr));
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000338 dstaddr.sin_family = PJ_AF_INET;
339 dstaddr.sin_port = pj_htons(UDP_PORT);
Benny Prijono42c5b9e2006-05-10 19:24:40 +0000340 dstaddr.sin_addr = pj_inet_addr(pj_cstr(&s, ADDRESS));
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000341
342 if ((rc=pj_sock_bind(ss, &dstaddr, sizeof(dstaddr))) != 0) {
Benny Prijono42c5b9e2006-05-10 19:24:40 +0000343 app_perror("...bind error udp:"ADDRESS, rc);
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000344 rc = -120; goto on_error;
345 }
346
347 /* Bind client socket. */
Benny Prijonoac623b32006-07-03 15:19:31 +0000348 pj_bzero(&srcaddr, sizeof(srcaddr));
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000349 srcaddr.sin_family = PJ_AF_INET;
350 srcaddr.sin_port = pj_htons(UDP_PORT-1);
Benny Prijono42c5b9e2006-05-10 19:24:40 +0000351 srcaddr.sin_addr = pj_inet_addr(pj_cstr(&s, ADDRESS));
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000352
353 if ((rc=pj_sock_bind(cs, &srcaddr, sizeof(srcaddr))) != 0) {
354 app_perror("...bind error", rc);
355 rc = -121; goto on_error;
356 }
357
358 /* Test send/recv, with sendto */
359 rc = send_recv_test(PJ_SOCK_DGRAM, ss, cs, &dstaddr, NULL,
360 sizeof(dstaddr));
361 if (rc != 0)
362 goto on_error;
363
364 /* Test send/recv, with sendto and recvfrom */
365 rc = send_recv_test(PJ_SOCK_DGRAM, ss, cs, &dstaddr,
366 &srcaddr, sizeof(dstaddr));
367 if (rc != 0)
368 goto on_error;
369
370 /* connect() the sockets. */
371 rc = pj_sock_connect(cs, &dstaddr, sizeof(dstaddr));
372 if (rc != 0) {
373 app_perror("...connect() error", rc);
374 rc = -122; goto on_error;
375 }
376
377 /* Test send/recv with send() */
378 rc = send_recv_test(PJ_SOCK_DGRAM, ss, cs, NULL, NULL, 0);
379 if (rc != 0)
380 goto on_error;
381
382 /* Test send/recv with send() and recvfrom */
383 rc = send_recv_test(PJ_SOCK_DGRAM, ss, cs, NULL, &srcaddr,
384 sizeof(srcaddr));
385 if (rc != 0)
386 goto on_error;
387
388on_error:
389 retval = rc;
390 if (cs != PJ_INVALID_SOCKET) {
391 rc = pj_sock_close(cs);
392 if (rc != PJ_SUCCESS) {
393 app_perror("...error in closing socket", rc);
394 return -1000;
395 }
396 }
397 if (ss != PJ_INVALID_SOCKET) {
398 rc = pj_sock_close(ss);
399 if (rc != PJ_SUCCESS) {
400 app_perror("...error in closing socket", rc);
401 return -1010;
402 }
403 }
404
405 return retval;
406}
407
408static int tcp_test(void)
409{
410 pj_sock_t cs, ss;
411 pj_status_t rc = 0, retval;
412
413 PJ_LOG(3,("test", "...tcp_test()"));
414
415 rc = app_socketpair(PJ_AF_INET, PJ_SOCK_STREAM, 0, &ss, &cs);
416 if (rc != PJ_SUCCESS) {
417 app_perror("...error: app_socketpair():", rc);
418 return -2000;
419 }
420
421 /* Test send/recv with send() and recv() */
422 retval = send_recv_test(PJ_SOCK_STREAM, ss, cs, NULL, NULL, 0);
423
424 rc = pj_sock_close(cs);
425 if (rc != PJ_SUCCESS) {
426 app_perror("...error in closing socket", rc);
427 return -2000;
428 }
429
430 rc = pj_sock_close(ss);
431 if (rc != PJ_SUCCESS) {
432 app_perror("...error in closing socket", rc);
433 return -2010;
434 }
435
436 return retval;
437}
438
439static int ioctl_test(void)
440{
441 return 0;
442}
443
444int sock_test()
445{
446 int rc;
447
448 pj_create_random_string(bigdata, BIG_DATA_LEN);
449
450 rc = format_test();
451 if (rc != 0)
452 return rc;
453
454 rc = simple_sock_test();
455 if (rc != 0)
456 return rc;
457
458 rc = ioctl_test();
459 if (rc != 0)
460 return rc;
461
462 rc = udp_test();
463 if (rc != 0)
464 return rc;
465
466 rc = tcp_test();
467 if (rc != 0)
468 return rc;
469
470 return 0;
471}
472
473
474#else
475/* To prevent warning about "translation unit is empty"
476 * when this test is disabled.
477 */
478int dummy_sock_test;
479#endif /* INCLUDE_SOCK_TEST */
480