blob: ef958d774c9270091a015db2801d35bf4a0adeea [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 * \page page_pjlib_ioqueue_tcp_test Test: I/O Queue (TCP)
23 *
24 * This file provides implementation to test the
25 * functionality of the I/O queue when TCP socket is used.
26 *
27 *
28 * This file is <b>pjlib-test/ioq_tcp.c</b>
29 *
30 * \include pjlib-test/ioq_tcp.c
31 */
32
33
34#if INCLUDE_TCP_IOQUEUE_TEST
35
36#include <pjlib.h>
37
38#if PJ_HAS_TCP
39
40#define THIS_FILE "test_tcp"
Benny Prijono5dcb38d2005-11-21 01:55:47 +000041#define NON_EXISTANT_PORT 50123
42#define LOOP 100
43#define BUF_MIN_SIZE 32
44#define BUF_MAX_SIZE 2048
45#define SOCK_INACTIVE_MIN (4-2)
46#define SOCK_INACTIVE_MAX (PJ_IOQUEUE_MAX_HANDLES - 2)
47#define POOL_SIZE (2*BUF_MAX_SIZE + SOCK_INACTIVE_MAX*128 + 2048)
48
49static pj_ssize_t callback_read_size,
50 callback_write_size,
51 callback_accept_status,
52 callback_connect_status;
53static pj_ioqueue_key_t *callback_read_key,
54 *callback_write_key,
55 *callback_accept_key,
56 *callback_connect_key;
57static pj_ioqueue_op_key_t *callback_read_op,
58 *callback_write_op,
59 *callback_accept_op;
60
61static void on_ioqueue_read(pj_ioqueue_key_t *key,
62 pj_ioqueue_op_key_t *op_key,
63 pj_ssize_t bytes_read)
64{
65 callback_read_key = key;
66 callback_read_op = op_key;
67 callback_read_size = bytes_read;
68}
69
70static void on_ioqueue_write(pj_ioqueue_key_t *key,
71 pj_ioqueue_op_key_t *op_key,
72 pj_ssize_t bytes_written)
73{
74 callback_write_key = key;
75 callback_write_op = op_key;
76 callback_write_size = bytes_written;
77}
78
79static void on_ioqueue_accept(pj_ioqueue_key_t *key,
80 pj_ioqueue_op_key_t *op_key,
81 pj_sock_t sock,
82 int status)
83{
Benny Prijono01de33b2006-06-28 15:23:18 +000084 if (sock == PJ_INVALID_SOCKET) {
Benny Prijono5dcb38d2005-11-21 01:55:47 +000085
Benny Prijono01de33b2006-06-28 15:23:18 +000086 if (status != PJ_SUCCESS) {
87 /* Ignore. Could be blocking error */
88 app_perror(".....warning: received error in on_ioqueue_accept() callback",
89 status);
90 } else {
91 callback_accept_status = -61;
92 PJ_LOG(3,("", "..... on_ioqueue_accept() callback was given "
93 "invalid socket and status is %d", status));
94 }
95 } else {
96 callback_accept_key = key;
97 callback_accept_op = op_key;
98 callback_accept_status = status;
99 }
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000100}
101
102static void on_ioqueue_connect(pj_ioqueue_key_t *key, int status)
103{
104 callback_connect_key = key;
105 callback_connect_status = status;
106}
107
108static pj_ioqueue_callback test_cb =
109{
110 &on_ioqueue_read,
111 &on_ioqueue_write,
112 &on_ioqueue_accept,
113 &on_ioqueue_connect,
114};
115
116static int send_recv_test(pj_ioqueue_t *ioque,
117 pj_ioqueue_key_t *skey,
118 pj_ioqueue_key_t *ckey,
119 void *send_buf,
120 void *recv_buf,
121 pj_ssize_t bufsize,
122 pj_timestamp *t_elapsed)
123{
124 pj_status_t status;
125 pj_ssize_t bytes;
126 pj_time_val timeout;
127 pj_timestamp t1, t2;
128 int pending_op = 0;
129 pj_ioqueue_op_key_t read_op, write_op;
130
131 // Start reading on the server side.
132 bytes = bufsize;
133 status = pj_ioqueue_recv(skey, &read_op, recv_buf, &bytes, 0);
134 if (status != PJ_SUCCESS && status != PJ_EPENDING) {
135 app_perror("...pj_ioqueue_recv error", status);
136 return -100;
137 }
138
139 if (status == PJ_EPENDING)
140 ++pending_op;
141 else {
142 /* Does not expect to return error or immediate data. */
143 return -115;
144 }
145
146 // Randomize send buffer.
147 pj_create_random_string((char*)send_buf, bufsize);
148
149 // Starts send on the client side.
150 bytes = bufsize;
151 status = pj_ioqueue_send(ckey, &write_op, send_buf, &bytes, 0);
152 if (status != PJ_SUCCESS && bytes != PJ_EPENDING) {
153 return -120;
154 }
155 if (status == PJ_EPENDING) {
156 ++pending_op;
157 }
158
159 // Begin time.
160 pj_get_timestamp(&t1);
161
162 // Reset indicators
163 callback_read_size = callback_write_size = 0;
164 callback_read_key = callback_write_key = NULL;
165 callback_read_op = callback_write_op = NULL;
166
167 // Poll the queue until we've got completion event in the server side.
168 status = 0;
169 while (pending_op > 0) {
170 timeout.sec = 1; timeout.msec = 0;
171 status = pj_ioqueue_poll(ioque, &timeout);
172 if (status > 0) {
173 if (callback_read_size) {
174 if (callback_read_size != bufsize)
175 return -160;
176 if (callback_read_key != skey)
177 return -161;
178 if (callback_read_op != &read_op)
179 return -162;
180 }
181 if (callback_write_size) {
182 if (callback_write_key != ckey)
183 return -163;
184 if (callback_write_op != &write_op)
185 return -164;
186 }
187 pending_op -= status;
188 }
189 if (status == 0) {
190 PJ_LOG(3,("", "...error: timed out"));
191 }
192 if (status < 0) {
193 return -170;
194 }
195 }
196
197 // Pending op is zero.
198 // Subsequent poll should yield zero too.
199 timeout.sec = timeout.msec = 0;
200 status = pj_ioqueue_poll(ioque, &timeout);
201 if (status != 0)
202 return -173;
203
204 // End time.
205 pj_get_timestamp(&t2);
206 t_elapsed->u32.lo += (t2.u32.lo - t1.u32.lo);
207
208 // Compare recv buffer with send buffer.
209 if (pj_memcmp(send_buf, recv_buf, bufsize) != 0) {
210 return -180;
211 }
212
213 // Success
214 return 0;
215}
216
217
218/*
219 * Compliance test for success scenario.
220 */
221static int compliance_test_0(void)
222{
223 pj_sock_t ssock=-1, csock0=-1, csock1=-1;
224 pj_sockaddr_in addr, client_addr, rmt_addr;
225 int client_addr_len;
226 pj_pool_t *pool = NULL;
227 char *send_buf, *recv_buf;
228 pj_ioqueue_t *ioque = NULL;
229 pj_ioqueue_key_t *skey, *ckey0, *ckey1;
230 pj_ioqueue_op_key_t accept_op;
231 int bufsize = BUF_MIN_SIZE;
232 pj_ssize_t status = -1;
233 int pending_op = 0;
234 pj_timestamp t_elapsed;
235 pj_str_t s;
236 pj_status_t rc;
237
238 // Create pool.
239 pool = pj_pool_create(mem, NULL, POOL_SIZE, 4000, NULL);
240
241 // Allocate buffers for send and receive.
242 send_buf = (char*)pj_pool_alloc(pool, bufsize);
243 recv_buf = (char*)pj_pool_alloc(pool, bufsize);
244
245 // Create server socket and client socket for connecting
246 rc = pj_sock_socket(PJ_AF_INET, PJ_SOCK_STREAM, 0, &ssock);
247 if (rc != PJ_SUCCESS) {
248 app_perror("...error creating socket", rc);
249 status=-1; goto on_error;
250 }
251
252 rc = pj_sock_socket(PJ_AF_INET, PJ_SOCK_STREAM, 0, &csock1);
253 if (rc != PJ_SUCCESS) {
254 app_perror("...error creating socket", rc);
255 status=-1; goto on_error;
256 }
257
258 // Bind server socket.
Benny Prijono63ab3562006-07-08 19:46:43 +0000259 pj_sockaddr_in_init(&addr, 0, 0);
260 if ((rc=pj_sock_bind(ssock, &addr, sizeof(addr))) != 0 ) {
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000261 app_perror("...bind error", rc);
262 status=-10; goto on_error;
263 }
264
Benny Prijono63ab3562006-07-08 19:46:43 +0000265 // Get server address.
266 client_addr_len = sizeof(addr);
267 rc = pj_sock_getsockname(ssock, &addr, &client_addr_len);
268 if (rc != PJ_SUCCESS) {
269 app_perror("...ERROR in pj_sock_getsockname()", rc);
270 status=-15; goto on_error;
271 }
272 addr.sin_addr = pj_inet_addr(pj_cstr(&s, "127.0.0.1"));
273
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000274 // Create I/O Queue.
275 rc = pj_ioqueue_create(pool, PJ_IOQUEUE_MAX_HANDLES, &ioque);
276 if (rc != PJ_SUCCESS) {
277 app_perror("...ERROR in pj_ioqueue_create()", rc);
278 status=-20; goto on_error;
279 }
280
281 // Register server socket and client socket.
282 rc = pj_ioqueue_register_sock(pool, ioque, ssock, NULL, &test_cb, &skey);
283 if (rc == PJ_SUCCESS)
284 rc = pj_ioqueue_register_sock(pool, ioque, csock1, NULL, &test_cb,
285 &ckey1);
286 else
287 ckey1 = NULL;
288 if (rc != PJ_SUCCESS) {
289 app_perror("...ERROR in pj_ioqueue_register_sock()", rc);
290 status=-23; goto on_error;
291 }
292
293 // Server socket listen().
294 if (pj_sock_listen(ssock, 5)) {
295 app_perror("...ERROR in pj_sock_listen()", rc);
296 status=-25; goto on_error;
297 }
298
299 // Server socket accept()
300 client_addr_len = sizeof(pj_sockaddr_in);
301 status = pj_ioqueue_accept(skey, &accept_op, &csock0,
302 &client_addr, &rmt_addr, &client_addr_len);
303 if (status != PJ_EPENDING) {
304 app_perror("...ERROR in pj_ioqueue_accept()", rc);
305 status=-30; goto on_error;
306 }
307 if (status==PJ_EPENDING) {
308 ++pending_op;
309 }
310
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000311 // Client socket connect()
312 status = pj_ioqueue_connect(ckey1, &addr, sizeof(addr));
313 if (status!=PJ_SUCCESS && status != PJ_EPENDING) {
314 app_perror("...ERROR in pj_ioqueue_connect()", rc);
315 status=-40; goto on_error;
316 }
317 if (status==PJ_EPENDING) {
318 ++pending_op;
319 }
320
321 // Poll until connected
322 callback_read_size = callback_write_size = 0;
323 callback_accept_status = callback_connect_status = -2;
324
325 callback_read_key = callback_write_key =
326 callback_accept_key = callback_connect_key = NULL;
327 callback_accept_op = callback_read_op = callback_write_op = NULL;
328
329 while (pending_op) {
330 pj_time_val timeout = {1, 0};
331
332 status=pj_ioqueue_poll(ioque, &timeout);
333 if (status > 0) {
334 if (callback_accept_status != -2) {
335 if (callback_accept_status != 0) {
336 status=-41; goto on_error;
337 }
338 if (callback_accept_key != skey) {
339 status=-42; goto on_error;
340 }
341 if (callback_accept_op != &accept_op) {
342 status=-43; goto on_error;
343 }
344 callback_accept_status = -2;
345 }
346
347 if (callback_connect_status != -2) {
348 if (callback_connect_status != 0) {
349 status=-50; goto on_error;
350 }
351 if (callback_connect_key != ckey1) {
352 status=-51; goto on_error;
353 }
354 callback_connect_status = -2;
355 }
356
Benny Prijono42c5b9e2006-05-10 19:24:40 +0000357 if (status > pending_op) {
358 PJ_LOG(3,(THIS_FILE,
359 "...error: pj_ioqueue_poll() returned %d "
360 "(only expecting %d)",
361 status, pending_op));
362 return -52;
363 }
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000364 pending_op -= status;
365
366 if (pending_op == 0) {
367 status = 0;
368 }
369 }
370 }
371
372 // There's no pending operation.
373 // When we poll the ioqueue, there must not be events.
374 if (pending_op == 0) {
375 pj_time_val timeout = {1, 0};
376 status = pj_ioqueue_poll(ioque, &timeout);
377 if (status != 0) {
378 status=-60; goto on_error;
379 }
380 }
381
382 // Check accepted socket.
383 if (csock0 == PJ_INVALID_SOCKET) {
384 status = -69;
385 app_perror("...accept() error", pj_get_os_error());
386 goto on_error;
387 }
388
389 // Register newly accepted socket.
390 rc = pj_ioqueue_register_sock(pool, ioque, csock0, NULL,
391 &test_cb, &ckey0);
392 if (rc != PJ_SUCCESS) {
393 app_perror("...ERROR in pj_ioqueue_register_sock", rc);
394 status = -70;
395 goto on_error;
396 }
397
398 // Test send and receive.
399 t_elapsed.u32.lo = 0;
400 status = send_recv_test(ioque, ckey0, ckey1, send_buf,
401 recv_buf, bufsize, &t_elapsed);
402 if (status != 0) {
403 goto on_error;
404 }
405
406 // Success
407 status = 0;
408
409on_error:
410 if (ssock != PJ_INVALID_SOCKET)
411 pj_sock_close(ssock);
412 if (csock1 != PJ_INVALID_SOCKET)
413 pj_sock_close(csock1);
414 if (csock0 != PJ_INVALID_SOCKET)
415 pj_sock_close(csock0);
416 if (ioque != NULL)
417 pj_ioqueue_destroy(ioque);
418 pj_pool_release(pool);
419 return status;
420
421}
422
423/*
424 * Compliance test for failed scenario.
425 * In this case, the client connects to a non-existant service.
426 */
427static int compliance_test_1(void)
428{
429 pj_sock_t csock1=-1;
430 pj_sockaddr_in addr;
431 pj_pool_t *pool = NULL;
432 pj_ioqueue_t *ioque = NULL;
433 pj_ioqueue_key_t *ckey1;
434 pj_ssize_t status = -1;
435 int pending_op = 0;
436 pj_str_t s;
437 pj_status_t rc;
438
439 // Create pool.
440 pool = pj_pool_create(mem, NULL, POOL_SIZE, 4000, NULL);
441
442 // Create I/O Queue.
443 rc = pj_ioqueue_create(pool, PJ_IOQUEUE_MAX_HANDLES, &ioque);
444 if (!ioque) {
445 status=-20; goto on_error;
446 }
447
448 // Create client socket
449 rc = pj_sock_socket(PJ_AF_INET, PJ_SOCK_STREAM, 0, &csock1);
450 if (rc != PJ_SUCCESS) {
451 app_perror("...ERROR in pj_sock_socket()", rc);
452 status=-1; goto on_error;
453 }
454
455 // Register client socket.
456 rc = pj_ioqueue_register_sock(pool, ioque, csock1, NULL,
457 &test_cb, &ckey1);
458 if (rc != PJ_SUCCESS) {
459 app_perror("...ERROR in pj_ioqueue_register_sock()", rc);
460 status=-23; goto on_error;
461 }
462
463 // Initialize remote address.
Benny Prijono63ab3562006-07-08 19:46:43 +0000464 pj_sockaddr_in_init(&addr, pj_cstr(&s, "127.0.0.1"), NON_EXISTANT_PORT);
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000465
466 // Client socket connect()
467 status = pj_ioqueue_connect(ckey1, &addr, sizeof(addr));
468 if (status==PJ_SUCCESS) {
469 // unexpectedly success!
470 status = -30;
471 goto on_error;
472 }
473 if (status != PJ_EPENDING) {
474 // success
475 } else {
476 ++pending_op;
477 }
478
479 callback_connect_status = -2;
480 callback_connect_key = NULL;
481
482 // Poll until we've got result
483 while (pending_op) {
484 pj_time_val timeout = {1, 0};
485
486 status=pj_ioqueue_poll(ioque, &timeout);
487 if (status > 0) {
488 if (callback_connect_key==ckey1) {
489 if (callback_connect_status == 0) {
490 // unexpectedly connected!
491 status = -50;
492 goto on_error;
493 }
494 }
495
Benny Prijono42c5b9e2006-05-10 19:24:40 +0000496 if (status > pending_op) {
497 PJ_LOG(3,(THIS_FILE,
498 "...error: pj_ioqueue_poll() returned %d "
499 "(only expecting %d)",
500 status, pending_op));
501 return -552;
502 }
503
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000504 pending_op -= status;
505 if (pending_op == 0) {
506 status = 0;
507 }
508 }
509 }
510
511 // There's no pending operation.
512 // When we poll the ioqueue, there must not be events.
513 if (pending_op == 0) {
514 pj_time_val timeout = {1, 0};
515 status = pj_ioqueue_poll(ioque, &timeout);
516 if (status != 0) {
517 status=-60; goto on_error;
518 }
519 }
520
521 // Success
522 status = 0;
523
524on_error:
525 if (csock1 != PJ_INVALID_SOCKET)
526 pj_sock_close(csock1);
527 if (ioque != NULL)
528 pj_ioqueue_destroy(ioque);
529 pj_pool_release(pool);
530 return status;
531}
532
Benny Prijono9c025eb2006-07-10 21:35:27 +0000533
534/*
535 * Repeated connect/accept on the same listener socket.
536 */
537static int compliance_test_2(void)
538{
539 enum { MAX_PAIR = 4, TEST_LOOP = 2 };
540
541 struct listener
542 {
543 pj_sock_t sock;
544 pj_ioqueue_key_t *key;
545 pj_sockaddr_in addr;
546 int addr_len;
547 } listener;
548
549 struct server
550 {
551 pj_sock_t sock;
552 pj_ioqueue_key_t *key;
553 pj_sockaddr_in local_addr;
554 pj_sockaddr_in rem_addr;
555 int rem_addr_len;
556 pj_ioqueue_op_key_t accept_op;
557 } server[MAX_PAIR];
558
559 struct client
560 {
561 pj_sock_t sock;
562 pj_ioqueue_key_t *key;
563 } client[MAX_PAIR];
564
565 pj_pool_t *pool = NULL;
566 char *send_buf, *recv_buf;
567 pj_ioqueue_t *ioque = NULL;
568 int i, bufsize = BUF_MIN_SIZE;
569 pj_ssize_t status;
570 int test_loop, pending_op = 0;
571 pj_timestamp t_elapsed;
572 pj_str_t s;
573 pj_status_t rc;
574
575 // Create pool.
576 pool = pj_pool_create(mem, NULL, POOL_SIZE, 4000, NULL);
577
578
579 // Create I/O Queue.
580 rc = pj_ioqueue_create(pool, PJ_IOQUEUE_MAX_HANDLES, &ioque);
581 if (rc != PJ_SUCCESS) {
582 app_perror("...ERROR in pj_ioqueue_create()", rc);
583 return -10;
584 }
585
586
587 // Allocate buffers for send and receive.
588 send_buf = (char*)pj_pool_alloc(pool, bufsize);
589 recv_buf = (char*)pj_pool_alloc(pool, bufsize);
590
591 // Create listener socket
592 rc = pj_sock_socket(PJ_AF_INET, PJ_SOCK_STREAM, 0, &listener.sock);
593 if (rc != PJ_SUCCESS) {
594 app_perror("...error creating socket", rc);
595 status=-20; goto on_error;
596 }
597
598 // Bind listener socket.
599 pj_sockaddr_in_init(&listener.addr, 0, 0);
600 if ((rc=pj_sock_bind(listener.sock, &listener.addr, sizeof(listener.addr))) != 0 ) {
601 app_perror("...bind error", rc);
602 status=-30; goto on_error;
603 }
604
605 // Get listener address.
606 listener.addr_len = sizeof(listener.addr);
607 rc = pj_sock_getsockname(listener.sock, &listener.addr, &listener.addr_len);
608 if (rc != PJ_SUCCESS) {
609 app_perror("...ERROR in pj_sock_getsockname()", rc);
610 status=-40; goto on_error;
611 }
612 listener.addr.sin_addr = pj_inet_addr(pj_cstr(&s, "127.0.0.1"));
613
614
615 // Register listener socket.
616 rc = pj_ioqueue_register_sock(pool, ioque, listener.sock, NULL, &test_cb,
617 &listener.key);
618 if (rc != PJ_SUCCESS) {
619 app_perror("...ERROR", rc);
620 status=-50; goto on_error;
621 }
622
623
624 // Listener socket listen().
625 if (pj_sock_listen(listener.sock, 5)) {
626 app_perror("...ERROR in pj_sock_listen()", rc);
627 status=-60; goto on_error;
628 }
629
630
631 for (test_loop=0; test_loop < TEST_LOOP; ++test_loop) {
632 // Client connect and server accept.
633 for (i=0; i<MAX_PAIR; ++i) {
634 rc = pj_sock_socket(PJ_AF_INET, PJ_SOCK_STREAM, 0, &client[i].sock);
635 if (rc != PJ_SUCCESS) {
636 app_perror("...error creating socket", rc);
637 status=-70; goto on_error;
638 }
639
640 rc = pj_ioqueue_register_sock(pool, ioque, client[i].sock, NULL,
641 &test_cb, &client[i].key);
642 if (rc != PJ_SUCCESS) {
643 app_perror("...error ", rc);
644 status=-80; goto on_error;
645 }
646
647 // Server socket accept()
648 pj_ioqueue_op_key_init(&server[i].accept_op,
649 sizeof(server[i].accept_op));
650 server[i].rem_addr_len = sizeof(pj_sockaddr_in);
651 status = pj_ioqueue_accept(listener.key, &server[i].accept_op,
652 &server[i].sock, &server[i].local_addr,
653 &server[i].rem_addr,
654 &server[i].rem_addr_len);
655 if (status!=PJ_SUCCESS && status != PJ_EPENDING) {
656 app_perror("...ERROR in pj_ioqueue_accept()", rc);
657 status=-90; goto on_error;
658 }
659 if (status==PJ_EPENDING) {
660 ++pending_op;
661 }
662
663
664 // Client socket connect()
665 status = pj_ioqueue_connect(client[i].key, &listener.addr,
666 sizeof(listener.addr));
667 if (status!=PJ_SUCCESS && status != PJ_EPENDING) {
668 app_perror("...ERROR in pj_ioqueue_connect()", rc);
669 status=-100; goto on_error;
670 }
671 if (status==PJ_EPENDING) {
672 ++pending_op;
673 }
674
675 }
676
677
678 // Poll until all connected
679 while (pending_op) {
680 pj_time_val timeout = {1, 0};
681
682 status=pj_ioqueue_poll(ioque, &timeout);
683 if (status > 0) {
684 if (status > pending_op) {
685 PJ_LOG(3,(THIS_FILE,
686 "...error: pj_ioqueue_poll() returned %d "
687 "(only expecting %d)",
688 status, pending_op));
689 return -110;
690 }
691 pending_op -= status;
692
693 if (pending_op == 0) {
694 status = 0;
695 }
696 }
697 }
698
699 // There's no pending operation.
700 // When we poll the ioqueue, there must not be events.
701 if (pending_op == 0) {
702 pj_time_val timeout = {1, 0};
703 status = pj_ioqueue_poll(ioque, &timeout);
704 if (status != 0) {
705 status=-120; goto on_error;
706 }
707 }
708
709 for (i=0; i<MAX_PAIR; ++i) {
710 // Check server socket.
711 if (server[i].sock == PJ_INVALID_SOCKET) {
712 status = -130;
713 app_perror("...accept() error", pj_get_os_error());
714 goto on_error;
715 }
716
717 // Check addresses
718 if (server[i].local_addr.sin_family != PJ_AF_INET ||
719 server[i].local_addr.sin_addr.s_addr == 0 ||
720 server[i].local_addr.sin_port == 0)
721 {
722 app_perror("...ERROR address not set", rc);
723 status = -140;
724 goto on_error;
725 }
726
727 if (server[i].rem_addr.sin_family != PJ_AF_INET ||
728 server[i].rem_addr.sin_addr.s_addr == 0 ||
729 server[i].rem_addr.sin_port == 0)
730 {
731 app_perror("...ERROR address not set", rc);
732 status = -150;
733 goto on_error;
734 }
735
736
737 // Register newly accepted socket.
738 rc = pj_ioqueue_register_sock(pool, ioque, server[i].sock, NULL,
739 &test_cb, &server[i].key);
740 if (rc != PJ_SUCCESS) {
741 app_perror("...ERROR in pj_ioqueue_register_sock", rc);
742 status = -160;
743 goto on_error;
744 }
745
746 // Test send and receive.
747 t_elapsed.u32.lo = 0;
748 status = send_recv_test(ioque, server[i].key, client[i].key,
749 send_buf, recv_buf, bufsize, &t_elapsed);
750 if (status != 0) {
751 goto on_error;
752 }
753 }
754
755 // Success
756 status = 0;
757
758 for (i=0; i<MAX_PAIR; ++i) {
759 if (server[i].key != NULL) {
760 pj_ioqueue_unregister(server[i].key);
761 server[i].key = NULL;
762 server[i].sock = PJ_INVALID_SOCKET;
763 } else if (server[i].sock != PJ_INVALID_SOCKET) {
764 pj_sock_close(server[i].sock);
765 server[i].sock = PJ_INVALID_SOCKET;
766 }
767
768 if (client[i].key != NULL) {
769 pj_ioqueue_unregister(client[i].key);
770 client[i].key = NULL;
771 client[i].sock = PJ_INVALID_SOCKET;
772 } else if (client[i].sock != PJ_INVALID_SOCKET) {
773 pj_sock_close(client[i].sock);
774 client[i].sock = PJ_INVALID_SOCKET;
775 }
776 }
777 }
778
779 status = 0;
780
781on_error:
782 for (i=0; i<MAX_PAIR; ++i) {
783 if (server[i].key != NULL) {
784 pj_ioqueue_unregister(server[i].key);
785 server[i].key = NULL;
786 server[i].sock = PJ_INVALID_SOCKET;
787 } else if (server[i].sock != PJ_INVALID_SOCKET) {
788 pj_sock_close(server[i].sock);
789 server[i].sock = PJ_INVALID_SOCKET;
790 }
791
792 if (client[i].key != NULL) {
793 pj_ioqueue_unregister(client[i].key);
794 client[i].key = NULL;
795 server[i].sock = PJ_INVALID_SOCKET;
796 } else if (client[i].sock != PJ_INVALID_SOCKET) {
797 pj_sock_close(client[i].sock);
798 client[i].sock = PJ_INVALID_SOCKET;
799 }
800 }
801
802 if (listener.key) {
803 pj_ioqueue_unregister(listener.key);
804 listener.key = NULL;
805 } else if (listener.sock != PJ_INVALID_SOCKET) {
806 pj_sock_close(listener.sock);
807 listener.sock = PJ_INVALID_SOCKET;
808 }
809
810 if (ioque != NULL)
811 pj_ioqueue_destroy(ioque);
812 pj_pool_release(pool);
813 return status;
814
815}
816
817
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000818int tcp_ioqueue_test()
819{
820 int status;
821
822 PJ_LOG(3, (THIS_FILE, "..%s compliance test 0 (success scenario)",
823 pj_ioqueue_name()));
824 if ((status=compliance_test_0()) != 0) {
825 PJ_LOG(1, (THIS_FILE, "....FAILED (status=%d)\n", status));
826 return status;
827 }
828 PJ_LOG(3, (THIS_FILE, "..%s compliance test 1 (failed scenario)",
829 pj_ioqueue_name()));
830 if ((status=compliance_test_1()) != 0) {
831 PJ_LOG(1, (THIS_FILE, "....FAILED (status=%d)\n", status));
832 return status;
833 }
834
Benny Prijono9c025eb2006-07-10 21:35:27 +0000835 PJ_LOG(3, (THIS_FILE, "..%s compliance test 2 (repeated accept)",
836 pj_ioqueue_name()));
837 if ((status=compliance_test_2()) != 0) {
838 PJ_LOG(1, (THIS_FILE, "....FAILED (status=%d)\n", status));
839 return status;
840 }
841
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000842 return 0;
843}
844
845#endif /* PJ_HAS_TCP */
846
847
848#else
849/* To prevent warning about "translation unit is empty"
850 * when this test is disabled.
851 */
852int dummy_uiq_tcp;
853#endif /* INCLUDE_TCP_IOQUEUE_TEST */
854
855