blob: 106a9645276d8d53aa72e660941b12557fae0655 [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 * \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;
Benny Prijono8ab968f2007-07-20 08:08:30 +000053static unsigned callback_call_count;
Benny Prijono5dcb38d2005-11-21 01:55:47 +000054static pj_ioqueue_key_t *callback_read_key,
55 *callback_write_key,
56 *callback_accept_key,
57 *callback_connect_key;
58static pj_ioqueue_op_key_t *callback_read_op,
59 *callback_write_op,
60 *callback_accept_op;
61
62static void on_ioqueue_read(pj_ioqueue_key_t *key,
63 pj_ioqueue_op_key_t *op_key,
64 pj_ssize_t bytes_read)
65{
66 callback_read_key = key;
67 callback_read_op = op_key;
68 callback_read_size = bytes_read;
Benny Prijono8ab968f2007-07-20 08:08:30 +000069 callback_call_count++;
Benny Prijono5dcb38d2005-11-21 01:55:47 +000070}
71
72static void on_ioqueue_write(pj_ioqueue_key_t *key,
73 pj_ioqueue_op_key_t *op_key,
74 pj_ssize_t bytes_written)
75{
76 callback_write_key = key;
77 callback_write_op = op_key;
78 callback_write_size = bytes_written;
Benny Prijono8ab968f2007-07-20 08:08:30 +000079 callback_call_count++;
Benny Prijono5dcb38d2005-11-21 01:55:47 +000080}
81
82static void on_ioqueue_accept(pj_ioqueue_key_t *key,
83 pj_ioqueue_op_key_t *op_key,
84 pj_sock_t sock,
85 int status)
86{
Benny Prijono01de33b2006-06-28 15:23:18 +000087 if (sock == PJ_INVALID_SOCKET) {
Benny Prijono5dcb38d2005-11-21 01:55:47 +000088
Benny Prijono01de33b2006-06-28 15:23:18 +000089 if (status != PJ_SUCCESS) {
90 /* Ignore. Could be blocking error */
91 app_perror(".....warning: received error in on_ioqueue_accept() callback",
92 status);
93 } else {
94 callback_accept_status = -61;
95 PJ_LOG(3,("", "..... on_ioqueue_accept() callback was given "
96 "invalid socket and status is %d", status));
97 }
98 } else {
99 callback_accept_key = key;
100 callback_accept_op = op_key;
101 callback_accept_status = status;
Benny Prijono8ab968f2007-07-20 08:08:30 +0000102 callback_call_count++;
Benny Prijono01de33b2006-06-28 15:23:18 +0000103 }
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000104}
105
106static void on_ioqueue_connect(pj_ioqueue_key_t *key, int status)
107{
108 callback_connect_key = key;
109 callback_connect_status = status;
Benny Prijono8ab968f2007-07-20 08:08:30 +0000110 callback_call_count++;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000111}
112
113static pj_ioqueue_callback test_cb =
114{
115 &on_ioqueue_read,
116 &on_ioqueue_write,
117 &on_ioqueue_accept,
118 &on_ioqueue_connect,
119};
120
121static int send_recv_test(pj_ioqueue_t *ioque,
122 pj_ioqueue_key_t *skey,
123 pj_ioqueue_key_t *ckey,
124 void *send_buf,
125 void *recv_buf,
126 pj_ssize_t bufsize,
127 pj_timestamp *t_elapsed)
128{
129 pj_status_t status;
130 pj_ssize_t bytes;
131 pj_time_val timeout;
132 pj_timestamp t1, t2;
133 int pending_op = 0;
134 pj_ioqueue_op_key_t read_op, write_op;
135
136 // Start reading on the server side.
137 bytes = bufsize;
138 status = pj_ioqueue_recv(skey, &read_op, recv_buf, &bytes, 0);
139 if (status != PJ_SUCCESS && status != PJ_EPENDING) {
140 app_perror("...pj_ioqueue_recv error", status);
141 return -100;
142 }
143
144 if (status == PJ_EPENDING)
145 ++pending_op;
146 else {
147 /* Does not expect to return error or immediate data. */
148 return -115;
149 }
150
151 // Randomize send buffer.
152 pj_create_random_string((char*)send_buf, bufsize);
153
154 // Starts send on the client side.
155 bytes = bufsize;
156 status = pj_ioqueue_send(ckey, &write_op, send_buf, &bytes, 0);
157 if (status != PJ_SUCCESS && bytes != PJ_EPENDING) {
158 return -120;
159 }
160 if (status == PJ_EPENDING) {
161 ++pending_op;
162 }
163
164 // Begin time.
165 pj_get_timestamp(&t1);
166
167 // Reset indicators
168 callback_read_size = callback_write_size = 0;
169 callback_read_key = callback_write_key = NULL;
170 callback_read_op = callback_write_op = NULL;
171
172 // Poll the queue until we've got completion event in the server side.
173 status = 0;
174 while (pending_op > 0) {
175 timeout.sec = 1; timeout.msec = 0;
Benny Prijono8ab968f2007-07-20 08:08:30 +0000176#ifdef PJ_SYMBIAN
177 PJ_UNUSED_ARG(ioque);
178 status = pj_symbianos_poll(-1, 1000);
179#else
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000180 status = pj_ioqueue_poll(ioque, &timeout);
Benny Prijono8ab968f2007-07-20 08:08:30 +0000181#endif
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000182 if (status > 0) {
183 if (callback_read_size) {
184 if (callback_read_size != bufsize)
185 return -160;
186 if (callback_read_key != skey)
187 return -161;
188 if (callback_read_op != &read_op)
189 return -162;
190 }
191 if (callback_write_size) {
192 if (callback_write_key != ckey)
193 return -163;
194 if (callback_write_op != &write_op)
195 return -164;
196 }
197 pending_op -= status;
198 }
199 if (status == 0) {
200 PJ_LOG(3,("", "...error: timed out"));
201 }
202 if (status < 0) {
203 return -170;
204 }
205 }
206
207 // Pending op is zero.
208 // Subsequent poll should yield zero too.
209 timeout.sec = timeout.msec = 0;
Benny Prijono8ab968f2007-07-20 08:08:30 +0000210#ifdef PJ_SYMBIAN
211 status = pj_symbianos_poll(-1, 1);
212#else
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000213 status = pj_ioqueue_poll(ioque, &timeout);
Benny Prijono8ab968f2007-07-20 08:08:30 +0000214#endif
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000215 if (status != 0)
216 return -173;
217
218 // End time.
219 pj_get_timestamp(&t2);
220 t_elapsed->u32.lo += (t2.u32.lo - t1.u32.lo);
221
222 // Compare recv buffer with send buffer.
223 if (pj_memcmp(send_buf, recv_buf, bufsize) != 0) {
224 return -180;
225 }
226
227 // Success
228 return 0;
229}
230
231
232/*
233 * Compliance test for success scenario.
234 */
Benny Prijonoe3f79fd2008-02-13 15:17:28 +0000235static int compliance_test_0(pj_bool_t allow_concur)
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000236{
237 pj_sock_t ssock=-1, csock0=-1, csock1=-1;
238 pj_sockaddr_in addr, client_addr, rmt_addr;
239 int client_addr_len;
240 pj_pool_t *pool = NULL;
241 char *send_buf, *recv_buf;
242 pj_ioqueue_t *ioque = NULL;
Benny Prijono8ab968f2007-07-20 08:08:30 +0000243 pj_ioqueue_key_t *skey=NULL, *ckey0=NULL, *ckey1=NULL;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000244 pj_ioqueue_op_key_t accept_op;
245 int bufsize = BUF_MIN_SIZE;
246 pj_ssize_t status = -1;
247 int pending_op = 0;
248 pj_timestamp t_elapsed;
249 pj_str_t s;
250 pj_status_t rc;
251
252 // Create pool.
253 pool = pj_pool_create(mem, NULL, POOL_SIZE, 4000, NULL);
254
255 // Allocate buffers for send and receive.
256 send_buf = (char*)pj_pool_alloc(pool, bufsize);
257 recv_buf = (char*)pj_pool_alloc(pool, bufsize);
258
259 // Create server socket and client socket for connecting
Benny Prijono8ab968f2007-07-20 08:08:30 +0000260 rc = pj_sock_socket(pj_AF_INET(), pj_SOCK_STREAM(), 0, &ssock);
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000261 if (rc != PJ_SUCCESS) {
262 app_perror("...error creating socket", rc);
263 status=-1; goto on_error;
264 }
265
Benny Prijono8ab968f2007-07-20 08:08:30 +0000266 rc = pj_sock_socket(pj_AF_INET(), pj_SOCK_STREAM(), 0, &csock1);
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000267 if (rc != PJ_SUCCESS) {
268 app_perror("...error creating socket", rc);
269 status=-1; goto on_error;
270 }
271
272 // Bind server socket.
Benny Prijono63ab3562006-07-08 19:46:43 +0000273 pj_sockaddr_in_init(&addr, 0, 0);
274 if ((rc=pj_sock_bind(ssock, &addr, sizeof(addr))) != 0 ) {
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000275 app_perror("...bind error", rc);
276 status=-10; goto on_error;
277 }
278
Benny Prijono63ab3562006-07-08 19:46:43 +0000279 // Get server address.
280 client_addr_len = sizeof(addr);
281 rc = pj_sock_getsockname(ssock, &addr, &client_addr_len);
282 if (rc != PJ_SUCCESS) {
283 app_perror("...ERROR in pj_sock_getsockname()", rc);
284 status=-15; goto on_error;
285 }
286 addr.sin_addr = pj_inet_addr(pj_cstr(&s, "127.0.0.1"));
287
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000288 // Create I/O Queue.
289 rc = pj_ioqueue_create(pool, PJ_IOQUEUE_MAX_HANDLES, &ioque);
290 if (rc != PJ_SUCCESS) {
291 app_perror("...ERROR in pj_ioqueue_create()", rc);
292 status=-20; goto on_error;
293 }
294
Benny Prijonoe3f79fd2008-02-13 15:17:28 +0000295 // Concurrency
296 rc = pj_ioqueue_set_default_concurrency(ioque, allow_concur);
297 if (rc != PJ_SUCCESS) {
298 app_perror("...ERROR in pj_ioqueue_set_default_concurrency()", rc);
299 status=-21; goto on_error;
300 }
301
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000302 // Register server socket and client socket.
303 rc = pj_ioqueue_register_sock(pool, ioque, ssock, NULL, &test_cb, &skey);
304 if (rc == PJ_SUCCESS)
305 rc = pj_ioqueue_register_sock(pool, ioque, csock1, NULL, &test_cb,
306 &ckey1);
307 else
308 ckey1 = NULL;
309 if (rc != PJ_SUCCESS) {
310 app_perror("...ERROR in pj_ioqueue_register_sock()", rc);
311 status=-23; goto on_error;
312 }
313
314 // Server socket listen().
315 if (pj_sock_listen(ssock, 5)) {
316 app_perror("...ERROR in pj_sock_listen()", rc);
317 status=-25; goto on_error;
318 }
319
320 // Server socket accept()
321 client_addr_len = sizeof(pj_sockaddr_in);
322 status = pj_ioqueue_accept(skey, &accept_op, &csock0,
323 &client_addr, &rmt_addr, &client_addr_len);
324 if (status != PJ_EPENDING) {
325 app_perror("...ERROR in pj_ioqueue_accept()", rc);
326 status=-30; goto on_error;
327 }
328 if (status==PJ_EPENDING) {
329 ++pending_op;
330 }
331
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000332 // Client socket connect()
333 status = pj_ioqueue_connect(ckey1, &addr, sizeof(addr));
334 if (status!=PJ_SUCCESS && status != PJ_EPENDING) {
335 app_perror("...ERROR in pj_ioqueue_connect()", rc);
336 status=-40; goto on_error;
337 }
338 if (status==PJ_EPENDING) {
339 ++pending_op;
340 }
341
342 // Poll until connected
343 callback_read_size = callback_write_size = 0;
344 callback_accept_status = callback_connect_status = -2;
Benny Prijono8ab968f2007-07-20 08:08:30 +0000345 callback_call_count = 0;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000346
347 callback_read_key = callback_write_key =
348 callback_accept_key = callback_connect_key = NULL;
349 callback_accept_op = callback_read_op = callback_write_op = NULL;
350
351 while (pending_op) {
352 pj_time_val timeout = {1, 0};
353
Benny Prijono8ab968f2007-07-20 08:08:30 +0000354#ifdef PJ_SYMBIAN
355 callback_call_count = 0;
356 pj_symbianos_poll(-1, 1000);
357 status = callback_call_count;
358#else
359 status = pj_ioqueue_poll(ioque, &timeout);
360#endif
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000361 if (status > 0) {
362 if (callback_accept_status != -2) {
363 if (callback_accept_status != 0) {
364 status=-41; goto on_error;
365 }
366 if (callback_accept_key != skey) {
367 status=-42; goto on_error;
368 }
369 if (callback_accept_op != &accept_op) {
370 status=-43; goto on_error;
371 }
372 callback_accept_status = -2;
373 }
374
375 if (callback_connect_status != -2) {
376 if (callback_connect_status != 0) {
377 status=-50; goto on_error;
378 }
379 if (callback_connect_key != ckey1) {
380 status=-51; goto on_error;
381 }
382 callback_connect_status = -2;
383 }
384
Benny Prijono42c5b9e2006-05-10 19:24:40 +0000385 if (status > pending_op) {
386 PJ_LOG(3,(THIS_FILE,
387 "...error: pj_ioqueue_poll() returned %d "
388 "(only expecting %d)",
389 status, pending_op));
390 return -52;
391 }
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000392 pending_op -= status;
393
394 if (pending_op == 0) {
395 status = 0;
396 }
397 }
398 }
399
400 // There's no pending operation.
401 // When we poll the ioqueue, there must not be events.
402 if (pending_op == 0) {
403 pj_time_val timeout = {1, 0};
Benny Prijono8ab968f2007-07-20 08:08:30 +0000404#ifdef PJ_SYMBIAN
405 status = pj_symbianos_poll(-1, 1000);
406#else
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000407 status = pj_ioqueue_poll(ioque, &timeout);
Benny Prijono8ab968f2007-07-20 08:08:30 +0000408#endif
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000409 if (status != 0) {
410 status=-60; goto on_error;
411 }
412 }
413
414 // Check accepted socket.
415 if (csock0 == PJ_INVALID_SOCKET) {
416 status = -69;
417 app_perror("...accept() error", pj_get_os_error());
418 goto on_error;
419 }
420
421 // Register newly accepted socket.
422 rc = pj_ioqueue_register_sock(pool, ioque, csock0, NULL,
423 &test_cb, &ckey0);
424 if (rc != PJ_SUCCESS) {
425 app_perror("...ERROR in pj_ioqueue_register_sock", rc);
426 status = -70;
427 goto on_error;
428 }
429
430 // Test send and receive.
431 t_elapsed.u32.lo = 0;
432 status = send_recv_test(ioque, ckey0, ckey1, send_buf,
433 recv_buf, bufsize, &t_elapsed);
434 if (status != 0) {
435 goto on_error;
436 }
437
438 // Success
439 status = 0;
440
441on_error:
Benny Prijono8ab968f2007-07-20 08:08:30 +0000442 if (skey != NULL)
443 pj_ioqueue_unregister(skey);
444 else if (ssock != PJ_INVALID_SOCKET)
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000445 pj_sock_close(ssock);
Benny Prijono8ab968f2007-07-20 08:08:30 +0000446
447 if (ckey1 != NULL)
448 pj_ioqueue_unregister(ckey1);
449 else if (csock1 != PJ_INVALID_SOCKET)
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000450 pj_sock_close(csock1);
Benny Prijono8ab968f2007-07-20 08:08:30 +0000451
452 if (ckey0 != NULL)
453 pj_ioqueue_unregister(ckey0);
454 else if (csock0 != PJ_INVALID_SOCKET)
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000455 pj_sock_close(csock0);
Benny Prijono8ab968f2007-07-20 08:08:30 +0000456
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000457 if (ioque != NULL)
458 pj_ioqueue_destroy(ioque);
459 pj_pool_release(pool);
460 return status;
461
462}
463
464/*
465 * Compliance test for failed scenario.
466 * In this case, the client connects to a non-existant service.
467 */
Benny Prijonoe3f79fd2008-02-13 15:17:28 +0000468static int compliance_test_1(pj_bool_t allow_concur)
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000469{
Benny Prijono8ab968f2007-07-20 08:08:30 +0000470 pj_sock_t csock1=PJ_INVALID_SOCKET;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000471 pj_sockaddr_in addr;
472 pj_pool_t *pool = NULL;
473 pj_ioqueue_t *ioque = NULL;
Benny Prijono8ab968f2007-07-20 08:08:30 +0000474 pj_ioqueue_key_t *ckey1 = NULL;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000475 pj_ssize_t status = -1;
476 int pending_op = 0;
477 pj_str_t s;
478 pj_status_t rc;
479
480 // Create pool.
481 pool = pj_pool_create(mem, NULL, POOL_SIZE, 4000, NULL);
482
483 // Create I/O Queue.
484 rc = pj_ioqueue_create(pool, PJ_IOQUEUE_MAX_HANDLES, &ioque);
485 if (!ioque) {
486 status=-20; goto on_error;
487 }
488
Benny Prijonoe3f79fd2008-02-13 15:17:28 +0000489 // Concurrency
490 rc = pj_ioqueue_set_default_concurrency(ioque, allow_concur);
491 if (rc != PJ_SUCCESS) {
492 status=-21; goto on_error;
493 }
494
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000495 // Create client socket
Benny Prijono8ab968f2007-07-20 08:08:30 +0000496 rc = pj_sock_socket(pj_AF_INET(), pj_SOCK_STREAM(), 0, &csock1);
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000497 if (rc != PJ_SUCCESS) {
498 app_perror("...ERROR in pj_sock_socket()", rc);
499 status=-1; goto on_error;
500 }
501
502 // Register client socket.
503 rc = pj_ioqueue_register_sock(pool, ioque, csock1, NULL,
504 &test_cb, &ckey1);
505 if (rc != PJ_SUCCESS) {
506 app_perror("...ERROR in pj_ioqueue_register_sock()", rc);
507 status=-23; goto on_error;
508 }
509
510 // Initialize remote address.
Benny Prijono63ab3562006-07-08 19:46:43 +0000511 pj_sockaddr_in_init(&addr, pj_cstr(&s, "127.0.0.1"), NON_EXISTANT_PORT);
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000512
513 // Client socket connect()
514 status = pj_ioqueue_connect(ckey1, &addr, sizeof(addr));
515 if (status==PJ_SUCCESS) {
516 // unexpectedly success!
517 status = -30;
518 goto on_error;
519 }
520 if (status != PJ_EPENDING) {
521 // success
522 } else {
523 ++pending_op;
524 }
525
526 callback_connect_status = -2;
527 callback_connect_key = NULL;
528
529 // Poll until we've got result
530 while (pending_op) {
531 pj_time_val timeout = {1, 0};
532
Benny Prijono8ab968f2007-07-20 08:08:30 +0000533#ifdef PJ_SYMBIAN
534 callback_call_count = 0;
535 pj_symbianos_poll(-1, 1000);
536 status = callback_call_count;
537#else
538 status = pj_ioqueue_poll(ioque, &timeout);
539#endif
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000540 if (status > 0) {
541 if (callback_connect_key==ckey1) {
542 if (callback_connect_status == 0) {
543 // unexpectedly connected!
544 status = -50;
545 goto on_error;
546 }
547 }
548
Benny Prijono42c5b9e2006-05-10 19:24:40 +0000549 if (status > pending_op) {
550 PJ_LOG(3,(THIS_FILE,
551 "...error: pj_ioqueue_poll() returned %d "
552 "(only expecting %d)",
553 status, pending_op));
554 return -552;
555 }
556
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000557 pending_op -= status;
558 if (pending_op == 0) {
559 status = 0;
560 }
561 }
562 }
563
564 // There's no pending operation.
565 // When we poll the ioqueue, there must not be events.
566 if (pending_op == 0) {
567 pj_time_val timeout = {1, 0};
Benny Prijono8ab968f2007-07-20 08:08:30 +0000568#ifdef PJ_SYMBIAN
569 status = pj_symbianos_poll(-1, 1000);
570#else
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000571 status = pj_ioqueue_poll(ioque, &timeout);
Benny Prijono8ab968f2007-07-20 08:08:30 +0000572#endif
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000573 if (status != 0) {
574 status=-60; goto on_error;
575 }
576 }
577
578 // Success
579 status = 0;
580
581on_error:
Benny Prijono8ab968f2007-07-20 08:08:30 +0000582 if (ckey1 != NULL)
583 pj_ioqueue_unregister(ckey1);
584 else if (csock1 != PJ_INVALID_SOCKET)
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000585 pj_sock_close(csock1);
Benny Prijono8ab968f2007-07-20 08:08:30 +0000586
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000587 if (ioque != NULL)
588 pj_ioqueue_destroy(ioque);
589 pj_pool_release(pool);
590 return status;
591}
592
Benny Prijono9c025eb2006-07-10 21:35:27 +0000593
594/*
595 * Repeated connect/accept on the same listener socket.
596 */
Benny Prijonoe3f79fd2008-02-13 15:17:28 +0000597static int compliance_test_2(pj_bool_t allow_concur)
Benny Prijono9c025eb2006-07-10 21:35:27 +0000598{
Benny Prijonoaeeb1d12007-05-01 10:42:22 +0000599#if defined(PJ_SYMBIAN) && PJ_SYMBIAN!=0
600 enum { MAX_PAIR = 1, TEST_LOOP = 2 };
601#else
Benny Prijono9c025eb2006-07-10 21:35:27 +0000602 enum { MAX_PAIR = 4, TEST_LOOP = 2 };
Benny Prijonoaeeb1d12007-05-01 10:42:22 +0000603#endif
Benny Prijono9c025eb2006-07-10 21:35:27 +0000604
605 struct listener
606 {
607 pj_sock_t sock;
608 pj_ioqueue_key_t *key;
609 pj_sockaddr_in addr;
610 int addr_len;
611 } listener;
612
613 struct server
614 {
615 pj_sock_t sock;
616 pj_ioqueue_key_t *key;
617 pj_sockaddr_in local_addr;
618 pj_sockaddr_in rem_addr;
619 int rem_addr_len;
620 pj_ioqueue_op_key_t accept_op;
621 } server[MAX_PAIR];
622
623 struct client
624 {
625 pj_sock_t sock;
626 pj_ioqueue_key_t *key;
627 } client[MAX_PAIR];
628
629 pj_pool_t *pool = NULL;
630 char *send_buf, *recv_buf;
631 pj_ioqueue_t *ioque = NULL;
632 int i, bufsize = BUF_MIN_SIZE;
633 pj_ssize_t status;
634 int test_loop, pending_op = 0;
635 pj_timestamp t_elapsed;
636 pj_str_t s;
637 pj_status_t rc;
638
Benny Prijono8ab968f2007-07-20 08:08:30 +0000639 listener.sock = PJ_INVALID_SOCKET;
640 listener.key = NULL;
641
642 for (i=0; i<MAX_PAIR; ++i) {
643 server[i].sock = PJ_INVALID_SOCKET;
644 server[i].key = NULL;
645 }
646
647 for (i=0; i<MAX_PAIR; ++i) {
648 client[i].sock = PJ_INVALID_SOCKET;
649 client[i].key = NULL;
650 }
651
Benny Prijono9c025eb2006-07-10 21:35:27 +0000652 // Create pool.
653 pool = pj_pool_create(mem, NULL, POOL_SIZE, 4000, NULL);
654
655
656 // Create I/O Queue.
657 rc = pj_ioqueue_create(pool, PJ_IOQUEUE_MAX_HANDLES, &ioque);
658 if (rc != PJ_SUCCESS) {
659 app_perror("...ERROR in pj_ioqueue_create()", rc);
660 return -10;
661 }
662
663
Benny Prijonoe3f79fd2008-02-13 15:17:28 +0000664 // Concurrency
665 rc = pj_ioqueue_set_default_concurrency(ioque, allow_concur);
666 if (rc != PJ_SUCCESS) {
667 app_perror("...ERROR in pj_ioqueue_set_default_concurrency()", rc);
668 return -11;
669 }
670
Benny Prijono9c025eb2006-07-10 21:35:27 +0000671 // Allocate buffers for send and receive.
672 send_buf = (char*)pj_pool_alloc(pool, bufsize);
673 recv_buf = (char*)pj_pool_alloc(pool, bufsize);
674
675 // Create listener socket
Benny Prijono8ab968f2007-07-20 08:08:30 +0000676 rc = pj_sock_socket(pj_AF_INET(), pj_SOCK_STREAM(), 0, &listener.sock);
Benny Prijono9c025eb2006-07-10 21:35:27 +0000677 if (rc != PJ_SUCCESS) {
678 app_perror("...error creating socket", rc);
679 status=-20; goto on_error;
680 }
681
682 // Bind listener socket.
683 pj_sockaddr_in_init(&listener.addr, 0, 0);
684 if ((rc=pj_sock_bind(listener.sock, &listener.addr, sizeof(listener.addr))) != 0 ) {
685 app_perror("...bind error", rc);
686 status=-30; goto on_error;
687 }
688
689 // Get listener address.
690 listener.addr_len = sizeof(listener.addr);
691 rc = pj_sock_getsockname(listener.sock, &listener.addr, &listener.addr_len);
692 if (rc != PJ_SUCCESS) {
693 app_perror("...ERROR in pj_sock_getsockname()", rc);
694 status=-40; goto on_error;
695 }
696 listener.addr.sin_addr = pj_inet_addr(pj_cstr(&s, "127.0.0.1"));
697
698
699 // Register listener socket.
700 rc = pj_ioqueue_register_sock(pool, ioque, listener.sock, NULL, &test_cb,
701 &listener.key);
702 if (rc != PJ_SUCCESS) {
703 app_perror("...ERROR", rc);
704 status=-50; goto on_error;
705 }
706
707
708 // Listener socket listen().
709 if (pj_sock_listen(listener.sock, 5)) {
710 app_perror("...ERROR in pj_sock_listen()", rc);
711 status=-60; goto on_error;
712 }
713
714
715 for (test_loop=0; test_loop < TEST_LOOP; ++test_loop) {
716 // Client connect and server accept.
717 for (i=0; i<MAX_PAIR; ++i) {
Benny Prijono8ab968f2007-07-20 08:08:30 +0000718 rc = pj_sock_socket(pj_AF_INET(), pj_SOCK_STREAM(), 0, &client[i].sock);
Benny Prijono9c025eb2006-07-10 21:35:27 +0000719 if (rc != PJ_SUCCESS) {
720 app_perror("...error creating socket", rc);
721 status=-70; goto on_error;
722 }
723
724 rc = pj_ioqueue_register_sock(pool, ioque, client[i].sock, NULL,
725 &test_cb, &client[i].key);
726 if (rc != PJ_SUCCESS) {
727 app_perror("...error ", rc);
728 status=-80; goto on_error;
729 }
730
731 // Server socket accept()
732 pj_ioqueue_op_key_init(&server[i].accept_op,
733 sizeof(server[i].accept_op));
734 server[i].rem_addr_len = sizeof(pj_sockaddr_in);
735 status = pj_ioqueue_accept(listener.key, &server[i].accept_op,
736 &server[i].sock, &server[i].local_addr,
737 &server[i].rem_addr,
738 &server[i].rem_addr_len);
739 if (status!=PJ_SUCCESS && status != PJ_EPENDING) {
740 app_perror("...ERROR in pj_ioqueue_accept()", rc);
741 status=-90; goto on_error;
742 }
743 if (status==PJ_EPENDING) {
744 ++pending_op;
745 }
746
747
748 // Client socket connect()
749 status = pj_ioqueue_connect(client[i].key, &listener.addr,
750 sizeof(listener.addr));
751 if (status!=PJ_SUCCESS && status != PJ_EPENDING) {
752 app_perror("...ERROR in pj_ioqueue_connect()", rc);
753 status=-100; goto on_error;
754 }
755 if (status==PJ_EPENDING) {
756 ++pending_op;
757 }
758
759 }
760
761
762 // Poll until all connected
763 while (pending_op) {
764 pj_time_val timeout = {1, 0};
765
Benny Prijono8ab968f2007-07-20 08:08:30 +0000766#ifdef PJ_SYMBIAN
767 status = pj_symbianos_poll(-1, 1000);
768#else
769 status = pj_ioqueue_poll(ioque, &timeout);
770#endif
Benny Prijono9c025eb2006-07-10 21:35:27 +0000771 if (status > 0) {
772 if (status > pending_op) {
773 PJ_LOG(3,(THIS_FILE,
774 "...error: pj_ioqueue_poll() returned %d "
775 "(only expecting %d)",
776 status, pending_op));
777 return -110;
778 }
779 pending_op -= status;
780
781 if (pending_op == 0) {
782 status = 0;
783 }
784 }
785 }
786
787 // There's no pending operation.
788 // When we poll the ioqueue, there must not be events.
789 if (pending_op == 0) {
790 pj_time_val timeout = {1, 0};
Benny Prijono8ab968f2007-07-20 08:08:30 +0000791#ifdef PJ_SYMBIAN
792 status = pj_symbianos_poll(-1, 1000);
793#else
Benny Prijono9c025eb2006-07-10 21:35:27 +0000794 status = pj_ioqueue_poll(ioque, &timeout);
Benny Prijono8ab968f2007-07-20 08:08:30 +0000795#endif
Benny Prijono9c025eb2006-07-10 21:35:27 +0000796 if (status != 0) {
797 status=-120; goto on_error;
798 }
799 }
800
801 for (i=0; i<MAX_PAIR; ++i) {
802 // Check server socket.
803 if (server[i].sock == PJ_INVALID_SOCKET) {
804 status = -130;
805 app_perror("...accept() error", pj_get_os_error());
806 goto on_error;
807 }
808
809 // Check addresses
Benny Prijono8ab968f2007-07-20 08:08:30 +0000810 if (server[i].local_addr.sin_family != pj_AF_INET() ||
Benny Prijono9c025eb2006-07-10 21:35:27 +0000811 server[i].local_addr.sin_addr.s_addr == 0 ||
812 server[i].local_addr.sin_port == 0)
813 {
814 app_perror("...ERROR address not set", rc);
815 status = -140;
816 goto on_error;
817 }
818
Benny Prijono8ab968f2007-07-20 08:08:30 +0000819 if (server[i].rem_addr.sin_family != pj_AF_INET() ||
Benny Prijono9c025eb2006-07-10 21:35:27 +0000820 server[i].rem_addr.sin_addr.s_addr == 0 ||
821 server[i].rem_addr.sin_port == 0)
822 {
823 app_perror("...ERROR address not set", rc);
824 status = -150;
825 goto on_error;
826 }
827
828
829 // Register newly accepted socket.
830 rc = pj_ioqueue_register_sock(pool, ioque, server[i].sock, NULL,
831 &test_cb, &server[i].key);
832 if (rc != PJ_SUCCESS) {
833 app_perror("...ERROR in pj_ioqueue_register_sock", rc);
834 status = -160;
835 goto on_error;
836 }
837
838 // Test send and receive.
839 t_elapsed.u32.lo = 0;
840 status = send_recv_test(ioque, server[i].key, client[i].key,
841 send_buf, recv_buf, bufsize, &t_elapsed);
842 if (status != 0) {
843 goto on_error;
844 }
845 }
846
847 // Success
848 status = 0;
849
850 for (i=0; i<MAX_PAIR; ++i) {
851 if (server[i].key != NULL) {
852 pj_ioqueue_unregister(server[i].key);
853 server[i].key = NULL;
854 server[i].sock = PJ_INVALID_SOCKET;
855 } else if (server[i].sock != PJ_INVALID_SOCKET) {
856 pj_sock_close(server[i].sock);
857 server[i].sock = PJ_INVALID_SOCKET;
858 }
859
860 if (client[i].key != NULL) {
861 pj_ioqueue_unregister(client[i].key);
862 client[i].key = NULL;
863 client[i].sock = PJ_INVALID_SOCKET;
864 } else if (client[i].sock != PJ_INVALID_SOCKET) {
865 pj_sock_close(client[i].sock);
866 client[i].sock = PJ_INVALID_SOCKET;
867 }
868 }
869 }
870
871 status = 0;
872
873on_error:
874 for (i=0; i<MAX_PAIR; ++i) {
875 if (server[i].key != NULL) {
876 pj_ioqueue_unregister(server[i].key);
877 server[i].key = NULL;
878 server[i].sock = PJ_INVALID_SOCKET;
879 } else if (server[i].sock != PJ_INVALID_SOCKET) {
880 pj_sock_close(server[i].sock);
881 server[i].sock = PJ_INVALID_SOCKET;
882 }
883
884 if (client[i].key != NULL) {
885 pj_ioqueue_unregister(client[i].key);
886 client[i].key = NULL;
887 server[i].sock = PJ_INVALID_SOCKET;
888 } else if (client[i].sock != PJ_INVALID_SOCKET) {
889 pj_sock_close(client[i].sock);
890 client[i].sock = PJ_INVALID_SOCKET;
891 }
892 }
893
894 if (listener.key) {
895 pj_ioqueue_unregister(listener.key);
896 listener.key = NULL;
897 } else if (listener.sock != PJ_INVALID_SOCKET) {
898 pj_sock_close(listener.sock);
899 listener.sock = PJ_INVALID_SOCKET;
900 }
901
902 if (ioque != NULL)
903 pj_ioqueue_destroy(ioque);
904 pj_pool_release(pool);
905 return status;
906
907}
908
909
Benny Prijonoe3f79fd2008-02-13 15:17:28 +0000910static int tcp_ioqueue_test_impl(pj_bool_t allow_concur)
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000911{
912 int status;
913
Benny Prijonoe3f79fd2008-02-13 15:17:28 +0000914 PJ_LOG(3,(THIS_FILE, "..testing with concurency=%d", allow_concur));
915
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000916 PJ_LOG(3, (THIS_FILE, "..%s compliance test 0 (success scenario)",
917 pj_ioqueue_name()));
Benny Prijonoe3f79fd2008-02-13 15:17:28 +0000918 if ((status=compliance_test_0(allow_concur)) != 0) {
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000919 PJ_LOG(1, (THIS_FILE, "....FAILED (status=%d)\n", status));
920 return status;
921 }
922 PJ_LOG(3, (THIS_FILE, "..%s compliance test 1 (failed scenario)",
923 pj_ioqueue_name()));
Benny Prijonoe3f79fd2008-02-13 15:17:28 +0000924 if ((status=compliance_test_1(allow_concur)) != 0) {
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000925 PJ_LOG(1, (THIS_FILE, "....FAILED (status=%d)\n", status));
926 return status;
927 }
928
Benny Prijono9c025eb2006-07-10 21:35:27 +0000929 PJ_LOG(3, (THIS_FILE, "..%s compliance test 2 (repeated accept)",
930 pj_ioqueue_name()));
Benny Prijonoe3f79fd2008-02-13 15:17:28 +0000931 if ((status=compliance_test_2(allow_concur)) != 0) {
Benny Prijono9c025eb2006-07-10 21:35:27 +0000932 PJ_LOG(1, (THIS_FILE, "....FAILED (status=%d)\n", status));
933 return status;
934 }
935
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000936 return 0;
937}
938
Benny Prijonoe3f79fd2008-02-13 15:17:28 +0000939int tcp_ioqueue_test()
940{
941 int rc;
942
943 rc = tcp_ioqueue_test_impl(PJ_TRUE);
944 if (rc != 0)
945 return rc;
946
947 rc = tcp_ioqueue_test_impl(PJ_FALSE);
948 if (rc != 0)
949 return rc;
950
951 return 0;
952}
953
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000954#endif /* PJ_HAS_TCP */
955
956
957#else
958/* To prevent warning about "translation unit is empty"
959 * when this test is disabled.
960 */
961int dummy_uiq_tcp;
962#endif /* INCLUDE_TCP_IOQUEUE_TEST */
963
964