blob: b81764f2e3c9f0d87d2125bc86449b61dac2b47e [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 "test.h"
20
21
22/**
23 * \page page_pjlib_ioqueue_udp_test Test: I/O Queue (UDP)
24 *
25 * This file provides implementation to test the
26 * functionality of the I/O queue when UDP socket is used.
27 *
28 *
29 * This file is <b>pjlib-test/ioq_udp.c</b>
30 *
31 * \include pjlib-test/ioq_udp.c
32 */
33
34
35#if INCLUDE_UDP_IOQUEUE_TEST
36
37#include <pjlib.h>
38
39#include <pj/compat/socket.h>
40
41#define THIS_FILE "test_udp"
42#define PORT 51233
43#define LOOP 100
44#define BUF_MIN_SIZE 32
45#define BUF_MAX_SIZE 2048
46#define SOCK_INACTIVE_MIN (1)
47#define SOCK_INACTIVE_MAX (PJ_IOQUEUE_MAX_HANDLES - 2)
48#define POOL_SIZE (2*BUF_MAX_SIZE + SOCK_INACTIVE_MAX*128 + 2048)
49
50#undef TRACE_
51#define TRACE_(msg) PJ_LOG(3,(THIS_FILE,"....." msg))
52
53static pj_ssize_t callback_read_size,
54 callback_write_size,
55 callback_accept_status,
56 callback_connect_status;
57static pj_ioqueue_key_t *callback_read_key,
58 *callback_write_key,
59 *callback_accept_key,
60 *callback_connect_key;
61static pj_ioqueue_op_key_t *callback_read_op,
62 *callback_write_op,
63 *callback_accept_op;
64
65static void on_ioqueue_read(pj_ioqueue_key_t *key,
66 pj_ioqueue_op_key_t *op_key,
67 pj_ssize_t bytes_read)
68{
69 callback_read_key = key;
70 callback_read_op = op_key;
71 callback_read_size = bytes_read;
72}
73
74static void on_ioqueue_write(pj_ioqueue_key_t *key,
75 pj_ioqueue_op_key_t *op_key,
76 pj_ssize_t bytes_written)
77{
78 callback_write_key = key;
79 callback_write_op = op_key;
80 callback_write_size = bytes_written;
81}
82
83static void on_ioqueue_accept(pj_ioqueue_key_t *key,
84 pj_ioqueue_op_key_t *op_key,
85 pj_sock_t sock, int status)
86{
87 PJ_UNUSED_ARG(sock);
88 callback_accept_key = key;
89 callback_accept_op = op_key;
90 callback_accept_status = status;
91}
92
93static void on_ioqueue_connect(pj_ioqueue_key_t *key, int status)
94{
95 callback_connect_key = key;
96 callback_connect_status = status;
97}
98
99static pj_ioqueue_callback test_cb =
100{
101 &on_ioqueue_read,
102 &on_ioqueue_write,
103 &on_ioqueue_accept,
104 &on_ioqueue_connect,
105};
106
107#ifdef PJ_WIN32
108# define S_ADDR S_un.S_addr
109#else
110# define S_ADDR s_addr
111#endif
112
113/*
114 * compliance_test()
115 * To test that the basic IOQueue functionality works. It will just exchange
116 * data between two sockets.
117 */
118static int compliance_test(void)
119{
120 pj_sock_t ssock=-1, csock=-1;
Benny Prijono37e8d332006-01-20 21:03:36 +0000121 pj_sockaddr_in addr, dst_addr;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000122 int addrlen;
123 pj_pool_t *pool = NULL;
124 char *send_buf, *recv_buf;
125 pj_ioqueue_t *ioque = NULL;
126 pj_ioqueue_key_t *skey, *ckey;
127 pj_ioqueue_op_key_t read_op, write_op;
128 int bufsize = BUF_MIN_SIZE;
129 pj_ssize_t bytes, status = -1;
130 pj_str_t temp;
131 pj_bool_t send_pending, recv_pending;
132 pj_status_t rc;
133
134 pj_set_os_error(PJ_SUCCESS);
135
136 // Create pool.
137 pool = pj_pool_create(mem, NULL, POOL_SIZE, 4000, NULL);
138
139 // Allocate buffers for send and receive.
140 send_buf = (char*)pj_pool_alloc(pool, bufsize);
141 recv_buf = (char*)pj_pool_alloc(pool, bufsize);
142
143 // Allocate sockets for sending and receiving.
144 TRACE_("creating sockets...");
145 rc = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &ssock);
146 if (rc==PJ_SUCCESS)
147 rc = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &csock);
148 else
149 csock = PJ_INVALID_SOCKET;
150 if (rc != PJ_SUCCESS) {
151 app_perror("...ERROR in pj_sock_socket()", rc);
152 status=-1; goto on_error;
153 }
154
155 // Bind server socket.
156 TRACE_("bind socket...");
Benny Prijono37e8d332006-01-20 21:03:36 +0000157 pj_memset(&addr, 0, sizeof(addr));
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000158 addr.sin_family = PJ_AF_INET;
159 addr.sin_port = pj_htons(PORT);
160 if (pj_sock_bind(ssock, &addr, sizeof(addr))) {
161 status=-10; goto on_error;
162 }
163
164 // Create I/O Queue.
165 TRACE_("create ioqueue...");
166 rc = pj_ioqueue_create(pool, PJ_IOQUEUE_MAX_HANDLES, &ioque);
167 if (rc != PJ_SUCCESS) {
168 status=-20; goto on_error;
169 }
170
171 // Register server and client socket.
172 // We put this after inactivity socket, hopefully this can represent the
173 // worst waiting time.
174 TRACE_("registering first sockets...");
175 rc = pj_ioqueue_register_sock(pool, ioque, ssock, NULL,
176 &test_cb, &skey);
177 if (rc != PJ_SUCCESS) {
178 app_perror("...error(10): ioqueue_register error", rc);
179 status=-25; goto on_error;
180 }
181 TRACE_("registering second sockets...");
182 rc = pj_ioqueue_register_sock( pool, ioque, csock, NULL,
183 &test_cb, &ckey);
184 if (rc != PJ_SUCCESS) {
185 app_perror("...error(11): ioqueue_register error", rc);
186 status=-26; goto on_error;
187 }
188
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000189 // Randomize send_buf.
190 pj_create_random_string(send_buf, bufsize);
191
192 // Register reading from ioqueue.
193 TRACE_("start recvfrom...");
Benny Prijono37e8d332006-01-20 21:03:36 +0000194 pj_memset(&addr, 0, sizeof(addr));
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000195 addrlen = sizeof(addr);
196 bytes = bufsize;
197 rc = pj_ioqueue_recvfrom(skey, &read_op, recv_buf, &bytes, 0,
198 &addr, &addrlen);
199 if (rc != PJ_SUCCESS && rc != PJ_EPENDING) {
200 app_perror("...error: pj_ioqueue_recvfrom", rc);
201 status=-28; goto on_error;
202 } else if (rc == PJ_EPENDING) {
203 recv_pending = 1;
204 PJ_LOG(3, (THIS_FILE,
205 "......ok: recvfrom returned pending"));
206 } else {
207 PJ_LOG(3, (THIS_FILE,
208 "......error: recvfrom returned immediate ok!"));
209 status=-29; goto on_error;
210 }
211
Benny Prijono37e8d332006-01-20 21:03:36 +0000212 // Set destination address to send the packet.
213 TRACE_("set destination address...");
214 temp = pj_str("127.0.0.1");
215 if ((rc=pj_sockaddr_in_init(&dst_addr, &temp, PORT)) != 0) {
216 app_perror("...error: unable to resolve 127.0.0.1", rc);
217 status=-290; goto on_error;
218 }
219
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000220 // Write must return the number of bytes.
221 TRACE_("start sendto...");
222 bytes = bufsize;
Benny Prijono37e8d332006-01-20 21:03:36 +0000223 rc = pj_ioqueue_sendto(ckey, &write_op, send_buf, &bytes, 0, &dst_addr,
224 sizeof(dst_addr));
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000225 if (rc != PJ_SUCCESS && rc != PJ_EPENDING) {
226 app_perror("...error: pj_ioqueue_sendto", rc);
227 status=-30; goto on_error;
228 } else if (rc == PJ_EPENDING) {
229 send_pending = 1;
230 PJ_LOG(3, (THIS_FILE,
231 "......ok: sendto returned pending"));
232 } else {
233 send_pending = 0;
234 PJ_LOG(3, (THIS_FILE,
235 "......ok: sendto returned immediate success"));
236 }
237
238 // reset callback variables.
239 callback_read_size = callback_write_size = 0;
240 callback_accept_status = callback_connect_status = -2;
241 callback_read_key = callback_write_key =
242 callback_accept_key = callback_connect_key = NULL;
243 callback_read_op = callback_write_op = NULL;
244
245 // Poll if pending.
246 while (send_pending || recv_pending) {
247 int rc;
248 pj_time_val timeout = { 5, 0 };
249
250 TRACE_("poll...");
251 rc = pj_ioqueue_poll(ioque, &timeout);
252
253 if (rc == 0) {
254 PJ_LOG(1,(THIS_FILE, "...ERROR: timed out..."));
255 status=-45; goto on_error;
256 } else if (rc < 0) {
257 app_perror("...ERROR in ioqueue_poll()", rc);
258 status=-50; goto on_error;
259 }
260
261 if (callback_read_key != NULL) {
262 if (callback_read_size != bufsize) {
263 status=-61; goto on_error;
264 }
265 if (callback_read_key != skey) {
266 status=-65; goto on_error;
267 }
268 if (callback_read_op != &read_op) {
269 status=-66; goto on_error;
270 }
271
Benny Prijono37e8d332006-01-20 21:03:36 +0000272 if (pj_memcmp(send_buf, recv_buf, bufsize) != 0) {
273 status=-67; goto on_error;
274 }
275 if (addrlen != sizeof(pj_sockaddr_in)) {
276 status=-68; goto on_error;
277 }
278 if (addr.sin_family != PJ_AF_INET) {
279 status=-69; goto on_error;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000280 }
281
282
283 recv_pending = 0;
284 }
285
286 if (callback_write_key != NULL) {
287 if (callback_write_size != bufsize) {
288 status=-73; goto on_error;
289 }
290 if (callback_write_key != ckey) {
291 status=-75; goto on_error;
292 }
293 if (callback_write_op != &write_op) {
294 status=-76; goto on_error;
295 }
296
297 send_pending = 0;
298 }
299 }
300
301 // Success
302 status = 0;
303
304on_error:
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000305 if (ssock)
306 pj_sock_close(ssock);
307 if (csock)
308 pj_sock_close(csock);
309 if (ioque != NULL)
310 pj_ioqueue_destroy(ioque);
311 pj_pool_release(pool);
312 return status;
313
314}
315
Benny Prijono8d317a02006-03-22 11:49:19 +0000316
317static void on_read_complete(pj_ioqueue_key_t *key,
318 pj_ioqueue_op_key_t *op_key,
319 pj_ssize_t bytes_read)
320{
321 unsigned *p_packet_cnt = pj_ioqueue_get_user_data(key);
322
323 PJ_UNUSED_ARG(op_key);
324 PJ_UNUSED_ARG(bytes_read);
325
326 (*p_packet_cnt)++;
327}
328
329/*
330 * unregister_test()
331 * Check if callback is still called after socket has been unregistered or
332 * closed.
333 */
334static int unregister_test(void)
335{
336 enum { RPORT = 50000, SPORT = 50001 };
337 pj_pool_t *pool;
338 pj_ioqueue_t *ioqueue;
339 pj_sock_t ssock;
340 pj_sock_t rsock;
341 int addrlen;
342 pj_sockaddr_in addr;
343 pj_ioqueue_key_t *key;
344 pj_ioqueue_op_key_t opkey;
345 pj_ioqueue_callback cb;
346 unsigned packet_cnt;
347 char sendbuf[10], recvbuf[10];
348 pj_ssize_t bytes;
349 pj_time_val timeout;
350 pj_status_t status;
351
352 pool = pj_pool_create(mem, "test", 4000, 4000, NULL);
353 if (!pool) {
354 app_perror("Unable to create pool", PJ_ENOMEM);
355 return -100;
356 }
357
358 status = pj_ioqueue_create(pool, 16, &ioqueue);
359 if (status != PJ_SUCCESS) {
360 app_perror("Error creating ioqueue", status);
361 return -110;
362 }
363
364 /* Create sender socket */
365 status = app_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, SPORT, &ssock);
366 if (status != PJ_SUCCESS) {
367 app_perror("Error initializing socket", status);
368 return -120;
369 }
370
371 /* Create receiver socket. */
372 status = app_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, RPORT, &rsock);
373 if (status != PJ_SUCCESS) {
374 app_perror("Error initializing socket", status);
375 return -130;
376 }
377
378 /* Register rsock to ioqueue. */
379 pj_memset(&cb, 0, sizeof(cb));
380 cb.on_read_complete = &on_read_complete;
381 packet_cnt = 0;
382 status = pj_ioqueue_register_sock(pool, ioqueue, rsock, &packet_cnt,
383 &cb, &key);
384 if (status != PJ_SUCCESS) {
385 app_perror("Error registering to ioqueue", status);
386 return -140;
387 }
388
389 /* Init operation key. */
390 pj_ioqueue_op_key_init(&opkey, sizeof(opkey));
391
392 /* Start reading. */
393 bytes = sizeof(recvbuf);
394 status = pj_ioqueue_recv( key, &opkey, recvbuf, &bytes, 0);
395 if (status != PJ_EPENDING) {
396 app_perror("Expecting PJ_EPENDING, but got this", status);
397 return -150;
398 }
399
400 /* Init destination address. */
401 addrlen = sizeof(addr);
402 status = pj_sock_getsockname(rsock, &addr, &addrlen);
403 if (status != PJ_SUCCESS) {
404 app_perror("getsockname error", status);
405 return -160;
406 }
407
408 /* Override address with 127.0.0.1, since getsockname will return
409 * zero in the address field.
410 */
411 addr.sin_addr = pj_inet_addr2("127.0.0.1");
412
413 /* Init buffer to send */
414 pj_ansi_strcpy(sendbuf, "Hello0123");
415
416 /* Send one packet. */
417 bytes = sizeof(sendbuf);
418 status = pj_sock_sendto(ssock, sendbuf, &bytes, 0,
419 &addr, sizeof(addr));
420
421 if (status != PJ_SUCCESS) {
422 app_perror("sendto error", status);
423 return -170;
424 }
425
426 /* Check if packet is received. */
427 timeout.sec = 1; timeout.msec = 0;
428 pj_ioqueue_poll(ioqueue, &timeout);
429
430 if (packet_cnt != 1) {
431 return -180;
432 }
433
434 /* Just to make sure things are settled.. */
435 pj_thread_sleep(100);
436
437 /* Start reading again. */
438 bytes = sizeof(recvbuf);
439 status = pj_ioqueue_recv( key, &opkey, recvbuf, &bytes, 0);
440 if (status != PJ_EPENDING) {
441 app_perror("Expecting PJ_EPENDING, but got this", status);
442 return -190;
443 }
444
445 /* Reset packet counter */
446 packet_cnt = 0;
447
448 /* Send one packet. */
449 bytes = sizeof(sendbuf);
450 status = pj_sock_sendto(ssock, sendbuf, &bytes, 0,
451 &addr, sizeof(addr));
452
453 if (status != PJ_SUCCESS) {
454 app_perror("sendto error", status);
455 return -200;
456 }
457
458 /* Now unregister and close socket. */
459 pj_ioqueue_unregister(key);
460 pj_sock_close(rsock);
461
462 /* Poll ioqueue. */
463 timeout.sec = 1; timeout.msec = 0;
464 pj_ioqueue_poll(ioqueue, &timeout);
465
466 /* Must NOT receive any packets after socket is closed! */
467 if (packet_cnt > 0) {
468 PJ_LOG(3,(THIS_FILE, "....errror: not expecting to receive packet "
469 "after socket has been closed"));
470 return -210;
471 }
472
473 /* Success */
474 pj_sock_close(ssock);
475 pj_ioqueue_destroy(ioqueue);
476
477 pj_pool_release(pool);
478
479 return 0;
480}
481
482
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000483/*
484 * Testing with many handles.
485 * This will just test registering PJ_IOQUEUE_MAX_HANDLES count
486 * of sockets to the ioqueue.
487 */
488static int many_handles_test(void)
489{
490 enum { MAX = PJ_IOQUEUE_MAX_HANDLES };
491 pj_pool_t *pool;
492 pj_ioqueue_t *ioqueue;
493 pj_sock_t *sock;
494 pj_ioqueue_key_t **key;
495 pj_status_t rc;
496 int count, i;
497
498 PJ_LOG(3,(THIS_FILE,"...testing with so many handles"));
499
500 pool = pj_pool_create(mem, NULL, 4000, 4000, NULL);
501 if (!pool)
502 return PJ_ENOMEM;
503
504 key = pj_pool_alloc(pool, MAX*sizeof(pj_ioqueue_key_t*));
505 sock = pj_pool_alloc(pool, MAX*sizeof(pj_sock_t));
506
507 /* Create IOQueue */
508 rc = pj_ioqueue_create(pool, MAX, &ioqueue);
509 if (rc != PJ_SUCCESS || ioqueue == NULL) {
510 app_perror("...error in pj_ioqueue_create", rc);
511 return -10;
512 }
513
514 /* Register as many sockets. */
515 for (count=0; count<MAX; ++count) {
516 sock[count] = PJ_INVALID_SOCKET;
517 rc = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &sock[count]);
518 if (rc != PJ_SUCCESS || sock[count] == PJ_INVALID_SOCKET) {
519 PJ_LOG(3,(THIS_FILE, "....unable to create %d-th socket, rc=%d",
520 count, rc));
521 break;
522 }
523 key[count] = NULL;
524 rc = pj_ioqueue_register_sock(pool, ioqueue, sock[count],
525 NULL, &test_cb, &key[count]);
526 if (rc != PJ_SUCCESS || key[count] == NULL) {
527 PJ_LOG(3,(THIS_FILE, "....unable to register %d-th socket, rc=%d",
528 count, rc));
529 return -30;
530 }
531 }
532
533 /* Test complete. */
534
535 /* Now deregister and close all handles. */
536
537 for (i=0; i<count; ++i) {
538 rc = pj_ioqueue_unregister(key[i]);
539 if (rc != PJ_SUCCESS) {
540 app_perror("...error in pj_ioqueue_unregister", rc);
541 }
542 rc = pj_sock_close(sock[i]);
543 if (rc != PJ_SUCCESS) {
544 app_perror("...error in pj_sock_close", rc);
545 }
546 }
547
548 rc = pj_ioqueue_destroy(ioqueue);
549 if (rc != PJ_SUCCESS) {
550 app_perror("...error in pj_ioqueue_destroy", rc);
551 }
552
553 pj_pool_release(pool);
554
555 PJ_LOG(3,(THIS_FILE,"....many_handles_test() ok"));
556
557 return 0;
558}
559
560/*
561 * Multi-operation test.
562 */
563
564/*
565 * Benchmarking IOQueue
566 */
567static int bench_test(int bufsize, int inactive_sock_count)
568{
569 pj_sock_t ssock=-1, csock=-1;
570 pj_sockaddr_in addr;
571 pj_pool_t *pool = NULL;
572 pj_sock_t *inactive_sock=NULL;
573 pj_ioqueue_op_key_t *inactive_read_op;
574 char *send_buf, *recv_buf;
575 pj_ioqueue_t *ioque = NULL;
576 pj_ioqueue_key_t *skey, *ckey, *key;
577 pj_timestamp t1, t2, t_elapsed;
578 int rc=0, i;
579 pj_str_t temp;
580 char errbuf[128];
581
582 // Create pool.
583 pool = pj_pool_create(mem, NULL, POOL_SIZE, 4000, NULL);
584
585 // Allocate buffers for send and receive.
586 send_buf = (char*)pj_pool_alloc(pool, bufsize);
587 recv_buf = (char*)pj_pool_alloc(pool, bufsize);
588
589 // Allocate sockets for sending and receiving.
590 rc = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &ssock);
591 if (rc == PJ_SUCCESS) {
592 rc = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &csock);
593 } else
594 csock = PJ_INVALID_SOCKET;
595 if (rc != PJ_SUCCESS) {
596 app_perror("...error: pj_sock_socket()", rc);
597 goto on_error;
598 }
599
600 // Bind server socket.
Benny Prijono37e8d332006-01-20 21:03:36 +0000601 pj_memset(&addr, 0, sizeof(addr));
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000602 addr.sin_family = PJ_AF_INET;
603 addr.sin_port = pj_htons(PORT);
604 if (pj_sock_bind(ssock, &addr, sizeof(addr)))
605 goto on_error;
606
607 pj_assert(inactive_sock_count+2 <= PJ_IOQUEUE_MAX_HANDLES);
608
609 // Create I/O Queue.
610 rc = pj_ioqueue_create(pool, PJ_IOQUEUE_MAX_HANDLES, &ioque);
611 if (rc != PJ_SUCCESS) {
612 app_perror("...error: pj_ioqueue_create()", rc);
613 goto on_error;
614 }
615
616 // Allocate inactive sockets, and bind them to some arbitrary address.
617 // Then register them to the I/O queue, and start a read operation.
618 inactive_sock = (pj_sock_t*)pj_pool_alloc(pool,
619 inactive_sock_count*sizeof(pj_sock_t));
620 inactive_read_op = (pj_ioqueue_op_key_t*)pj_pool_alloc(pool,
621 inactive_sock_count*sizeof(pj_ioqueue_op_key_t));
Benny Prijono37e8d332006-01-20 21:03:36 +0000622 pj_memset(&addr, 0, sizeof(addr));
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000623 addr.sin_family = PJ_AF_INET;
624 for (i=0; i<inactive_sock_count; ++i) {
625 pj_ssize_t bytes;
626
627 rc = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &inactive_sock[i]);
628 if (rc != PJ_SUCCESS || inactive_sock[i] < 0) {
629 app_perror("...error: pj_sock_socket()", rc);
630 goto on_error;
631 }
632 if ((rc=pj_sock_bind(inactive_sock[i], &addr, sizeof(addr))) != 0) {
633 pj_sock_close(inactive_sock[i]);
634 inactive_sock[i] = PJ_INVALID_SOCKET;
635 app_perror("...error: pj_sock_bind()", rc);
636 goto on_error;
637 }
638 rc = pj_ioqueue_register_sock(pool, ioque, inactive_sock[i],
639 NULL, &test_cb, &key);
640 if (rc != PJ_SUCCESS) {
641 pj_sock_close(inactive_sock[i]);
642 inactive_sock[i] = PJ_INVALID_SOCKET;
643 app_perror("...error(1): pj_ioqueue_register_sock()", rc);
644 PJ_LOG(3,(THIS_FILE, "....i=%d", i));
645 goto on_error;
646 }
647 bytes = bufsize;
648 rc = pj_ioqueue_recv(key, &inactive_read_op[i], recv_buf, &bytes, 0);
Benny Prijono37e8d332006-01-20 21:03:36 +0000649 if (rc != PJ_EPENDING) {
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000650 pj_sock_close(inactive_sock[i]);
651 inactive_sock[i] = PJ_INVALID_SOCKET;
652 app_perror("...error: pj_ioqueue_read()", rc);
653 goto on_error;
654 }
655 }
656
657 // Register server and client socket.
658 // We put this after inactivity socket, hopefully this can represent the
659 // worst waiting time.
660 rc = pj_ioqueue_register_sock(pool, ioque, ssock, NULL,
661 &test_cb, &skey);
662 if (rc != PJ_SUCCESS) {
663 app_perror("...error(2): pj_ioqueue_register_sock()", rc);
664 goto on_error;
665 }
666
667 rc = pj_ioqueue_register_sock(pool, ioque, csock, NULL,
668 &test_cb, &ckey);
669 if (rc != PJ_SUCCESS) {
670 app_perror("...error(3): pj_ioqueue_register_sock()", rc);
671 goto on_error;
672 }
673
674 // Set destination address to send the packet.
675 pj_sockaddr_in_init(&addr, pj_cstr(&temp, "127.0.0.1"), PORT);
676
677 // Test loop.
678 t_elapsed.u64 = 0;
679 for (i=0; i<LOOP; ++i) {
680 pj_ssize_t bytes;
681 pj_ioqueue_op_key_t read_op, write_op;
682
683 // Randomize send buffer.
684 pj_create_random_string(send_buf, bufsize);
685
686 // Start reading on the server side.
687 bytes = bufsize;
688 rc = pj_ioqueue_recv(skey, &read_op, recv_buf, &bytes, 0);
Benny Prijono37e8d332006-01-20 21:03:36 +0000689 if (rc != PJ_EPENDING) {
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000690 app_perror("...error: pj_ioqueue_read()", rc);
691 break;
692 }
693
694 // Starts send on the client side.
695 bytes = bufsize;
696 rc = pj_ioqueue_sendto(ckey, &write_op, send_buf, &bytes, 0,
697 &addr, sizeof(addr));
698 if (rc != PJ_SUCCESS && rc != PJ_EPENDING) {
699 app_perror("...error: pj_ioqueue_write()", bytes);
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000700 break;
701 }
702
703 // Begin time.
704 pj_get_timestamp(&t1);
705
706 // Poll the queue until we've got completion event in the server side.
707 callback_read_key = NULL;
708 callback_read_size = 0;
709 do {
710 rc = pj_ioqueue_poll(ioque, NULL);
711 } while (rc >= 0 && callback_read_key != skey);
712
713 // End time.
714 pj_get_timestamp(&t2);
715 t_elapsed.u64 += (t2.u64 - t1.u64);
716
Benny Prijono37e8d332006-01-20 21:03:36 +0000717 if (rc < 0) {
718 app_perror(" error: pj_ioqueue_poll", -rc);
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000719 break;
Benny Prijono37e8d332006-01-20 21:03:36 +0000720 }
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000721
722 // Compare recv buffer with send buffer.
723 if (callback_read_size != bufsize ||
Benny Prijono37e8d332006-01-20 21:03:36 +0000724 pj_memcmp(send_buf, recv_buf, bufsize))
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000725 {
Benny Prijono37e8d332006-01-20 21:03:36 +0000726 rc = -10;
727 PJ_LOG(3,(THIS_FILE, " error: size/buffer mismatch"));
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000728 break;
729 }
730
731 // Poll until all events are exhausted, before we start the next loop.
732 do {
733 pj_time_val timeout = { 0, 10 };
734 rc = pj_ioqueue_poll(ioque, &timeout);
735 } while (rc>0);
736
737 rc = 0;
738 }
739
740 // Print results
741 if (rc == 0) {
742 pj_timestamp tzero;
743 pj_uint32_t usec_delay;
744
745 tzero.u32.hi = tzero.u32.lo = 0;
746 usec_delay = pj_elapsed_usec( &tzero, &t_elapsed);
747
748 PJ_LOG(3, (THIS_FILE, "...%10d %15d % 9d",
749 bufsize, inactive_sock_count, usec_delay));
750
751 } else {
Benny Prijono37e8d332006-01-20 21:03:36 +0000752 PJ_LOG(2, (THIS_FILE, "...ERROR rc=%d (buf:%d, fds:%d)",
753 rc, bufsize, inactive_sock_count+2));
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000754 }
755
756 // Cleaning up.
757 for (i=0; i<inactive_sock_count; ++i)
758 pj_sock_close(inactive_sock[i]);
759 pj_sock_close(ssock);
760 pj_sock_close(csock);
761
762 pj_ioqueue_destroy(ioque);
763 pj_pool_release( pool);
Benny Prijono37e8d332006-01-20 21:03:36 +0000764 return rc;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000765
766on_error:
767 PJ_LOG(1,(THIS_FILE, "...ERROR: %s",
768 pj_strerror(pj_get_netos_error(), errbuf, sizeof(errbuf))));
769 if (ssock)
770 pj_sock_close(ssock);
771 if (csock)
772 pj_sock_close(csock);
773 for (i=0; i<inactive_sock_count && inactive_sock &&
774 inactive_sock[i]!=PJ_INVALID_SOCKET; ++i)
775 {
776 pj_sock_close(inactive_sock[i]);
777 }
778 if (ioque != NULL)
779 pj_ioqueue_destroy(ioque);
780 pj_pool_release( pool);
781 return -1;
782}
783
784int udp_ioqueue_test()
785{
786 int status;
787 int bufsize, sock_count;
788
789 PJ_LOG(3, (THIS_FILE, "...compliance test (%s)", pj_ioqueue_name()));
790 if ((status=compliance_test()) != 0) {
791 return status;
792 }
793 PJ_LOG(3, (THIS_FILE, "....compliance test ok"));
794
Benny Prijono8d317a02006-03-22 11:49:19 +0000795
796 PJ_LOG(3, (THIS_FILE, "...unregister test (%s)", pj_ioqueue_name()));
797 if ((status=unregister_test()) != 0) {
798 return status;
799 }
800 PJ_LOG(3, (THIS_FILE, "....unregister test ok"));
801
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000802 if ((status=many_handles_test()) != 0) {
803 return status;
804 }
805
806 PJ_LOG(4, (THIS_FILE, "...benchmarking different buffer size:"));
807 PJ_LOG(4, (THIS_FILE, "... note: buf=bytes sent, fds=# of fds, "
808 "elapsed=in timer ticks"));
809
810 PJ_LOG(3, (THIS_FILE, "...Benchmarking poll times for %s:", pj_ioqueue_name()));
811 PJ_LOG(3, (THIS_FILE, "...====================================="));
812 PJ_LOG(3, (THIS_FILE, "...Buf.size #inactive-socks Time/poll"));
813 PJ_LOG(3, (THIS_FILE, "... (bytes) (nanosec)"));
814 PJ_LOG(3, (THIS_FILE, "...====================================="));
815
816 for (bufsize=BUF_MIN_SIZE; bufsize <= BUF_MAX_SIZE; bufsize *= 2) {
Benny Prijono37e8d332006-01-20 21:03:36 +0000817 if ((status=bench_test(bufsize, SOCK_INACTIVE_MIN)) != 0)
818 return status;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000819 }
820 bufsize = 512;
821 for (sock_count=SOCK_INACTIVE_MIN+2;
822 sock_count<=SOCK_INACTIVE_MAX+2;
823 sock_count *= 2)
824 {
825 //PJ_LOG(3,(THIS_FILE, "...testing with %d fds", sock_count));
Benny Prijono37e8d332006-01-20 21:03:36 +0000826 if ((status=bench_test(bufsize, sock_count-2)) != 0)
827 return status;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000828 }
829 return 0;
830}
831
832#else
833/* To prevent warning about "translation unit is empty"
834 * when this test is disabled.
835 */
836int dummy_uiq_udp;
837#endif /* INCLUDE_UDP_IOQUEUE_TEST */
838
839