blob: e6f4c0f96f443bd4427eb4a46ba0e1ec56e7cd53 [file] [log] [blame]
Benny Prijono5dcb38d2005-11-21 01:55:47 +00001/* $Id$ */
2/*
Benny Prijonoa771a512007-02-19 01:13:53 +00003 * Copyright (C)2003-2007 Benny Prijono <benny@prijono.org>
Benny Prijono5dcb38d2005-11-21 01:55:47 +00004 *
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
Benny Prijono63ab3562006-07-08 19:46:43 +000043#define LOOP 2
Benny Prijono42c5b9e2006-05-10 19:24:40 +000044///#define LOOP 2
Benny Prijono5dcb38d2005-11-21 01:55:47 +000045#define BUF_MIN_SIZE 32
46#define BUF_MAX_SIZE 2048
47#define SOCK_INACTIVE_MIN (1)
48#define SOCK_INACTIVE_MAX (PJ_IOQUEUE_MAX_HANDLES - 2)
49#define POOL_SIZE (2*BUF_MAX_SIZE + SOCK_INACTIVE_MAX*128 + 2048)
50
51#undef TRACE_
52#define TRACE_(msg) PJ_LOG(3,(THIS_FILE,"....." msg))
53
Benny Prijono42c5b9e2006-05-10 19:24:40 +000054#if 0
55# define TRACE__(args) PJ_LOG(3,args)
56#else
57# define TRACE__(args)
58#endif
59
60
Benny Prijono5dcb38d2005-11-21 01:55:47 +000061static pj_ssize_t callback_read_size,
62 callback_write_size,
63 callback_accept_status,
64 callback_connect_status;
65static pj_ioqueue_key_t *callback_read_key,
66 *callback_write_key,
67 *callback_accept_key,
68 *callback_connect_key;
69static pj_ioqueue_op_key_t *callback_read_op,
70 *callback_write_op,
71 *callback_accept_op;
72
73static void on_ioqueue_read(pj_ioqueue_key_t *key,
74 pj_ioqueue_op_key_t *op_key,
75 pj_ssize_t bytes_read)
76{
77 callback_read_key = key;
78 callback_read_op = op_key;
79 callback_read_size = bytes_read;
Benny Prijono42c5b9e2006-05-10 19:24:40 +000080 TRACE__((THIS_FILE, " callback_read_key = %p, bytes=%d",
81 key, bytes_read));
Benny Prijono5dcb38d2005-11-21 01:55:47 +000082}
83
84static void on_ioqueue_write(pj_ioqueue_key_t *key,
85 pj_ioqueue_op_key_t *op_key,
86 pj_ssize_t bytes_written)
87{
88 callback_write_key = key;
89 callback_write_op = op_key;
90 callback_write_size = bytes_written;
91}
92
93static void on_ioqueue_accept(pj_ioqueue_key_t *key,
94 pj_ioqueue_op_key_t *op_key,
95 pj_sock_t sock, int status)
96{
97 PJ_UNUSED_ARG(sock);
98 callback_accept_key = key;
99 callback_accept_op = op_key;
100 callback_accept_status = status;
101}
102
103static void on_ioqueue_connect(pj_ioqueue_key_t *key, int status)
104{
105 callback_connect_key = key;
106 callback_connect_status = status;
107}
108
109static pj_ioqueue_callback test_cb =
110{
111 &on_ioqueue_read,
112 &on_ioqueue_write,
113 &on_ioqueue_accept,
114 &on_ioqueue_connect,
115};
116
117#ifdef PJ_WIN32
118# define S_ADDR S_un.S_addr
119#else
120# define S_ADDR s_addr
121#endif
122
123/*
124 * compliance_test()
125 * To test that the basic IOQueue functionality works. It will just exchange
126 * data between two sockets.
127 */
128static int compliance_test(void)
129{
130 pj_sock_t ssock=-1, csock=-1;
Benny Prijono37e8d332006-01-20 21:03:36 +0000131 pj_sockaddr_in addr, dst_addr;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000132 int addrlen;
133 pj_pool_t *pool = NULL;
134 char *send_buf, *recv_buf;
135 pj_ioqueue_t *ioque = NULL;
136 pj_ioqueue_key_t *skey, *ckey;
137 pj_ioqueue_op_key_t read_op, write_op;
138 int bufsize = BUF_MIN_SIZE;
139 pj_ssize_t bytes, status = -1;
140 pj_str_t temp;
141 pj_bool_t send_pending, recv_pending;
142 pj_status_t rc;
143
144 pj_set_os_error(PJ_SUCCESS);
145
146 // Create pool.
147 pool = pj_pool_create(mem, NULL, POOL_SIZE, 4000, NULL);
148
149 // Allocate buffers for send and receive.
150 send_buf = (char*)pj_pool_alloc(pool, bufsize);
151 recv_buf = (char*)pj_pool_alloc(pool, bufsize);
152
153 // Allocate sockets for sending and receiving.
154 TRACE_("creating sockets...");
155 rc = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &ssock);
156 if (rc==PJ_SUCCESS)
157 rc = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &csock);
158 else
159 csock = PJ_INVALID_SOCKET;
160 if (rc != PJ_SUCCESS) {
161 app_perror("...ERROR in pj_sock_socket()", rc);
162 status=-1; goto on_error;
163 }
164
165 // Bind server socket.
166 TRACE_("bind socket...");
Benny Prijonoac623b32006-07-03 15:19:31 +0000167 pj_bzero(&addr, sizeof(addr));
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000168 addr.sin_family = PJ_AF_INET;
169 addr.sin_port = pj_htons(PORT);
170 if (pj_sock_bind(ssock, &addr, sizeof(addr))) {
171 status=-10; goto on_error;
172 }
173
174 // Create I/O Queue.
175 TRACE_("create ioqueue...");
176 rc = pj_ioqueue_create(pool, PJ_IOQUEUE_MAX_HANDLES, &ioque);
177 if (rc != PJ_SUCCESS) {
178 status=-20; goto on_error;
179 }
180
181 // Register server and client socket.
182 // We put this after inactivity socket, hopefully this can represent the
183 // worst waiting time.
184 TRACE_("registering first sockets...");
185 rc = pj_ioqueue_register_sock(pool, ioque, ssock, NULL,
186 &test_cb, &skey);
187 if (rc != PJ_SUCCESS) {
188 app_perror("...error(10): ioqueue_register error", rc);
189 status=-25; goto on_error;
190 }
191 TRACE_("registering second sockets...");
192 rc = pj_ioqueue_register_sock( pool, ioque, csock, NULL,
193 &test_cb, &ckey);
194 if (rc != PJ_SUCCESS) {
195 app_perror("...error(11): ioqueue_register error", rc);
196 status=-26; goto on_error;
197 }
198
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000199 // Randomize send_buf.
200 pj_create_random_string(send_buf, bufsize);
201
202 // Register reading from ioqueue.
203 TRACE_("start recvfrom...");
Benny Prijonoac623b32006-07-03 15:19:31 +0000204 pj_bzero(&addr, sizeof(addr));
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000205 addrlen = sizeof(addr);
206 bytes = bufsize;
207 rc = pj_ioqueue_recvfrom(skey, &read_op, recv_buf, &bytes, 0,
208 &addr, &addrlen);
209 if (rc != PJ_SUCCESS && rc != PJ_EPENDING) {
210 app_perror("...error: pj_ioqueue_recvfrom", rc);
211 status=-28; goto on_error;
212 } else if (rc == PJ_EPENDING) {
213 recv_pending = 1;
214 PJ_LOG(3, (THIS_FILE,
215 "......ok: recvfrom returned pending"));
216 } else {
217 PJ_LOG(3, (THIS_FILE,
218 "......error: recvfrom returned immediate ok!"));
219 status=-29; goto on_error;
220 }
221
Benny Prijono37e8d332006-01-20 21:03:36 +0000222 // Set destination address to send the packet.
223 TRACE_("set destination address...");
224 temp = pj_str("127.0.0.1");
225 if ((rc=pj_sockaddr_in_init(&dst_addr, &temp, PORT)) != 0) {
226 app_perror("...error: unable to resolve 127.0.0.1", rc);
227 status=-290; goto on_error;
228 }
229
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000230 // Write must return the number of bytes.
231 TRACE_("start sendto...");
232 bytes = bufsize;
Benny Prijono37e8d332006-01-20 21:03:36 +0000233 rc = pj_ioqueue_sendto(ckey, &write_op, send_buf, &bytes, 0, &dst_addr,
234 sizeof(dst_addr));
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000235 if (rc != PJ_SUCCESS && rc != PJ_EPENDING) {
236 app_perror("...error: pj_ioqueue_sendto", rc);
237 status=-30; goto on_error;
238 } else if (rc == PJ_EPENDING) {
239 send_pending = 1;
240 PJ_LOG(3, (THIS_FILE,
241 "......ok: sendto returned pending"));
242 } else {
243 send_pending = 0;
244 PJ_LOG(3, (THIS_FILE,
245 "......ok: sendto returned immediate success"));
246 }
247
248 // reset callback variables.
249 callback_read_size = callback_write_size = 0;
250 callback_accept_status = callback_connect_status = -2;
251 callback_read_key = callback_write_key =
252 callback_accept_key = callback_connect_key = NULL;
253 callback_read_op = callback_write_op = NULL;
254
255 // Poll if pending.
256 while (send_pending || recv_pending) {
257 int rc;
258 pj_time_val timeout = { 5, 0 };
259
260 TRACE_("poll...");
261 rc = pj_ioqueue_poll(ioque, &timeout);
262
263 if (rc == 0) {
264 PJ_LOG(1,(THIS_FILE, "...ERROR: timed out..."));
265 status=-45; goto on_error;
266 } else if (rc < 0) {
Benny Prijono42c5b9e2006-05-10 19:24:40 +0000267 app_perror("...ERROR in ioqueue_poll()", -rc);
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000268 status=-50; goto on_error;
269 }
270
271 if (callback_read_key != NULL) {
272 if (callback_read_size != bufsize) {
273 status=-61; goto on_error;
274 }
275 if (callback_read_key != skey) {
276 status=-65; goto on_error;
277 }
278 if (callback_read_op != &read_op) {
279 status=-66; goto on_error;
280 }
281
Benny Prijono37e8d332006-01-20 21:03:36 +0000282 if (pj_memcmp(send_buf, recv_buf, bufsize) != 0) {
283 status=-67; goto on_error;
284 }
285 if (addrlen != sizeof(pj_sockaddr_in)) {
286 status=-68; goto on_error;
287 }
288 if (addr.sin_family != PJ_AF_INET) {
289 status=-69; goto on_error;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000290 }
291
292
293 recv_pending = 0;
294 }
295
296 if (callback_write_key != NULL) {
297 if (callback_write_size != bufsize) {
298 status=-73; goto on_error;
299 }
300 if (callback_write_key != ckey) {
301 status=-75; goto on_error;
302 }
303 if (callback_write_op != &write_op) {
304 status=-76; goto on_error;
305 }
306
307 send_pending = 0;
308 }
309 }
310
311 // Success
312 status = 0;
313
314on_error:
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000315 if (ssock)
316 pj_sock_close(ssock);
317 if (csock)
318 pj_sock_close(csock);
319 if (ioque != NULL)
320 pj_ioqueue_destroy(ioque);
321 pj_pool_release(pool);
322 return status;
323
324}
325
Benny Prijono8d317a02006-03-22 11:49:19 +0000326
327static void on_read_complete(pj_ioqueue_key_t *key,
328 pj_ioqueue_op_key_t *op_key,
329 pj_ssize_t bytes_read)
330{
Benny Prijonof260e462007-04-30 21:03:32 +0000331 unsigned *p_packet_cnt = (unsigned*) pj_ioqueue_get_user_data(key);
Benny Prijono8d317a02006-03-22 11:49:19 +0000332
333 PJ_UNUSED_ARG(op_key);
334 PJ_UNUSED_ARG(bytes_read);
335
336 (*p_packet_cnt)++;
337}
338
339/*
340 * unregister_test()
341 * Check if callback is still called after socket has been unregistered or
342 * closed.
343 */
344static int unregister_test(void)
345{
346 enum { RPORT = 50000, SPORT = 50001 };
347 pj_pool_t *pool;
348 pj_ioqueue_t *ioqueue;
349 pj_sock_t ssock;
350 pj_sock_t rsock;
351 int addrlen;
352 pj_sockaddr_in addr;
353 pj_ioqueue_key_t *key;
354 pj_ioqueue_op_key_t opkey;
355 pj_ioqueue_callback cb;
356 unsigned packet_cnt;
357 char sendbuf[10], recvbuf[10];
358 pj_ssize_t bytes;
359 pj_time_val timeout;
360 pj_status_t status;
361
362 pool = pj_pool_create(mem, "test", 4000, 4000, NULL);
363 if (!pool) {
364 app_perror("Unable to create pool", PJ_ENOMEM);
365 return -100;
366 }
367
368 status = pj_ioqueue_create(pool, 16, &ioqueue);
369 if (status != PJ_SUCCESS) {
370 app_perror("Error creating ioqueue", status);
371 return -110;
372 }
373
374 /* Create sender socket */
375 status = app_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, SPORT, &ssock);
376 if (status != PJ_SUCCESS) {
377 app_perror("Error initializing socket", status);
378 return -120;
379 }
380
381 /* Create receiver socket. */
382 status = app_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, RPORT, &rsock);
383 if (status != PJ_SUCCESS) {
384 app_perror("Error initializing socket", status);
385 return -130;
386 }
387
388 /* Register rsock to ioqueue. */
Benny Prijonoac623b32006-07-03 15:19:31 +0000389 pj_bzero(&cb, sizeof(cb));
Benny Prijono8d317a02006-03-22 11:49:19 +0000390 cb.on_read_complete = &on_read_complete;
391 packet_cnt = 0;
392 status = pj_ioqueue_register_sock(pool, ioqueue, rsock, &packet_cnt,
393 &cb, &key);
394 if (status != PJ_SUCCESS) {
395 app_perror("Error registering to ioqueue", status);
396 return -140;
397 }
398
399 /* Init operation key. */
400 pj_ioqueue_op_key_init(&opkey, sizeof(opkey));
401
402 /* Start reading. */
403 bytes = sizeof(recvbuf);
404 status = pj_ioqueue_recv( key, &opkey, recvbuf, &bytes, 0);
405 if (status != PJ_EPENDING) {
406 app_perror("Expecting PJ_EPENDING, but got this", status);
407 return -150;
408 }
409
410 /* Init destination address. */
411 addrlen = sizeof(addr);
412 status = pj_sock_getsockname(rsock, &addr, &addrlen);
413 if (status != PJ_SUCCESS) {
414 app_perror("getsockname error", status);
415 return -160;
416 }
417
418 /* Override address with 127.0.0.1, since getsockname will return
419 * zero in the address field.
420 */
421 addr.sin_addr = pj_inet_addr2("127.0.0.1");
422
423 /* Init buffer to send */
424 pj_ansi_strcpy(sendbuf, "Hello0123");
425
426 /* Send one packet. */
427 bytes = sizeof(sendbuf);
428 status = pj_sock_sendto(ssock, sendbuf, &bytes, 0,
429 &addr, sizeof(addr));
430
431 if (status != PJ_SUCCESS) {
432 app_perror("sendto error", status);
433 return -170;
434 }
435
436 /* Check if packet is received. */
437 timeout.sec = 1; timeout.msec = 0;
438 pj_ioqueue_poll(ioqueue, &timeout);
439
440 if (packet_cnt != 1) {
441 return -180;
442 }
443
444 /* Just to make sure things are settled.. */
445 pj_thread_sleep(100);
446
447 /* Start reading again. */
448 bytes = sizeof(recvbuf);
449 status = pj_ioqueue_recv( key, &opkey, recvbuf, &bytes, 0);
450 if (status != PJ_EPENDING) {
451 app_perror("Expecting PJ_EPENDING, but got this", status);
452 return -190;
453 }
454
455 /* Reset packet counter */
456 packet_cnt = 0;
457
458 /* Send one packet. */
459 bytes = sizeof(sendbuf);
460 status = pj_sock_sendto(ssock, sendbuf, &bytes, 0,
461 &addr, sizeof(addr));
462
463 if (status != PJ_SUCCESS) {
464 app_perror("sendto error", status);
465 return -200;
466 }
467
468 /* Now unregister and close socket. */
469 pj_ioqueue_unregister(key);
Benny Prijono8d317a02006-03-22 11:49:19 +0000470
471 /* Poll ioqueue. */
472 timeout.sec = 1; timeout.msec = 0;
473 pj_ioqueue_poll(ioqueue, &timeout);
474
475 /* Must NOT receive any packets after socket is closed! */
476 if (packet_cnt > 0) {
477 PJ_LOG(3,(THIS_FILE, "....errror: not expecting to receive packet "
478 "after socket has been closed"));
479 return -210;
480 }
481
482 /* Success */
483 pj_sock_close(ssock);
484 pj_ioqueue_destroy(ioqueue);
485
486 pj_pool_release(pool);
487
488 return 0;
489}
490
491
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000492/*
493 * Testing with many handles.
494 * This will just test registering PJ_IOQUEUE_MAX_HANDLES count
495 * of sockets to the ioqueue.
496 */
497static int many_handles_test(void)
498{
499 enum { MAX = PJ_IOQUEUE_MAX_HANDLES };
500 pj_pool_t *pool;
501 pj_ioqueue_t *ioqueue;
502 pj_sock_t *sock;
503 pj_ioqueue_key_t **key;
504 pj_status_t rc;
Benny Prijono42c5b9e2006-05-10 19:24:40 +0000505 int count, i; /* must be signed */
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000506
507 PJ_LOG(3,(THIS_FILE,"...testing with so many handles"));
508
509 pool = pj_pool_create(mem, NULL, 4000, 4000, NULL);
510 if (!pool)
511 return PJ_ENOMEM;
512
Benny Prijonof260e462007-04-30 21:03:32 +0000513 key = (pj_ioqueue_key_t**)
514 pj_pool_alloc(pool, MAX*sizeof(pj_ioqueue_key_t*));
515 sock = (pj_sock_t*) pj_pool_alloc(pool, MAX*sizeof(pj_sock_t));
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000516
517 /* Create IOQueue */
518 rc = pj_ioqueue_create(pool, MAX, &ioqueue);
519 if (rc != PJ_SUCCESS || ioqueue == NULL) {
520 app_perror("...error in pj_ioqueue_create", rc);
521 return -10;
522 }
523
524 /* Register as many sockets. */
525 for (count=0; count<MAX; ++count) {
526 sock[count] = PJ_INVALID_SOCKET;
527 rc = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &sock[count]);
528 if (rc != PJ_SUCCESS || sock[count] == PJ_INVALID_SOCKET) {
529 PJ_LOG(3,(THIS_FILE, "....unable to create %d-th socket, rc=%d",
530 count, rc));
531 break;
532 }
533 key[count] = NULL;
534 rc = pj_ioqueue_register_sock(pool, ioqueue, sock[count],
535 NULL, &test_cb, &key[count]);
536 if (rc != PJ_SUCCESS || key[count] == NULL) {
537 PJ_LOG(3,(THIS_FILE, "....unable to register %d-th socket, rc=%d",
538 count, rc));
539 return -30;
540 }
541 }
542
543 /* Test complete. */
544
545 /* Now deregister and close all handles. */
546
Benny Prijono42c5b9e2006-05-10 19:24:40 +0000547 /* NOTE for RTEMS:
548 * It seems that the order of close(sock) is pretty important here.
549 * If we close the sockets with the same order as when they were created,
550 * RTEMS doesn't seem to reuse the sockets, thus next socket created
551 * will have descriptor higher than the last socket created.
552 * If we close the sockets in the reverse order, then the descriptor will
553 * get reused.
554 * This used to cause problem with select ioqueue, since the ioqueue
555 * always gives FD_SETSIZE for the first select() argument. This ioqueue
556 * behavior can be changed with setting PJ_SELECT_NEEDS_NFDS macro.
557 */
558 for (i=count-1; i>=0; --i) {
559 ///for (i=0; i<count; ++i) {
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000560 rc = pj_ioqueue_unregister(key[i]);
561 if (rc != PJ_SUCCESS) {
562 app_perror("...error in pj_ioqueue_unregister", rc);
563 }
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000564 }
565
566 rc = pj_ioqueue_destroy(ioqueue);
567 if (rc != PJ_SUCCESS) {
568 app_perror("...error in pj_ioqueue_destroy", rc);
569 }
570
571 pj_pool_release(pool);
572
573 PJ_LOG(3,(THIS_FILE,"....many_handles_test() ok"));
574
575 return 0;
576}
577
578/*
579 * Multi-operation test.
580 */
581
582/*
583 * Benchmarking IOQueue
584 */
585static int bench_test(int bufsize, int inactive_sock_count)
586{
587 pj_sock_t ssock=-1, csock=-1;
588 pj_sockaddr_in addr;
589 pj_pool_t *pool = NULL;
590 pj_sock_t *inactive_sock=NULL;
591 pj_ioqueue_op_key_t *inactive_read_op;
592 char *send_buf, *recv_buf;
593 pj_ioqueue_t *ioque = NULL;
594 pj_ioqueue_key_t *skey, *ckey, *key;
595 pj_timestamp t1, t2, t_elapsed;
Benny Prijono42c5b9e2006-05-10 19:24:40 +0000596 int rc=0, i; /* i must be signed */
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000597 pj_str_t temp;
Benny Prijono42c5b9e2006-05-10 19:24:40 +0000598 char errbuf[PJ_ERR_MSG_SIZE];
599
600 TRACE__((THIS_FILE, " bench test %d", inactive_sock_count));
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000601
602 // Create pool.
603 pool = pj_pool_create(mem, NULL, POOL_SIZE, 4000, NULL);
604
605 // Allocate buffers for send and receive.
606 send_buf = (char*)pj_pool_alloc(pool, bufsize);
607 recv_buf = (char*)pj_pool_alloc(pool, bufsize);
608
609 // Allocate sockets for sending and receiving.
610 rc = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &ssock);
611 if (rc == PJ_SUCCESS) {
612 rc = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &csock);
613 } else
614 csock = PJ_INVALID_SOCKET;
615 if (rc != PJ_SUCCESS) {
616 app_perror("...error: pj_sock_socket()", rc);
617 goto on_error;
618 }
619
620 // Bind server socket.
Benny Prijonoac623b32006-07-03 15:19:31 +0000621 pj_bzero(&addr, sizeof(addr));
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000622 addr.sin_family = PJ_AF_INET;
623 addr.sin_port = pj_htons(PORT);
624 if (pj_sock_bind(ssock, &addr, sizeof(addr)))
625 goto on_error;
626
627 pj_assert(inactive_sock_count+2 <= PJ_IOQUEUE_MAX_HANDLES);
628
629 // Create I/O Queue.
630 rc = pj_ioqueue_create(pool, PJ_IOQUEUE_MAX_HANDLES, &ioque);
631 if (rc != PJ_SUCCESS) {
632 app_perror("...error: pj_ioqueue_create()", rc);
633 goto on_error;
634 }
635
636 // Allocate inactive sockets, and bind them to some arbitrary address.
637 // Then register them to the I/O queue, and start a read operation.
638 inactive_sock = (pj_sock_t*)pj_pool_alloc(pool,
639 inactive_sock_count*sizeof(pj_sock_t));
640 inactive_read_op = (pj_ioqueue_op_key_t*)pj_pool_alloc(pool,
641 inactive_sock_count*sizeof(pj_ioqueue_op_key_t));
Benny Prijonoac623b32006-07-03 15:19:31 +0000642 pj_bzero(&addr, sizeof(addr));
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000643 addr.sin_family = PJ_AF_INET;
644 for (i=0; i<inactive_sock_count; ++i) {
645 pj_ssize_t bytes;
646
647 rc = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &inactive_sock[i]);
648 if (rc != PJ_SUCCESS || inactive_sock[i] < 0) {
649 app_perror("...error: pj_sock_socket()", rc);
650 goto on_error;
651 }
652 if ((rc=pj_sock_bind(inactive_sock[i], &addr, sizeof(addr))) != 0) {
653 pj_sock_close(inactive_sock[i]);
654 inactive_sock[i] = PJ_INVALID_SOCKET;
655 app_perror("...error: pj_sock_bind()", rc);
656 goto on_error;
657 }
658 rc = pj_ioqueue_register_sock(pool, ioque, inactive_sock[i],
659 NULL, &test_cb, &key);
660 if (rc != PJ_SUCCESS) {
661 pj_sock_close(inactive_sock[i]);
662 inactive_sock[i] = PJ_INVALID_SOCKET;
663 app_perror("...error(1): pj_ioqueue_register_sock()", rc);
664 PJ_LOG(3,(THIS_FILE, "....i=%d", i));
665 goto on_error;
666 }
667 bytes = bufsize;
668 rc = pj_ioqueue_recv(key, &inactive_read_op[i], recv_buf, &bytes, 0);
Benny Prijono37e8d332006-01-20 21:03:36 +0000669 if (rc != PJ_EPENDING) {
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000670 pj_sock_close(inactive_sock[i]);
671 inactive_sock[i] = PJ_INVALID_SOCKET;
672 app_perror("...error: pj_ioqueue_read()", rc);
673 goto on_error;
674 }
675 }
676
677 // Register server and client socket.
678 // We put this after inactivity socket, hopefully this can represent the
679 // worst waiting time.
680 rc = pj_ioqueue_register_sock(pool, ioque, ssock, NULL,
681 &test_cb, &skey);
682 if (rc != PJ_SUCCESS) {
683 app_perror("...error(2): pj_ioqueue_register_sock()", rc);
684 goto on_error;
685 }
686
687 rc = pj_ioqueue_register_sock(pool, ioque, csock, NULL,
688 &test_cb, &ckey);
689 if (rc != PJ_SUCCESS) {
690 app_perror("...error(3): pj_ioqueue_register_sock()", rc);
691 goto on_error;
692 }
693
694 // Set destination address to send the packet.
695 pj_sockaddr_in_init(&addr, pj_cstr(&temp, "127.0.0.1"), PORT);
696
697 // Test loop.
698 t_elapsed.u64 = 0;
699 for (i=0; i<LOOP; ++i) {
700 pj_ssize_t bytes;
701 pj_ioqueue_op_key_t read_op, write_op;
702
703 // Randomize send buffer.
704 pj_create_random_string(send_buf, bufsize);
705
706 // Start reading on the server side.
707 bytes = bufsize;
708 rc = pj_ioqueue_recv(skey, &read_op, recv_buf, &bytes, 0);
Benny Prijono37e8d332006-01-20 21:03:36 +0000709 if (rc != PJ_EPENDING) {
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000710 app_perror("...error: pj_ioqueue_read()", rc);
711 break;
712 }
713
714 // Starts send on the client side.
715 bytes = bufsize;
716 rc = pj_ioqueue_sendto(ckey, &write_op, send_buf, &bytes, 0,
717 &addr, sizeof(addr));
718 if (rc != PJ_SUCCESS && rc != PJ_EPENDING) {
Benny Prijono42c5b9e2006-05-10 19:24:40 +0000719 app_perror("...error: pj_ioqueue_write()", rc);
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000720 break;
721 }
Benny Prijono42c5b9e2006-05-10 19:24:40 +0000722 if (rc == PJ_SUCCESS) {
723 if (bytes < 0) {
724 app_perror("...error: pj_ioqueue_sendto()", -bytes);
725 break;
726 }
727 }
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000728
729 // Begin time.
730 pj_get_timestamp(&t1);
731
732 // Poll the queue until we've got completion event in the server side.
733 callback_read_key = NULL;
734 callback_read_size = 0;
Benny Prijono42c5b9e2006-05-10 19:24:40 +0000735 TRACE__((THIS_FILE, " waiting for key = %p", skey));
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000736 do {
Benny Prijono42c5b9e2006-05-10 19:24:40 +0000737 pj_time_val timeout = { 1, 0 };
738 rc = pj_ioqueue_poll(ioque, &timeout);
739 TRACE__((THIS_FILE, " poll rc=%d", rc));
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000740 } while (rc >= 0 && callback_read_key != skey);
741
742 // End time.
743 pj_get_timestamp(&t2);
744 t_elapsed.u64 += (t2.u64 - t1.u64);
745
Benny Prijono37e8d332006-01-20 21:03:36 +0000746 if (rc < 0) {
747 app_perror(" error: pj_ioqueue_poll", -rc);
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000748 break;
Benny Prijono37e8d332006-01-20 21:03:36 +0000749 }
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000750
751 // Compare recv buffer with send buffer.
752 if (callback_read_size != bufsize ||
Benny Prijono37e8d332006-01-20 21:03:36 +0000753 pj_memcmp(send_buf, recv_buf, bufsize))
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000754 {
Benny Prijono37e8d332006-01-20 21:03:36 +0000755 rc = -10;
756 PJ_LOG(3,(THIS_FILE, " error: size/buffer mismatch"));
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000757 break;
758 }
759
760 // Poll until all events are exhausted, before we start the next loop.
761 do {
762 pj_time_val timeout = { 0, 10 };
763 rc = pj_ioqueue_poll(ioque, &timeout);
764 } while (rc>0);
765
766 rc = 0;
767 }
768
769 // Print results
770 if (rc == 0) {
771 pj_timestamp tzero;
772 pj_uint32_t usec_delay;
773
774 tzero.u32.hi = tzero.u32.lo = 0;
775 usec_delay = pj_elapsed_usec( &tzero, &t_elapsed);
776
777 PJ_LOG(3, (THIS_FILE, "...%10d %15d % 9d",
778 bufsize, inactive_sock_count, usec_delay));
779
780 } else {
Benny Prijono37e8d332006-01-20 21:03:36 +0000781 PJ_LOG(2, (THIS_FILE, "...ERROR rc=%d (buf:%d, fds:%d)",
782 rc, bufsize, inactive_sock_count+2));
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000783 }
784
785 // Cleaning up.
Benny Prijono42c5b9e2006-05-10 19:24:40 +0000786 for (i=inactive_sock_count-1; i>=0; --i) {
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000787 pj_sock_close(inactive_sock[i]);
Benny Prijono42c5b9e2006-05-10 19:24:40 +0000788 }
789
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000790 pj_sock_close(ssock);
791 pj_sock_close(csock);
792
Benny Prijono42c5b9e2006-05-10 19:24:40 +0000793
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000794 pj_ioqueue_destroy(ioque);
795 pj_pool_release( pool);
Benny Prijono37e8d332006-01-20 21:03:36 +0000796 return rc;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000797
798on_error:
799 PJ_LOG(1,(THIS_FILE, "...ERROR: %s",
800 pj_strerror(pj_get_netos_error(), errbuf, sizeof(errbuf))));
801 if (ssock)
802 pj_sock_close(ssock);
803 if (csock)
804 pj_sock_close(csock);
805 for (i=0; i<inactive_sock_count && inactive_sock &&
806 inactive_sock[i]!=PJ_INVALID_SOCKET; ++i)
807 {
808 pj_sock_close(inactive_sock[i]);
809 }
810 if (ioque != NULL)
811 pj_ioqueue_destroy(ioque);
812 pj_pool_release( pool);
813 return -1;
814}
815
816int udp_ioqueue_test()
817{
818 int status;
819 int bufsize, sock_count;
820
Benny Prijono63ab3562006-07-08 19:46:43 +0000821 //goto pass1;
Benny Prijonofe9c9b62006-07-06 20:43:07 +0000822
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000823 PJ_LOG(3, (THIS_FILE, "...compliance test (%s)", pj_ioqueue_name()));
824 if ((status=compliance_test()) != 0) {
825 return status;
826 }
827 PJ_LOG(3, (THIS_FILE, "....compliance test ok"));
828
Benny Prijono8d317a02006-03-22 11:49:19 +0000829
830 PJ_LOG(3, (THIS_FILE, "...unregister test (%s)", pj_ioqueue_name()));
831 if ((status=unregister_test()) != 0) {
832 return status;
833 }
834 PJ_LOG(3, (THIS_FILE, "....unregister test ok"));
835
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000836 if ((status=many_handles_test()) != 0) {
837 return status;
838 }
839
Benny Prijono63ab3562006-07-08 19:46:43 +0000840 //return 0;
841
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000842 PJ_LOG(4, (THIS_FILE, "...benchmarking different buffer size:"));
843 PJ_LOG(4, (THIS_FILE, "... note: buf=bytes sent, fds=# of fds, "
844 "elapsed=in timer ticks"));
845
Benny Prijono5fb99e52007-01-23 04:17:56 +0000846//pass1:
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000847 PJ_LOG(3, (THIS_FILE, "...Benchmarking poll times for %s:", pj_ioqueue_name()));
848 PJ_LOG(3, (THIS_FILE, "...====================================="));
849 PJ_LOG(3, (THIS_FILE, "...Buf.size #inactive-socks Time/poll"));
850 PJ_LOG(3, (THIS_FILE, "... (bytes) (nanosec)"));
851 PJ_LOG(3, (THIS_FILE, "...====================================="));
852
Benny Prijono63ab3562006-07-08 19:46:43 +0000853 //goto pass2;
Benny Prijonofe9c9b62006-07-06 20:43:07 +0000854
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000855 for (bufsize=BUF_MIN_SIZE; bufsize <= BUF_MAX_SIZE; bufsize *= 2) {
Benny Prijono37e8d332006-01-20 21:03:36 +0000856 if ((status=bench_test(bufsize, SOCK_INACTIVE_MIN)) != 0)
857 return status;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000858 }
Benny Prijono5fb99e52007-01-23 04:17:56 +0000859//pass2:
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000860 bufsize = 512;
861 for (sock_count=SOCK_INACTIVE_MIN+2;
862 sock_count<=SOCK_INACTIVE_MAX+2;
863 sock_count *= 2)
864 {
Benny Prijono63ab3562006-07-08 19:46:43 +0000865 //PJ_LOG(3,(THIS_FILE, "...testing with %d fds", sock_count));
Benny Prijono37e8d332006-01-20 21:03:36 +0000866 if ((status=bench_test(bufsize, sock_count-2)) != 0)
867 return status;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000868 }
869 return 0;
870}
871
872#else
873/* To prevent warning about "translation unit is empty"
874 * when this test is disabled.
875 */
876int dummy_uiq_udp;
877#endif /* INCLUDE_UDP_IOQUEUE_TEST */
878
879