blob: 64adb2f905032bb6566abbf81163f1db787e8ba6 [file] [log] [blame]
Benny Prijono5dcb38d2005-11-21 01:55:47 +00001/* $Id$ */
2/*
Benny Prijono844653c2008-12-23 17:27:53 +00003 * Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com)
4 * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
Benny Prijono5dcb38d2005-11-21 01:55:47 +00005 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20#include "test.h"
21
22/**
23 * \page page_pjlib_ioqueue_tcp_test Test: I/O Queue (TCP)
24 *
25 * This file provides implementation to test the
26 * functionality of the I/O queue when TCP socket is used.
27 *
28 *
29 * This file is <b>pjlib-test/ioq_tcp.c</b>
30 *
31 * \include pjlib-test/ioq_tcp.c
32 */
33
34
35#if INCLUDE_TCP_IOQUEUE_TEST
36
37#include <pjlib.h>
38
39#if PJ_HAS_TCP
40
41#define THIS_FILE "test_tcp"
Benny Prijono5dcb38d2005-11-21 01:55:47 +000042#define NON_EXISTANT_PORT 50123
43#define LOOP 100
44#define BUF_MIN_SIZE 32
45#define BUF_MAX_SIZE 2048
46#define SOCK_INACTIVE_MIN (4-2)
47#define SOCK_INACTIVE_MAX (PJ_IOQUEUE_MAX_HANDLES - 2)
48#define POOL_SIZE (2*BUF_MAX_SIZE + SOCK_INACTIVE_MAX*128 + 2048)
49
50static pj_ssize_t callback_read_size,
51 callback_write_size,
52 callback_accept_status,
53 callback_connect_status;
Benny Prijono8ab968f2007-07-20 08:08:30 +000054static unsigned callback_call_count;
Benny Prijono5dcb38d2005-11-21 01:55:47 +000055static pj_ioqueue_key_t *callback_read_key,
56 *callback_write_key,
57 *callback_accept_key,
58 *callback_connect_key;
59static pj_ioqueue_op_key_t *callback_read_op,
60 *callback_write_op,
61 *callback_accept_op;
62
63static void on_ioqueue_read(pj_ioqueue_key_t *key,
64 pj_ioqueue_op_key_t *op_key,
65 pj_ssize_t bytes_read)
66{
67 callback_read_key = key;
68 callback_read_op = op_key;
69 callback_read_size = bytes_read;
Benny Prijono8ab968f2007-07-20 08:08:30 +000070 callback_call_count++;
Benny Prijono5dcb38d2005-11-21 01:55:47 +000071}
72
73static void on_ioqueue_write(pj_ioqueue_key_t *key,
74 pj_ioqueue_op_key_t *op_key,
75 pj_ssize_t bytes_written)
76{
77 callback_write_key = key;
78 callback_write_op = op_key;
79 callback_write_size = bytes_written;
Benny Prijono8ab968f2007-07-20 08:08:30 +000080 callback_call_count++;
Benny Prijono5dcb38d2005-11-21 01:55:47 +000081}
82
83static void on_ioqueue_accept(pj_ioqueue_key_t *key,
84 pj_ioqueue_op_key_t *op_key,
85 pj_sock_t sock,
86 int status)
87{
Benny Prijono01de33b2006-06-28 15:23:18 +000088 if (sock == PJ_INVALID_SOCKET) {
Benny Prijono5dcb38d2005-11-21 01:55:47 +000089
Benny Prijono01de33b2006-06-28 15:23:18 +000090 if (status != PJ_SUCCESS) {
91 /* Ignore. Could be blocking error */
92 app_perror(".....warning: received error in on_ioqueue_accept() callback",
93 status);
94 } else {
95 callback_accept_status = -61;
96 PJ_LOG(3,("", "..... on_ioqueue_accept() callback was given "
97 "invalid socket and status is %d", status));
98 }
99 } else {
100 callback_accept_key = key;
101 callback_accept_op = op_key;
102 callback_accept_status = status;
Benny Prijono8ab968f2007-07-20 08:08:30 +0000103 callback_call_count++;
Benny Prijono01de33b2006-06-28 15:23:18 +0000104 }
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000105}
106
107static void on_ioqueue_connect(pj_ioqueue_key_t *key, int status)
108{
109 callback_connect_key = key;
110 callback_connect_status = status;
Benny Prijono8ab968f2007-07-20 08:08:30 +0000111 callback_call_count++;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000112}
113
114static pj_ioqueue_callback test_cb =
115{
116 &on_ioqueue_read,
117 &on_ioqueue_write,
118 &on_ioqueue_accept,
119 &on_ioqueue_connect,
120};
121
122static int send_recv_test(pj_ioqueue_t *ioque,
123 pj_ioqueue_key_t *skey,
124 pj_ioqueue_key_t *ckey,
125 void *send_buf,
126 void *recv_buf,
127 pj_ssize_t bufsize,
128 pj_timestamp *t_elapsed)
129{
130 pj_status_t status;
131 pj_ssize_t bytes;
132 pj_time_val timeout;
133 pj_timestamp t1, t2;
134 int pending_op = 0;
135 pj_ioqueue_op_key_t read_op, write_op;
136
137 // Start reading on the server side.
138 bytes = bufsize;
139 status = pj_ioqueue_recv(skey, &read_op, recv_buf, &bytes, 0);
140 if (status != PJ_SUCCESS && status != PJ_EPENDING) {
141 app_perror("...pj_ioqueue_recv error", status);
142 return -100;
143 }
144
145 if (status == PJ_EPENDING)
146 ++pending_op;
147 else {
148 /* Does not expect to return error or immediate data. */
149 return -115;
150 }
151
152 // Randomize send buffer.
153 pj_create_random_string((char*)send_buf, bufsize);
154
155 // Starts send on the client side.
156 bytes = bufsize;
157 status = pj_ioqueue_send(ckey, &write_op, send_buf, &bytes, 0);
158 if (status != PJ_SUCCESS && bytes != PJ_EPENDING) {
159 return -120;
160 }
161 if (status == PJ_EPENDING) {
162 ++pending_op;
163 }
164
165 // Begin time.
166 pj_get_timestamp(&t1);
167
168 // Reset indicators
169 callback_read_size = callback_write_size = 0;
170 callback_read_key = callback_write_key = NULL;
171 callback_read_op = callback_write_op = NULL;
172
173 // Poll the queue until we've got completion event in the server side.
174 status = 0;
175 while (pending_op > 0) {
176 timeout.sec = 1; timeout.msec = 0;
Benny Prijono8ab968f2007-07-20 08:08:30 +0000177#ifdef PJ_SYMBIAN
178 PJ_UNUSED_ARG(ioque);
179 status = pj_symbianos_poll(-1, 1000);
180#else
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000181 status = pj_ioqueue_poll(ioque, &timeout);
Benny Prijono8ab968f2007-07-20 08:08:30 +0000182#endif
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000183 if (status > 0) {
184 if (callback_read_size) {
185 if (callback_read_size != bufsize)
186 return -160;
187 if (callback_read_key != skey)
188 return -161;
189 if (callback_read_op != &read_op)
190 return -162;
191 }
192 if (callback_write_size) {
193 if (callback_write_key != ckey)
194 return -163;
195 if (callback_write_op != &write_op)
196 return -164;
197 }
198 pending_op -= status;
199 }
200 if (status == 0) {
201 PJ_LOG(3,("", "...error: timed out"));
202 }
203 if (status < 0) {
204 return -170;
205 }
206 }
207
208 // Pending op is zero.
209 // Subsequent poll should yield zero too.
210 timeout.sec = timeout.msec = 0;
Benny Prijono8ab968f2007-07-20 08:08:30 +0000211#ifdef PJ_SYMBIAN
212 status = pj_symbianos_poll(-1, 1);
213#else
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000214 status = pj_ioqueue_poll(ioque, &timeout);
Benny Prijono8ab968f2007-07-20 08:08:30 +0000215#endif
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000216 if (status != 0)
217 return -173;
218
219 // End time.
220 pj_get_timestamp(&t2);
221 t_elapsed->u32.lo += (t2.u32.lo - t1.u32.lo);
222
223 // Compare recv buffer with send buffer.
224 if (pj_memcmp(send_buf, recv_buf, bufsize) != 0) {
225 return -180;
226 }
227
228 // Success
229 return 0;
230}
231
232
233/*
234 * Compliance test for success scenario.
235 */
Benny Prijonoe3f79fd2008-02-13 15:17:28 +0000236static int compliance_test_0(pj_bool_t allow_concur)
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000237{
238 pj_sock_t ssock=-1, csock0=-1, csock1=-1;
239 pj_sockaddr_in addr, client_addr, rmt_addr;
240 int client_addr_len;
241 pj_pool_t *pool = NULL;
242 char *send_buf, *recv_buf;
243 pj_ioqueue_t *ioque = NULL;
Benny Prijono8ab968f2007-07-20 08:08:30 +0000244 pj_ioqueue_key_t *skey=NULL, *ckey0=NULL, *ckey1=NULL;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000245 pj_ioqueue_op_key_t accept_op;
246 int bufsize = BUF_MIN_SIZE;
247 pj_ssize_t status = -1;
248 int pending_op = 0;
249 pj_timestamp t_elapsed;
250 pj_str_t s;
251 pj_status_t rc;
252
253 // Create pool.
254 pool = pj_pool_create(mem, NULL, POOL_SIZE, 4000, NULL);
255
256 // Allocate buffers for send and receive.
257 send_buf = (char*)pj_pool_alloc(pool, bufsize);
258 recv_buf = (char*)pj_pool_alloc(pool, bufsize);
259
260 // Create server socket and client socket for connecting
Benny Prijono8ab968f2007-07-20 08:08:30 +0000261 rc = pj_sock_socket(pj_AF_INET(), pj_SOCK_STREAM(), 0, &ssock);
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000262 if (rc != PJ_SUCCESS) {
263 app_perror("...error creating socket", rc);
264 status=-1; goto on_error;
265 }
266
Benny Prijono8ab968f2007-07-20 08:08:30 +0000267 rc = pj_sock_socket(pj_AF_INET(), pj_SOCK_STREAM(), 0, &csock1);
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000268 if (rc != PJ_SUCCESS) {
269 app_perror("...error creating socket", rc);
270 status=-1; goto on_error;
271 }
272
273 // Bind server socket.
Benny Prijono63ab3562006-07-08 19:46:43 +0000274 pj_sockaddr_in_init(&addr, 0, 0);
275 if ((rc=pj_sock_bind(ssock, &addr, sizeof(addr))) != 0 ) {
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000276 app_perror("...bind error", rc);
277 status=-10; goto on_error;
278 }
279
Benny Prijono63ab3562006-07-08 19:46:43 +0000280 // Get server address.
281 client_addr_len = sizeof(addr);
282 rc = pj_sock_getsockname(ssock, &addr, &client_addr_len);
283 if (rc != PJ_SUCCESS) {
284 app_perror("...ERROR in pj_sock_getsockname()", rc);
285 status=-15; goto on_error;
286 }
287 addr.sin_addr = pj_inet_addr(pj_cstr(&s, "127.0.0.1"));
288
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000289 // Create I/O Queue.
290 rc = pj_ioqueue_create(pool, PJ_IOQUEUE_MAX_HANDLES, &ioque);
291 if (rc != PJ_SUCCESS) {
292 app_perror("...ERROR in pj_ioqueue_create()", rc);
293 status=-20; goto on_error;
294 }
295
Benny Prijonoe3f79fd2008-02-13 15:17:28 +0000296 // Concurrency
297 rc = pj_ioqueue_set_default_concurrency(ioque, allow_concur);
298 if (rc != PJ_SUCCESS) {
299 app_perror("...ERROR in pj_ioqueue_set_default_concurrency()", rc);
300 status=-21; goto on_error;
301 }
302
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000303 // Register server socket and client socket.
304 rc = pj_ioqueue_register_sock(pool, ioque, ssock, NULL, &test_cb, &skey);
305 if (rc == PJ_SUCCESS)
306 rc = pj_ioqueue_register_sock(pool, ioque, csock1, NULL, &test_cb,
307 &ckey1);
308 else
309 ckey1 = NULL;
310 if (rc != PJ_SUCCESS) {
311 app_perror("...ERROR in pj_ioqueue_register_sock()", rc);
312 status=-23; goto on_error;
313 }
314
315 // Server socket listen().
316 if (pj_sock_listen(ssock, 5)) {
317 app_perror("...ERROR in pj_sock_listen()", rc);
318 status=-25; goto on_error;
319 }
320
321 // Server socket accept()
322 client_addr_len = sizeof(pj_sockaddr_in);
323 status = pj_ioqueue_accept(skey, &accept_op, &csock0,
324 &client_addr, &rmt_addr, &client_addr_len);
325 if (status != PJ_EPENDING) {
326 app_perror("...ERROR in pj_ioqueue_accept()", rc);
327 status=-30; goto on_error;
328 }
329 if (status==PJ_EPENDING) {
330 ++pending_op;
331 }
332
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000333 // Client socket connect()
334 status = pj_ioqueue_connect(ckey1, &addr, sizeof(addr));
335 if (status!=PJ_SUCCESS && status != PJ_EPENDING) {
336 app_perror("...ERROR in pj_ioqueue_connect()", rc);
337 status=-40; goto on_error;
338 }
339 if (status==PJ_EPENDING) {
340 ++pending_op;
341 }
342
343 // Poll until connected
344 callback_read_size = callback_write_size = 0;
345 callback_accept_status = callback_connect_status = -2;
Benny Prijono8ab968f2007-07-20 08:08:30 +0000346 callback_call_count = 0;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000347
348 callback_read_key = callback_write_key =
349 callback_accept_key = callback_connect_key = NULL;
350 callback_accept_op = callback_read_op = callback_write_op = NULL;
351
352 while (pending_op) {
353 pj_time_val timeout = {1, 0};
354
Benny Prijono8ab968f2007-07-20 08:08:30 +0000355#ifdef PJ_SYMBIAN
356 callback_call_count = 0;
357 pj_symbianos_poll(-1, 1000);
358 status = callback_call_count;
359#else
360 status = pj_ioqueue_poll(ioque, &timeout);
361#endif
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000362 if (status > 0) {
363 if (callback_accept_status != -2) {
364 if (callback_accept_status != 0) {
365 status=-41; goto on_error;
366 }
367 if (callback_accept_key != skey) {
368 status=-42; goto on_error;
369 }
370 if (callback_accept_op != &accept_op) {
371 status=-43; goto on_error;
372 }
373 callback_accept_status = -2;
374 }
375
376 if (callback_connect_status != -2) {
377 if (callback_connect_status != 0) {
378 status=-50; goto on_error;
379 }
380 if (callback_connect_key != ckey1) {
381 status=-51; goto on_error;
382 }
383 callback_connect_status = -2;
384 }
385
Benny Prijono42c5b9e2006-05-10 19:24:40 +0000386 if (status > pending_op) {
387 PJ_LOG(3,(THIS_FILE,
388 "...error: pj_ioqueue_poll() returned %d "
389 "(only expecting %d)",
390 status, pending_op));
391 return -52;
392 }
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000393 pending_op -= status;
394
395 if (pending_op == 0) {
396 status = 0;
397 }
398 }
399 }
400
401 // There's no pending operation.
402 // When we poll the ioqueue, there must not be events.
403 if (pending_op == 0) {
404 pj_time_val timeout = {1, 0};
Benny Prijono8ab968f2007-07-20 08:08:30 +0000405#ifdef PJ_SYMBIAN
406 status = pj_symbianos_poll(-1, 1000);
407#else
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000408 status = pj_ioqueue_poll(ioque, &timeout);
Benny Prijono8ab968f2007-07-20 08:08:30 +0000409#endif
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000410 if (status != 0) {
411 status=-60; goto on_error;
412 }
413 }
414
415 // Check accepted socket.
416 if (csock0 == PJ_INVALID_SOCKET) {
417 status = -69;
418 app_perror("...accept() error", pj_get_os_error());
419 goto on_error;
420 }
421
422 // Register newly accepted socket.
423 rc = pj_ioqueue_register_sock(pool, ioque, csock0, NULL,
424 &test_cb, &ckey0);
425 if (rc != PJ_SUCCESS) {
426 app_perror("...ERROR in pj_ioqueue_register_sock", rc);
427 status = -70;
428 goto on_error;
429 }
430
431 // Test send and receive.
432 t_elapsed.u32.lo = 0;
433 status = send_recv_test(ioque, ckey0, ckey1, send_buf,
434 recv_buf, bufsize, &t_elapsed);
435 if (status != 0) {
436 goto on_error;
437 }
438
439 // Success
440 status = 0;
441
442on_error:
Benny Prijono8ab968f2007-07-20 08:08:30 +0000443 if (skey != NULL)
444 pj_ioqueue_unregister(skey);
445 else if (ssock != PJ_INVALID_SOCKET)
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000446 pj_sock_close(ssock);
Benny Prijono8ab968f2007-07-20 08:08:30 +0000447
448 if (ckey1 != NULL)
449 pj_ioqueue_unregister(ckey1);
450 else if (csock1 != PJ_INVALID_SOCKET)
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000451 pj_sock_close(csock1);
Benny Prijono8ab968f2007-07-20 08:08:30 +0000452
453 if (ckey0 != NULL)
454 pj_ioqueue_unregister(ckey0);
455 else if (csock0 != PJ_INVALID_SOCKET)
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000456 pj_sock_close(csock0);
Benny Prijono8ab968f2007-07-20 08:08:30 +0000457
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000458 if (ioque != NULL)
459 pj_ioqueue_destroy(ioque);
460 pj_pool_release(pool);
461 return status;
462
463}
464
465/*
466 * Compliance test for failed scenario.
467 * In this case, the client connects to a non-existant service.
468 */
Benny Prijonoe3f79fd2008-02-13 15:17:28 +0000469static int compliance_test_1(pj_bool_t allow_concur)
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000470{
Benny Prijono8ab968f2007-07-20 08:08:30 +0000471 pj_sock_t csock1=PJ_INVALID_SOCKET;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000472 pj_sockaddr_in addr;
473 pj_pool_t *pool = NULL;
474 pj_ioqueue_t *ioque = NULL;
Benny Prijono8ab968f2007-07-20 08:08:30 +0000475 pj_ioqueue_key_t *ckey1 = NULL;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000476 pj_ssize_t status = -1;
477 int pending_op = 0;
478 pj_str_t s;
479 pj_status_t rc;
480
481 // Create pool.
482 pool = pj_pool_create(mem, NULL, POOL_SIZE, 4000, NULL);
483
484 // Create I/O Queue.
485 rc = pj_ioqueue_create(pool, PJ_IOQUEUE_MAX_HANDLES, &ioque);
486 if (!ioque) {
487 status=-20; goto on_error;
488 }
489
Benny Prijonoe3f79fd2008-02-13 15:17:28 +0000490 // Concurrency
491 rc = pj_ioqueue_set_default_concurrency(ioque, allow_concur);
492 if (rc != PJ_SUCCESS) {
493 status=-21; goto on_error;
494 }
495
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000496 // Create client socket
Benny Prijono8ab968f2007-07-20 08:08:30 +0000497 rc = pj_sock_socket(pj_AF_INET(), pj_SOCK_STREAM(), 0, &csock1);
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000498 if (rc != PJ_SUCCESS) {
499 app_perror("...ERROR in pj_sock_socket()", rc);
500 status=-1; goto on_error;
501 }
502
503 // Register client socket.
504 rc = pj_ioqueue_register_sock(pool, ioque, csock1, NULL,
505 &test_cb, &ckey1);
506 if (rc != PJ_SUCCESS) {
507 app_perror("...ERROR in pj_ioqueue_register_sock()", rc);
508 status=-23; goto on_error;
509 }
510
511 // Initialize remote address.
Benny Prijono63ab3562006-07-08 19:46:43 +0000512 pj_sockaddr_in_init(&addr, pj_cstr(&s, "127.0.0.1"), NON_EXISTANT_PORT);
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000513
514 // Client socket connect()
515 status = pj_ioqueue_connect(ckey1, &addr, sizeof(addr));
516 if (status==PJ_SUCCESS) {
517 // unexpectedly success!
518 status = -30;
519 goto on_error;
520 }
521 if (status != PJ_EPENDING) {
522 // success
523 } else {
524 ++pending_op;
525 }
526
527 callback_connect_status = -2;
528 callback_connect_key = NULL;
529
530 // Poll until we've got result
531 while (pending_op) {
532 pj_time_val timeout = {1, 0};
533
Benny Prijono8ab968f2007-07-20 08:08:30 +0000534#ifdef PJ_SYMBIAN
535 callback_call_count = 0;
536 pj_symbianos_poll(-1, 1000);
537 status = callback_call_count;
538#else
539 status = pj_ioqueue_poll(ioque, &timeout);
540#endif
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000541 if (status > 0) {
542 if (callback_connect_key==ckey1) {
543 if (callback_connect_status == 0) {
544 // unexpectedly connected!
545 status = -50;
546 goto on_error;
547 }
548 }
549
Benny Prijono42c5b9e2006-05-10 19:24:40 +0000550 if (status > pending_op) {
551 PJ_LOG(3,(THIS_FILE,
552 "...error: pj_ioqueue_poll() returned %d "
553 "(only expecting %d)",
554 status, pending_op));
555 return -552;
556 }
557
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000558 pending_op -= status;
559 if (pending_op == 0) {
560 status = 0;
561 }
562 }
563 }
564
565 // There's no pending operation.
566 // When we poll the ioqueue, there must not be events.
567 if (pending_op == 0) {
568 pj_time_val timeout = {1, 0};
Benny Prijono8ab968f2007-07-20 08:08:30 +0000569#ifdef PJ_SYMBIAN
570 status = pj_symbianos_poll(-1, 1000);
571#else
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000572 status = pj_ioqueue_poll(ioque, &timeout);
Benny Prijono8ab968f2007-07-20 08:08:30 +0000573#endif
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000574 if (status != 0) {
575 status=-60; goto on_error;
576 }
577 }
578
579 // Success
580 status = 0;
581
582on_error:
Benny Prijono8ab968f2007-07-20 08:08:30 +0000583 if (ckey1 != NULL)
584 pj_ioqueue_unregister(ckey1);
585 else if (csock1 != PJ_INVALID_SOCKET)
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000586 pj_sock_close(csock1);
Benny Prijono8ab968f2007-07-20 08:08:30 +0000587
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000588 if (ioque != NULL)
589 pj_ioqueue_destroy(ioque);
590 pj_pool_release(pool);
591 return status;
592}
593
Benny Prijono9c025eb2006-07-10 21:35:27 +0000594
595/*
596 * Repeated connect/accept on the same listener socket.
597 */
Benny Prijonoe3f79fd2008-02-13 15:17:28 +0000598static int compliance_test_2(pj_bool_t allow_concur)
Benny Prijono9c025eb2006-07-10 21:35:27 +0000599{
Benny Prijonoaeeb1d12007-05-01 10:42:22 +0000600#if defined(PJ_SYMBIAN) && PJ_SYMBIAN!=0
601 enum { MAX_PAIR = 1, TEST_LOOP = 2 };
602#else
Benny Prijono9c025eb2006-07-10 21:35:27 +0000603 enum { MAX_PAIR = 4, TEST_LOOP = 2 };
Benny Prijonoaeeb1d12007-05-01 10:42:22 +0000604#endif
Benny Prijono9c025eb2006-07-10 21:35:27 +0000605
606 struct listener
607 {
608 pj_sock_t sock;
609 pj_ioqueue_key_t *key;
610 pj_sockaddr_in addr;
611 int addr_len;
612 } listener;
613
614 struct server
615 {
616 pj_sock_t sock;
617 pj_ioqueue_key_t *key;
618 pj_sockaddr_in local_addr;
619 pj_sockaddr_in rem_addr;
620 int rem_addr_len;
621 pj_ioqueue_op_key_t accept_op;
622 } server[MAX_PAIR];
623
624 struct client
625 {
626 pj_sock_t sock;
627 pj_ioqueue_key_t *key;
628 } client[MAX_PAIR];
629
630 pj_pool_t *pool = NULL;
631 char *send_buf, *recv_buf;
632 pj_ioqueue_t *ioque = NULL;
633 int i, bufsize = BUF_MIN_SIZE;
634 pj_ssize_t status;
635 int test_loop, pending_op = 0;
636 pj_timestamp t_elapsed;
637 pj_str_t s;
638 pj_status_t rc;
639
Benny Prijono8ab968f2007-07-20 08:08:30 +0000640 listener.sock = PJ_INVALID_SOCKET;
641 listener.key = NULL;
642
643 for (i=0; i<MAX_PAIR; ++i) {
644 server[i].sock = PJ_INVALID_SOCKET;
645 server[i].key = NULL;
646 }
647
648 for (i=0; i<MAX_PAIR; ++i) {
649 client[i].sock = PJ_INVALID_SOCKET;
650 client[i].key = NULL;
651 }
652
Benny Prijono9c025eb2006-07-10 21:35:27 +0000653 // Create pool.
654 pool = pj_pool_create(mem, NULL, POOL_SIZE, 4000, NULL);
655
656
657 // Create I/O Queue.
658 rc = pj_ioqueue_create(pool, PJ_IOQUEUE_MAX_HANDLES, &ioque);
659 if (rc != PJ_SUCCESS) {
660 app_perror("...ERROR in pj_ioqueue_create()", rc);
661 return -10;
662 }
663
664
Benny Prijonoe3f79fd2008-02-13 15:17:28 +0000665 // Concurrency
666 rc = pj_ioqueue_set_default_concurrency(ioque, allow_concur);
667 if (rc != PJ_SUCCESS) {
668 app_perror("...ERROR in pj_ioqueue_set_default_concurrency()", rc);
669 return -11;
670 }
671
Benny Prijono9c025eb2006-07-10 21:35:27 +0000672 // Allocate buffers for send and receive.
673 send_buf = (char*)pj_pool_alloc(pool, bufsize);
674 recv_buf = (char*)pj_pool_alloc(pool, bufsize);
675
676 // Create listener socket
Benny Prijono8ab968f2007-07-20 08:08:30 +0000677 rc = pj_sock_socket(pj_AF_INET(), pj_SOCK_STREAM(), 0, &listener.sock);
Benny Prijono9c025eb2006-07-10 21:35:27 +0000678 if (rc != PJ_SUCCESS) {
679 app_perror("...error creating socket", rc);
680 status=-20; goto on_error;
681 }
682
683 // Bind listener socket.
684 pj_sockaddr_in_init(&listener.addr, 0, 0);
685 if ((rc=pj_sock_bind(listener.sock, &listener.addr, sizeof(listener.addr))) != 0 ) {
686 app_perror("...bind error", rc);
687 status=-30; goto on_error;
688 }
689
690 // Get listener address.
691 listener.addr_len = sizeof(listener.addr);
692 rc = pj_sock_getsockname(listener.sock, &listener.addr, &listener.addr_len);
693 if (rc != PJ_SUCCESS) {
694 app_perror("...ERROR in pj_sock_getsockname()", rc);
695 status=-40; goto on_error;
696 }
697 listener.addr.sin_addr = pj_inet_addr(pj_cstr(&s, "127.0.0.1"));
698
699
700 // Register listener socket.
701 rc = pj_ioqueue_register_sock(pool, ioque, listener.sock, NULL, &test_cb,
702 &listener.key);
703 if (rc != PJ_SUCCESS) {
704 app_perror("...ERROR", rc);
705 status=-50; goto on_error;
706 }
707
708
709 // Listener socket listen().
710 if (pj_sock_listen(listener.sock, 5)) {
711 app_perror("...ERROR in pj_sock_listen()", rc);
712 status=-60; goto on_error;
713 }
714
715
716 for (test_loop=0; test_loop < TEST_LOOP; ++test_loop) {
717 // Client connect and server accept.
718 for (i=0; i<MAX_PAIR; ++i) {
Benny Prijono8ab968f2007-07-20 08:08:30 +0000719 rc = pj_sock_socket(pj_AF_INET(), pj_SOCK_STREAM(), 0, &client[i].sock);
Benny Prijono9c025eb2006-07-10 21:35:27 +0000720 if (rc != PJ_SUCCESS) {
721 app_perror("...error creating socket", rc);
722 status=-70; goto on_error;
723 }
724
725 rc = pj_ioqueue_register_sock(pool, ioque, client[i].sock, NULL,
726 &test_cb, &client[i].key);
727 if (rc != PJ_SUCCESS) {
728 app_perror("...error ", rc);
729 status=-80; goto on_error;
730 }
731
732 // Server socket accept()
733 pj_ioqueue_op_key_init(&server[i].accept_op,
734 sizeof(server[i].accept_op));
735 server[i].rem_addr_len = sizeof(pj_sockaddr_in);
736 status = pj_ioqueue_accept(listener.key, &server[i].accept_op,
737 &server[i].sock, &server[i].local_addr,
738 &server[i].rem_addr,
739 &server[i].rem_addr_len);
740 if (status!=PJ_SUCCESS && status != PJ_EPENDING) {
741 app_perror("...ERROR in pj_ioqueue_accept()", rc);
742 status=-90; goto on_error;
743 }
744 if (status==PJ_EPENDING) {
745 ++pending_op;
746 }
747
748
749 // Client socket connect()
750 status = pj_ioqueue_connect(client[i].key, &listener.addr,
751 sizeof(listener.addr));
752 if (status!=PJ_SUCCESS && status != PJ_EPENDING) {
753 app_perror("...ERROR in pj_ioqueue_connect()", rc);
754 status=-100; goto on_error;
755 }
756 if (status==PJ_EPENDING) {
757 ++pending_op;
758 }
759
Nanang Izzuddin3128a122009-11-04 03:35:13 +0000760 // Poll until connection of this pair established
761 while (pending_op) {
762 pj_time_val timeout = {1, 0};
Benny Prijono9c025eb2006-07-10 21:35:27 +0000763
Benny Prijono8ab968f2007-07-20 08:08:30 +0000764#ifdef PJ_SYMBIAN
Nanang Izzuddin3128a122009-11-04 03:35:13 +0000765 status = pj_symbianos_poll(-1, 1000);
Benny Prijono8ab968f2007-07-20 08:08:30 +0000766#else
Nanang Izzuddin3128a122009-11-04 03:35:13 +0000767 status = pj_ioqueue_poll(ioque, &timeout);
Benny Prijono8ab968f2007-07-20 08:08:30 +0000768#endif
Nanang Izzuddin3128a122009-11-04 03:35:13 +0000769 if (status > 0) {
770 if (status > pending_op) {
771 PJ_LOG(3,(THIS_FILE,
772 "...error: pj_ioqueue_poll() returned %d "
773 "(only expecting %d)",
774 status, pending_op));
775 return -110;
776 }
777 pending_op -= status;
Benny Prijono9c025eb2006-07-10 21:35:27 +0000778
Nanang Izzuddin3128a122009-11-04 03:35:13 +0000779 if (pending_op == 0) {
780 status = 0;
781 }
Benny Prijono9c025eb2006-07-10 21:35:27 +0000782 }
783 }
784 }
785
786 // There's no pending operation.
787 // When we poll the ioqueue, there must not be events.
788 if (pending_op == 0) {
789 pj_time_val timeout = {1, 0};
Benny Prijono8ab968f2007-07-20 08:08:30 +0000790#ifdef PJ_SYMBIAN
791 status = pj_symbianos_poll(-1, 1000);
792#else
Benny Prijono9c025eb2006-07-10 21:35:27 +0000793 status = pj_ioqueue_poll(ioque, &timeout);
Benny Prijono8ab968f2007-07-20 08:08:30 +0000794#endif
Benny Prijono9c025eb2006-07-10 21:35:27 +0000795 if (status != 0) {
796 status=-120; goto on_error;
797 }
798 }
799
800 for (i=0; i<MAX_PAIR; ++i) {
801 // Check server socket.
802 if (server[i].sock == PJ_INVALID_SOCKET) {
803 status = -130;
804 app_perror("...accept() error", pj_get_os_error());
805 goto on_error;
806 }
807
808 // Check addresses
Benny Prijono8ab968f2007-07-20 08:08:30 +0000809 if (server[i].local_addr.sin_family != pj_AF_INET() ||
Benny Prijono9c025eb2006-07-10 21:35:27 +0000810 server[i].local_addr.sin_addr.s_addr == 0 ||
811 server[i].local_addr.sin_port == 0)
812 {
813 app_perror("...ERROR address not set", rc);
814 status = -140;
815 goto on_error;
816 }
817
Benny Prijono8ab968f2007-07-20 08:08:30 +0000818 if (server[i].rem_addr.sin_family != pj_AF_INET() ||
Benny Prijono9c025eb2006-07-10 21:35:27 +0000819 server[i].rem_addr.sin_addr.s_addr == 0 ||
820 server[i].rem_addr.sin_port == 0)
821 {
822 app_perror("...ERROR address not set", rc);
823 status = -150;
824 goto on_error;
825 }
826
827
828 // Register newly accepted socket.
829 rc = pj_ioqueue_register_sock(pool, ioque, server[i].sock, NULL,
830 &test_cb, &server[i].key);
831 if (rc != PJ_SUCCESS) {
832 app_perror("...ERROR in pj_ioqueue_register_sock", rc);
833 status = -160;
834 goto on_error;
835 }
836
837 // Test send and receive.
838 t_elapsed.u32.lo = 0;
839 status = send_recv_test(ioque, server[i].key, client[i].key,
840 send_buf, recv_buf, bufsize, &t_elapsed);
841 if (status != 0) {
842 goto on_error;
843 }
844 }
845
846 // Success
847 status = 0;
848
849 for (i=0; i<MAX_PAIR; ++i) {
850 if (server[i].key != NULL) {
851 pj_ioqueue_unregister(server[i].key);
852 server[i].key = NULL;
853 server[i].sock = PJ_INVALID_SOCKET;
854 } else if (server[i].sock != PJ_INVALID_SOCKET) {
855 pj_sock_close(server[i].sock);
856 server[i].sock = PJ_INVALID_SOCKET;
857 }
858
859 if (client[i].key != NULL) {
860 pj_ioqueue_unregister(client[i].key);
861 client[i].key = NULL;
862 client[i].sock = PJ_INVALID_SOCKET;
863 } else if (client[i].sock != PJ_INVALID_SOCKET) {
864 pj_sock_close(client[i].sock);
865 client[i].sock = PJ_INVALID_SOCKET;
866 }
867 }
868 }
869
870 status = 0;
871
872on_error:
873 for (i=0; i<MAX_PAIR; ++i) {
874 if (server[i].key != NULL) {
875 pj_ioqueue_unregister(server[i].key);
876 server[i].key = NULL;
877 server[i].sock = PJ_INVALID_SOCKET;
878 } else if (server[i].sock != PJ_INVALID_SOCKET) {
879 pj_sock_close(server[i].sock);
880 server[i].sock = PJ_INVALID_SOCKET;
881 }
882
883 if (client[i].key != NULL) {
884 pj_ioqueue_unregister(client[i].key);
885 client[i].key = NULL;
886 server[i].sock = PJ_INVALID_SOCKET;
887 } else if (client[i].sock != PJ_INVALID_SOCKET) {
888 pj_sock_close(client[i].sock);
889 client[i].sock = PJ_INVALID_SOCKET;
890 }
891 }
892
893 if (listener.key) {
894 pj_ioqueue_unregister(listener.key);
895 listener.key = NULL;
896 } else if (listener.sock != PJ_INVALID_SOCKET) {
897 pj_sock_close(listener.sock);
898 listener.sock = PJ_INVALID_SOCKET;
899 }
900
901 if (ioque != NULL)
902 pj_ioqueue_destroy(ioque);
903 pj_pool_release(pool);
904 return status;
905
906}
907
908
Benny Prijonoe3f79fd2008-02-13 15:17:28 +0000909static int tcp_ioqueue_test_impl(pj_bool_t allow_concur)
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000910{
911 int status;
912
Benny Prijonoe3f79fd2008-02-13 15:17:28 +0000913 PJ_LOG(3,(THIS_FILE, "..testing with concurency=%d", allow_concur));
914
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000915 PJ_LOG(3, (THIS_FILE, "..%s compliance test 0 (success scenario)",
916 pj_ioqueue_name()));
Benny Prijonoe3f79fd2008-02-13 15:17:28 +0000917 if ((status=compliance_test_0(allow_concur)) != 0) {
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000918 PJ_LOG(1, (THIS_FILE, "....FAILED (status=%d)\n", status));
919 return status;
920 }
921 PJ_LOG(3, (THIS_FILE, "..%s compliance test 1 (failed scenario)",
922 pj_ioqueue_name()));
Benny Prijonoe3f79fd2008-02-13 15:17:28 +0000923 if ((status=compliance_test_1(allow_concur)) != 0) {
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000924 PJ_LOG(1, (THIS_FILE, "....FAILED (status=%d)\n", status));
925 return status;
926 }
927
Benny Prijono9c025eb2006-07-10 21:35:27 +0000928 PJ_LOG(3, (THIS_FILE, "..%s compliance test 2 (repeated accept)",
929 pj_ioqueue_name()));
Benny Prijonoe3f79fd2008-02-13 15:17:28 +0000930 if ((status=compliance_test_2(allow_concur)) != 0) {
Benny Prijono9c025eb2006-07-10 21:35:27 +0000931 PJ_LOG(1, (THIS_FILE, "....FAILED (status=%d)\n", status));
932 return status;
933 }
934
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000935 return 0;
936}
937
Benny Prijonoe3f79fd2008-02-13 15:17:28 +0000938int tcp_ioqueue_test()
939{
940 int rc;
941
942 rc = tcp_ioqueue_test_impl(PJ_TRUE);
943 if (rc != 0)
944 return rc;
945
946 rc = tcp_ioqueue_test_impl(PJ_FALSE);
947 if (rc != 0)
948 return rc;
949
950 return 0;
951}
952
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000953#endif /* PJ_HAS_TCP */
954
955
956#else
957/* To prevent warning about "translation unit is empty"
958 * when this test is disabled.
959 */
960int dummy_uiq_tcp;
961#endif /* INCLUDE_TCP_IOQUEUE_TEST */
962
963