blob: 8e8b6d1fe4ada861ff32f6e096243a7d343fbb3d [file] [log] [blame]
Benny Prijonoe7224612005-11-13 19:40:44 +00001/* $Id$
2 */
3/*
4 * PJLIB - PJ Foundation Library
5 * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>
6 *
7 * Author:
8 * Benny Prijono <bennylp@bulukucing.org>
9 *
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
14 *
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
19 *
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 */
24#include "test.h"
25
26
27/**
28 * \page page_pjlib_ioqueue_udp_test Test: I/O Queue (UDP)
29 *
30 * This file provides implementation to test the
31 * functionality of the I/O queue when UDP socket is used.
32 *
33 *
34 * This file is <b>pjlib-test/ioq_udp.c</b>
35 *
36 * \include pjlib-test/ioq_udp.c
37 */
38
39
40#if INCLUDE_UDP_IOQUEUE_TEST
41
42#include <pjlib.h>
43
44#include <pj/compat/socket.h>
45
46#define THIS_FILE "test_udp"
47#define PORT 51233
48#define LOOP 100
49#define BUF_MIN_SIZE 32
50#define BUF_MAX_SIZE 2048
51#define SOCK_INACTIVE_MIN (1)
52#define SOCK_INACTIVE_MAX (PJ_IOQUEUE_MAX_HANDLES - 2)
53#define POOL_SIZE (2*BUF_MAX_SIZE + SOCK_INACTIVE_MAX*128 + 2048)
54
55#undef TRACE_
56#define TRACE_(msg) PJ_LOG(3,(THIS_FILE,"....." msg))
57
58static pj_ssize_t callback_read_size,
59 callback_write_size,
60 callback_accept_status,
61 callback_connect_status;
62static pj_ioqueue_key_t *callback_read_key,
63 *callback_write_key,
64 *callback_accept_key,
65 *callback_connect_key;
66static pj_ioqueue_op_key_t *callback_read_op,
67 *callback_write_op,
68 *callback_accept_op;
69
70static void on_ioqueue_read(pj_ioqueue_key_t *key,
71 pj_ioqueue_op_key_t *op_key,
72 pj_ssize_t bytes_read)
73{
74 callback_read_key = key;
75 callback_read_op = op_key;
76 callback_read_size = bytes_read;
77}
78
79static void on_ioqueue_write(pj_ioqueue_key_t *key,
80 pj_ioqueue_op_key_t *op_key,
81 pj_ssize_t bytes_written)
82{
83 callback_write_key = key;
84 callback_write_op = op_key;
85 callback_write_size = bytes_written;
86}
87
88static void on_ioqueue_accept(pj_ioqueue_key_t *key,
89 pj_ioqueue_op_key_t *op_key,
90 pj_sock_t sock, int status)
91{
92 PJ_UNUSED_ARG(sock);
93 callback_accept_key = key;
94 callback_accept_op = op_key;
95 callback_accept_status = status;
96}
97
98static void on_ioqueue_connect(pj_ioqueue_key_t *key, int status)
99{
100 callback_connect_key = key;
101 callback_connect_status = status;
102}
103
104static pj_ioqueue_callback test_cb =
105{
106 &on_ioqueue_read,
107 &on_ioqueue_write,
108 &on_ioqueue_accept,
109 &on_ioqueue_connect,
110};
111
112#ifdef PJ_WIN32
113# define S_ADDR S_un.S_addr
114#else
115# define S_ADDR s_addr
116#endif
117
118/*
119 * compliance_test()
120 * To test that the basic IOQueue functionality works. It will just exchange
121 * data between two sockets.
122 */
123static int compliance_test(void)
124{
125 pj_sock_t ssock=-1, csock=-1;
126 pj_sockaddr_in addr;
127 int addrlen;
128 pj_pool_t *pool = NULL;
129 char *send_buf, *recv_buf;
130 pj_ioqueue_t *ioque = NULL;
131 pj_ioqueue_key_t *skey, *ckey;
132 pj_ioqueue_op_key_t read_op, write_op;
133 int bufsize = BUF_MIN_SIZE;
134 pj_ssize_t bytes, status = -1;
135 pj_str_t temp;
136 pj_bool_t send_pending, recv_pending;
137 pj_status_t rc;
138
139 pj_set_os_error(PJ_SUCCESS);
140
141 // Create pool.
142 pool = pj_pool_create(mem, NULL, POOL_SIZE, 4000, NULL);
143
144 // Allocate buffers for send and receive.
145 send_buf = (char*)pj_pool_alloc(pool, bufsize);
146 recv_buf = (char*)pj_pool_alloc(pool, bufsize);
147
148 // Allocate sockets for sending and receiving.
149 TRACE_("creating sockets...");
150 rc = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &ssock);
151 if (rc==PJ_SUCCESS)
152 rc = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &csock);
153 else
154 csock = PJ_INVALID_SOCKET;
155 if (rc != PJ_SUCCESS) {
156 app_perror("...ERROR in pj_sock_socket()", rc);
157 status=-1; goto on_error;
158 }
159
160 // Bind server socket.
161 TRACE_("bind socket...");
162 memset(&addr, 0, sizeof(addr));
163 addr.sin_family = PJ_AF_INET;
164 addr.sin_port = pj_htons(PORT);
165 if (pj_sock_bind(ssock, &addr, sizeof(addr))) {
166 status=-10; goto on_error;
167 }
168
169 // Create I/O Queue.
170 TRACE_("create ioqueue...");
171 rc = pj_ioqueue_create(pool, PJ_IOQUEUE_MAX_HANDLES, &ioque);
172 if (rc != PJ_SUCCESS) {
173 status=-20; goto on_error;
174 }
175
176 // Register server and client socket.
177 // We put this after inactivity socket, hopefully this can represent the
178 // worst waiting time.
179 TRACE_("registering first sockets...");
180 rc = pj_ioqueue_register_sock(pool, ioque, ssock, NULL,
181 &test_cb, &skey);
182 if (rc != PJ_SUCCESS) {
183 app_perror("...error(10): ioqueue_register error", rc);
184 status=-25; goto on_error;
185 }
186 TRACE_("registering second sockets...");
187 rc = pj_ioqueue_register_sock( pool, ioque, csock, NULL,
188 &test_cb, &ckey);
189 if (rc != PJ_SUCCESS) {
190 app_perror("...error(11): ioqueue_register error", rc);
191 status=-26; goto on_error;
192 }
193
194 // Set destination address to send the packet.
195 TRACE_("set destination address...");
196 temp = pj_str("127.0.0.1");
197 if ((rc=pj_sockaddr_in_init(&addr, &temp, PORT)) != 0) {
198 app_perror("...error: unable to resolve 127.0.0.1", rc);
199 status=-26; goto on_error;
200 }
201
202 // Randomize send_buf.
203 pj_create_random_string(send_buf, bufsize);
204
205 // Register reading from ioqueue.
206 TRACE_("start recvfrom...");
207 addrlen = sizeof(addr);
208 bytes = bufsize;
209 rc = pj_ioqueue_recvfrom(skey, &read_op, recv_buf, &bytes, 0,
210 &addr, &addrlen);
211 if (rc != PJ_SUCCESS && rc != PJ_EPENDING) {
212 app_perror("...error: pj_ioqueue_recvfrom", rc);
213 status=-28; goto on_error;
214 } else if (rc == PJ_EPENDING) {
215 recv_pending = 1;
216 PJ_LOG(3, (THIS_FILE,
217 "......ok: recvfrom returned pending"));
218 } else {
219 PJ_LOG(3, (THIS_FILE,
220 "......error: recvfrom returned immediate ok!"));
221 status=-29; goto on_error;
222 }
223
224 // Write must return the number of bytes.
225 TRACE_("start sendto...");
226 bytes = bufsize;
227 rc = pj_ioqueue_sendto(ckey, &write_op, send_buf, &bytes, 0, &addr,
228 sizeof(addr));
229 if (rc != PJ_SUCCESS && rc != PJ_EPENDING) {
230 app_perror("...error: pj_ioqueue_sendto", rc);
231 status=-30; goto on_error;
232 } else if (rc == PJ_EPENDING) {
233 send_pending = 1;
234 PJ_LOG(3, (THIS_FILE,
235 "......ok: sendto returned pending"));
236 } else {
237 send_pending = 0;
238 PJ_LOG(3, (THIS_FILE,
239 "......ok: sendto returned immediate success"));
240 }
241
242 // reset callback variables.
243 callback_read_size = callback_write_size = 0;
244 callback_accept_status = callback_connect_status = -2;
245 callback_read_key = callback_write_key =
246 callback_accept_key = callback_connect_key = NULL;
247 callback_read_op = callback_write_op = NULL;
248
249 // Poll if pending.
250 while (send_pending || recv_pending) {
251 int rc;
252 pj_time_val timeout = { 5, 0 };
253
254 TRACE_("poll...");
255 rc = pj_ioqueue_poll(ioque, &timeout);
256
257 if (rc == 0) {
258 PJ_LOG(1,(THIS_FILE, "...ERROR: timed out..."));
259 status=-45; goto on_error;
260 } else if (rc < 0) {
261 app_perror("...ERROR in ioqueue_poll()", rc);
262 status=-50; goto on_error;
263 }
264
265 if (callback_read_key != NULL) {
266 if (callback_read_size != bufsize) {
267 status=-61; goto on_error;
268 }
269 if (callback_read_key != skey) {
270 status=-65; goto on_error;
271 }
272 if (callback_read_op != &read_op) {
273 status=-66; goto on_error;
274 }
275
276 if (memcmp(send_buf, recv_buf, bufsize) != 0) {
277 status=-70; goto on_error;
278 }
279
280
281 recv_pending = 0;
282 }
283
284 if (callback_write_key != NULL) {
285 if (callback_write_size != bufsize) {
286 status=-73; goto on_error;
287 }
288 if (callback_write_key != ckey) {
289 status=-75; goto on_error;
290 }
291 if (callback_write_op != &write_op) {
292 status=-76; goto on_error;
293 }
294
295 send_pending = 0;
296 }
297 }
298
299 // Success
300 status = 0;
301
302on_error:
303 if (status != 0) {
304 char errbuf[128];
305 PJ_LOG(1, (THIS_FILE,
306 "...compliance test error: status=%d, os_err=%d (%s)",
307 status, pj_get_netos_error(),
308 pj_strerror(pj_get_netos_error(), errbuf, sizeof(errbuf))));
309 }
310 if (ssock)
311 pj_sock_close(ssock);
312 if (csock)
313 pj_sock_close(csock);
314 if (ioque != NULL)
315 pj_ioqueue_destroy(ioque);
316 pj_pool_release(pool);
317 return status;
318
319}
320
321/*
322 * Testing with many handles.
323 * This will just test registering PJ_IOQUEUE_MAX_HANDLES count
324 * of sockets to the ioqueue.
325 */
326static int many_handles_test(void)
327{
328 enum { MAX = PJ_IOQUEUE_MAX_HANDLES };
329 pj_pool_t *pool;
330 pj_ioqueue_t *ioqueue;
331 pj_sock_t *sock;
332 pj_ioqueue_key_t **key;
333 pj_status_t rc;
334 int count, i;
335
336 PJ_LOG(3,(THIS_FILE,"...testing with so many handles"));
337
338 pool = pj_pool_create(mem, NULL, 4000, 4000, NULL);
339 if (!pool)
340 return PJ_ENOMEM;
341
342 key = pj_pool_alloc(pool, MAX*sizeof(pj_ioqueue_key_t*));
343 sock = pj_pool_alloc(pool, MAX*sizeof(pj_sock_t));
344
345 /* Create IOQueue */
346 rc = pj_ioqueue_create(pool, MAX, &ioqueue);
347 if (rc != PJ_SUCCESS || ioqueue == NULL) {
348 app_perror("...error in pj_ioqueue_create", rc);
349 return -10;
350 }
351
352 /* Register as many sockets. */
353 for (count=0; count<MAX; ++count) {
354 sock[count] = PJ_INVALID_SOCKET;
355 rc = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &sock[count]);
356 if (rc != PJ_SUCCESS || sock[count] == PJ_INVALID_SOCKET) {
357 PJ_LOG(3,(THIS_FILE, "....unable to create %d-th socket, rc=%d",
358 count, rc));
359 break;
360 }
361 key[count] = NULL;
362 rc = pj_ioqueue_register_sock(pool, ioqueue, sock[count],
363 NULL, &test_cb, &key[count]);
364 if (rc != PJ_SUCCESS || key[count] == NULL) {
365 PJ_LOG(3,(THIS_FILE, "....unable to register %d-th socket, rc=%d",
366 count, rc));
367 return -30;
368 }
369 }
370
371 /* Test complete. */
372
373 /* Now deregister and close all handles. */
374
375 for (i=0; i<count; ++i) {
376 rc = pj_ioqueue_unregister(key[i]);
377 if (rc != PJ_SUCCESS) {
378 app_perror("...error in pj_ioqueue_unregister", rc);
379 }
380 rc = pj_sock_close(sock[i]);
381 if (rc != PJ_SUCCESS) {
382 app_perror("...error in pj_sock_close", rc);
383 }
384 }
385
386 rc = pj_ioqueue_destroy(ioqueue);
387 if (rc != PJ_SUCCESS) {
388 app_perror("...error in pj_ioqueue_destroy", rc);
389 }
390
391 pj_pool_release(pool);
392
393 PJ_LOG(3,(THIS_FILE,"....many_handles_test() ok"));
394
395 return 0;
396}
397
398/*
399 * Multi-operation test.
400 */
401
402/*
403 * Benchmarking IOQueue
404 */
405static int bench_test(int bufsize, int inactive_sock_count)
406{
407 pj_sock_t ssock=-1, csock=-1;
408 pj_sockaddr_in addr;
409 pj_pool_t *pool = NULL;
410 pj_sock_t *inactive_sock=NULL;
411 pj_ioqueue_op_key_t *inactive_read_op;
412 char *send_buf, *recv_buf;
413 pj_ioqueue_t *ioque = NULL;
414 pj_ioqueue_key_t *skey, *ckey, *key;
415 pj_timestamp t1, t2, t_elapsed;
416 int rc=0, i;
417 pj_str_t temp;
418 char errbuf[128];
419
420 // Create pool.
421 pool = pj_pool_create(mem, NULL, POOL_SIZE, 4000, NULL);
422
423 // Allocate buffers for send and receive.
424 send_buf = (char*)pj_pool_alloc(pool, bufsize);
425 recv_buf = (char*)pj_pool_alloc(pool, bufsize);
426
427 // Allocate sockets for sending and receiving.
428 rc = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &ssock);
429 if (rc == PJ_SUCCESS) {
430 rc = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &csock);
431 } else
432 csock = PJ_INVALID_SOCKET;
433 if (rc != PJ_SUCCESS) {
434 app_perror("...error: pj_sock_socket()", rc);
435 goto on_error;
436 }
437
438 // Bind server socket.
439 memset(&addr, 0, sizeof(addr));
440 addr.sin_family = PJ_AF_INET;
441 addr.sin_port = pj_htons(PORT);
442 if (pj_sock_bind(ssock, &addr, sizeof(addr)))
443 goto on_error;
444
445 pj_assert(inactive_sock_count+2 <= PJ_IOQUEUE_MAX_HANDLES);
446
447 // Create I/O Queue.
448 rc = pj_ioqueue_create(pool, PJ_IOQUEUE_MAX_HANDLES, &ioque);
449 if (rc != PJ_SUCCESS) {
450 app_perror("...error: pj_ioqueue_create()", rc);
451 goto on_error;
452 }
453
454 // Allocate inactive sockets, and bind them to some arbitrary address.
455 // Then register them to the I/O queue, and start a read operation.
456 inactive_sock = (pj_sock_t*)pj_pool_alloc(pool,
457 inactive_sock_count*sizeof(pj_sock_t));
458 inactive_read_op = (pj_ioqueue_op_key_t*)pj_pool_alloc(pool,
459 inactive_sock_count*sizeof(pj_ioqueue_op_key_t));
460 memset(&addr, 0, sizeof(addr));
461 addr.sin_family = PJ_AF_INET;
462 for (i=0; i<inactive_sock_count; ++i) {
463 pj_ssize_t bytes;
464
465 rc = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &inactive_sock[i]);
466 if (rc != PJ_SUCCESS || inactive_sock[i] < 0) {
467 app_perror("...error: pj_sock_socket()", rc);
468 goto on_error;
469 }
470 if ((rc=pj_sock_bind(inactive_sock[i], &addr, sizeof(addr))) != 0) {
471 pj_sock_close(inactive_sock[i]);
472 inactive_sock[i] = PJ_INVALID_SOCKET;
473 app_perror("...error: pj_sock_bind()", rc);
474 goto on_error;
475 }
476 rc = pj_ioqueue_register_sock(pool, ioque, inactive_sock[i],
477 NULL, &test_cb, &key);
478 if (rc != PJ_SUCCESS) {
479 pj_sock_close(inactive_sock[i]);
480 inactive_sock[i] = PJ_INVALID_SOCKET;
481 app_perror("...error(1): pj_ioqueue_register_sock()", rc);
482 PJ_LOG(3,(THIS_FILE, "....i=%d", i));
483 goto on_error;
484 }
485 bytes = bufsize;
486 rc = pj_ioqueue_recv(key, &inactive_read_op[i], recv_buf, &bytes, 0);
487 if ( rc < 0 && rc != PJ_EPENDING) {
488 pj_sock_close(inactive_sock[i]);
489 inactive_sock[i] = PJ_INVALID_SOCKET;
490 app_perror("...error: pj_ioqueue_read()", rc);
491 goto on_error;
492 }
493 }
494
495 // Register server and client socket.
496 // We put this after inactivity socket, hopefully this can represent the
497 // worst waiting time.
498 rc = pj_ioqueue_register_sock(pool, ioque, ssock, NULL,
499 &test_cb, &skey);
500 if (rc != PJ_SUCCESS) {
501 app_perror("...error(2): pj_ioqueue_register_sock()", rc);
502 goto on_error;
503 }
504
505 rc = pj_ioqueue_register_sock(pool, ioque, csock, NULL,
506 &test_cb, &ckey);
507 if (rc != PJ_SUCCESS) {
508 app_perror("...error(3): pj_ioqueue_register_sock()", rc);
509 goto on_error;
510 }
511
512 // Set destination address to send the packet.
513 pj_sockaddr_in_init(&addr, pj_cstr(&temp, "127.0.0.1"), PORT);
514
515 // Test loop.
516 t_elapsed.u64 = 0;
517 for (i=0; i<LOOP; ++i) {
518 pj_ssize_t bytes;
519 pj_ioqueue_op_key_t read_op, write_op;
520
521 // Randomize send buffer.
522 pj_create_random_string(send_buf, bufsize);
523
524 // Start reading on the server side.
525 bytes = bufsize;
526 rc = pj_ioqueue_recv(skey, &read_op, recv_buf, &bytes, 0);
527 if (rc < 0 && rc != PJ_EPENDING) {
528 app_perror("...error: pj_ioqueue_read()", rc);
529 break;
530 }
531
532 // Starts send on the client side.
533 bytes = bufsize;
534 rc = pj_ioqueue_sendto(ckey, &write_op, send_buf, &bytes, 0,
535 &addr, sizeof(addr));
536 if (rc != PJ_SUCCESS && rc != PJ_EPENDING) {
537 app_perror("...error: pj_ioqueue_write()", bytes);
538 rc = -1;
539 break;
540 }
541
542 // Begin time.
543 pj_get_timestamp(&t1);
544
545 // Poll the queue until we've got completion event in the server side.
546 callback_read_key = NULL;
547 callback_read_size = 0;
548 do {
549 rc = pj_ioqueue_poll(ioque, NULL);
550 } while (rc >= 0 && callback_read_key != skey);
551
552 // End time.
553 pj_get_timestamp(&t2);
554 t_elapsed.u64 += (t2.u64 - t1.u64);
555
556 if (rc < 0)
557 break;
558
559 // Compare recv buffer with send buffer.
560 if (callback_read_size != bufsize ||
561 memcmp(send_buf, recv_buf, bufsize))
562 {
563 rc = -1;
564 break;
565 }
566
567 // Poll until all events are exhausted, before we start the next loop.
568 do {
569 pj_time_val timeout = { 0, 10 };
570 rc = pj_ioqueue_poll(ioque, &timeout);
571 } while (rc>0);
572
573 rc = 0;
574 }
575
576 // Print results
577 if (rc == 0) {
578 pj_timestamp tzero;
579 pj_uint32_t usec_delay;
580
581 tzero.u32.hi = tzero.u32.lo = 0;
582 usec_delay = pj_elapsed_usec( &tzero, &t_elapsed);
583
584 PJ_LOG(3, (THIS_FILE, "...%10d %15d % 9d",
585 bufsize, inactive_sock_count, usec_delay));
586
587 } else {
588 PJ_LOG(2, (THIS_FILE, "...ERROR (buf:%d, fds:%d)",
589 bufsize, inactive_sock_count+2));
590 }
591
592 // Cleaning up.
593 for (i=0; i<inactive_sock_count; ++i)
594 pj_sock_close(inactive_sock[i]);
595 pj_sock_close(ssock);
596 pj_sock_close(csock);
597
598 pj_ioqueue_destroy(ioque);
599 pj_pool_release( pool);
600 return 0;
601
602on_error:
603 PJ_LOG(1,(THIS_FILE, "...ERROR: %s",
604 pj_strerror(pj_get_netos_error(), errbuf, sizeof(errbuf))));
605 if (ssock)
606 pj_sock_close(ssock);
607 if (csock)
608 pj_sock_close(csock);
609 for (i=0; i<inactive_sock_count && inactive_sock &&
610 inactive_sock[i]!=PJ_INVALID_SOCKET; ++i)
611 {
612 pj_sock_close(inactive_sock[i]);
613 }
614 if (ioque != NULL)
615 pj_ioqueue_destroy(ioque);
616 pj_pool_release( pool);
617 return -1;
618}
619
620int udp_ioqueue_test()
621{
622 int status;
623 int bufsize, sock_count;
624
625 PJ_LOG(3, (THIS_FILE, "...compliance test (%s)", pj_ioqueue_name()));
626 if ((status=compliance_test()) != 0) {
627 return status;
628 }
629 PJ_LOG(3, (THIS_FILE, "....compliance test ok"));
630
631 if ((status=many_handles_test()) != 0) {
632 return status;
633 }
634
635 PJ_LOG(4, (THIS_FILE, "...benchmarking different buffer size:"));
636 PJ_LOG(4, (THIS_FILE, "... note: buf=bytes sent, fds=# of fds, "
637 "elapsed=in timer ticks"));
638
639 PJ_LOG(3, (THIS_FILE, "...Benchmarking poll times for %s:", pj_ioqueue_name()));
640 PJ_LOG(3, (THIS_FILE, "...====================================="));
641 PJ_LOG(3, (THIS_FILE, "...Buf.size #inactive-socks Time/poll"));
642 PJ_LOG(3, (THIS_FILE, "... (bytes) (nanosec)"));
643 PJ_LOG(3, (THIS_FILE, "...====================================="));
644
645 for (bufsize=BUF_MIN_SIZE; bufsize <= BUF_MAX_SIZE; bufsize *= 2) {
646 if (bench_test(bufsize, SOCK_INACTIVE_MIN))
647 return -1;
648 }
649 bufsize = 512;
650 for (sock_count=SOCK_INACTIVE_MIN+2;
651 sock_count<=SOCK_INACTIVE_MAX+2;
652 sock_count *= 2)
653 {
654 //PJ_LOG(3,(THIS_FILE, "...testing with %d fds", sock_count));
655 if (bench_test(bufsize, sock_count-2))
656 return -1;
657 }
658 return 0;
659}
660
661#else
662/* To prevent warning about "translation unit is empty"
663 * when this test is disabled.
664 */
665int dummy_uiq_udp;
666#endif /* INCLUDE_UDP_IOQUEUE_TEST */
667
668