blob: ab3f9f3e81e7d6e9708a8f8c7adfcc26cb7d1664 [file] [log] [blame]
Nanang Izzuddinea6d3c42009-10-26 15:47:52 +00001/* $Id$ */
2/*
3 * Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com)
4 * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
5 *
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#include <pjlib.h>
22
Nanang Izzuddinea6d3c42009-10-26 15:47:52 +000023
Nanang Izzuddin6cfc6d52009-10-27 02:21:28 +000024#define CERT_DIR "../build/"
Nanang Izzuddin2fb937e2010-02-24 05:43:34 +000025#define CERT_CA_FILE CERT_DIR "cacert.pem"
Nanang Izzuddinea6d3c42009-10-26 15:47:52 +000026#define CERT_FILE CERT_DIR "cacert.pem"
27#define CERT_PRIVKEY_FILE CERT_DIR "privkey.pem"
28#define CERT_PRIVKEY_PASS ""
29
30
31#if INCLUDE_SSLSOCK_TEST
32
Nanang Izzuddinabce36a2009-11-03 14:29:31 +000033/* Global vars */
34static int clients_num;
Nanang Izzuddinea6d3c42009-10-26 15:47:52 +000035
36struct send_key {
37 pj_ioqueue_op_key_t op_key;
38};
39
40
41static int get_cipher_list(void) {
42 pj_status_t status;
43 pj_ssl_cipher ciphers[100];
44 unsigned cipher_num;
45 unsigned i;
46
47 cipher_num = PJ_ARRAY_SIZE(ciphers);
48 status = pj_ssl_cipher_get_availables(ciphers, &cipher_num);
49 if (status != PJ_SUCCESS) {
50 app_perror("...FAILED to get available ciphers", status);
Nanang Izzuddin6cfc6d52009-10-27 02:21:28 +000051 return status;
Nanang Izzuddinea6d3c42009-10-26 15:47:52 +000052 }
53
54 PJ_LOG(3, ("", "...Found %u ciphers:", cipher_num));
55 for (i = 0; i < cipher_num; ++i) {
56 const char* st;
57 st = pj_ssl_cipher_name(ciphers[i]);
58 if (st == NULL)
59 st = "[Unknown]";
60
61 PJ_LOG(3, ("", "...%3u: 0x%08x=%s", i+1, ciphers[i], st));
62 }
63
64 return PJ_SUCCESS;
65}
66
67
68struct test_state
69{
70 pj_pool_t *pool; /* pool */
Nanang Izzuddina7719d32010-03-06 02:04:52 +000071 pj_ioqueue_t *ioqueue; /* ioqueue */
Nanang Izzuddinabce36a2009-11-03 14:29:31 +000072 pj_bool_t is_server; /* server role flag */
73 pj_bool_t is_verbose; /* verbose flag, e.g: cert info */
Nanang Izzuddinea6d3c42009-10-26 15:47:52 +000074 pj_bool_t echo; /* echo received data */
75 pj_status_t err; /* error flag */
76 unsigned sent; /* bytes sent */
77 unsigned recv; /* bytes received */
78 pj_uint8_t read_buf[256]; /* read buffer */
79 pj_bool_t done; /* test done flag */
80 char *send_str; /* data to send once connected */
81 unsigned send_str_len; /* send data length */
82 pj_bool_t check_echo; /* flag to compare sent & echoed data */
83 const char *check_echo_ptr; /* pointer/cursor for comparing data */
84 struct send_key send_key; /* send op key */
85};
86
Nanang Izzuddin2fb937e2010-02-24 05:43:34 +000087static void dump_ssl_info(const pj_ssl_sock_info *si)
Nanang Izzuddinea6d3c42009-10-26 15:47:52 +000088{
Nanang Izzuddin2fb937e2010-02-24 05:43:34 +000089 const char *tmp_st;
Nanang Izzuddinea6d3c42009-10-26 15:47:52 +000090
Nanang Izzuddin2fb937e2010-02-24 05:43:34 +000091 /* Print cipher name */
92 tmp_st = pj_ssl_cipher_name(si->cipher);
93 if (tmp_st == NULL)
94 tmp_st = "[Unknown]";
95 PJ_LOG(3, ("", ".....Cipher: %s", tmp_st));
Nanang Izzuddinea6d3c42009-10-26 15:47:52 +000096
Nanang Izzuddin2fb937e2010-02-24 05:43:34 +000097 /* Print remote certificate info and verification result */
98 if (si->remote_cert_info && si->remote_cert_info->subject.info.slen)
99 {
100 char buf[2048];
101 const char *verif_msgs[32];
102 unsigned verif_msg_cnt;
103
104 /* Dump remote TLS certificate info */
105 PJ_LOG(3, ("", ".....Remote certificate info:"));
106 pj_ssl_cert_info_dump(si->remote_cert_info, " ", buf, sizeof(buf));
107 PJ_LOG(3,("", "\n%s", buf));
108
109 /* Dump remote TLS certificate verification result */
110 verif_msg_cnt = PJ_ARRAY_SIZE(verif_msgs);
Nanang Izzuddin5e69da52010-02-25 11:58:19 +0000111 pj_ssl_cert_get_verify_status_strings(si->verify_status,
112 verif_msgs, &verif_msg_cnt);
Nanang Izzuddin2fb937e2010-02-24 05:43:34 +0000113 PJ_LOG(3,("", ".....Remote certificate verification result: %s",
114 (verif_msg_cnt == 1? verif_msgs[0]:"")));
115 if (verif_msg_cnt > 1) {
116 unsigned i;
117 for (i = 0; i < verif_msg_cnt; ++i)
118 PJ_LOG(3,("", "..... - %s", verif_msgs[i]));
119 }
120 }
Nanang Izzuddinea6d3c42009-10-26 15:47:52 +0000121}
122
123
124static pj_bool_t ssl_on_connect_complete(pj_ssl_sock_t *ssock,
125 pj_status_t status)
126{
127 struct test_state *st = (struct test_state*)
128 pj_ssl_sock_get_user_data(ssock);
129 void *read_buf[1];
130 pj_ssl_sock_info info;
Nanang Izzuddinabce36a2009-11-03 14:29:31 +0000131 char buf1[64], buf2[64];
Nanang Izzuddinea6d3c42009-10-26 15:47:52 +0000132
133 if (status != PJ_SUCCESS) {
134 app_perror("...ERROR ssl_on_connect_complete()", status);
135 goto on_return;
136 }
137
138 status = pj_ssl_sock_get_info(ssock, &info);
139 if (status != PJ_SUCCESS) {
140 app_perror("...ERROR pj_ssl_sock_get_info()", status);
141 goto on_return;
142 }
143
Nanang Izzuddinabce36a2009-11-03 14:29:31 +0000144 pj_sockaddr_print((pj_sockaddr_t*)&info.local_addr, buf1, sizeof(buf1), 1);
145 pj_sockaddr_print((pj_sockaddr_t*)&info.remote_addr, buf2, sizeof(buf2), 1);
146 PJ_LOG(3, ("", "...Connected %s -> %s!", buf1, buf2));
Nanang Izzuddinea6d3c42009-10-26 15:47:52 +0000147
Nanang Izzuddin2fb937e2010-02-24 05:43:34 +0000148 if (st->is_verbose)
149 dump_ssl_info(&info);
Nanang Izzuddinea6d3c42009-10-26 15:47:52 +0000150
Nanang Izzuddin2d0f8fe2009-11-04 17:08:32 +0000151 /* Start reading data */
152 read_buf[0] = st->read_buf;
153 status = pj_ssl_sock_start_read2(ssock, st->pool, sizeof(st->read_buf), (void**)read_buf, 0);
154 if (status != PJ_SUCCESS) {
155 app_perror("...ERROR pj_ssl_sock_start_read2()", status);
156 goto on_return;
157 }
158
Nanang Izzuddinea6d3c42009-10-26 15:47:52 +0000159 /* Start sending data */
160 while (st->sent < st->send_str_len) {
161 pj_ssize_t size;
162
163 size = st->send_str_len - st->sent;
164 status = pj_ssl_sock_send(ssock, (pj_ioqueue_op_key_t*)&st->send_key,
165 st->send_str + st->sent, &size, 0);
166 if (status != PJ_SUCCESS && status != PJ_EPENDING) {
167 app_perror("...ERROR pj_ssl_sock_send()", status);
168 goto on_return;
169 }
170
171 if (status == PJ_SUCCESS)
172 st->sent += size;
173 else
174 break;
175 }
176
Nanang Izzuddinea6d3c42009-10-26 15:47:52 +0000177on_return:
178 st->err = status;
Nanang Izzuddinabce36a2009-11-03 14:29:31 +0000179
180 if (st->err != PJ_SUCCESS) {
181 pj_ssl_sock_close(ssock);
182 clients_num--;
183 return PJ_FALSE;
184 }
185
Nanang Izzuddinea6d3c42009-10-26 15:47:52 +0000186 return PJ_TRUE;
187}
188
189
190static pj_bool_t ssl_on_accept_complete(pj_ssl_sock_t *ssock,
191 pj_ssl_sock_t *newsock,
192 const pj_sockaddr_t *src_addr,
193 int src_addr_len)
194{
Nanang Izzuddinabce36a2009-11-03 14:29:31 +0000195 struct test_state *parent_st = (struct test_state*)
Nanang Izzuddin2d0f8fe2009-11-04 17:08:32 +0000196 pj_ssl_sock_get_user_data(ssock);
Nanang Izzuddinabce36a2009-11-03 14:29:31 +0000197 struct test_state *st;
Nanang Izzuddinea6d3c42009-10-26 15:47:52 +0000198 void *read_buf[1];
Nanang Izzuddin2fb937e2010-02-24 05:43:34 +0000199 pj_ssl_sock_info info;
200 char buf[64];
Nanang Izzuddinea6d3c42009-10-26 15:47:52 +0000201 pj_status_t status;
Nanang Izzuddinea6d3c42009-10-26 15:47:52 +0000202
203 PJ_UNUSED_ARG(src_addr_len);
204
Nanang Izzuddinabce36a2009-11-03 14:29:31 +0000205 /* Duplicate parent test state to newly accepted test state */
206 st = pj_pool_zalloc(parent_st->pool, sizeof(struct test_state));
207 *st = *parent_st;
Nanang Izzuddinea6d3c42009-10-26 15:47:52 +0000208 pj_ssl_sock_set_user_data(newsock, st);
209
Nanang Izzuddin2fb937e2010-02-24 05:43:34 +0000210 status = pj_ssl_sock_get_info(newsock, &info);
211 if (status != PJ_SUCCESS) {
212 app_perror("...ERROR pj_ssl_sock_get_info()", status);
213 goto on_return;
Nanang Izzuddinabce36a2009-11-03 14:29:31 +0000214 }
215
Nanang Izzuddin2fb937e2010-02-24 05:43:34 +0000216 pj_sockaddr_print(src_addr, buf, sizeof(buf), 1);
217 PJ_LOG(3, ("", "...Accepted connection from %s", buf));
218
219 if (st->is_verbose)
220 dump_ssl_info(&info);
221
Nanang Izzuddin2d0f8fe2009-11-04 17:08:32 +0000222 /* Start reading data */
223 read_buf[0] = st->read_buf;
224 status = pj_ssl_sock_start_read2(newsock, st->pool, sizeof(st->read_buf), (void**)read_buf, 0);
225 if (status != PJ_SUCCESS) {
226 app_perror("...ERROR pj_ssl_sock_start_read2()", status);
227 goto on_return;
228 }
229
Nanang Izzuddinea6d3c42009-10-26 15:47:52 +0000230 /* Start sending data */
231 while (st->sent < st->send_str_len) {
232 pj_ssize_t size;
233
234 size = st->send_str_len - st->sent;
Nanang Izzuddinabce36a2009-11-03 14:29:31 +0000235 status = pj_ssl_sock_send(newsock, (pj_ioqueue_op_key_t*)&st->send_key,
Nanang Izzuddinea6d3c42009-10-26 15:47:52 +0000236 st->send_str + st->sent, &size, 0);
237 if (status != PJ_SUCCESS && status != PJ_EPENDING) {
238 app_perror("...ERROR pj_ssl_sock_send()", status);
239 goto on_return;
240 }
241
242 if (status == PJ_SUCCESS)
243 st->sent += size;
244 else
245 break;
246 }
247
Nanang Izzuddinea6d3c42009-10-26 15:47:52 +0000248on_return:
249 st->err = status;
Nanang Izzuddinabce36a2009-11-03 14:29:31 +0000250
251 if (st->err != PJ_SUCCESS) {
252 pj_ssl_sock_close(newsock);
253 return PJ_FALSE;
254 }
255
Nanang Izzuddinea6d3c42009-10-26 15:47:52 +0000256 return PJ_TRUE;
257}
258
259static pj_bool_t ssl_on_data_read(pj_ssl_sock_t *ssock,
260 void *data,
261 pj_size_t size,
262 pj_status_t status,
263 pj_size_t *remainder)
264{
265 struct test_state *st = (struct test_state*)
266 pj_ssl_sock_get_user_data(ssock);
267
268 PJ_UNUSED_ARG(remainder);
269 PJ_UNUSED_ARG(data);
270
271 if (size > 0) {
272 pj_size_t consumed;
273
274 /* Set random remainder */
275 *remainder = pj_rand() % 100;
276
277 /* Apply zero remainder if:
278 * - remainder is less than size, or
279 * - connection closed/error
280 * - echo/check_eco set
281 */
282 if (*remainder > size || status != PJ_SUCCESS || st->echo || st->check_echo)
283 *remainder = 0;
284
285 consumed = size - *remainder;
286 st->recv += consumed;
287
288 //printf("%.*s", consumed, (char*)data);
289
290 pj_memmove(data, (char*)data + consumed, *remainder);
291
292 /* Echo data when specified to */
293 if (st->echo) {
294 pj_ssize_t size_ = consumed;
295 status = pj_ssl_sock_send(ssock, (pj_ioqueue_op_key_t*)&st->send_key, data, &size_, 0);
296 if (status != PJ_SUCCESS && status != PJ_EPENDING) {
297 app_perror("...ERROR pj_ssl_sock_send()", status);
298 goto on_return;
299 }
300
301 if (status == PJ_SUCCESS)
302 st->sent += size_;
303 }
304
305 /* Verify echoed data when specified to */
306 if (st->check_echo) {
307 if (!st->check_echo_ptr)
308 st->check_echo_ptr = st->send_str;
309
310 if (pj_memcmp(st->check_echo_ptr, data, consumed)) {
311 status = PJ_EINVAL;
312 app_perror("...ERROR echoed data not exact", status);
313 goto on_return;
314 }
315 st->check_echo_ptr += consumed;
316
Nanang Izzuddinabce36a2009-11-03 14:29:31 +0000317 /* Echo received completely */
318 if (st->send_str_len == st->recv) {
319 pj_ssl_sock_info info;
320 char buf[64];
321
322 status = pj_ssl_sock_get_info(ssock, &info);
323 if (status != PJ_SUCCESS) {
324 app_perror("...ERROR pj_ssl_sock_get_info()", status);
325 goto on_return;
326 }
327
328 pj_sockaddr_print((pj_sockaddr_t*)&info.local_addr, buf, sizeof(buf), 1);
329 PJ_LOG(3, ("", "...%s successfully recv %d bytes echo", buf, st->recv));
Nanang Izzuddinea6d3c42009-10-26 15:47:52 +0000330 st->done = PJ_TRUE;
Nanang Izzuddinabce36a2009-11-03 14:29:31 +0000331 }
Nanang Izzuddinea6d3c42009-10-26 15:47:52 +0000332 }
333 }
334
335 if (status != PJ_SUCCESS) {
336 if (status == PJ_EEOF) {
337 status = PJ_SUCCESS;
338 st->done = PJ_TRUE;
339 } else {
340 app_perror("...ERROR ssl_on_data_read()", status);
341 }
342 }
343
344on_return:
345 st->err = status;
Nanang Izzuddinabce36a2009-11-03 14:29:31 +0000346
347 if (st->err != PJ_SUCCESS || st->done) {
348 pj_ssl_sock_close(ssock);
349 if (!st->is_server)
350 clients_num--;
351 return PJ_FALSE;
352 }
353
Nanang Izzuddinea6d3c42009-10-26 15:47:52 +0000354 return PJ_TRUE;
355}
356
357static pj_bool_t ssl_on_data_sent(pj_ssl_sock_t *ssock,
358 pj_ioqueue_op_key_t *op_key,
359 pj_ssize_t sent)
360{
361 struct test_state *st = (struct test_state*)
362 pj_ssl_sock_get_user_data(ssock);
363 PJ_UNUSED_ARG(op_key);
364
Nanang Izzuddinabce36a2009-11-03 14:29:31 +0000365 if (sent < 0) {
366 st->err = -sent;
Nanang Izzuddinea6d3c42009-10-26 15:47:52 +0000367 } else {
368 st->sent += sent;
369
370 /* Send more if any */
371 while (st->sent < st->send_str_len) {
372 pj_ssize_t size;
373 pj_status_t status;
374
375 size = st->send_str_len - st->sent;
376 status = pj_ssl_sock_send(ssock, (pj_ioqueue_op_key_t*)&st->send_key,
377 st->send_str + st->sent, &size, 0);
378 if (status != PJ_SUCCESS && status != PJ_EPENDING) {
379 app_perror("...ERROR pj_ssl_sock_send()", status);
Nanang Izzuddinabce36a2009-11-03 14:29:31 +0000380 st->err = status;
Nanang Izzuddinea6d3c42009-10-26 15:47:52 +0000381 break;
382 }
383
384 if (status == PJ_SUCCESS)
385 st->sent += size;
386 else
387 break;
388 }
389 }
390
Nanang Izzuddinabce36a2009-11-03 14:29:31 +0000391 if (st->err != PJ_SUCCESS) {
392 pj_ssl_sock_close(ssock);
393 if (!st->is_server)
394 clients_num--;
395 return PJ_FALSE;
396 }
397
Nanang Izzuddinea6d3c42009-10-26 15:47:52 +0000398 return PJ_TRUE;
399}
400
401#define HTTP_REQ "GET / HTTP/1.0\r\n\r\n";
402#define HTTP_SERVER_ADDR "trac.pjsip.org"
403#define HTTP_SERVER_PORT 443
404
Nanang Izzuddin2d0f8fe2009-11-04 17:08:32 +0000405static int https_client_test(unsigned ms_timeout)
Nanang Izzuddinea6d3c42009-10-26 15:47:52 +0000406{
407 pj_pool_t *pool = NULL;
408 pj_ioqueue_t *ioqueue = NULL;
Nanang Izzuddin2d0f8fe2009-11-04 17:08:32 +0000409 pj_timer_heap_t *timer = NULL;
Nanang Izzuddinea6d3c42009-10-26 15:47:52 +0000410 pj_ssl_sock_t *ssock = NULL;
411 pj_ssl_sock_param param;
412 pj_status_t status;
413 struct test_state state = {0};
414 pj_sockaddr local_addr, rem_addr;
415 pj_str_t tmp_st;
416
Nanang Izzuddinabce36a2009-11-03 14:29:31 +0000417 pool = pj_pool_create(mem, "https_get", 256, 256, NULL);
Nanang Izzuddinea6d3c42009-10-26 15:47:52 +0000418
419 status = pj_ioqueue_create(pool, 4, &ioqueue);
420 if (status != PJ_SUCCESS) {
421 goto on_return;
422 }
423
Nanang Izzuddin2d0f8fe2009-11-04 17:08:32 +0000424 status = pj_timer_heap_create(pool, 4, &timer);
425 if (status != PJ_SUCCESS) {
426 goto on_return;
427 }
428
Nanang Izzuddinea6d3c42009-10-26 15:47:52 +0000429 state.pool = pool;
430 state.send_str = HTTP_REQ;
431 state.send_str_len = pj_ansi_strlen(state.send_str);
Nanang Izzuddinabce36a2009-11-03 14:29:31 +0000432 state.is_verbose = PJ_TRUE;
Nanang Izzuddinea6d3c42009-10-26 15:47:52 +0000433
434 pj_ssl_sock_param_default(&param);
435 param.cb.on_connect_complete = &ssl_on_connect_complete;
436 param.cb.on_data_read = &ssl_on_data_read;
437 param.cb.on_data_sent = &ssl_on_data_sent;
438 param.ioqueue = ioqueue;
439 param.user_data = &state;
440 param.server_name = pj_str((char*)HTTP_SERVER_ADDR);
Nanang Izzuddin2d0f8fe2009-11-04 17:08:32 +0000441 param.timer_heap = timer;
442 param.timeout.sec = 0;
443 param.timeout.msec = ms_timeout;
Nanang Izzuddin2fb937e2010-02-24 05:43:34 +0000444 param.proto = PJ_SSL_SOCK_PROTO_SSL23;
Nanang Izzuddin2d0f8fe2009-11-04 17:08:32 +0000445 pj_time_val_normalize(&param.timeout);
Nanang Izzuddinea6d3c42009-10-26 15:47:52 +0000446
447 status = pj_ssl_sock_create(pool, &param, &ssock);
448 if (status != PJ_SUCCESS) {
449 goto on_return;
450 }
451
452 pj_sockaddr_init(PJ_AF_INET, &local_addr, pj_strset2(&tmp_st, "0.0.0.0"), 0);
453 pj_sockaddr_init(PJ_AF_INET, &rem_addr, pj_strset2(&tmp_st, HTTP_SERVER_ADDR), HTTP_SERVER_PORT);
454 status = pj_ssl_sock_start_connect(ssock, pool, &local_addr, &rem_addr, sizeof(rem_addr));
455 if (status == PJ_SUCCESS) {
456 ssl_on_connect_complete(ssock, PJ_SUCCESS);
457 } else if (status == PJ_EPENDING) {
458 status = PJ_SUCCESS;
459 } else {
460 goto on_return;
461 }
462
463 /* Wait until everything has been sent/received */
464 while (state.err == PJ_SUCCESS && !state.done) {
465#ifdef PJ_SYMBIAN
466 pj_symbianos_poll(-1, 1000);
467#else
468 pj_time_val delay = {0, 100};
469 pj_ioqueue_poll(ioqueue, &delay);
Nanang Izzuddin2d0f8fe2009-11-04 17:08:32 +0000470 pj_timer_heap_poll(timer, &delay);
Nanang Izzuddinea6d3c42009-10-26 15:47:52 +0000471#endif
472 }
473
474 if (state.err) {
475 status = state.err;
476 goto on_return;
477 }
478
479 PJ_LOG(3, ("", "...Done!"));
480 PJ_LOG(3, ("", ".....Sent/recv: %d/%d bytes", state.sent, state.recv));
481
482on_return:
Nanang Izzuddinabce36a2009-11-03 14:29:31 +0000483 if (ssock && !state.err && !state.done)
Nanang Izzuddinea6d3c42009-10-26 15:47:52 +0000484 pj_ssl_sock_close(ssock);
485 if (ioqueue)
486 pj_ioqueue_destroy(ioqueue);
Nanang Izzuddin2d0f8fe2009-11-04 17:08:32 +0000487 if (timer)
488 pj_timer_heap_destroy(timer);
Nanang Izzuddinea6d3c42009-10-26 15:47:52 +0000489 if (pool)
490 pj_pool_release(pool);
491
492 return status;
493}
494
495
Nanang Izzuddinabce36a2009-11-03 14:29:31 +0000496static int echo_test(pj_ssl_sock_proto srv_proto, pj_ssl_sock_proto cli_proto,
Nanang Izzuddin2fb937e2010-02-24 05:43:34 +0000497 pj_ssl_cipher srv_cipher, pj_ssl_cipher cli_cipher,
498 pj_bool_t req_client_cert, pj_bool_t client_provide_cert)
Nanang Izzuddinea6d3c42009-10-26 15:47:52 +0000499{
500 pj_pool_t *pool = NULL;
501 pj_ioqueue_t *ioqueue = NULL;
502 pj_ssl_sock_t *ssock_serv = NULL;
503 pj_ssl_sock_t *ssock_cli = NULL;
504 pj_ssl_sock_param param;
505 struct test_state state_serv = { 0 };
506 struct test_state state_cli = { 0 };
Nanang Izzuddinabce36a2009-11-03 14:29:31 +0000507 pj_sockaddr addr, listen_addr;
Nanang Izzuddinea6d3c42009-10-26 15:47:52 +0000508 pj_ssl_cipher ciphers[1];
509 pj_ssl_cert_t *cert = NULL;
510 pj_status_t status;
511
Nanang Izzuddinabce36a2009-11-03 14:29:31 +0000512 pool = pj_pool_create(mem, "ssl_echo", 256, 256, NULL);
Nanang Izzuddinea6d3c42009-10-26 15:47:52 +0000513
514 status = pj_ioqueue_create(pool, 4, &ioqueue);
515 if (status != PJ_SUCCESS) {
516 goto on_return;
517 }
518
Nanang Izzuddinea6d3c42009-10-26 15:47:52 +0000519 pj_ssl_sock_param_default(&param);
Nanang Izzuddinea6d3c42009-10-26 15:47:52 +0000520 param.cb.on_accept_complete = &ssl_on_accept_complete;
521 param.cb.on_connect_complete = &ssl_on_connect_complete;
522 param.cb.on_data_read = &ssl_on_data_read;
523 param.cb.on_data_sent = &ssl_on_data_sent;
524 param.ioqueue = ioqueue;
Nanang Izzuddinea6d3c42009-10-26 15:47:52 +0000525 param.ciphers = ciphers;
526
Nanang Izzuddinabce36a2009-11-03 14:29:31 +0000527 /* Init default bind address */
528 {
529 pj_str_t tmp_st;
530 pj_sockaddr_init(PJ_AF_INET, &addr, pj_strset2(&tmp_st, "127.0.0.1"), 0);
531 }
532
Nanang Izzuddin2fb937e2010-02-24 05:43:34 +0000533 /* === SERVER === */
Nanang Izzuddinabce36a2009-11-03 14:29:31 +0000534 param.proto = srv_proto;
Nanang Izzuddinea6d3c42009-10-26 15:47:52 +0000535 param.user_data = &state_serv;
Nanang Izzuddinabce36a2009-11-03 14:29:31 +0000536 param.ciphers_num = (srv_cipher == -1)? 0 : 1;
Nanang Izzuddin2fb937e2010-02-24 05:43:34 +0000537 param.require_client_cert = req_client_cert;
Nanang Izzuddinea6d3c42009-10-26 15:47:52 +0000538 ciphers[0] = srv_cipher;
539
540 state_serv.pool = pool;
541 state_serv.echo = PJ_TRUE;
Nanang Izzuddinabce36a2009-11-03 14:29:31 +0000542 state_serv.is_server = PJ_TRUE;
543 state_serv.is_verbose = PJ_TRUE;
Nanang Izzuddinea6d3c42009-10-26 15:47:52 +0000544
545 status = pj_ssl_sock_create(pool, &param, &ssock_serv);
546 if (status != PJ_SUCCESS) {
547 goto on_return;
548 }
549
Nanang Izzuddin2fb937e2010-02-24 05:43:34 +0000550 /* Set server cert */
551 {
552 pj_str_t tmp1, tmp2, tmp3, tmp4;
553
554 status = pj_ssl_cert_load_from_files(pool,
555 pj_strset2(&tmp1, (char*)CERT_CA_FILE),
556 pj_strset2(&tmp2, (char*)CERT_FILE),
557 pj_strset2(&tmp3, (char*)CERT_PRIVKEY_FILE),
558 pj_strset2(&tmp4, (char*)CERT_PRIVKEY_PASS),
559 &cert);
560 if (status != PJ_SUCCESS) {
561 goto on_return;
562 }
563
564 status = pj_ssl_sock_set_certificate(ssock_serv, pool, cert);
565 if (status != PJ_SUCCESS) {
566 goto on_return;
567 }
Nanang Izzuddinea6d3c42009-10-26 15:47:52 +0000568 }
569
Nanang Izzuddinabce36a2009-11-03 14:29:31 +0000570 status = pj_ssl_sock_start_accept(ssock_serv, pool, &addr, pj_sockaddr_get_len(&addr));
Nanang Izzuddinea6d3c42009-10-26 15:47:52 +0000571 if (status != PJ_SUCCESS) {
572 goto on_return;
573 }
574
Nanang Izzuddinabce36a2009-11-03 14:29:31 +0000575 /* Get listener address */
576 {
577 pj_ssl_sock_info info;
578
579 pj_ssl_sock_get_info(ssock_serv, &info);
580 pj_sockaddr_cp(&listen_addr, &info.local_addr);
581 }
582
Nanang Izzuddin2fb937e2010-02-24 05:43:34 +0000583 /* === CLIENT === */
Nanang Izzuddinabce36a2009-11-03 14:29:31 +0000584 param.proto = cli_proto;
Nanang Izzuddinea6d3c42009-10-26 15:47:52 +0000585 param.user_data = &state_cli;
Nanang Izzuddinabce36a2009-11-03 14:29:31 +0000586 param.ciphers_num = (cli_cipher == -1)? 0 : 1;
Nanang Izzuddinea6d3c42009-10-26 15:47:52 +0000587 ciphers[0] = cli_cipher;
588
589 state_cli.pool = pool;
590 state_cli.check_echo = PJ_TRUE;
Nanang Izzuddinabce36a2009-11-03 14:29:31 +0000591 state_cli.is_verbose = PJ_TRUE;
Nanang Izzuddinea6d3c42009-10-26 15:47:52 +0000592
593 {
594 pj_time_val now;
595
596 pj_gettimeofday(&now);
Nanang Izzuddineef9b8d2009-11-06 13:31:37 +0000597 pj_srand((unsigned)now.sec);
Nanang Izzuddinea6d3c42009-10-26 15:47:52 +0000598 state_cli.send_str_len = (pj_rand() % 5 + 1) * 1024 + pj_rand() % 1024;
599 }
600 state_cli.send_str = pj_pool_alloc(pool, state_cli.send_str_len);
601 {
602 unsigned i;
603 for (i = 0; i < state_cli.send_str_len; ++i)
604 state_cli.send_str[i] = (char)(pj_rand() % 256);
605 }
606
607 status = pj_ssl_sock_create(pool, &param, &ssock_cli);
608 if (status != PJ_SUCCESS) {
609 goto on_return;
610 }
611
Nanang Izzuddin2fb937e2010-02-24 05:43:34 +0000612 /* Set cert for client */
613 {
614
615 if (!client_provide_cert) {
616 pj_str_t tmp1, tmp2;
617
618 pj_strset2(&tmp1, (char*)CERT_CA_FILE);
619 pj_strset2(&tmp2, NULL);
620 status = pj_ssl_cert_load_from_files(pool,
621 &tmp1, &tmp2, &tmp2, &tmp2,
622 &cert);
623 if (status != PJ_SUCCESS) {
624 goto on_return;
625 }
626 }
627
628 status = pj_ssl_sock_set_certificate(ssock_cli, pool, cert);
629 if (status != PJ_SUCCESS) {
630 goto on_return;
631 }
632 }
633
Nanang Izzuddinabce36a2009-11-03 14:29:31 +0000634 status = pj_ssl_sock_start_connect(ssock_cli, pool, &addr, &listen_addr, pj_sockaddr_get_len(&addr));
Nanang Izzuddinea6d3c42009-10-26 15:47:52 +0000635 if (status == PJ_SUCCESS) {
636 ssl_on_connect_complete(ssock_cli, PJ_SUCCESS);
637 } else if (status == PJ_EPENDING) {
638 status = PJ_SUCCESS;
639 } else {
640 goto on_return;
641 }
642
643 /* Wait until everything has been sent/received or error */
644 while (!state_serv.err && !state_cli.err && !state_serv.done && !state_cli.done)
645 {
646#ifdef PJ_SYMBIAN
647 pj_symbianos_poll(-1, 1000);
648#else
649 pj_time_val delay = {0, 100};
650 pj_ioqueue_poll(ioqueue, &delay);
651#endif
652 }
653
Nanang Izzuddin2d0f8fe2009-11-04 17:08:32 +0000654 /* Clean up sockets */
655 {
656 pj_time_val delay = {0, 100};
657 while (pj_ioqueue_poll(ioqueue, &delay) > 0);
658 }
659
Nanang Izzuddinea6d3c42009-10-26 15:47:52 +0000660 if (state_serv.err || state_cli.err) {
661 if (state_serv.err != PJ_SUCCESS)
662 status = state_serv.err;
663 else
664 status = state_cli.err;
665
666 goto on_return;
667 }
668
669 PJ_LOG(3, ("", "...Done!"));
Nanang Izzuddinabce36a2009-11-03 14:29:31 +0000670 PJ_LOG(3, ("", ".....Sent/recv: %d/%d bytes", state_cli.sent, state_cli.recv));
Nanang Izzuddinea6d3c42009-10-26 15:47:52 +0000671
672on_return:
Nanang Izzuddinabce36a2009-11-03 14:29:31 +0000673 if (ssock_serv)
Nanang Izzuddinea6d3c42009-10-26 15:47:52 +0000674 pj_ssl_sock_close(ssock_serv);
Nanang Izzuddinabce36a2009-11-03 14:29:31 +0000675 if (ssock_cli && !state_cli.err && !state_cli.done)
Nanang Izzuddinea6d3c42009-10-26 15:47:52 +0000676 pj_ssl_sock_close(ssock_cli);
677 if (ioqueue)
678 pj_ioqueue_destroy(ioqueue);
679 if (pool)
680 pj_pool_release(pool);
681
682 return status;
683}
684
685
686static pj_bool_t asock_on_data_read(pj_activesock_t *asock,
687 void *data,
688 pj_size_t size,
689 pj_status_t status,
690 pj_size_t *remainder)
691{
692 struct test_state *st = (struct test_state*)
693 pj_activesock_get_user_data(asock);
694
695 PJ_UNUSED_ARG(data);
696 PJ_UNUSED_ARG(size);
697 PJ_UNUSED_ARG(remainder);
698
699 if (status != PJ_SUCCESS) {
700 if (status == PJ_EEOF) {
701 status = PJ_SUCCESS;
702 st->done = PJ_TRUE;
703 } else {
704 app_perror("...ERROR asock_on_data_read()", status);
705 }
706 }
707
708 st->err = status;
709
Nanang Izzuddin2d0f8fe2009-11-04 17:08:32 +0000710 if (st->err != PJ_SUCCESS || st->done) {
711 pj_activesock_close(asock);
712 if (!st->is_server)
713 clients_num--;
714 return PJ_FALSE;
715 }
716
Nanang Izzuddinea6d3c42009-10-26 15:47:52 +0000717 return PJ_TRUE;
718}
719
720
721static pj_bool_t asock_on_connect_complete(pj_activesock_t *asock,
722 pj_status_t status)
723{
724 struct test_state *st = (struct test_state*)
725 pj_activesock_get_user_data(asock);
726
727 if (status == PJ_SUCCESS) {
Nanang Izzuddin2d0f8fe2009-11-04 17:08:32 +0000728 void *read_buf[1];
729
730 /* Start reading data */
731 read_buf[0] = st->read_buf;
732 status = pj_activesock_start_read2(asock, st->pool, sizeof(st->read_buf), (void**)read_buf, 0);
733 if (status != PJ_SUCCESS) {
734 app_perror("...ERROR pj_ssl_sock_start_read2()", status);
735 }
Nanang Izzuddinea6d3c42009-10-26 15:47:52 +0000736 }
737
738 st->err = status;
739
Nanang Izzuddin2d0f8fe2009-11-04 17:08:32 +0000740 if (st->err != PJ_SUCCESS) {
741 pj_activesock_close(asock);
742 if (!st->is_server)
743 clients_num--;
744 return PJ_FALSE;
745 }
746
Nanang Izzuddinea6d3c42009-10-26 15:47:52 +0000747 return PJ_TRUE;
748}
749
Nanang Izzuddina7719d32010-03-06 02:04:52 +0000750static pj_bool_t asock_on_accept_complete(pj_activesock_t *asock,
751 pj_sock_t newsock,
752 const pj_sockaddr_t *src_addr,
753 int src_addr_len)
754{
755 struct test_state *st;
756 void *read_buf[1];
757 pj_activesock_t *new_asock;
758 pj_activesock_cb asock_cb = { 0 };
759 pj_status_t status;
760
761 PJ_UNUSED_ARG(src_addr);
762 PJ_UNUSED_ARG(src_addr_len);
763
764 st = (struct test_state*) pj_activesock_get_user_data(asock);
765
766 asock_cb.on_data_read = &asock_on_data_read;
767 status = pj_activesock_create(st->pool, newsock, pj_SOCK_STREAM(), NULL,
768 st->ioqueue, &asock_cb, st, &new_asock);
769 if (status != PJ_SUCCESS) {
770 goto on_return;
771 }
772
773 /* Start reading data */
774 read_buf[0] = st->read_buf;
775 status = pj_activesock_start_read2(new_asock, st->pool,
776 sizeof(st->read_buf),
777 (void**)read_buf, 0);
778 if (status != PJ_SUCCESS) {
779 app_perror("...ERROR pj_ssl_sock_start_read2()", status);
780 }
781
782on_return:
783 st->err = status;
784
785 if (st->err != PJ_SUCCESS)
786 pj_activesock_close(new_asock);
787
788 return PJ_TRUE;
789}
790
Nanang Izzuddinea6d3c42009-10-26 15:47:52 +0000791
Nanang Izzuddinabce36a2009-11-03 14:29:31 +0000792/* Raw TCP socket try to connect to SSL socket server, once
793 * connection established, it will just do nothing, SSL socket
794 * server should be able to close the connection after specified
795 * timeout period (set ms_timeout to 0 to disable timer).
796 */
Nanang Izzuddinea6d3c42009-10-26 15:47:52 +0000797static int client_non_ssl(unsigned ms_timeout)
798{
799 pj_pool_t *pool = NULL;
800 pj_ioqueue_t *ioqueue = NULL;
801 pj_timer_heap_t *timer = NULL;
802 pj_ssl_sock_t *ssock_serv = NULL;
803 pj_activesock_t *asock_cli = NULL;
804 pj_activesock_cb asock_cb = { 0 };
805 pj_sock_t sock = PJ_INVALID_SOCKET;
806 pj_ssl_sock_param param;
807 struct test_state state_serv = { 0 };
808 struct test_state state_cli = { 0 };
809 pj_sockaddr listen_addr;
Nanang Izzuddinea6d3c42009-10-26 15:47:52 +0000810 pj_ssl_cert_t *cert = NULL;
811 pj_status_t status;
812
Nanang Izzuddinabce36a2009-11-03 14:29:31 +0000813 pool = pj_pool_create(mem, "ssl_accept_raw_tcp", 256, 256, NULL);
Nanang Izzuddinea6d3c42009-10-26 15:47:52 +0000814
815 status = pj_ioqueue_create(pool, 4, &ioqueue);
816 if (status != PJ_SUCCESS) {
817 goto on_return;
818 }
819
820 status = pj_timer_heap_create(pool, 4, &timer);
821 if (status != PJ_SUCCESS) {
822 goto on_return;
823 }
824
825 /* Set cert */
826 {
827 pj_str_t tmp1, tmp2, tmp3, tmp4;
828 status = pj_ssl_cert_load_from_files(pool,
829 pj_strset2(&tmp1, (char*)CERT_CA_FILE),
830 pj_strset2(&tmp2, (char*)CERT_FILE),
831 pj_strset2(&tmp3, (char*)CERT_PRIVKEY_FILE),
832 pj_strset2(&tmp4, (char*)CERT_PRIVKEY_PASS),
833 &cert);
834 if (status != PJ_SUCCESS) {
835 goto on_return;
836 }
837 }
838
839 pj_ssl_sock_param_default(&param);
840 param.cb.on_accept_complete = &ssl_on_accept_complete;
841 param.cb.on_data_read = &ssl_on_data_read;
842 param.cb.on_data_sent = &ssl_on_data_sent;
843 param.ioqueue = ioqueue;
Nanang Izzuddin6cfc6d52009-10-27 02:21:28 +0000844 param.timer_heap = timer;
Nanang Izzuddinea6d3c42009-10-26 15:47:52 +0000845 param.timeout.sec = 0;
846 param.timeout.msec = ms_timeout;
Nanang Izzuddinea6d3c42009-10-26 15:47:52 +0000847 pj_time_val_normalize(&param.timeout);
848
849 /* SERVER */
850 param.user_data = &state_serv;
851 state_serv.pool = pool;
Nanang Izzuddinabce36a2009-11-03 14:29:31 +0000852 state_serv.is_server = PJ_TRUE;
853 state_serv.is_verbose = PJ_TRUE;
Nanang Izzuddinea6d3c42009-10-26 15:47:52 +0000854
855 status = pj_ssl_sock_create(pool, &param, &ssock_serv);
856 if (status != PJ_SUCCESS) {
857 goto on_return;
858 }
859
860 status = pj_ssl_sock_set_certificate(ssock_serv, pool, cert);
861 if (status != PJ_SUCCESS) {
862 goto on_return;
863 }
864
Nanang Izzuddinabce36a2009-11-03 14:29:31 +0000865 /* Init bind address */
866 {
867 pj_str_t tmp_st;
868 pj_sockaddr_init(PJ_AF_INET, &listen_addr, pj_strset2(&tmp_st, "127.0.0.1"), 0);
869 }
870
Nanang Izzuddin6cfc6d52009-10-27 02:21:28 +0000871 status = pj_ssl_sock_start_accept(ssock_serv, pool, &listen_addr, pj_sockaddr_get_len(&listen_addr));
Nanang Izzuddinea6d3c42009-10-26 15:47:52 +0000872 if (status != PJ_SUCCESS) {
873 goto on_return;
874 }
875
Nanang Izzuddinabce36a2009-11-03 14:29:31 +0000876 /* Update listener address */
Nanang Izzuddin6cfc6d52009-10-27 02:21:28 +0000877 {
878 pj_ssl_sock_info info;
879
880 pj_ssl_sock_get_info(ssock_serv, &info);
881 pj_sockaddr_cp(&listen_addr, &info.local_addr);
882 }
883
Nanang Izzuddinea6d3c42009-10-26 15:47:52 +0000884 /* CLIENT */
885 state_cli.pool = pool;
886 status = pj_sock_socket(pj_AF_INET(), pj_SOCK_STREAM(), 0, &sock);
887 if (status != PJ_SUCCESS) {
888 goto on_return;
889 }
890
891 asock_cb.on_connect_complete = &asock_on_connect_complete;
892 asock_cb.on_data_read = &asock_on_data_read;
893 status = pj_activesock_create(pool, sock, pj_SOCK_STREAM(), NULL,
894 ioqueue, &asock_cb, &state_cli, &asock_cli);
895 if (status != PJ_SUCCESS) {
896 goto on_return;
897 }
898
899 status = pj_activesock_start_connect(asock_cli, pool, (pj_sockaddr_t*)&listen_addr,
900 pj_sockaddr_get_len(&listen_addr));
901 if (status == PJ_SUCCESS) {
902 asock_on_connect_complete(asock_cli, PJ_SUCCESS);
903 } else if (status == PJ_EPENDING) {
904 status = PJ_SUCCESS;
905 } else {
906 goto on_return;
907 }
908
909 /* Wait until everything has been sent/received or error */
910 while (!state_serv.err && !state_cli.err && !state_serv.done && !state_cli.done)
911 {
912#ifdef PJ_SYMBIAN
913 pj_symbianos_poll(-1, 1000);
914#else
915 pj_time_val delay = {0, 100};
916 pj_ioqueue_poll(ioqueue, &delay);
917 pj_timer_heap_poll(timer, &delay);
918#endif
919 }
920
921 if (state_serv.err || state_cli.err) {
922 if (state_serv.err != PJ_SUCCESS)
923 status = state_serv.err;
924 else
925 status = state_cli.err;
926
927 goto on_return;
928 }
929
930 PJ_LOG(3, ("", "...Done!"));
931
932on_return:
Nanang Izzuddinabce36a2009-11-03 14:29:31 +0000933 if (ssock_serv)
Nanang Izzuddinea6d3c42009-10-26 15:47:52 +0000934 pj_ssl_sock_close(ssock_serv);
Nanang Izzuddin2d0f8fe2009-11-04 17:08:32 +0000935 if (asock_cli && !state_cli.err && !state_cli.done)
Nanang Izzuddinea6d3c42009-10-26 15:47:52 +0000936 pj_activesock_close(asock_cli);
937 if (timer)
938 pj_timer_heap_destroy(timer);
939 if (ioqueue)
940 pj_ioqueue_destroy(ioqueue);
941 if (pool)
942 pj_pool_release(pool);
943
944 return status;
945}
946
947
Nanang Izzuddina7719d32010-03-06 02:04:52 +0000948/* SSL socket try to connect to raw TCP socket server, once
949 * connection established, SSL socket will try to perform SSL
950 * handshake. SSL client socket should be able to close the
951 * connection after specified timeout period (set ms_timeout to
952 * 0 to disable timer).
953 */
954static int server_non_ssl(unsigned ms_timeout)
955{
956 pj_pool_t *pool = NULL;
957 pj_ioqueue_t *ioqueue = NULL;
958 pj_timer_heap_t *timer = NULL;
959 pj_activesock_t *asock_serv = NULL;
960 pj_ssl_sock_t *ssock_cli = NULL;
961 pj_activesock_cb asock_cb = { 0 };
962 pj_sock_t sock = PJ_INVALID_SOCKET;
963 pj_ssl_sock_param param;
964 struct test_state state_serv = { 0 };
965 struct test_state state_cli = { 0 };
966 pj_sockaddr addr, listen_addr;
967 pj_status_t status;
968
969 pool = pj_pool_create(mem, "ssl_connect_raw_tcp", 256, 256, NULL);
970
971 status = pj_ioqueue_create(pool, 4, &ioqueue);
972 if (status != PJ_SUCCESS) {
973 goto on_return;
974 }
975
976 status = pj_timer_heap_create(pool, 4, &timer);
977 if (status != PJ_SUCCESS) {
978 goto on_return;
979 }
980
981 /* SERVER */
982 state_serv.pool = pool;
983 state_serv.ioqueue = ioqueue;
984
985 status = pj_sock_socket(pj_AF_INET(), pj_SOCK_STREAM(), 0, &sock);
986 if (status != PJ_SUCCESS) {
987 goto on_return;
988 }
989
990 /* Init bind address */
991 {
992 pj_str_t tmp_st;
993 pj_sockaddr_init(PJ_AF_INET, &listen_addr, pj_strset2(&tmp_st, "127.0.0.1"), 0);
994 }
995
996 status = pj_sock_bind(sock, (pj_sockaddr_t*)&listen_addr,
997 pj_sockaddr_get_len((pj_sockaddr_t*)&listen_addr));
998 if (status != PJ_SUCCESS) {
999 goto on_return;
1000 }
1001
1002 status = pj_sock_listen(sock, PJ_SOMAXCONN);
1003 if (status != PJ_SUCCESS) {
1004 goto on_return;
1005 }
1006
1007 asock_cb.on_accept_complete = &asock_on_accept_complete;
1008 status = pj_activesock_create(pool, sock, pj_SOCK_STREAM(), NULL,
1009 ioqueue, &asock_cb, &state_serv, &asock_serv);
1010 if (status != PJ_SUCCESS) {
1011 goto on_return;
1012 }
1013
1014 status = pj_activesock_start_accept(asock_serv, pool);
1015 if (status != PJ_SUCCESS)
1016 goto on_return;
1017
1018 /* Update listener address */
1019 {
1020 int addr_len;
1021
1022 addr_len = sizeof(listen_addr);
1023 pj_sock_getsockname(sock, (pj_sockaddr_t*)&listen_addr, &addr_len);
1024 }
1025
1026 /* CLIENT */
1027 pj_ssl_sock_param_default(&param);
1028 param.cb.on_connect_complete = &ssl_on_connect_complete;
1029 param.cb.on_data_read = &ssl_on_data_read;
1030 param.cb.on_data_sent = &ssl_on_data_sent;
1031 param.ioqueue = ioqueue;
1032 param.timer_heap = timer;
1033 param.timeout.sec = 0;
1034 param.timeout.msec = ms_timeout;
1035 pj_time_val_normalize(&param.timeout);
1036 param.user_data = &state_cli;
1037
1038 state_cli.pool = pool;
1039 state_cli.is_server = PJ_FALSE;
1040 state_cli.is_verbose = PJ_TRUE;
1041
1042 status = pj_ssl_sock_create(pool, &param, &ssock_cli);
1043 if (status != PJ_SUCCESS) {
1044 goto on_return;
1045 }
1046
1047 /* Init default bind address */
1048 {
1049 pj_str_t tmp_st;
1050 pj_sockaddr_init(PJ_AF_INET, &addr, pj_strset2(&tmp_st, "127.0.0.1"), 0);
1051 }
1052
1053 status = pj_ssl_sock_start_connect(ssock_cli, pool,
1054 (pj_sockaddr_t*)&addr,
1055 (pj_sockaddr_t*)&listen_addr,
1056 pj_sockaddr_get_len(&listen_addr));
1057 if (status != PJ_EPENDING) {
1058 goto on_return;
1059 }
1060
1061 /* Wait until everything has been sent/received or error */
1062 while ((!state_serv.err && !state_serv.done) || (!state_cli.err && !state_cli.done))
1063 {
1064#ifdef PJ_SYMBIAN
1065 pj_symbianos_poll(-1, 1000);
1066#else
1067 pj_time_val delay = {0, 100};
1068 pj_ioqueue_poll(ioqueue, &delay);
1069 pj_timer_heap_poll(timer, &delay);
1070#endif
1071 }
1072
1073 if (state_serv.err || state_cli.err) {
1074 if (state_cli.err != PJ_SUCCESS)
1075 status = state_cli.err;
1076 else
1077 status = state_serv.err;
1078
1079 goto on_return;
1080 }
1081
1082 PJ_LOG(3, ("", "...Done!"));
1083
1084on_return:
1085 if (asock_serv)
1086 pj_activesock_close(asock_serv);
1087 if (ssock_cli && !state_cli.err && !state_cli.done)
1088 pj_ssl_sock_close(ssock_cli);
1089 if (timer)
1090 pj_timer_heap_destroy(timer);
1091 if (ioqueue)
1092 pj_ioqueue_destroy(ioqueue);
1093 if (pool)
1094 pj_pool_release(pool);
1095
1096 return status;
1097}
1098
1099
Nanang Izzuddin2d0f8fe2009-11-04 17:08:32 +00001100/* Test will perform multiple clients trying to connect to single server.
1101 * Once SSL connection established, echo test will be performed.
1102 */
Nanang Izzuddinabce36a2009-11-03 14:29:31 +00001103static int perf_test(unsigned clients, unsigned ms_handshake_timeout)
1104{
1105 pj_pool_t *pool = NULL;
1106 pj_ioqueue_t *ioqueue = NULL;
1107 pj_timer_heap_t *timer = NULL;
1108 pj_ssl_sock_t *ssock_serv = NULL;
1109 pj_ssl_sock_t **ssock_cli = NULL;
1110 pj_ssl_sock_param param;
1111 struct test_state state_serv = { 0 };
1112 struct test_state *state_cli = NULL;
1113 pj_sockaddr addr, listen_addr;
1114 pj_ssl_cert_t *cert = NULL;
1115 pj_status_t status;
1116 unsigned i, cli_err = 0, tot_sent = 0, tot_recv = 0;
1117 pj_time_val start;
1118
1119 pool = pj_pool_create(mem, "ssl_perf", 256, 256, NULL);
1120
1121 status = pj_ioqueue_create(pool, PJ_IOQUEUE_MAX_HANDLES, &ioqueue);
1122 if (status != PJ_SUCCESS) {
1123 goto on_return;
1124 }
1125
1126 status = pj_timer_heap_create(pool, PJ_IOQUEUE_MAX_HANDLES, &timer);
1127 if (status != PJ_SUCCESS) {
1128 goto on_return;
1129 }
1130
1131 /* Set cert */
1132 {
1133 pj_str_t tmp1, tmp2, tmp3, tmp4;
1134
1135 status = pj_ssl_cert_load_from_files(pool,
1136 pj_strset2(&tmp1, (char*)CERT_CA_FILE),
1137 pj_strset2(&tmp2, (char*)CERT_FILE),
1138 pj_strset2(&tmp3, (char*)CERT_PRIVKEY_FILE),
1139 pj_strset2(&tmp4, (char*)CERT_PRIVKEY_PASS),
1140 &cert);
1141 if (status != PJ_SUCCESS) {
1142 goto on_return;
1143 }
1144 }
1145
1146 pj_ssl_sock_param_default(&param);
1147 param.cb.on_accept_complete = &ssl_on_accept_complete;
1148 param.cb.on_connect_complete = &ssl_on_connect_complete;
1149 param.cb.on_data_read = &ssl_on_data_read;
1150 param.cb.on_data_sent = &ssl_on_data_sent;
1151 param.ioqueue = ioqueue;
1152 param.timer_heap = timer;
1153 param.timeout.sec = 0;
1154 param.timeout.msec = ms_handshake_timeout;
1155 pj_time_val_normalize(&param.timeout);
1156
1157 /* Init default bind address */
1158 {
1159 pj_str_t tmp_st;
1160 pj_sockaddr_init(PJ_AF_INET, &addr, pj_strset2(&tmp_st, "127.0.0.1"), 0);
1161 }
1162
1163 /* SERVER */
1164 param.user_data = &state_serv;
1165
1166 state_serv.pool = pool;
1167 state_serv.echo = PJ_TRUE;
1168 state_serv.is_server = PJ_TRUE;
1169
1170 status = pj_ssl_sock_create(pool, &param, &ssock_serv);
1171 if (status != PJ_SUCCESS) {
1172 goto on_return;
1173 }
1174
1175 status = pj_ssl_sock_set_certificate(ssock_serv, pool, cert);
1176 if (status != PJ_SUCCESS) {
1177 goto on_return;
1178 }
1179
1180 status = pj_ssl_sock_start_accept(ssock_serv, pool, &addr, pj_sockaddr_get_len(&addr));
1181 if (status != PJ_SUCCESS) {
1182 goto on_return;
1183 }
1184
1185 /* Get listening address for clients to connect to */
1186 {
1187 pj_ssl_sock_info info;
1188 char buf[64];
1189
1190 pj_ssl_sock_get_info(ssock_serv, &info);
1191 pj_sockaddr_cp(&listen_addr, &info.local_addr);
1192
1193 pj_sockaddr_print((pj_sockaddr_t*)&listen_addr, buf, sizeof(buf), 1);
1194 PJ_LOG(3, ("", "...Listener ready at %s", buf));
1195 }
1196
1197
1198 /* CLIENTS */
1199 clients_num = clients;
1200 param.timeout.sec = 0;
1201 param.timeout.msec = 0;
1202
1203 /* Init random seed */
1204 {
1205 pj_time_val now;
1206
1207 pj_gettimeofday(&now);
Nanang Izzuddineef9b8d2009-11-06 13:31:37 +00001208 pj_srand((unsigned)now.sec);
Nanang Izzuddinabce36a2009-11-03 14:29:31 +00001209 }
1210
1211 /* Allocate SSL socket pointers and test state */
1212 ssock_cli = pj_pool_calloc(pool, clients, sizeof(pj_ssl_sock_t*));
1213 state_cli = pj_pool_calloc(pool, clients, sizeof(struct test_state));
1214
Nanang Izzuddin2fb937e2010-02-24 05:43:34 +00001215 /* Get start timestamp */
1216 pj_gettimeofday(&start);
1217
Nanang Izzuddinabce36a2009-11-03 14:29:31 +00001218 /* Setup clients */
1219 for (i = 0; i < clients; ++i) {
1220 param.user_data = &state_cli[i];
1221
1222 state_cli[i].pool = pool;
1223 state_cli[i].check_echo = PJ_TRUE;
1224 state_cli[i].send_str_len = (pj_rand() % 5 + 1) * 1024 + pj_rand() % 1024;
1225 state_cli[i].send_str = pj_pool_alloc(pool, state_cli[i].send_str_len);
1226 {
1227 unsigned j;
1228 for (j = 0; j < state_cli[i].send_str_len; ++j)
1229 state_cli[i].send_str[j] = (char)(pj_rand() % 256);
1230 }
1231
1232 status = pj_ssl_sock_create(pool, &param, &ssock_cli[i]);
1233 if (status != PJ_SUCCESS) {
1234 app_perror("...ERROR pj_ssl_sock_create()", status);
1235 cli_err++;
1236 clients_num--;
1237 continue;
1238 }
1239
1240 status = pj_ssl_sock_start_connect(ssock_cli[i], pool, &addr, &listen_addr, pj_sockaddr_get_len(&addr));
1241 if (status == PJ_SUCCESS) {
1242 ssl_on_connect_complete(ssock_cli[i], PJ_SUCCESS);
1243 } else if (status == PJ_EPENDING) {
1244 status = PJ_SUCCESS;
1245 } else {
1246 app_perror("...ERROR pj_ssl_sock_create()", status);
1247 pj_ssl_sock_close(ssock_cli[i]);
1248 ssock_cli[i] = NULL;
1249 clients_num--;
1250 cli_err++;
1251 continue;
1252 }
Nanang Izzuddina4cf8d82009-11-11 07:14:28 +00001253
1254 /* Give chance to server to accept this client */
1255 {
1256 unsigned n = 5;
1257
1258#ifdef PJ_SYMBIAN
1259 while(n && pj_symbianos_poll(-1, 1000))
1260 n--;
1261#else
1262 pj_time_val delay = {0, 100};
1263 while(n && pj_ioqueue_poll(ioqueue, &delay) > 0)
1264 n--;
1265#endif
1266 }
Nanang Izzuddinabce36a2009-11-03 14:29:31 +00001267 }
1268
Nanang Izzuddinabce36a2009-11-03 14:29:31 +00001269 /* Wait until everything has been sent/received or error */
1270 while (clients_num)
1271 {
1272#ifdef PJ_SYMBIAN
1273 pj_symbianos_poll(-1, 1000);
1274#else
1275 pj_time_val delay = {0, 100};
1276 pj_ioqueue_poll(ioqueue, &delay);
1277 pj_timer_heap_poll(timer, &delay);
1278#endif
1279 }
1280
Nanang Izzuddin2d0f8fe2009-11-04 17:08:32 +00001281 /* Clean up sockets */
1282 {
1283 pj_time_val delay = {0, 500};
1284 while (pj_ioqueue_poll(ioqueue, &delay) > 0);
1285 }
1286
Nanang Izzuddinabce36a2009-11-03 14:29:31 +00001287 if (state_serv.err != PJ_SUCCESS) {
1288 status = state_serv.err;
1289 goto on_return;
1290 }
1291
1292 PJ_LOG(3, ("", "...Done!"));
1293
1294 /* SSL setup and data transfer duration */
1295 {
1296 pj_time_val stop;
1297
1298 pj_gettimeofday(&stop);
1299 PJ_TIME_VAL_SUB(stop, start);
1300
1301 PJ_LOG(3, ("", ".....Setup & data transfer duration: %d.%03ds", stop.sec, stop.msec));
1302 }
1303
1304 /* Check clients status */
1305 for (i = 0; i < clients; ++i) {
1306 if (state_cli[i].err != PJ_SUCCESS)
1307 cli_err++;
1308
1309 tot_sent += state_cli[1].sent;
1310 tot_recv += state_cli[1].recv;
1311 }
1312
1313 PJ_LOG(3, ("", ".....Clients: %d (%d errors)", clients, cli_err));
1314 PJ_LOG(3, ("", ".....Total sent/recv: %d/%d bytes", tot_sent, tot_recv));
1315
1316on_return:
1317 if (ssock_serv)
1318 pj_ssl_sock_close(ssock_serv);
1319
1320 for (i = 0; i < clients; ++i) {
1321 if (ssock_cli[i] && !state_cli[i].err && !state_cli[i].done)
1322 pj_ssl_sock_close(ssock_cli[i]);
1323 }
1324 if (ioqueue)
1325 pj_ioqueue_destroy(ioqueue);
1326 if (pool)
1327 pj_pool_release(pool);
1328
1329 return status;
1330}
1331
1332
Nanang Izzuddinea6d3c42009-10-26 15:47:52 +00001333int ssl_sock_test(void)
1334{
1335 int ret;
1336
1337 PJ_LOG(3,("", "..get cipher list test"));
1338 ret = get_cipher_list();
1339 if (ret != 0)
1340 return ret;
1341
Nanang Izzuddinea6d3c42009-10-26 15:47:52 +00001342 PJ_LOG(3,("", "..https client test"));
Nanang Izzuddin2d0f8fe2009-11-04 17:08:32 +00001343 ret = https_client_test(30000);
1344 // Ignore test result as internet connection may not be available.
1345 //if (ret != 0)
1346 //return ret;
1347
1348#ifndef PJ_SYMBIAN
Nanang Izzuddina7719d32010-03-06 02:04:52 +00001349
1350 /* On Symbian platforms, SSL socket is implemented using CSecureSocket,
1351 * and it hasn't supported server mode, so exclude the following tests,
1352 * which require SSL server, for now.
1353 */
Nanang Izzuddinea6d3c42009-10-26 15:47:52 +00001354
Nanang Izzuddin5e69da52010-02-25 11:58:19 +00001355 PJ_LOG(3,("", "..echo test w/ TLSv1 and PJ_TLS_RSA_WITH_DES_CBC_SHA cipher"));
Nanang Izzuddinabce36a2009-11-03 14:29:31 +00001356 ret = echo_test(PJ_SSL_SOCK_PROTO_TLS1, PJ_SSL_SOCK_PROTO_TLS1,
Nanang Izzuddin5e69da52010-02-25 11:58:19 +00001357 PJ_TLS_RSA_WITH_DES_CBC_SHA, PJ_TLS_RSA_WITH_DES_CBC_SHA,
Nanang Izzuddin2fb937e2010-02-24 05:43:34 +00001358 PJ_FALSE, PJ_FALSE);
Nanang Izzuddinea6d3c42009-10-26 15:47:52 +00001359 if (ret != 0)
1360 return ret;
1361
Nanang Izzuddin5e69da52010-02-25 11:58:19 +00001362 PJ_LOG(3,("", "..echo test w/ SSLv23 and PJ_TLS_RSA_WITH_AES_256_CBC_SHA cipher"));
Nanang Izzuddinabce36a2009-11-03 14:29:31 +00001363 ret = echo_test(PJ_SSL_SOCK_PROTO_SSL23, PJ_SSL_SOCK_PROTO_SSL23,
Nanang Izzuddin5e69da52010-02-25 11:58:19 +00001364 PJ_TLS_RSA_WITH_AES_256_CBC_SHA, PJ_TLS_RSA_WITH_AES_256_CBC_SHA,
Nanang Izzuddin2fb937e2010-02-24 05:43:34 +00001365 PJ_FALSE, PJ_FALSE);
Nanang Izzuddinea6d3c42009-10-26 15:47:52 +00001366 if (ret != 0)
1367 return ret;
1368
Nanang Izzuddinabce36a2009-11-03 14:29:31 +00001369 PJ_LOG(3,("", "..echo test w/ incompatible proto"));
1370 ret = echo_test(PJ_SSL_SOCK_PROTO_TLS1, PJ_SSL_SOCK_PROTO_SSL3,
Nanang Izzuddin5e69da52010-02-25 11:58:19 +00001371 PJ_TLS_RSA_WITH_DES_CBC_SHA, PJ_TLS_RSA_WITH_DES_CBC_SHA,
Nanang Izzuddin2fb937e2010-02-24 05:43:34 +00001372 PJ_FALSE, PJ_FALSE);
Nanang Izzuddinabce36a2009-11-03 14:29:31 +00001373 if (ret == 0)
1374 return PJ_EBUG;
1375
Nanang Izzuddinea6d3c42009-10-26 15:47:52 +00001376 PJ_LOG(3,("", "..echo test w/ incompatible ciphers"));
Nanang Izzuddinabce36a2009-11-03 14:29:31 +00001377 ret = echo_test(PJ_SSL_SOCK_PROTO_DEFAULT, PJ_SSL_SOCK_PROTO_DEFAULT,
Nanang Izzuddin5e69da52010-02-25 11:58:19 +00001378 PJ_TLS_RSA_WITH_DES_CBC_SHA, PJ_TLS_RSA_WITH_AES_256_CBC_SHA,
Nanang Izzuddin2fb937e2010-02-24 05:43:34 +00001379 PJ_FALSE, PJ_FALSE);
Nanang Izzuddinabce36a2009-11-03 14:29:31 +00001380 if (ret == 0)
1381 return PJ_EBUG;
Nanang Izzuddinea6d3c42009-10-26 15:47:52 +00001382
Nanang Izzuddin2fb937e2010-02-24 05:43:34 +00001383 PJ_LOG(3,("", "..echo test w/ client cert required but not provided"));
1384 ret = echo_test(PJ_SSL_SOCK_PROTO_DEFAULT, PJ_SSL_SOCK_PROTO_DEFAULT,
Nanang Izzuddin5e69da52010-02-25 11:58:19 +00001385 PJ_TLS_RSA_WITH_AES_256_CBC_SHA, PJ_TLS_RSA_WITH_AES_256_CBC_SHA,
Nanang Izzuddin2fb937e2010-02-24 05:43:34 +00001386 PJ_TRUE, PJ_FALSE);
1387 if (ret == 0)
1388 return PJ_EBUG;
1389
1390 PJ_LOG(3,("", "..echo test w/ client cert required and provided"));
1391 ret = echo_test(PJ_SSL_SOCK_PROTO_DEFAULT, PJ_SSL_SOCK_PROTO_DEFAULT,
Nanang Izzuddin5e69da52010-02-25 11:58:19 +00001392 PJ_TLS_RSA_WITH_AES_256_CBC_SHA, PJ_TLS_RSA_WITH_AES_256_CBC_SHA,
Nanang Izzuddin2fb937e2010-02-24 05:43:34 +00001393 PJ_TRUE, PJ_TRUE);
1394 if (ret != 0)
1395 return ret;
1396
Nanang Izzuddinabce36a2009-11-03 14:29:31 +00001397 PJ_LOG(3,("", "..performance test"));
1398 ret = perf_test(PJ_IOQUEUE_MAX_HANDLES/2 - 1, 0);
1399 if (ret != 0)
1400 return ret;
1401
Nanang Izzuddina7719d32010-03-06 02:04:52 +00001402 PJ_LOG(3,("", "..client non-SSL (handshake timeout 5 secs)"));
1403 ret = client_non_ssl(5000);
1404 /* PJ_TIMEDOUT won't be returned as accepted socket is deleted silently */
1405 if (ret != 0)
1406 return ret;
1407
Nanang Izzuddin2d0f8fe2009-11-04 17:08:32 +00001408#endif
1409
Nanang Izzuddina7719d32010-03-06 02:04:52 +00001410 PJ_LOG(3,("", "..server non-SSL (handshake timeout 5 secs)"));
1411 ret = server_non_ssl(5000);
1412 if (ret != PJ_ETIMEDOUT)
1413 return ret;
1414
Nanang Izzuddinea6d3c42009-10-26 15:47:52 +00001415 return 0;
1416}
1417
1418#else /* INCLUDE_SSLSOCK_TEST */
1419/* To prevent warning about "translation unit is empty"
1420 * when this test is disabled.
1421 */
1422int dummy_ssl_sock_test;
1423#endif /* INCLUDE_SSLSOCK_TEST */
1424