blob: 66c856c9a73bad9b00c0f33ffd11079c40e6cbf6 [file] [log] [blame]
Benny Prijono5dcb38d2005-11-21 01:55:47 +00001/* $Id$ */
2/*
Nanang Izzuddina62ffc92011-05-05 06:14:19 +00003 * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
Benny Prijono844653c2008-12-23 17:27:53 +00004 * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
Benny Prijono5dcb38d2005-11-21 01:55:47 +00005 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20#include "test.h"
21
22
23/**
24 * \page page_pjlib_ioqueue_udp_test Test: I/O Queue (UDP)
25 *
26 * This file provides implementation to test the
27 * functionality of the I/O queue when UDP socket is used.
28 *
29 *
30 * This file is <b>pjlib-test/ioq_udp.c</b>
31 *
32 * \include pjlib-test/ioq_udp.c
33 */
34
35
36#if INCLUDE_UDP_IOQUEUE_TEST
37
38#include <pjlib.h>
39
40#include <pj/compat/socket.h>
41
42#define THIS_FILE "test_udp"
43#define PORT 51233
Benny Prijono63ab3562006-07-08 19:46:43 +000044#define LOOP 2
Benny Prijono42c5b9e2006-05-10 19:24:40 +000045///#define LOOP 2
Benny Prijono5dcb38d2005-11-21 01:55:47 +000046#define BUF_MIN_SIZE 32
47#define BUF_MAX_SIZE 2048
48#define SOCK_INACTIVE_MIN (1)
49#define SOCK_INACTIVE_MAX (PJ_IOQUEUE_MAX_HANDLES - 2)
50#define POOL_SIZE (2*BUF_MAX_SIZE + SOCK_INACTIVE_MAX*128 + 2048)
51
52#undef TRACE_
53#define TRACE_(msg) PJ_LOG(3,(THIS_FILE,"....." msg))
54
Benny Prijono42c5b9e2006-05-10 19:24:40 +000055#if 0
56# define TRACE__(args) PJ_LOG(3,args)
57#else
58# define TRACE__(args)
59#endif
60
61
Benny Prijono5dcb38d2005-11-21 01:55:47 +000062static pj_ssize_t callback_read_size,
63 callback_write_size,
64 callback_accept_status,
65 callback_connect_status;
66static pj_ioqueue_key_t *callback_read_key,
67 *callback_write_key,
68 *callback_accept_key,
69 *callback_connect_key;
70static pj_ioqueue_op_key_t *callback_read_op,
71 *callback_write_op,
72 *callback_accept_op;
73
74static void on_ioqueue_read(pj_ioqueue_key_t *key,
75 pj_ioqueue_op_key_t *op_key,
76 pj_ssize_t bytes_read)
77{
78 callback_read_key = key;
79 callback_read_op = op_key;
80 callback_read_size = bytes_read;
Benny Prijono42c5b9e2006-05-10 19:24:40 +000081 TRACE__((THIS_FILE, " callback_read_key = %p, bytes=%d",
82 key, bytes_read));
Benny Prijono5dcb38d2005-11-21 01:55:47 +000083}
84
85static void on_ioqueue_write(pj_ioqueue_key_t *key,
86 pj_ioqueue_op_key_t *op_key,
87 pj_ssize_t bytes_written)
88{
89 callback_write_key = key;
90 callback_write_op = op_key;
91 callback_write_size = bytes_written;
92}
93
94static void on_ioqueue_accept(pj_ioqueue_key_t *key,
95 pj_ioqueue_op_key_t *op_key,
96 pj_sock_t sock, int status)
97{
98 PJ_UNUSED_ARG(sock);
99 callback_accept_key = key;
100 callback_accept_op = op_key;
101 callback_accept_status = status;
102}
103
104static void on_ioqueue_connect(pj_ioqueue_key_t *key, int status)
105{
106 callback_connect_key = key;
107 callback_connect_status = status;
108}
109
110static pj_ioqueue_callback test_cb =
111{
112 &on_ioqueue_read,
113 &on_ioqueue_write,
114 &on_ioqueue_accept,
115 &on_ioqueue_connect,
116};
117
118#ifdef PJ_WIN32
119# define S_ADDR S_un.S_addr
120#else
121# define S_ADDR s_addr
122#endif
123
124/*
125 * compliance_test()
126 * To test that the basic IOQueue functionality works. It will just exchange
127 * data between two sockets.
128 */
Benny Prijonoe3f79fd2008-02-13 15:17:28 +0000129static int compliance_test(pj_bool_t allow_concur)
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000130{
131 pj_sock_t ssock=-1, csock=-1;
Benny Prijono37e8d332006-01-20 21:03:36 +0000132 pj_sockaddr_in addr, dst_addr;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000133 int addrlen;
134 pj_pool_t *pool = NULL;
135 char *send_buf, *recv_buf;
136 pj_ioqueue_t *ioque = NULL;
Benny Prijono8ab968f2007-07-20 08:08:30 +0000137 pj_ioqueue_key_t *skey = NULL, *ckey = NULL;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000138 pj_ioqueue_op_key_t read_op, write_op;
139 int bufsize = BUF_MIN_SIZE;
140 pj_ssize_t bytes, status = -1;
141 pj_str_t temp;
142 pj_bool_t send_pending, recv_pending;
143 pj_status_t rc;
144
145 pj_set_os_error(PJ_SUCCESS);
146
147 // Create pool.
148 pool = pj_pool_create(mem, NULL, POOL_SIZE, 4000, NULL);
149
150 // Allocate buffers for send and receive.
151 send_buf = (char*)pj_pool_alloc(pool, bufsize);
152 recv_buf = (char*)pj_pool_alloc(pool, bufsize);
153
154 // Allocate sockets for sending and receiving.
155 TRACE_("creating sockets...");
Benny Prijono8ab968f2007-07-20 08:08:30 +0000156 rc = pj_sock_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, &ssock);
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000157 if (rc==PJ_SUCCESS)
Benny Prijono8ab968f2007-07-20 08:08:30 +0000158 rc = pj_sock_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, &csock);
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000159 else
160 csock = PJ_INVALID_SOCKET;
161 if (rc != PJ_SUCCESS) {
162 app_perror("...ERROR in pj_sock_socket()", rc);
163 status=-1; goto on_error;
164 }
165
166 // Bind server socket.
167 TRACE_("bind socket...");
Benny Prijonoac623b32006-07-03 15:19:31 +0000168 pj_bzero(&addr, sizeof(addr));
Benny Prijono8ab968f2007-07-20 08:08:30 +0000169 addr.sin_family = pj_AF_INET();
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000170 addr.sin_port = pj_htons(PORT);
171 if (pj_sock_bind(ssock, &addr, sizeof(addr))) {
172 status=-10; goto on_error;
173 }
174
175 // Create I/O Queue.
176 TRACE_("create ioqueue...");
177 rc = pj_ioqueue_create(pool, PJ_IOQUEUE_MAX_HANDLES, &ioque);
178 if (rc != PJ_SUCCESS) {
179 status=-20; goto on_error;
180 }
181
Benny Prijonoe3f79fd2008-02-13 15:17:28 +0000182 // Set concurrency
183 TRACE_("set concurrency...");
184 rc = pj_ioqueue_set_default_concurrency(ioque, allow_concur);
185 if (rc != PJ_SUCCESS) {
186 status=-21; goto on_error;
187 }
188
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000189 // Register server and client socket.
190 // We put this after inactivity socket, hopefully this can represent the
191 // worst waiting time.
192 TRACE_("registering first sockets...");
193 rc = pj_ioqueue_register_sock(pool, ioque, ssock, NULL,
194 &test_cb, &skey);
195 if (rc != PJ_SUCCESS) {
196 app_perror("...error(10): ioqueue_register error", rc);
197 status=-25; goto on_error;
198 }
199 TRACE_("registering second sockets...");
200 rc = pj_ioqueue_register_sock( pool, ioque, csock, NULL,
201 &test_cb, &ckey);
202 if (rc != PJ_SUCCESS) {
203 app_perror("...error(11): ioqueue_register error", rc);
204 status=-26; goto on_error;
205 }
206
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000207 // Randomize send_buf.
208 pj_create_random_string(send_buf, bufsize);
209
210 // Register reading from ioqueue.
211 TRACE_("start recvfrom...");
Benny Prijonoac623b32006-07-03 15:19:31 +0000212 pj_bzero(&addr, sizeof(addr));
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000213 addrlen = sizeof(addr);
214 bytes = bufsize;
215 rc = pj_ioqueue_recvfrom(skey, &read_op, recv_buf, &bytes, 0,
216 &addr, &addrlen);
217 if (rc != PJ_SUCCESS && rc != PJ_EPENDING) {
218 app_perror("...error: pj_ioqueue_recvfrom", rc);
219 status=-28; goto on_error;
220 } else if (rc == PJ_EPENDING) {
221 recv_pending = 1;
222 PJ_LOG(3, (THIS_FILE,
223 "......ok: recvfrom returned pending"));
224 } else {
225 PJ_LOG(3, (THIS_FILE,
226 "......error: recvfrom returned immediate ok!"));
227 status=-29; goto on_error;
228 }
229
Benny Prijono37e8d332006-01-20 21:03:36 +0000230 // Set destination address to send the packet.
231 TRACE_("set destination address...");
232 temp = pj_str("127.0.0.1");
233 if ((rc=pj_sockaddr_in_init(&dst_addr, &temp, PORT)) != 0) {
234 app_perror("...error: unable to resolve 127.0.0.1", rc);
235 status=-290; goto on_error;
236 }
237
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000238 // Write must return the number of bytes.
239 TRACE_("start sendto...");
240 bytes = bufsize;
Benny Prijono37e8d332006-01-20 21:03:36 +0000241 rc = pj_ioqueue_sendto(ckey, &write_op, send_buf, &bytes, 0, &dst_addr,
242 sizeof(dst_addr));
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000243 if (rc != PJ_SUCCESS && rc != PJ_EPENDING) {
244 app_perror("...error: pj_ioqueue_sendto", rc);
245 status=-30; goto on_error;
246 } else if (rc == PJ_EPENDING) {
247 send_pending = 1;
248 PJ_LOG(3, (THIS_FILE,
249 "......ok: sendto returned pending"));
250 } else {
251 send_pending = 0;
252 PJ_LOG(3, (THIS_FILE,
253 "......ok: sendto returned immediate success"));
254 }
255
256 // reset callback variables.
257 callback_read_size = callback_write_size = 0;
258 callback_accept_status = callback_connect_status = -2;
259 callback_read_key = callback_write_key =
260 callback_accept_key = callback_connect_key = NULL;
261 callback_read_op = callback_write_op = NULL;
262
263 // Poll if pending.
264 while (send_pending || recv_pending) {
265 int rc;
266 pj_time_val timeout = { 5, 0 };
267
268 TRACE_("poll...");
Benny Prijono8ab968f2007-07-20 08:08:30 +0000269#ifdef PJ_SYMBIAN
Nanang Izzuddinb4bad702012-08-31 06:17:56 +0000270 rc = pj_symbianos_poll(-1, PJ_TIME_VAL_MSEC(timeout));
Benny Prijono8ab968f2007-07-20 08:08:30 +0000271#else
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000272 rc = pj_ioqueue_poll(ioque, &timeout);
Benny Prijono8ab968f2007-07-20 08:08:30 +0000273#endif
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000274
275 if (rc == 0) {
276 PJ_LOG(1,(THIS_FILE, "...ERROR: timed out..."));
277 status=-45; goto on_error;
278 } else if (rc < 0) {
Benny Prijono42c5b9e2006-05-10 19:24:40 +0000279 app_perror("...ERROR in ioqueue_poll()", -rc);
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000280 status=-50; goto on_error;
281 }
282
283 if (callback_read_key != NULL) {
284 if (callback_read_size != bufsize) {
285 status=-61; goto on_error;
286 }
287 if (callback_read_key != skey) {
288 status=-65; goto on_error;
289 }
290 if (callback_read_op != &read_op) {
291 status=-66; goto on_error;
292 }
293
Benny Prijono37e8d332006-01-20 21:03:36 +0000294 if (pj_memcmp(send_buf, recv_buf, bufsize) != 0) {
295 status=-67; goto on_error;
296 }
297 if (addrlen != sizeof(pj_sockaddr_in)) {
298 status=-68; goto on_error;
299 }
Benny Prijono8ab968f2007-07-20 08:08:30 +0000300 if (addr.sin_family != pj_AF_INET()) {
Benny Prijono37e8d332006-01-20 21:03:36 +0000301 status=-69; goto on_error;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000302 }
303
304
305 recv_pending = 0;
306 }
307
308 if (callback_write_key != NULL) {
309 if (callback_write_size != bufsize) {
310 status=-73; goto on_error;
311 }
312 if (callback_write_key != ckey) {
313 status=-75; goto on_error;
314 }
315 if (callback_write_op != &write_op) {
316 status=-76; goto on_error;
317 }
318
319 send_pending = 0;
320 }
321 }
322
323 // Success
324 status = 0;
325
326on_error:
Benny Prijono8ab968f2007-07-20 08:08:30 +0000327 if (skey)
328 pj_ioqueue_unregister(skey);
329 else if (ssock != -1)
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000330 pj_sock_close(ssock);
Benny Prijono8ab968f2007-07-20 08:08:30 +0000331
332 if (ckey)
333 pj_ioqueue_unregister(ckey);
334 else if (csock != -1)
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000335 pj_sock_close(csock);
Benny Prijono8ab968f2007-07-20 08:08:30 +0000336
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000337 if (ioque != NULL)
338 pj_ioqueue_destroy(ioque);
339 pj_pool_release(pool);
340 return status;
341
342}
343
Benny Prijono8d317a02006-03-22 11:49:19 +0000344
345static void on_read_complete(pj_ioqueue_key_t *key,
346 pj_ioqueue_op_key_t *op_key,
347 pj_ssize_t bytes_read)
348{
Benny Prijonof260e462007-04-30 21:03:32 +0000349 unsigned *p_packet_cnt = (unsigned*) pj_ioqueue_get_user_data(key);
Benny Prijono8d317a02006-03-22 11:49:19 +0000350
351 PJ_UNUSED_ARG(op_key);
352 PJ_UNUSED_ARG(bytes_read);
353
354 (*p_packet_cnt)++;
355}
356
357/*
358 * unregister_test()
359 * Check if callback is still called after socket has been unregistered or
360 * closed.
361 */
Benny Prijonoe3f79fd2008-02-13 15:17:28 +0000362static int unregister_test(pj_bool_t allow_concur)
Benny Prijono8d317a02006-03-22 11:49:19 +0000363{
364 enum { RPORT = 50000, SPORT = 50001 };
365 pj_pool_t *pool;
366 pj_ioqueue_t *ioqueue;
367 pj_sock_t ssock;
368 pj_sock_t rsock;
369 int addrlen;
370 pj_sockaddr_in addr;
371 pj_ioqueue_key_t *key;
372 pj_ioqueue_op_key_t opkey;
373 pj_ioqueue_callback cb;
374 unsigned packet_cnt;
375 char sendbuf[10], recvbuf[10];
376 pj_ssize_t bytes;
377 pj_time_val timeout;
378 pj_status_t status;
379
380 pool = pj_pool_create(mem, "test", 4000, 4000, NULL);
381 if (!pool) {
382 app_perror("Unable to create pool", PJ_ENOMEM);
383 return -100;
384 }
385
386 status = pj_ioqueue_create(pool, 16, &ioqueue);
387 if (status != PJ_SUCCESS) {
388 app_perror("Error creating ioqueue", status);
389 return -110;
390 }
391
Benny Prijonoe3f79fd2008-02-13 15:17:28 +0000392 // Set concurrency
393 TRACE_("set concurrency...");
394 status = pj_ioqueue_set_default_concurrency(ioqueue, allow_concur);
395 if (status != PJ_SUCCESS) {
396 return -112;
397 }
398
Benny Prijono8d317a02006-03-22 11:49:19 +0000399 /* Create sender socket */
Benny Prijono8ab968f2007-07-20 08:08:30 +0000400 status = app_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, SPORT, &ssock);
Benny Prijono8d317a02006-03-22 11:49:19 +0000401 if (status != PJ_SUCCESS) {
402 app_perror("Error initializing socket", status);
403 return -120;
404 }
405
406 /* Create receiver socket. */
Benny Prijono8ab968f2007-07-20 08:08:30 +0000407 status = app_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, RPORT, &rsock);
Benny Prijono8d317a02006-03-22 11:49:19 +0000408 if (status != PJ_SUCCESS) {
409 app_perror("Error initializing socket", status);
410 return -130;
411 }
412
413 /* Register rsock to ioqueue. */
Benny Prijonoac623b32006-07-03 15:19:31 +0000414 pj_bzero(&cb, sizeof(cb));
Benny Prijono8d317a02006-03-22 11:49:19 +0000415 cb.on_read_complete = &on_read_complete;
416 packet_cnt = 0;
417 status = pj_ioqueue_register_sock(pool, ioqueue, rsock, &packet_cnt,
418 &cb, &key);
419 if (status != PJ_SUCCESS) {
420 app_perror("Error registering to ioqueue", status);
421 return -140;
422 }
423
424 /* Init operation key. */
425 pj_ioqueue_op_key_init(&opkey, sizeof(opkey));
426
427 /* Start reading. */
428 bytes = sizeof(recvbuf);
429 status = pj_ioqueue_recv( key, &opkey, recvbuf, &bytes, 0);
430 if (status != PJ_EPENDING) {
431 app_perror("Expecting PJ_EPENDING, but got this", status);
432 return -150;
433 }
434
435 /* Init destination address. */
436 addrlen = sizeof(addr);
437 status = pj_sock_getsockname(rsock, &addr, &addrlen);
438 if (status != PJ_SUCCESS) {
439 app_perror("getsockname error", status);
440 return -160;
441 }
442
443 /* Override address with 127.0.0.1, since getsockname will return
444 * zero in the address field.
445 */
446 addr.sin_addr = pj_inet_addr2("127.0.0.1");
447
448 /* Init buffer to send */
449 pj_ansi_strcpy(sendbuf, "Hello0123");
450
451 /* Send one packet. */
452 bytes = sizeof(sendbuf);
453 status = pj_sock_sendto(ssock, sendbuf, &bytes, 0,
454 &addr, sizeof(addr));
455
456 if (status != PJ_SUCCESS) {
457 app_perror("sendto error", status);
458 return -170;
459 }
460
461 /* Check if packet is received. */
462 timeout.sec = 1; timeout.msec = 0;
Benny Prijono8ab968f2007-07-20 08:08:30 +0000463#ifdef PJ_SYMBIAN
464 pj_symbianos_poll(-1, 1000);
465#else
Benny Prijono8d317a02006-03-22 11:49:19 +0000466 pj_ioqueue_poll(ioqueue, &timeout);
Benny Prijono8ab968f2007-07-20 08:08:30 +0000467#endif
Benny Prijono8d317a02006-03-22 11:49:19 +0000468
469 if (packet_cnt != 1) {
470 return -180;
471 }
472
473 /* Just to make sure things are settled.. */
474 pj_thread_sleep(100);
475
476 /* Start reading again. */
477 bytes = sizeof(recvbuf);
478 status = pj_ioqueue_recv( key, &opkey, recvbuf, &bytes, 0);
479 if (status != PJ_EPENDING) {
480 app_perror("Expecting PJ_EPENDING, but got this", status);
481 return -190;
482 }
483
484 /* Reset packet counter */
485 packet_cnt = 0;
486
487 /* Send one packet. */
488 bytes = sizeof(sendbuf);
489 status = pj_sock_sendto(ssock, sendbuf, &bytes, 0,
490 &addr, sizeof(addr));
491
492 if (status != PJ_SUCCESS) {
493 app_perror("sendto error", status);
494 return -200;
495 }
496
497 /* Now unregister and close socket. */
498 pj_ioqueue_unregister(key);
Benny Prijono8d317a02006-03-22 11:49:19 +0000499
500 /* Poll ioqueue. */
Benny Prijono8ab968f2007-07-20 08:08:30 +0000501#ifdef PJ_SYMBIAN
502 pj_symbianos_poll(-1, 1000);
503#else
Benny Prijono8d317a02006-03-22 11:49:19 +0000504 timeout.sec = 1; timeout.msec = 0;
505 pj_ioqueue_poll(ioqueue, &timeout);
Benny Prijono8ab968f2007-07-20 08:08:30 +0000506#endif
Benny Prijono8d317a02006-03-22 11:49:19 +0000507
508 /* Must NOT receive any packets after socket is closed! */
509 if (packet_cnt > 0) {
510 PJ_LOG(3,(THIS_FILE, "....errror: not expecting to receive packet "
511 "after socket has been closed"));
512 return -210;
513 }
514
515 /* Success */
516 pj_sock_close(ssock);
517 pj_ioqueue_destroy(ioqueue);
518
519 pj_pool_release(pool);
520
521 return 0;
522}
523
524
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000525/*
526 * Testing with many handles.
527 * This will just test registering PJ_IOQUEUE_MAX_HANDLES count
528 * of sockets to the ioqueue.
529 */
Benny Prijonoe3f79fd2008-02-13 15:17:28 +0000530static int many_handles_test(pj_bool_t allow_concur)
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000531{
532 enum { MAX = PJ_IOQUEUE_MAX_HANDLES };
533 pj_pool_t *pool;
534 pj_ioqueue_t *ioqueue;
535 pj_sock_t *sock;
536 pj_ioqueue_key_t **key;
537 pj_status_t rc;
Benny Prijono42c5b9e2006-05-10 19:24:40 +0000538 int count, i; /* must be signed */
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000539
540 PJ_LOG(3,(THIS_FILE,"...testing with so many handles"));
541
542 pool = pj_pool_create(mem, NULL, 4000, 4000, NULL);
543 if (!pool)
544 return PJ_ENOMEM;
545
Benny Prijonof260e462007-04-30 21:03:32 +0000546 key = (pj_ioqueue_key_t**)
547 pj_pool_alloc(pool, MAX*sizeof(pj_ioqueue_key_t*));
548 sock = (pj_sock_t*) pj_pool_alloc(pool, MAX*sizeof(pj_sock_t));
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000549
550 /* Create IOQueue */
551 rc = pj_ioqueue_create(pool, MAX, &ioqueue);
552 if (rc != PJ_SUCCESS || ioqueue == NULL) {
553 app_perror("...error in pj_ioqueue_create", rc);
554 return -10;
555 }
556
Benny Prijonoe3f79fd2008-02-13 15:17:28 +0000557 // Set concurrency
558 rc = pj_ioqueue_set_default_concurrency(ioqueue, allow_concur);
559 if (rc != PJ_SUCCESS) {
560 return -11;
561 }
562
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000563 /* Register as many sockets. */
564 for (count=0; count<MAX; ++count) {
565 sock[count] = PJ_INVALID_SOCKET;
Benny Prijono8ab968f2007-07-20 08:08:30 +0000566 rc = pj_sock_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, &sock[count]);
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000567 if (rc != PJ_SUCCESS || sock[count] == PJ_INVALID_SOCKET) {
568 PJ_LOG(3,(THIS_FILE, "....unable to create %d-th socket, rc=%d",
569 count, rc));
570 break;
571 }
572 key[count] = NULL;
573 rc = pj_ioqueue_register_sock(pool, ioqueue, sock[count],
574 NULL, &test_cb, &key[count]);
575 if (rc != PJ_SUCCESS || key[count] == NULL) {
576 PJ_LOG(3,(THIS_FILE, "....unable to register %d-th socket, rc=%d",
577 count, rc));
578 return -30;
579 }
580 }
581
582 /* Test complete. */
583
584 /* Now deregister and close all handles. */
585
Benny Prijono42c5b9e2006-05-10 19:24:40 +0000586 /* NOTE for RTEMS:
587 * It seems that the order of close(sock) is pretty important here.
588 * If we close the sockets with the same order as when they were created,
589 * RTEMS doesn't seem to reuse the sockets, thus next socket created
590 * will have descriptor higher than the last socket created.
591 * If we close the sockets in the reverse order, then the descriptor will
592 * get reused.
593 * This used to cause problem with select ioqueue, since the ioqueue
594 * always gives FD_SETSIZE for the first select() argument. This ioqueue
595 * behavior can be changed with setting PJ_SELECT_NEEDS_NFDS macro.
596 */
597 for (i=count-1; i>=0; --i) {
598 ///for (i=0; i<count; ++i) {
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000599 rc = pj_ioqueue_unregister(key[i]);
600 if (rc != PJ_SUCCESS) {
601 app_perror("...error in pj_ioqueue_unregister", rc);
602 }
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000603 }
604
605 rc = pj_ioqueue_destroy(ioqueue);
606 if (rc != PJ_SUCCESS) {
607 app_perror("...error in pj_ioqueue_destroy", rc);
608 }
609
610 pj_pool_release(pool);
611
612 PJ_LOG(3,(THIS_FILE,"....many_handles_test() ok"));
613
614 return 0;
615}
616
617/*
618 * Multi-operation test.
619 */
620
621/*
622 * Benchmarking IOQueue
623 */
Benny Prijonoe3f79fd2008-02-13 15:17:28 +0000624static int bench_test(pj_bool_t allow_concur, int bufsize,
625 int inactive_sock_count)
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000626{
627 pj_sock_t ssock=-1, csock=-1;
628 pj_sockaddr_in addr;
629 pj_pool_t *pool = NULL;
630 pj_sock_t *inactive_sock=NULL;
631 pj_ioqueue_op_key_t *inactive_read_op;
632 char *send_buf, *recv_buf;
633 pj_ioqueue_t *ioque = NULL;
Benny Prijono8ab968f2007-07-20 08:08:30 +0000634 pj_ioqueue_key_t *skey, *ckey, *keys[SOCK_INACTIVE_MAX+2];
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000635 pj_timestamp t1, t2, t_elapsed;
Benny Prijono42c5b9e2006-05-10 19:24:40 +0000636 int rc=0, i; /* i must be signed */
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000637 pj_str_t temp;
Benny Prijono42c5b9e2006-05-10 19:24:40 +0000638 char errbuf[PJ_ERR_MSG_SIZE];
639
640 TRACE__((THIS_FILE, " bench test %d", inactive_sock_count));
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000641
642 // Create pool.
643 pool = pj_pool_create(mem, NULL, POOL_SIZE, 4000, NULL);
644
645 // Allocate buffers for send and receive.
646 send_buf = (char*)pj_pool_alloc(pool, bufsize);
647 recv_buf = (char*)pj_pool_alloc(pool, bufsize);
648
649 // Allocate sockets for sending and receiving.
Benny Prijono8ab968f2007-07-20 08:08:30 +0000650 rc = pj_sock_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, &ssock);
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000651 if (rc == PJ_SUCCESS) {
Benny Prijono8ab968f2007-07-20 08:08:30 +0000652 rc = pj_sock_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, &csock);
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000653 } else
654 csock = PJ_INVALID_SOCKET;
655 if (rc != PJ_SUCCESS) {
656 app_perror("...error: pj_sock_socket()", rc);
657 goto on_error;
658 }
659
660 // Bind server socket.
Benny Prijonoac623b32006-07-03 15:19:31 +0000661 pj_bzero(&addr, sizeof(addr));
Benny Prijono8ab968f2007-07-20 08:08:30 +0000662 addr.sin_family = pj_AF_INET();
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000663 addr.sin_port = pj_htons(PORT);
664 if (pj_sock_bind(ssock, &addr, sizeof(addr)))
665 goto on_error;
666
667 pj_assert(inactive_sock_count+2 <= PJ_IOQUEUE_MAX_HANDLES);
668
669 // Create I/O Queue.
670 rc = pj_ioqueue_create(pool, PJ_IOQUEUE_MAX_HANDLES, &ioque);
671 if (rc != PJ_SUCCESS) {
672 app_perror("...error: pj_ioqueue_create()", rc);
673 goto on_error;
674 }
675
Benny Prijonoe3f79fd2008-02-13 15:17:28 +0000676 // Set concurrency
677 rc = pj_ioqueue_set_default_concurrency(ioque, allow_concur);
678 if (rc != PJ_SUCCESS) {
679 app_perror("...error: pj_ioqueue_set_default_concurrency()", rc);
680 goto on_error;
681 }
682
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000683 // Allocate inactive sockets, and bind them to some arbitrary address.
684 // Then register them to the I/O queue, and start a read operation.
685 inactive_sock = (pj_sock_t*)pj_pool_alloc(pool,
686 inactive_sock_count*sizeof(pj_sock_t));
687 inactive_read_op = (pj_ioqueue_op_key_t*)pj_pool_alloc(pool,
688 inactive_sock_count*sizeof(pj_ioqueue_op_key_t));
Benny Prijonoac623b32006-07-03 15:19:31 +0000689 pj_bzero(&addr, sizeof(addr));
Benny Prijono8ab968f2007-07-20 08:08:30 +0000690 addr.sin_family = pj_AF_INET();
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000691 for (i=0; i<inactive_sock_count; ++i) {
692 pj_ssize_t bytes;
693
Benny Prijono8ab968f2007-07-20 08:08:30 +0000694 rc = pj_sock_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, &inactive_sock[i]);
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000695 if (rc != PJ_SUCCESS || inactive_sock[i] < 0) {
696 app_perror("...error: pj_sock_socket()", rc);
697 goto on_error;
698 }
699 if ((rc=pj_sock_bind(inactive_sock[i], &addr, sizeof(addr))) != 0) {
700 pj_sock_close(inactive_sock[i]);
701 inactive_sock[i] = PJ_INVALID_SOCKET;
702 app_perror("...error: pj_sock_bind()", rc);
703 goto on_error;
704 }
705 rc = pj_ioqueue_register_sock(pool, ioque, inactive_sock[i],
Benny Prijono8ab968f2007-07-20 08:08:30 +0000706 NULL, &test_cb, &keys[i]);
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000707 if (rc != PJ_SUCCESS) {
708 pj_sock_close(inactive_sock[i]);
709 inactive_sock[i] = PJ_INVALID_SOCKET;
710 app_perror("...error(1): pj_ioqueue_register_sock()", rc);
711 PJ_LOG(3,(THIS_FILE, "....i=%d", i));
712 goto on_error;
713 }
714 bytes = bufsize;
Benny Prijono8ab968f2007-07-20 08:08:30 +0000715 rc = pj_ioqueue_recv(keys[i], &inactive_read_op[i], recv_buf, &bytes, 0);
Benny Prijono37e8d332006-01-20 21:03:36 +0000716 if (rc != PJ_EPENDING) {
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000717 pj_sock_close(inactive_sock[i]);
718 inactive_sock[i] = PJ_INVALID_SOCKET;
719 app_perror("...error: pj_ioqueue_read()", rc);
720 goto on_error;
721 }
722 }
723
724 // Register server and client socket.
725 // We put this after inactivity socket, hopefully this can represent the
726 // worst waiting time.
727 rc = pj_ioqueue_register_sock(pool, ioque, ssock, NULL,
728 &test_cb, &skey);
729 if (rc != PJ_SUCCESS) {
730 app_perror("...error(2): pj_ioqueue_register_sock()", rc);
731 goto on_error;
732 }
733
734 rc = pj_ioqueue_register_sock(pool, ioque, csock, NULL,
735 &test_cb, &ckey);
736 if (rc != PJ_SUCCESS) {
737 app_perror("...error(3): pj_ioqueue_register_sock()", rc);
738 goto on_error;
739 }
740
741 // Set destination address to send the packet.
742 pj_sockaddr_in_init(&addr, pj_cstr(&temp, "127.0.0.1"), PORT);
743
744 // Test loop.
745 t_elapsed.u64 = 0;
746 for (i=0; i<LOOP; ++i) {
747 pj_ssize_t bytes;
748 pj_ioqueue_op_key_t read_op, write_op;
749
750 // Randomize send buffer.
751 pj_create_random_string(send_buf, bufsize);
752
753 // Start reading on the server side.
754 bytes = bufsize;
755 rc = pj_ioqueue_recv(skey, &read_op, recv_buf, &bytes, 0);
Benny Prijono37e8d332006-01-20 21:03:36 +0000756 if (rc != PJ_EPENDING) {
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000757 app_perror("...error: pj_ioqueue_read()", rc);
758 break;
759 }
760
761 // Starts send on the client side.
762 bytes = bufsize;
763 rc = pj_ioqueue_sendto(ckey, &write_op, send_buf, &bytes, 0,
764 &addr, sizeof(addr));
765 if (rc != PJ_SUCCESS && rc != PJ_EPENDING) {
Benny Prijono42c5b9e2006-05-10 19:24:40 +0000766 app_perror("...error: pj_ioqueue_write()", rc);
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000767 break;
768 }
Benny Prijono42c5b9e2006-05-10 19:24:40 +0000769 if (rc == PJ_SUCCESS) {
770 if (bytes < 0) {
771 app_perror("...error: pj_ioqueue_sendto()", -bytes);
772 break;
773 }
774 }
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000775
776 // Begin time.
777 pj_get_timestamp(&t1);
778
779 // Poll the queue until we've got completion event in the server side.
780 callback_read_key = NULL;
781 callback_read_size = 0;
Benny Prijono42c5b9e2006-05-10 19:24:40 +0000782 TRACE__((THIS_FILE, " waiting for key = %p", skey));
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000783 do {
Benny Prijono42c5b9e2006-05-10 19:24:40 +0000784 pj_time_val timeout = { 1, 0 };
Benny Prijono8ab968f2007-07-20 08:08:30 +0000785#ifdef PJ_SYMBIAN
Nanang Izzuddinb4bad702012-08-31 06:17:56 +0000786 rc = pj_symbianos_poll(-1, PJ_TIME_VAL_MSEC(timeout));
Benny Prijono8ab968f2007-07-20 08:08:30 +0000787#else
Benny Prijono42c5b9e2006-05-10 19:24:40 +0000788 rc = pj_ioqueue_poll(ioque, &timeout);
Benny Prijono8ab968f2007-07-20 08:08:30 +0000789#endif
Benny Prijono42c5b9e2006-05-10 19:24:40 +0000790 TRACE__((THIS_FILE, " poll rc=%d", rc));
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000791 } while (rc >= 0 && callback_read_key != skey);
792
793 // End time.
794 pj_get_timestamp(&t2);
795 t_elapsed.u64 += (t2.u64 - t1.u64);
796
Benny Prijono37e8d332006-01-20 21:03:36 +0000797 if (rc < 0) {
798 app_perror(" error: pj_ioqueue_poll", -rc);
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000799 break;
Benny Prijono37e8d332006-01-20 21:03:36 +0000800 }
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000801
802 // Compare recv buffer with send buffer.
803 if (callback_read_size != bufsize ||
Benny Prijono37e8d332006-01-20 21:03:36 +0000804 pj_memcmp(send_buf, recv_buf, bufsize))
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000805 {
Benny Prijono37e8d332006-01-20 21:03:36 +0000806 rc = -10;
807 PJ_LOG(3,(THIS_FILE, " error: size/buffer mismatch"));
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000808 break;
809 }
810
811 // Poll until all events are exhausted, before we start the next loop.
812 do {
813 pj_time_val timeout = { 0, 10 };
Benny Prijono8ab968f2007-07-20 08:08:30 +0000814#ifdef PJ_SYMBIAN
Nanang Izzuddinb4bad702012-08-31 06:17:56 +0000815 PJ_UNUSED_ARG(timeout);
Benny Prijono8ab968f2007-07-20 08:08:30 +0000816 rc = pj_symbianos_poll(-1, 100);
817#else
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000818 rc = pj_ioqueue_poll(ioque, &timeout);
Benny Prijono8ab968f2007-07-20 08:08:30 +0000819#endif
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000820 } while (rc>0);
821
822 rc = 0;
823 }
824
825 // Print results
826 if (rc == 0) {
827 pj_timestamp tzero;
828 pj_uint32_t usec_delay;
829
830 tzero.u32.hi = tzero.u32.lo = 0;
831 usec_delay = pj_elapsed_usec( &tzero, &t_elapsed);
832
833 PJ_LOG(3, (THIS_FILE, "...%10d %15d % 9d",
834 bufsize, inactive_sock_count, usec_delay));
835
836 } else {
Benny Prijono37e8d332006-01-20 21:03:36 +0000837 PJ_LOG(2, (THIS_FILE, "...ERROR rc=%d (buf:%d, fds:%d)",
838 rc, bufsize, inactive_sock_count+2));
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000839 }
840
841 // Cleaning up.
Benny Prijono42c5b9e2006-05-10 19:24:40 +0000842 for (i=inactive_sock_count-1; i>=0; --i) {
Benny Prijono8ab968f2007-07-20 08:08:30 +0000843 pj_ioqueue_unregister(keys[i]);
Benny Prijono42c5b9e2006-05-10 19:24:40 +0000844 }
845
Benny Prijono8ab968f2007-07-20 08:08:30 +0000846 pj_ioqueue_unregister(skey);
847 pj_ioqueue_unregister(ckey);
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000848
Benny Prijono42c5b9e2006-05-10 19:24:40 +0000849
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000850 pj_ioqueue_destroy(ioque);
851 pj_pool_release( pool);
Benny Prijono37e8d332006-01-20 21:03:36 +0000852 return rc;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000853
854on_error:
855 PJ_LOG(1,(THIS_FILE, "...ERROR: %s",
856 pj_strerror(pj_get_netos_error(), errbuf, sizeof(errbuf))));
857 if (ssock)
858 pj_sock_close(ssock);
859 if (csock)
860 pj_sock_close(csock);
861 for (i=0; i<inactive_sock_count && inactive_sock &&
862 inactive_sock[i]!=PJ_INVALID_SOCKET; ++i)
863 {
864 pj_sock_close(inactive_sock[i]);
865 }
866 if (ioque != NULL)
867 pj_ioqueue_destroy(ioque);
868 pj_pool_release( pool);
869 return -1;
870}
871
Benny Prijonoe3f79fd2008-02-13 15:17:28 +0000872static int udp_ioqueue_test_imp(pj_bool_t allow_concur)
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000873{
874 int status;
875 int bufsize, sock_count;
876
Benny Prijonoe3f79fd2008-02-13 15:17:28 +0000877 PJ_LOG(3,(THIS_FILE, "..testing with concurency=%d", allow_concur));
878
Benny Prijono63ab3562006-07-08 19:46:43 +0000879 //goto pass1;
Benny Prijonofe9c9b62006-07-06 20:43:07 +0000880
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000881 PJ_LOG(3, (THIS_FILE, "...compliance test (%s)", pj_ioqueue_name()));
Benny Prijonoe3f79fd2008-02-13 15:17:28 +0000882 if ((status=compliance_test(allow_concur)) != 0) {
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000883 return status;
884 }
885 PJ_LOG(3, (THIS_FILE, "....compliance test ok"));
886
Benny Prijono8d317a02006-03-22 11:49:19 +0000887
888 PJ_LOG(3, (THIS_FILE, "...unregister test (%s)", pj_ioqueue_name()));
Benny Prijonoe3f79fd2008-02-13 15:17:28 +0000889 if ((status=unregister_test(allow_concur)) != 0) {
Benny Prijono8d317a02006-03-22 11:49:19 +0000890 return status;
891 }
892 PJ_LOG(3, (THIS_FILE, "....unregister test ok"));
893
Benny Prijonoe3f79fd2008-02-13 15:17:28 +0000894 if ((status=many_handles_test(allow_concur)) != 0) {
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000895 return status;
896 }
897
Benny Prijono63ab3562006-07-08 19:46:43 +0000898 //return 0;
899
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000900 PJ_LOG(4, (THIS_FILE, "...benchmarking different buffer size:"));
901 PJ_LOG(4, (THIS_FILE, "... note: buf=bytes sent, fds=# of fds, "
902 "elapsed=in timer ticks"));
903
Benny Prijono5fb99e52007-01-23 04:17:56 +0000904//pass1:
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000905 PJ_LOG(3, (THIS_FILE, "...Benchmarking poll times for %s:", pj_ioqueue_name()));
906 PJ_LOG(3, (THIS_FILE, "...====================================="));
907 PJ_LOG(3, (THIS_FILE, "...Buf.size #inactive-socks Time/poll"));
908 PJ_LOG(3, (THIS_FILE, "... (bytes) (nanosec)"));
909 PJ_LOG(3, (THIS_FILE, "...====================================="));
910
Benny Prijono63ab3562006-07-08 19:46:43 +0000911 //goto pass2;
Benny Prijonofe9c9b62006-07-06 20:43:07 +0000912
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000913 for (bufsize=BUF_MIN_SIZE; bufsize <= BUF_MAX_SIZE; bufsize *= 2) {
Benny Prijonoe3f79fd2008-02-13 15:17:28 +0000914 if ((status=bench_test(allow_concur, bufsize, SOCK_INACTIVE_MIN)) != 0)
Benny Prijono37e8d332006-01-20 21:03:36 +0000915 return status;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000916 }
Benny Prijono5fb99e52007-01-23 04:17:56 +0000917//pass2:
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000918 bufsize = 512;
919 for (sock_count=SOCK_INACTIVE_MIN+2;
920 sock_count<=SOCK_INACTIVE_MAX+2;
921 sock_count *= 2)
922 {
Benny Prijono63ab3562006-07-08 19:46:43 +0000923 //PJ_LOG(3,(THIS_FILE, "...testing with %d fds", sock_count));
Benny Prijonoe3f79fd2008-02-13 15:17:28 +0000924 if ((status=bench_test(allow_concur, bufsize, sock_count-2)) != 0)
Benny Prijono37e8d332006-01-20 21:03:36 +0000925 return status;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000926 }
927 return 0;
928}
929
Benny Prijonoe3f79fd2008-02-13 15:17:28 +0000930int udp_ioqueue_test()
931{
932 int rc;
933
934 rc = udp_ioqueue_test_imp(PJ_TRUE);
935 if (rc != 0)
936 return rc;
937
938 rc = udp_ioqueue_test_imp(PJ_FALSE);
939 if (rc != 0)
940 return rc;
941
942 return 0;
943}
944
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000945#else
946/* To prevent warning about "translation unit is empty"
947 * when this test is disabled.
948 */
949int dummy_uiq_udp;
950#endif /* INCLUDE_UDP_IOQUEUE_TEST */
951
952