void poll_events(pj_stun_config *stun_cfg, unsigned msec, pj_bool_t first_event_only) { pj_time_val stop_time; int count = 0; pj_gettimeofday(&stop_time); stop_time.msec += msec; pj_time_val_normalize(&stop_time); /* Process all events for the specified duration. */ for (;;) { pj_time_val timeout = {0, 1}, now; int c; c = pj_timer_heap_poll( stun_cfg->timer_heap, NULL ); if (c > 0) count += c; //timeout.sec = timeout.msec = 0; c = pj_ioqueue_poll( stun_cfg->ioqueue, &timeout); if (c > 0) count += c; pj_gettimeofday(&now); if (PJ_TIME_VAL_GTE(now, stop_time)) break; if (first_event_only && count >= 0) break; } }
// // Handle events. // int handle_events(Pj_Time_Val *max_timeout) { Pj_Time_Val timeout(0, 0); int timer_count; timer_count = pj_timer_heap_poll( th_, &timeout ); if (timeout.get_sec() < 0) timeout.sec = PJ_MAXINT32; /* If caller specifies maximum time to wait, then compare the value * with the timeout to wait from timer, and use the minimum value. */ if (max_timeout && timeout >= *max_timeout) { timeout = *max_timeout; } /* Poll events in ioqueue. */ int ioqueue_count; ioqueue_count = pj_ioqueue_poll(ioq_, &timeout); if (ioqueue_count < 0) return ioqueue_count; return ioqueue_count + timer_count; }
/* * udp_destroy() * * This function is called by transport manager (by transport->destroy()). */ static pj_status_t udp_destroy( pjsip_transport *transport ) { struct udp_transport *tp = (struct udp_transport*)transport; int i; /* Mark this transport as closing. */ tp->is_closing = 1; /* Cancel all pending operations. */ /* blp: NO NO NO... * No need to post queued completion as we poll the ioqueue until * we've got events anyway. Posting completion will only cause * callback to be called twice with IOCP: one for the post completion * and another one for closing the socket. * for (i=0; i<tp->rdata_cnt; ++i) { pj_ioqueue_post_completion(tp->key, &tp->rdata[i]->tp_info.op_key.op_key, -1); } */ /* Unregister from ioqueue. */ if (tp->key) { pj_ioqueue_unregister(tp->key); tp->key = NULL; } else { /* Close socket. */ if (tp->sock && tp->sock != PJ_INVALID_SOCKET) { pj_sock_close(tp->sock); tp->sock = PJ_INVALID_SOCKET; } } /* Must poll ioqueue because IOCP calls the callback when socket * is closed. We poll the ioqueue until all pending callbacks * have been called. */ for (i=0; i<50 && tp->is_closing < 1+tp->rdata_cnt; ++i) { int cnt; pj_time_val timeout = {0, 1}; cnt = pj_ioqueue_poll(pjsip_endpt_get_ioqueue(transport->endpt), &timeout); if (cnt == 0) break; } if (tp->grp_lock) { pj_grp_lock_t *grp_lock = tp->grp_lock; tp->grp_lock = NULL; pj_grp_lock_dec_ref(grp_lock); /* Transport may have been deleted at this point */ } else { udp_on_destroy(tp); } return PJ_SUCCESS; }
static int worker_thread(void *arg) { pj_ioqueue_t *ioqueue = (pj_ioqueue_t*) arg; while (!thread_quitting) { pj_time_val timeout = { 0, 20 }; pj_ioqueue_poll(ioqueue, &timeout); } return 0; }
/** * Worker thread proc. */ static int PJ_THREAD_FUNC worker_proc(void *arg) { pjmedia_endpt *endpt = (pjmedia_endpt*) arg; while (!endpt->quit_flag) { pj_time_val timeout = { 0, 500 }; pj_ioqueue_poll(endpt->ioqueue, &timeout); } return 0; }
static void handle_events(pj_stun_config *cfg, unsigned msec_delay) { pj_time_val delay; pj_timer_heap_poll(cfg->timer_heap, NULL); delay.sec = 0; delay.msec = msec_delay; pj_time_val_normalize(&delay); pj_ioqueue_poll(cfg->ioqueue, &delay); }
/* * Handle timer and network events */ static void srv_handle_events(pj_turn_srv *srv, const pj_time_val *max_timeout) { /* timeout is 'out' var. This just to make compiler happy. */ pj_time_val timeout = { 0, 0}; unsigned net_event_count = 0; int c; /* Poll the timer. The timer heap has its own mutex for better * granularity, so we don't need to lock the server. */ timeout.sec = timeout.msec = 0; c = pj_timer_heap_poll( srv->core.timer_heap, &timeout ); /* timer_heap_poll should never ever returns negative value, or otherwise * ioqueue_poll() will block forever! */ pj_assert(timeout.sec >= 0 && timeout.msec >= 0); if (timeout.msec >= 1000) timeout.msec = 999; /* If caller specifies maximum time to wait, then compare the value with * the timeout to wait from timer, and use the minimum value. */ if (max_timeout && PJ_TIME_VAL_GT(timeout, *max_timeout)) { timeout = *max_timeout; } /* Poll ioqueue. * Repeat polling the ioqueue while we have immediate events, because * timer heap may process more than one events, so if we only process * one network events at a time (such as when IOCP backend is used), * the ioqueue may have trouble keeping up with the request rate. * * For example, for each send() request, one network event will be * reported by ioqueue for the send() completion. If we don't poll * the ioqueue often enough, the send() completion will not be * reported in timely manner. */ do { c = pj_ioqueue_poll( srv->core.ioqueue, &timeout); if (c < 0) { pj_thread_sleep(PJ_TIME_VAL_MSEC(timeout)); return; } else if (c == 0) { break; } else { net_event_count += c; timeout.sec = timeout.msec = 0; } } while (c > 0 && net_event_count < MAX_NET_EVENTS); }
pj_status_t PJStunTurn::handle_events(unsigned max_msec, unsigned* p_count) { enum { MAX_NET_EVENTS = 1 }; pj_time_val max_timeout = {0, 0}; pj_time_val timeout = {0, 0}; unsigned count = 0, net_event_count = 0; int c; max_timeout.msec = max_msec; /* Poll the timer to run it and also to retrieve the earliest entry. */ timeout.sec = timeout.msec = 0; c = pj_timer_heap_poll(ice_cfg_.stun_cfg.timer_heap, &timeout); if (c > 0) count += c; /* timer_heap_poll should never ever returns negative value, or otherwise * ioqueue_poll() will block forever! */ pj_assert(timeout.sec >= 0 && timeout.msec >= 0); if (timeout.msec >= 1000) timeout.msec = 999; /* compare the value with the timeout to wait from timer, and use the * minimum value. */ if (PJ_TIME_VAL_GT(timeout, max_timeout)) timeout = max_timeout; /* Poll ioqueue. * Repeat polling the ioqueue while we have immediate events, because * timer heap may process more than one events, so if we only process * one network events at a time (such as when IOCP backend is used), * the ioqueue may have trouble keeping up with the request rate. * * For example, for each send() request, one network event will be * reported by ioqueue for the send() completion. If we don't poll * the ioqueue often enough, the send() completion will not be * reported in timely manner. */ do { c = pj_ioqueue_poll(ice_cfg_.stun_cfg.ioqueue, &timeout); if (c < 0) { pj_status_t err = pj_get_netos_error(); pj_thread_sleep(PJ_TIME_VAL_MSEC(timeout)); if (p_count) *p_count = count; return err; } else if (c == 0) { break; } else { net_event_count += c; timeout.sec = timeout.msec = 0; } } while (c > 0 && net_event_count < MAX_NET_EVENTS); count += net_event_count; if (p_count) *p_count = count; return PJ_SUCCESS; }
static int worker_thread_proc(void *p) { struct stun_test_session *test_sess = (struct stun_test_session*)p; PJ_LOG(4,(THIS_FILE, "Worker thread running")); while (!test_sess->thread_quit_flag) { pj_time_val timeout = {0, 10}; pj_timer_heap_poll(test_sess->stun_cfg.timer_heap, NULL); pj_ioqueue_poll(test_sess->stun_cfg.ioqueue, &timeout); } PJ_LOG(4,(THIS_FILE, "Worker thread quitting")); return 0; }
static int worker_thread(void *unused) { PJ_UNUSED_ARG(unused); while (!g.quit) { const pj_time_val delay = {0, 10}; /* Poll ioqueue for the TURN client */ pj_ioqueue_poll(g.stun_config.ioqueue, &delay); /* Poll the timer heap */ pj_timer_heap_poll(g.stun_config.timer_heap, NULL); } return 0; }
pj_status_t getURL(const char *curl) { pj_str_t url; pj_http_req_callback hcb; pj_status_t status; pj_bzero(&hcb, sizeof(hcb)); hcb.on_complete = &on_complete; hcb.on_data_read = &on_data_read; hcb.on_send_data = &on_send_data; hcb.on_response = &on_response; /* Create pool, timer, and ioqueue */ pool = pj_pool_create(mem, NULL, 8192, 4096, NULL); if (pj_timer_heap_create(pool, 16, &timer_heap)) return -31; if (pj_ioqueue_create(pool, 16, &ioqueue)) return -32; pj_strdup2(pool, &url, curl); if ((status = pj_http_req_create(pool, &url, timer_heap, ioqueue, NULL, &hcb, &http_req)) != PJ_SUCCESS) return status; if ((status = pj_http_req_start(http_req)) != PJ_SUCCESS) return status; while (pj_http_req_is_running(http_req)) { pj_time_val delay = {0, 50}; pj_ioqueue_poll(ioqueue, &delay); pj_timer_heap_poll(timer_heap, NULL); } pj_http_req_destroy(http_req); pj_ioqueue_destroy(ioqueue); pj_timer_heap_destroy(timer_heap); pj_pool_release(pool); return PJ_SUCCESS; }
/* The worker thread. */ static int worker_thread(void *p) { struct thread_arg *arg = (struct thread_arg*) p; const pj_time_val timeout = {0, 100}; int rc; while (!thread_quit_flag) { ++arg->counter; rc = pj_ioqueue_poll(arg->ioqueue, &timeout); //TRACE_((THIS_FILE, " thread: poll returned rc=%d", rc)); if (rc < 0) { char errmsg[PJ_ERR_MSG_SIZE]; pj_strerror(-rc, errmsg, sizeof(errmsg)); PJ_LOG(3, (THIS_FILE, "...error in pj_ioqueue_poll() in thread %d " "after %d loop: %s [pj_status_t=%d]", arg->id, arg->counter, errmsg, -rc)); //return -1; } } return 0; }
static int worker_thread(void *arg) { pj_ioqueue_t *ioqueue = (pj_ioqueue_t*) arg; struct op_key read_op, write_op; char recv_buf[512], send_buf[512]; pj_ssize_t length; pj_status_t rc; read_op.peer = &write_op; read_op.is_pending = 0; read_op.last_err = 0; read_op.buffer = recv_buf; read_op.size = sizeof(recv_buf); read_op.addrlen = sizeof(read_op.addr); write_op.peer = &read_op; write_op.is_pending = 0; write_op.last_err = 0; write_op.buffer = send_buf; write_op.size = sizeof(send_buf); length = sizeof(recv_buf); rc = pj_ioqueue_recvfrom(key, &read_op.op_key_, recv_buf, &length, 0, &read_op.addr, &read_op.addrlen); if (rc == PJ_SUCCESS) { read_op.is_pending = 1; on_read_complete(key, &read_op.op_key_, length); } while (!thread_quit_flag) { pj_time_val timeout; timeout.sec = 0; timeout.msec = 10; rc = pj_ioqueue_poll(ioqueue, &timeout); } return 0; }
/* SSL socket try to connect to raw TCP socket server, once * connection established, SSL socket will try to perform SSL * handshake. SSL client socket should be able to close the * connection after specified timeout period (set ms_timeout to * 0 to disable timer). */ static int server_non_ssl(unsigned ms_timeout) { pj_pool_t *pool = NULL; pj_ioqueue_t *ioqueue = NULL; pj_timer_heap_t *timer = NULL; pj_activesock_t *asock_serv = NULL; pj_ssl_sock_t *ssock_cli = NULL; pj_activesock_cb asock_cb = { 0 }; pj_sock_t sock = PJ_INVALID_SOCKET; pj_ssl_sock_param param; struct test_state state_serv = { 0 }; struct test_state state_cli = { 0 }; pj_sockaddr addr, listen_addr; pj_status_t status; pool = pj_pool_create(mem, "ssl_connect_raw_tcp", 256, 256, NULL); status = pj_ioqueue_create(pool, 4, &ioqueue); if (status != PJ_SUCCESS) { goto on_return; } status = pj_timer_heap_create(pool, 4, &timer); if (status != PJ_SUCCESS) { goto on_return; } /* SERVER */ state_serv.pool = pool; state_serv.ioqueue = ioqueue; status = pj_sock_socket(pj_AF_INET(), pj_SOCK_STREAM(), 0, &sock); if (status != PJ_SUCCESS) { goto on_return; } /* Init bind address */ { pj_str_t tmp_st; pj_sockaddr_init(PJ_AF_INET, &listen_addr, pj_strset2(&tmp_st, "127.0.0.1"), 0); } status = pj_sock_bind(sock, (pj_sockaddr_t*)&listen_addr, pj_sockaddr_get_len((pj_sockaddr_t*)&listen_addr)); if (status != PJ_SUCCESS) { goto on_return; } status = pj_sock_listen(sock, PJ_SOMAXCONN); if (status != PJ_SUCCESS) { goto on_return; } asock_cb.on_accept_complete = &asock_on_accept_complete; status = pj_activesock_create(pool, sock, pj_SOCK_STREAM(), NULL, ioqueue, &asock_cb, &state_serv, &asock_serv); if (status != PJ_SUCCESS) { goto on_return; } status = pj_activesock_start_accept(asock_serv, pool); if (status != PJ_SUCCESS) goto on_return; /* Update listener address */ { int addr_len; addr_len = sizeof(listen_addr); pj_sock_getsockname(sock, (pj_sockaddr_t*)&listen_addr, &addr_len); } /* CLIENT */ pj_ssl_sock_param_default(¶m); param.cb.on_connect_complete = &ssl_on_connect_complete; param.cb.on_data_read = &ssl_on_data_read; param.cb.on_data_sent = &ssl_on_data_sent; param.ioqueue = ioqueue; param.timer_heap = timer; param.timeout.sec = 0; param.timeout.msec = ms_timeout; pj_time_val_normalize(¶m.timeout); param.user_data = &state_cli; state_cli.pool = pool; state_cli.is_server = PJ_FALSE; state_cli.is_verbose = PJ_TRUE; status = pj_ssl_sock_create(pool, ¶m, &ssock_cli); if (status != PJ_SUCCESS) { goto on_return; } /* Init default bind address */ { pj_str_t tmp_st; pj_sockaddr_init(PJ_AF_INET, &addr, pj_strset2(&tmp_st, "127.0.0.1"), 0); } status = pj_ssl_sock_start_connect(ssock_cli, pool, (pj_sockaddr_t*)&addr, (pj_sockaddr_t*)&listen_addr, pj_sockaddr_get_len(&listen_addr)); if (status != PJ_EPENDING) { goto on_return; } /* Wait until everything has been sent/received or error */ while ((!state_serv.err && !state_serv.done) || (!state_cli.err && !state_cli.done)) { #ifdef PJ_SYMBIAN pj_symbianos_poll(-1, 1000); #else pj_time_val delay = {0, 100}; pj_ioqueue_poll(ioqueue, &delay); pj_timer_heap_poll(timer, &delay); #endif } if (state_serv.err || state_cli.err) { if (state_cli.err != PJ_SUCCESS) status = state_cli.err; else status = state_serv.err; goto on_return; } PJ_LOG(3, ("", "...Done!")); on_return: if (asock_serv) pj_activesock_close(asock_serv); if (ssock_cli && !state_cli.err && !state_cli.done) pj_ssl_sock_close(ssock_cli); if (timer) pj_timer_heap_destroy(timer); if (ioqueue) pj_ioqueue_destroy(ioqueue); if (pool) pj_pool_release(pool); return status; }
/* Raw TCP socket try to connect to SSL socket server, once * connection established, it will just do nothing, SSL socket * server should be able to close the connection after specified * timeout period (set ms_timeout to 0 to disable timer). */ static int client_non_ssl(unsigned ms_timeout) { pj_pool_t *pool = NULL; pj_ioqueue_t *ioqueue = NULL; pj_timer_heap_t *timer = NULL; pj_ssl_sock_t *ssock_serv = NULL; pj_activesock_t *asock_cli = NULL; pj_activesock_cb asock_cb = { 0 }; pj_sock_t sock = PJ_INVALID_SOCKET; pj_ssl_sock_param param; struct test_state state_serv = { 0 }; struct test_state state_cli = { 0 }; pj_sockaddr listen_addr; pj_ssl_cert_t *cert = NULL; pj_status_t status; pool = pj_pool_create(mem, "ssl_accept_raw_tcp", 256, 256, NULL); status = pj_ioqueue_create(pool, 4, &ioqueue); if (status != PJ_SUCCESS) { goto on_return; } status = pj_timer_heap_create(pool, 4, &timer); if (status != PJ_SUCCESS) { goto on_return; } /* Set cert */ { pj_str_t tmp1, tmp2, tmp3, tmp4; status = pj_ssl_cert_load_from_files(pool, pj_strset2(&tmp1, (char*)CERT_CA_FILE), pj_strset2(&tmp2, (char*)CERT_FILE), pj_strset2(&tmp3, (char*)CERT_PRIVKEY_FILE), pj_strset2(&tmp4, (char*)CERT_PRIVKEY_PASS), &cert); if (status != PJ_SUCCESS) { goto on_return; } } pj_ssl_sock_param_default(¶m); param.cb.on_accept_complete = &ssl_on_accept_complete; param.cb.on_data_read = &ssl_on_data_read; param.cb.on_data_sent = &ssl_on_data_sent; param.ioqueue = ioqueue; param.timer_heap = timer; param.timeout.sec = 0; param.timeout.msec = ms_timeout; pj_time_val_normalize(¶m.timeout); /* SERVER */ param.user_data = &state_serv; state_serv.pool = pool; state_serv.is_server = PJ_TRUE; state_serv.is_verbose = PJ_TRUE; status = pj_ssl_sock_create(pool, ¶m, &ssock_serv); if (status != PJ_SUCCESS) { goto on_return; } status = pj_ssl_sock_set_certificate(ssock_serv, pool, cert); if (status != PJ_SUCCESS) { goto on_return; } /* Init bind address */ { pj_str_t tmp_st; pj_sockaddr_init(PJ_AF_INET, &listen_addr, pj_strset2(&tmp_st, "127.0.0.1"), 0); } status = pj_ssl_sock_start_accept(ssock_serv, pool, &listen_addr, pj_sockaddr_get_len(&listen_addr)); if (status != PJ_SUCCESS) { goto on_return; } /* Update listener address */ { pj_ssl_sock_info info; pj_ssl_sock_get_info(ssock_serv, &info); pj_sockaddr_cp(&listen_addr, &info.local_addr); } /* CLIENT */ state_cli.pool = pool; status = pj_sock_socket(pj_AF_INET(), pj_SOCK_STREAM(), 0, &sock); if (status != PJ_SUCCESS) { goto on_return; } asock_cb.on_connect_complete = &asock_on_connect_complete; asock_cb.on_data_read = &asock_on_data_read; status = pj_activesock_create(pool, sock, pj_SOCK_STREAM(), NULL, ioqueue, &asock_cb, &state_cli, &asock_cli); if (status != PJ_SUCCESS) { goto on_return; } status = pj_activesock_start_connect(asock_cli, pool, (pj_sockaddr_t*)&listen_addr, pj_sockaddr_get_len(&listen_addr)); if (status == PJ_SUCCESS) { asock_on_connect_complete(asock_cli, PJ_SUCCESS); } else if (status == PJ_EPENDING) { status = PJ_SUCCESS; } else { goto on_return; } /* Wait until everything has been sent/received or error */ while (!state_serv.err && !state_cli.err && !state_serv.done && !state_cli.done) { #ifdef PJ_SYMBIAN pj_symbianos_poll(-1, 1000); #else pj_time_val delay = {0, 100}; pj_ioqueue_poll(ioqueue, &delay); pj_timer_heap_poll(timer, &delay); #endif } if (state_serv.err || state_cli.err) { if (state_serv.err != PJ_SUCCESS) status = state_serv.err; else status = state_cli.err; goto on_return; } PJ_LOG(3, ("", "...Done!")); on_return: if (ssock_serv) pj_ssl_sock_close(ssock_serv); if (asock_cli && !state_cli.err && !state_cli.done) pj_activesock_close(asock_cli); if (timer) pj_timer_heap_destroy(timer); if (ioqueue) pj_ioqueue_destroy(ioqueue); if (pool) pj_pool_release(pool); return status; }
static int echo_test(pj_ssl_sock_proto srv_proto, pj_ssl_sock_proto cli_proto, pj_ssl_cipher srv_cipher, pj_ssl_cipher cli_cipher, pj_bool_t req_client_cert, pj_bool_t client_provide_cert) { pj_pool_t *pool = NULL; pj_ioqueue_t *ioqueue = NULL; pj_ssl_sock_t *ssock_serv = NULL; pj_ssl_sock_t *ssock_cli = NULL; pj_ssl_sock_param param; struct test_state state_serv = { 0 }; struct test_state state_cli = { 0 }; pj_sockaddr addr, listen_addr; pj_ssl_cipher ciphers[1]; pj_ssl_cert_t *cert = NULL; pj_status_t status; pool = pj_pool_create(mem, "ssl_echo", 256, 256, NULL); status = pj_ioqueue_create(pool, 4, &ioqueue); if (status != PJ_SUCCESS) { goto on_return; } pj_ssl_sock_param_default(¶m); param.cb.on_accept_complete = &ssl_on_accept_complete; param.cb.on_connect_complete = &ssl_on_connect_complete; param.cb.on_data_read = &ssl_on_data_read; param.cb.on_data_sent = &ssl_on_data_sent; param.ioqueue = ioqueue; param.ciphers = ciphers; /* Init default bind address */ { pj_str_t tmp_st; pj_sockaddr_init(PJ_AF_INET, &addr, pj_strset2(&tmp_st, "127.0.0.1"), 0); } /* === SERVER === */ param.proto = srv_proto; param.user_data = &state_serv; param.ciphers_num = (srv_cipher == -1)? 0 : 1; param.require_client_cert = req_client_cert; ciphers[0] = srv_cipher; state_serv.pool = pool; state_serv.echo = PJ_TRUE; state_serv.is_server = PJ_TRUE; state_serv.is_verbose = PJ_TRUE; status = pj_ssl_sock_create(pool, ¶m, &ssock_serv); if (status != PJ_SUCCESS) { goto on_return; } /* Set server cert */ { pj_str_t tmp1, tmp2, tmp3, tmp4; status = pj_ssl_cert_load_from_files(pool, pj_strset2(&tmp1, (char*)CERT_CA_FILE), pj_strset2(&tmp2, (char*)CERT_FILE), pj_strset2(&tmp3, (char*)CERT_PRIVKEY_FILE), pj_strset2(&tmp4, (char*)CERT_PRIVKEY_PASS), &cert); if (status != PJ_SUCCESS) { goto on_return; } status = pj_ssl_sock_set_certificate(ssock_serv, pool, cert); if (status != PJ_SUCCESS) { goto on_return; } } status = pj_ssl_sock_start_accept(ssock_serv, pool, &addr, pj_sockaddr_get_len(&addr)); if (status != PJ_SUCCESS) { goto on_return; } /* Get listener address */ { pj_ssl_sock_info info; pj_ssl_sock_get_info(ssock_serv, &info); pj_sockaddr_cp(&listen_addr, &info.local_addr); } /* === CLIENT === */ param.proto = cli_proto; param.user_data = &state_cli; param.ciphers_num = (cli_cipher == -1)? 0 : 1; ciphers[0] = cli_cipher; state_cli.pool = pool; state_cli.check_echo = PJ_TRUE; state_cli.is_verbose = PJ_TRUE; { pj_time_val now; pj_gettimeofday(&now); pj_srand((unsigned)now.sec); state_cli.send_str_len = (pj_rand() % 5 + 1) * 1024 + pj_rand() % 1024; } state_cli.send_str = pj_pool_alloc(pool, state_cli.send_str_len); { unsigned i; for (i = 0; i < state_cli.send_str_len; ++i) state_cli.send_str[i] = (char)(pj_rand() % 256); } status = pj_ssl_sock_create(pool, ¶m, &ssock_cli); if (status != PJ_SUCCESS) { goto on_return; } /* Set cert for client */ { if (!client_provide_cert) { pj_str_t tmp1, tmp2; pj_strset2(&tmp1, (char*)CERT_CA_FILE); pj_strset2(&tmp2, NULL); status = pj_ssl_cert_load_from_files(pool, &tmp1, &tmp2, &tmp2, &tmp2, &cert); if (status != PJ_SUCCESS) { goto on_return; } } status = pj_ssl_sock_set_certificate(ssock_cli, pool, cert); if (status != PJ_SUCCESS) { goto on_return; } } status = pj_ssl_sock_start_connect(ssock_cli, pool, &addr, &listen_addr, pj_sockaddr_get_len(&addr)); if (status == PJ_SUCCESS) { ssl_on_connect_complete(ssock_cli, PJ_SUCCESS); } else if (status == PJ_EPENDING) { status = PJ_SUCCESS; } else { goto on_return; } /* Wait until everything has been sent/received or error */ while (!state_serv.err && !state_cli.err && !state_serv.done && !state_cli.done) { #ifdef PJ_SYMBIAN pj_symbianos_poll(-1, 1000); #else pj_time_val delay = {0, 100}; pj_ioqueue_poll(ioqueue, &delay); #endif } /* Clean up sockets */ { pj_time_val delay = {0, 100}; while (pj_ioqueue_poll(ioqueue, &delay) > 0); } if (state_serv.err || state_cli.err) { if (state_serv.err != PJ_SUCCESS) status = state_serv.err; else status = state_cli.err; goto on_return; } PJ_LOG(3, ("", "...Done!")); PJ_LOG(3, ("", ".....Sent/recv: %d/%d bytes", state_cli.sent, state_cli.recv)); on_return: if (ssock_serv) pj_ssl_sock_close(ssock_serv); if (ssock_cli && !state_cli.err && !state_cli.done) pj_ssl_sock_close(ssock_cli); if (ioqueue) pj_ioqueue_destroy(ioqueue); if (pool) pj_pool_release(pool); return status; }
static int https_client_test(unsigned ms_timeout) { pj_pool_t *pool = NULL; pj_ioqueue_t *ioqueue = NULL; pj_timer_heap_t *timer = NULL; pj_ssl_sock_t *ssock = NULL; pj_ssl_sock_param param; pj_status_t status; struct test_state state = {0}; pj_sockaddr local_addr, rem_addr; pj_str_t tmp_st; pool = pj_pool_create(mem, "https_get", 256, 256, NULL); status = pj_ioqueue_create(pool, 4, &ioqueue); if (status != PJ_SUCCESS) { goto on_return; } status = pj_timer_heap_create(pool, 4, &timer); if (status != PJ_SUCCESS) { goto on_return; } state.pool = pool; state.send_str = HTTP_REQ; state.send_str_len = pj_ansi_strlen(state.send_str); state.is_verbose = PJ_TRUE; pj_ssl_sock_param_default(¶m); param.cb.on_connect_complete = &ssl_on_connect_complete; param.cb.on_data_read = &ssl_on_data_read; param.cb.on_data_sent = &ssl_on_data_sent; param.ioqueue = ioqueue; param.user_data = &state; param.server_name = pj_str((char*)HTTP_SERVER_ADDR); param.timer_heap = timer; param.timeout.sec = 0; param.timeout.msec = ms_timeout; param.proto = PJ_SSL_SOCK_PROTO_SSL23; pj_time_val_normalize(¶m.timeout); status = pj_ssl_sock_create(pool, ¶m, &ssock); if (status != PJ_SUCCESS) { goto on_return; } pj_sockaddr_init(PJ_AF_INET, &local_addr, pj_strset2(&tmp_st, "0.0.0.0"), 0); pj_sockaddr_init(PJ_AF_INET, &rem_addr, pj_strset2(&tmp_st, HTTP_SERVER_ADDR), HTTP_SERVER_PORT); status = pj_ssl_sock_start_connect(ssock, pool, &local_addr, &rem_addr, sizeof(rem_addr)); if (status == PJ_SUCCESS) { ssl_on_connect_complete(ssock, PJ_SUCCESS); } else if (status == PJ_EPENDING) { status = PJ_SUCCESS; } else { goto on_return; } /* Wait until everything has been sent/received */ while (state.err == PJ_SUCCESS && !state.done) { #ifdef PJ_SYMBIAN pj_symbianos_poll(-1, 1000); #else pj_time_val delay = {0, 100}; pj_ioqueue_poll(ioqueue, &delay); pj_timer_heap_poll(timer, &delay); #endif } if (state.err) { status = state.err; goto on_return; } PJ_LOG(3, ("", "...Done!")); PJ_LOG(3, ("", ".....Sent/recv: %d/%d bytes", state.sent, state.recv)); on_return: if (ssock && !state.err && !state.done) pj_ssl_sock_close(ssock); if (ioqueue) pj_ioqueue_destroy(ioqueue); if (timer) pj_timer_heap_destroy(timer); if (pool) pj_pool_release(pool); return status; }
/* Test will perform multiple clients trying to connect to single server. * Once SSL connection established, echo test will be performed. */ static int perf_test(unsigned clients, unsigned ms_handshake_timeout) { pj_pool_t *pool = NULL; pj_ioqueue_t *ioqueue = NULL; pj_timer_heap_t *timer = NULL; pj_ssl_sock_t *ssock_serv = NULL; pj_ssl_sock_t **ssock_cli = NULL; pj_ssl_sock_param param; struct test_state state_serv = { 0 }; struct test_state *state_cli = NULL; pj_sockaddr addr, listen_addr; pj_ssl_cert_t *cert = NULL; pj_status_t status; unsigned i, cli_err = 0, tot_sent = 0, tot_recv = 0; pj_time_val start; pool = pj_pool_create(mem, "ssl_perf", 256, 256, NULL); status = pj_ioqueue_create(pool, PJ_IOQUEUE_MAX_HANDLES, &ioqueue); if (status != PJ_SUCCESS) { goto on_return; } status = pj_timer_heap_create(pool, PJ_IOQUEUE_MAX_HANDLES, &timer); if (status != PJ_SUCCESS) { goto on_return; } /* Set cert */ { pj_str_t tmp1, tmp2, tmp3, tmp4; status = pj_ssl_cert_load_from_files(pool, pj_strset2(&tmp1, (char*)CERT_CA_FILE), pj_strset2(&tmp2, (char*)CERT_FILE), pj_strset2(&tmp3, (char*)CERT_PRIVKEY_FILE), pj_strset2(&tmp4, (char*)CERT_PRIVKEY_PASS), &cert); if (status != PJ_SUCCESS) { goto on_return; } } pj_ssl_sock_param_default(¶m); param.cb.on_accept_complete = &ssl_on_accept_complete; param.cb.on_connect_complete = &ssl_on_connect_complete; param.cb.on_data_read = &ssl_on_data_read; param.cb.on_data_sent = &ssl_on_data_sent; param.ioqueue = ioqueue; param.timer_heap = timer; param.timeout.sec = 0; param.timeout.msec = ms_handshake_timeout; pj_time_val_normalize(¶m.timeout); /* Init default bind address */ { pj_str_t tmp_st; pj_sockaddr_init(PJ_AF_INET, &addr, pj_strset2(&tmp_st, "127.0.0.1"), 0); } /* SERVER */ param.user_data = &state_serv; state_serv.pool = pool; state_serv.echo = PJ_TRUE; state_serv.is_server = PJ_TRUE; status = pj_ssl_sock_create(pool, ¶m, &ssock_serv); if (status != PJ_SUCCESS) { goto on_return; } status = pj_ssl_sock_set_certificate(ssock_serv, pool, cert); if (status != PJ_SUCCESS) { goto on_return; } status = pj_ssl_sock_start_accept(ssock_serv, pool, &addr, pj_sockaddr_get_len(&addr)); if (status != PJ_SUCCESS) { goto on_return; } /* Get listening address for clients to connect to */ { pj_ssl_sock_info info; char buf[64]; pj_ssl_sock_get_info(ssock_serv, &info); pj_sockaddr_cp(&listen_addr, &info.local_addr); pj_sockaddr_print((pj_sockaddr_t*)&listen_addr, buf, sizeof(buf), 1); PJ_LOG(3, ("", "...Listener ready at %s", buf)); } /* CLIENTS */ clients_num = clients; param.timeout.sec = 0; param.timeout.msec = 0; /* Init random seed */ { pj_time_val now; pj_gettimeofday(&now); pj_srand((unsigned)now.sec); } /* Allocate SSL socket pointers and test state */ ssock_cli = pj_pool_calloc(pool, clients, sizeof(pj_ssl_sock_t*)); state_cli = pj_pool_calloc(pool, clients, sizeof(struct test_state)); /* Get start timestamp */ pj_gettimeofday(&start); /* Setup clients */ for (i = 0; i < clients; ++i) { param.user_data = &state_cli[i]; state_cli[i].pool = pool; state_cli[i].check_echo = PJ_TRUE; state_cli[i].send_str_len = (pj_rand() % 5 + 1) * 1024 + pj_rand() % 1024; state_cli[i].send_str = pj_pool_alloc(pool, state_cli[i].send_str_len); { unsigned j; for (j = 0; j < state_cli[i].send_str_len; ++j) state_cli[i].send_str[j] = (char)(pj_rand() % 256); } status = pj_ssl_sock_create(pool, ¶m, &ssock_cli[i]); if (status != PJ_SUCCESS) { app_perror("...ERROR pj_ssl_sock_create()", status); cli_err++; clients_num--; continue; } status = pj_ssl_sock_start_connect(ssock_cli[i], pool, &addr, &listen_addr, pj_sockaddr_get_len(&addr)); if (status == PJ_SUCCESS) { ssl_on_connect_complete(ssock_cli[i], PJ_SUCCESS); } else if (status == PJ_EPENDING) { status = PJ_SUCCESS; } else { app_perror("...ERROR pj_ssl_sock_create()", status); pj_ssl_sock_close(ssock_cli[i]); ssock_cli[i] = NULL; clients_num--; cli_err++; continue; } /* Give chance to server to accept this client */ { unsigned n = 5; #ifdef PJ_SYMBIAN while(n && pj_symbianos_poll(-1, 1000)) n--; #else pj_time_val delay = {0, 100}; while(n && pj_ioqueue_poll(ioqueue, &delay) > 0) n--; #endif } } /* Wait until everything has been sent/received or error */ while (clients_num) { #ifdef PJ_SYMBIAN pj_symbianos_poll(-1, 1000); #else pj_time_val delay = {0, 100}; pj_ioqueue_poll(ioqueue, &delay); pj_timer_heap_poll(timer, &delay); #endif } /* Clean up sockets */ { pj_time_val delay = {0, 500}; while (pj_ioqueue_poll(ioqueue, &delay) > 0); } if (state_serv.err != PJ_SUCCESS) { status = state_serv.err; goto on_return; } PJ_LOG(3, ("", "...Done!")); /* SSL setup and data transfer duration */ { pj_time_val stop; pj_gettimeofday(&stop); PJ_TIME_VAL_SUB(stop, start); PJ_LOG(3, ("", ".....Setup & data transfer duration: %d.%03ds", stop.sec, stop.msec)); } /* Check clients status */ for (i = 0; i < clients; ++i) { if (state_cli[i].err != PJ_SUCCESS) cli_err++; tot_sent += state_cli[1].sent; tot_recv += state_cli[1].recv; } PJ_LOG(3, ("", ".....Clients: %d (%d errors)", clients, cli_err)); PJ_LOG(3, ("", ".....Total sent/recv: %d/%d bytes", tot_sent, tot_recv)); on_return: if (ssock_serv) pj_ssl_sock_close(ssock_serv); for (i = 0; i < clients; ++i) { if (ssock_cli[i] && !state_cli[i].err && !state_cli[i].done) pj_ssl_sock_close(ssock_cli[i]); } if (ioqueue) pj_ioqueue_destroy(ioqueue); if (pool) pj_pool_release(pool); return status; }
/* * Compliance test for success scenario. */ static int compliance_test_0(pj_bool_t allow_concur) { pj_sock_t ssock=-1, csock0=-1, csock1=-1; pj_sockaddr_in addr, client_addr, rmt_addr; int client_addr_len; pj_pool_t *pool = NULL; char *send_buf, *recv_buf; pj_ioqueue_t *ioque = NULL; pj_ioqueue_key_t *skey=NULL, *ckey0=NULL, *ckey1=NULL; pj_ioqueue_op_key_t accept_op; int bufsize = BUF_MIN_SIZE; pj_ssize_t status = -1; int pending_op = 0; pj_timestamp t_elapsed; pj_str_t s; pj_status_t rc; // Create pool. pool = pj_pool_create(mem, NULL, POOL_SIZE, 4000, NULL); // Allocate buffers for send and receive. send_buf = (char*)pj_pool_alloc(pool, bufsize); recv_buf = (char*)pj_pool_alloc(pool, bufsize); // Create server socket and client socket for connecting rc = pj_sock_socket(pj_AF_INET(), pj_SOCK_STREAM(), 0, &ssock); if (rc != PJ_SUCCESS) { app_perror("...error creating socket", rc); status=-1; goto on_error; } rc = pj_sock_socket(pj_AF_INET(), pj_SOCK_STREAM(), 0, &csock1); if (rc != PJ_SUCCESS) { app_perror("...error creating socket", rc); status=-1; goto on_error; } // Bind server socket. pj_sockaddr_in_init(&addr, 0, 0); if ((rc=pj_sock_bind(ssock, &addr, sizeof(addr))) != 0 ) { app_perror("...bind error", rc); status=-10; goto on_error; } // Get server address. client_addr_len = sizeof(addr); rc = pj_sock_getsockname(ssock, &addr, &client_addr_len); if (rc != PJ_SUCCESS) { app_perror("...ERROR in pj_sock_getsockname()", rc); status=-15; goto on_error; } addr.sin_addr = pj_inet_addr(pj_cstr(&s, "127.0.0.1")); // Create I/O Queue. rc = pj_ioqueue_create(pool, PJ_IOQUEUE_MAX_HANDLES, &ioque); if (rc != PJ_SUCCESS) { app_perror("...ERROR in pj_ioqueue_create()", rc); status=-20; goto on_error; } // Concurrency rc = pj_ioqueue_set_default_concurrency(ioque, allow_concur); if (rc != PJ_SUCCESS) { app_perror("...ERROR in pj_ioqueue_set_default_concurrency()", rc); status=-21; goto on_error; } // Register server socket and client socket. rc = pj_ioqueue_register_sock(pool, ioque, ssock, NULL, &test_cb, &skey); if (rc == PJ_SUCCESS) rc = pj_ioqueue_register_sock(pool, ioque, csock1, NULL, &test_cb, &ckey1); else ckey1 = NULL; if (rc != PJ_SUCCESS) { app_perror("...ERROR in pj_ioqueue_register_sock()", rc); status=-23; goto on_error; } // Server socket listen(). if (pj_sock_listen(ssock, 5)) { app_perror("...ERROR in pj_sock_listen()", rc); status=-25; goto on_error; } // Server socket accept() client_addr_len = sizeof(pj_sockaddr_in); status = pj_ioqueue_accept(skey, &accept_op, &csock0, &client_addr, &rmt_addr, &client_addr_len); if (status != PJ_EPENDING) { app_perror("...ERROR in pj_ioqueue_accept()", rc); status=-30; goto on_error; } if (status==PJ_EPENDING) { ++pending_op; } // Client socket connect() status = pj_ioqueue_connect(ckey1, &addr, sizeof(addr)); if (status!=PJ_SUCCESS && status != PJ_EPENDING) { app_perror("...ERROR in pj_ioqueue_connect()", rc); status=-40; goto on_error; } if (status==PJ_EPENDING) { ++pending_op; } // Poll until connected callback_read_size = callback_write_size = 0; callback_accept_status = callback_connect_status = -2; callback_call_count = 0; callback_read_key = callback_write_key = callback_accept_key = callback_connect_key = NULL; callback_accept_op = callback_read_op = callback_write_op = NULL; while (pending_op) { pj_time_val timeout = {1, 0}; #ifdef PJ_SYMBIAN callback_call_count = 0; pj_symbianos_poll(-1, 1000); status = callback_call_count; #else status = pj_ioqueue_poll(ioque, &timeout); #endif if (status > 0) { if (callback_accept_status != -2) { if (callback_accept_status != 0) { status=-41; goto on_error; } if (callback_accept_key != skey) { status=-42; goto on_error; } if (callback_accept_op != &accept_op) { status=-43; goto on_error; } callback_accept_status = -2; } if (callback_connect_status != -2) { if (callback_connect_status != 0) { status=-50; goto on_error; } if (callback_connect_key != ckey1) { status=-51; goto on_error; } callback_connect_status = -2; } if (status > pending_op) { PJ_LOG(3,(THIS_FILE, "...error: pj_ioqueue_poll() returned %d " "(only expecting %d)", status, pending_op)); return -52; } pending_op -= status; if (pending_op == 0) { status = 0; } } } // There's no pending operation. // When we poll the ioqueue, there must not be events. if (pending_op == 0) { pj_time_val timeout = {1, 0}; #ifdef PJ_SYMBIAN status = pj_symbianos_poll(-1, 1000); #else status = pj_ioqueue_poll(ioque, &timeout); #endif if (status != 0) { status=-60; goto on_error; } } // Check accepted socket. if (csock0 == PJ_INVALID_SOCKET) { status = -69; app_perror("...accept() error", pj_get_os_error()); goto on_error; } // Register newly accepted socket. rc = pj_ioqueue_register_sock(pool, ioque, csock0, NULL, &test_cb, &ckey0); if (rc != PJ_SUCCESS) { app_perror("...ERROR in pj_ioqueue_register_sock", rc); status = -70; goto on_error; } // Test send and receive. t_elapsed.u32.lo = 0; status = send_recv_test(ioque, ckey0, ckey1, send_buf, recv_buf, bufsize, &t_elapsed); if (status != 0) { goto on_error; } // Success status = 0; on_error: if (skey != NULL) pj_ioqueue_unregister(skey); else if (ssock != PJ_INVALID_SOCKET) pj_sock_close(ssock); if (ckey1 != NULL) pj_ioqueue_unregister(ckey1); else if (csock1 != PJ_INVALID_SOCKET) pj_sock_close(csock1); if (ckey0 != NULL) pj_ioqueue_unregister(ckey0); else if (csock0 != PJ_INVALID_SOCKET) pj_sock_close(csock0); if (ioque != NULL) pj_ioqueue_destroy(ioque); pj_pool_release(pool); return status; }
/* * compliance_test() * To test that the basic IOQueue functionality works. It will just exchange * data between two sockets. */ static int compliance_test(pj_bool_t allow_concur) { pj_sock_t ssock=-1, csock=-1; pj_sockaddr_in addr, dst_addr; int addrlen; pj_pool_t *pool = NULL; char *send_buf, *recv_buf; pj_ioqueue_t *ioque = NULL; pj_ioqueue_key_t *skey = NULL, *ckey = NULL; pj_ioqueue_op_key_t read_op, write_op; int bufsize = BUF_MIN_SIZE; pj_ssize_t bytes; int status = -1; pj_str_t temp; pj_bool_t send_pending, recv_pending; pj_status_t rc; pj_set_os_error(PJ_SUCCESS); // Create pool. pool = pj_pool_create(mem, NULL, POOL_SIZE, 4000, NULL); // Allocate buffers for send and receive. send_buf = (char*)pj_pool_alloc(pool, bufsize); recv_buf = (char*)pj_pool_alloc(pool, bufsize); // Allocate sockets for sending and receiving. TRACE_("creating sockets..."); rc = pj_sock_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, &ssock); if (rc==PJ_SUCCESS) rc = pj_sock_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, &csock); else csock = PJ_INVALID_SOCKET; if (rc != PJ_SUCCESS) { app_perror("...ERROR in pj_sock_socket()", rc); status=-1; goto on_error; } // Bind server socket. TRACE_("bind socket..."); pj_bzero(&addr, sizeof(addr)); addr.sin_family = pj_AF_INET(); addr.sin_port = pj_htons(PORT); if (pj_sock_bind(ssock, &addr, sizeof(addr))) { status=-10; goto on_error; } // Create I/O Queue. TRACE_("create ioqueue..."); rc = pj_ioqueue_create(pool, PJ_IOQUEUE_MAX_HANDLES, &ioque); if (rc != PJ_SUCCESS) { status=-20; goto on_error; } // Set concurrency TRACE_("set concurrency..."); rc = pj_ioqueue_set_default_concurrency(ioque, allow_concur); if (rc != PJ_SUCCESS) { status=-21; goto on_error; } // Register server and client socket. // We put this after inactivity socket, hopefully this can represent the // worst waiting time. TRACE_("registering first sockets..."); rc = pj_ioqueue_register_sock(pool, ioque, ssock, NULL, &test_cb, &skey); if (rc != PJ_SUCCESS) { app_perror("...error(10): ioqueue_register error", rc); status=-25; goto on_error; } TRACE_("registering second sockets..."); rc = pj_ioqueue_register_sock( pool, ioque, csock, NULL, &test_cb, &ckey); if (rc != PJ_SUCCESS) { app_perror("...error(11): ioqueue_register error", rc); status=-26; goto on_error; } // Randomize send_buf. pj_create_random_string(send_buf, bufsize); // Register reading from ioqueue. TRACE_("start recvfrom..."); pj_bzero(&addr, sizeof(addr)); addrlen = sizeof(addr); bytes = bufsize; rc = pj_ioqueue_recvfrom(skey, &read_op, recv_buf, &bytes, 0, &addr, &addrlen); if (rc != PJ_SUCCESS && rc != PJ_EPENDING) { app_perror("...error: pj_ioqueue_recvfrom", rc); status=-28; goto on_error; } else if (rc == PJ_EPENDING) { recv_pending = 1; PJ_LOG(3, (THIS_FILE, "......ok: recvfrom returned pending")); } else { PJ_LOG(3, (THIS_FILE, "......error: recvfrom returned immediate ok!")); status=-29; goto on_error; } // Set destination address to send the packet. TRACE_("set destination address..."); temp = pj_str("127.0.0.1"); if ((rc=pj_sockaddr_in_init(&dst_addr, &temp, PORT)) != 0) { app_perror("...error: unable to resolve 127.0.0.1", rc); status=-290; goto on_error; } // Write must return the number of bytes. TRACE_("start sendto..."); bytes = bufsize; rc = pj_ioqueue_sendto(ckey, &write_op, send_buf, &bytes, 0, &dst_addr, sizeof(dst_addr)); if (rc != PJ_SUCCESS && rc != PJ_EPENDING) { app_perror("...error: pj_ioqueue_sendto", rc); status=-30; goto on_error; } else if (rc == PJ_EPENDING) { send_pending = 1; PJ_LOG(3, (THIS_FILE, "......ok: sendto returned pending")); } else { send_pending = 0; PJ_LOG(3, (THIS_FILE, "......ok: sendto returned immediate success")); } // reset callback variables. callback_read_size = callback_write_size = 0; callback_accept_status = callback_connect_status = -2; callback_read_key = callback_write_key = callback_accept_key = callback_connect_key = NULL; callback_read_op = callback_write_op = NULL; // Poll if pending. while (send_pending || recv_pending) { int rc; pj_time_val timeout = { 5, 0 }; TRACE_("poll..."); #ifdef PJ_SYMBIAN rc = pj_symbianos_poll(-1, PJ_TIME_VAL_MSEC(timeout)); #else rc = pj_ioqueue_poll(ioque, &timeout); #endif if (rc == 0) { PJ_LOG(1,(THIS_FILE, "...ERROR: timed out...")); status=-45; goto on_error; } else if (rc < 0) { app_perror("...ERROR in ioqueue_poll()", -rc); status=-50; goto on_error; } if (callback_read_key != NULL) { if (callback_read_size != bufsize) { status=-61; goto on_error; } if (callback_read_key != skey) { status=-65; goto on_error; } if (callback_read_op != &read_op) { status=-66; goto on_error; } if (pj_memcmp(send_buf, recv_buf, bufsize) != 0) { status=-67; goto on_error; } if (addrlen != sizeof(pj_sockaddr_in)) { status=-68; goto on_error; } if (addr.sin_family != pj_AF_INET()) { status=-69; goto on_error; } recv_pending = 0; } if (callback_write_key != NULL) { if (callback_write_size != bufsize) { status=-73; goto on_error; } if (callback_write_key != ckey) { status=-75; goto on_error; } if (callback_write_op != &write_op) { status=-76; goto on_error; } send_pending = 0; } } // Success status = 0; on_error: if (skey) pj_ioqueue_unregister(skey); else if (ssock != -1) pj_sock_close(ssock); if (ckey) pj_ioqueue_unregister(ckey); else if (csock != -1) pj_sock_close(csock); if (ioque != NULL) pj_ioqueue_destroy(ioque); pj_pool_release(pool); return status; }
/* * unregister_test() * Check if callback is still called after socket has been unregistered or * closed. */ static int unregister_test(pj_bool_t allow_concur) { enum { RPORT = 50000, SPORT = 50001 }; pj_pool_t *pool; pj_ioqueue_t *ioqueue; pj_sock_t ssock; pj_sock_t rsock; int addrlen; pj_sockaddr_in addr; pj_ioqueue_key_t *key; pj_ioqueue_op_key_t opkey; pj_ioqueue_callback cb; unsigned packet_cnt; char sendbuf[10], recvbuf[10]; pj_ssize_t bytes; pj_time_val timeout; pj_status_t status; pool = pj_pool_create(mem, "test", 4000, 4000, NULL); if (!pool) { app_perror("Unable to create pool", PJ_ENOMEM); return -100; } status = pj_ioqueue_create(pool, 16, &ioqueue); if (status != PJ_SUCCESS) { app_perror("Error creating ioqueue", status); return -110; } // Set concurrency TRACE_("set concurrency..."); status = pj_ioqueue_set_default_concurrency(ioqueue, allow_concur); if (status != PJ_SUCCESS) { return -112; } /* Create sender socket */ status = app_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, SPORT, &ssock); if (status != PJ_SUCCESS) { app_perror("Error initializing socket", status); return -120; } /* Create receiver socket. */ status = app_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, RPORT, &rsock); if (status != PJ_SUCCESS) { app_perror("Error initializing socket", status); return -130; } /* Register rsock to ioqueue. */ pj_bzero(&cb, sizeof(cb)); cb.on_read_complete = &on_read_complete; packet_cnt = 0; status = pj_ioqueue_register_sock(pool, ioqueue, rsock, &packet_cnt, &cb, &key); if (status != PJ_SUCCESS) { app_perror("Error registering to ioqueue", status); return -140; } /* Init operation key. */ pj_ioqueue_op_key_init(&opkey, sizeof(opkey)); /* Start reading. */ bytes = sizeof(recvbuf); status = pj_ioqueue_recv( key, &opkey, recvbuf, &bytes, 0); if (status != PJ_EPENDING) { app_perror("Expecting PJ_EPENDING, but got this", status); return -150; } /* Init destination address. */ addrlen = sizeof(addr); status = pj_sock_getsockname(rsock, &addr, &addrlen); if (status != PJ_SUCCESS) { app_perror("getsockname error", status); return -160; } /* Override address with 127.0.0.1, since getsockname will return * zero in the address field. */ addr.sin_addr = pj_inet_addr2("127.0.0.1"); /* Init buffer to send */ pj_ansi_strcpy(sendbuf, "Hello0123"); /* Send one packet. */ bytes = sizeof(sendbuf); status = pj_sock_sendto(ssock, sendbuf, &bytes, 0, &addr, sizeof(addr)); if (status != PJ_SUCCESS) { app_perror("sendto error", status); return -170; } /* Check if packet is received. */ timeout.sec = 1; timeout.msec = 0; #ifdef PJ_SYMBIAN pj_symbianos_poll(-1, 1000); #else pj_ioqueue_poll(ioqueue, &timeout); #endif if (packet_cnt != 1) { return -180; } /* Just to make sure things are settled.. */ pj_thread_sleep(100); /* Start reading again. */ bytes = sizeof(recvbuf); status = pj_ioqueue_recv( key, &opkey, recvbuf, &bytes, 0); if (status != PJ_EPENDING) { app_perror("Expecting PJ_EPENDING, but got this", status); return -190; } /* Reset packet counter */ packet_cnt = 0; /* Send one packet. */ bytes = sizeof(sendbuf); status = pj_sock_sendto(ssock, sendbuf, &bytes, 0, &addr, sizeof(addr)); if (status != PJ_SUCCESS) { app_perror("sendto error", status); return -200; } /* Now unregister and close socket. */ pj_ioqueue_unregister(key); /* Poll ioqueue. */ #ifdef PJ_SYMBIAN pj_symbianos_poll(-1, 1000); #else timeout.sec = 1; timeout.msec = 0; pj_ioqueue_poll(ioqueue, &timeout); #endif /* Must NOT receive any packets after socket is closed! */ if (packet_cnt > 0) { PJ_LOG(3,(THIS_FILE, "....errror: not expecting to receive packet " "after socket has been closed")); return -210; } /* Success */ pj_sock_close(ssock); pj_ioqueue_destroy(ioqueue); pj_pool_release(pool); return 0; }
int http_client_test_delete() { pj_str_t url; pj_http_req_callback hcb; pj_http_req_param param; char urlbuf[80]; pj_bzero(&hcb, sizeof(hcb)); hcb.on_complete = &on_complete; hcb.on_response = &on_response; /* Create pool, timer, and ioqueue */ pool = pj_pool_create(mem, NULL, 8192, 4096, NULL); if (pj_timer_heap_create(pool, 16, &timer_heap)) return -61; if (pj_ioqueue_create(pool, 16, &ioqueue)) return -62; #ifdef USE_LOCAL_SERVER thread_quit = PJ_FALSE; g_server.action = ACTION_REPLY; g_server.send_content_length = PJ_TRUE; g_server.data_size = 0; g_server.buf_size = 1024; sstatus = pj_sock_socket(pj_AF_INET(), pj_SOCK_STREAM(), 0, &g_server.sock); if (sstatus != PJ_SUCCESS) return -41; pj_sockaddr_in_init(&addr, NULL, 0); sstatus = pj_sock_bind(g_server.sock, &addr, sizeof(addr)); if (sstatus != PJ_SUCCESS) return -43; { pj_sockaddr_in addr; int addr_len = sizeof(addr); sstatus = pj_sock_getsockname(g_server.sock, &addr, &addr_len); if (sstatus != PJ_SUCCESS) return -44; g_server.port = pj_sockaddr_in_get_port(&addr); pj_ansi_snprintf(urlbuf, sizeof(urlbuf), "http://127.0.0.1:%d/test/test2.txt", g_server.port); url = pj_str(urlbuf); } sstatus = pj_sock_listen(g_server.sock, 8); if (sstatus != PJ_SUCCESS) return -45; sstatus = pj_thread_create(pool, NULL, &server_thread, &g_server, 0, 0, &g_server.thread); if (sstatus != PJ_SUCCESS) return -47; #else pj_cstr(&url, "http://127.0.0.1:280/test/test2.txt"); #endif pj_http_req_param_default(¶m); pj_strset2(¶m.method, (char*)"DELETE"); if (pj_http_req_create(pool, &url, timer_heap, ioqueue, ¶m, &hcb, &http_req)) return -63; if (pj_http_req_start(http_req)) return -65; while (pj_http_req_is_running(http_req)) { pj_time_val delay = {0, 50}; pj_ioqueue_poll(ioqueue, &delay); pj_timer_heap_poll(timer_heap, NULL); } #ifdef USE_LOCAL_SERVER thread_quit = PJ_TRUE; pj_thread_join(g_server.thread); pj_sock_close(g_server.sock); #endif pj_http_req_destroy(http_req); pj_ioqueue_destroy(ioqueue); pj_timer_heap_destroy(timer_heap); pj_pool_release(pool); return PJ_SUCCESS; }
/* * Perform unregistration test. * * This will create ioqueue and register a server socket. Depending * on the test method, either the callback or the main thread will * unregister and destroy the server socket after some period of time. */ static int perform_unreg_test(pj_ioqueue_t *ioqueue, pj_pool_t *test_pool, const char *title, pj_bool_t other_socket) { enum { WORKER_CNT = 1, MSEC = 500, QUIT_MSEC = 500 }; int i; pj_thread_t *thread[WORKER_CNT]; struct sock_data osd; pj_ioqueue_callback callback; pj_time_val end_time; pj_status_t status; /* Sometimes its important to have other sockets registered to * the ioqueue, because when no sockets are registered, the ioqueue * will return from the poll early. */ if (other_socket) { status = app_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, 56127, &osd.sock); if (status != PJ_SUCCESS) { app_perror("Error creating other socket", status); return -12; } pj_bzero(&callback, sizeof(callback)); status = pj_ioqueue_register_sock(test_pool, ioqueue, osd.sock, NULL, &callback, &osd.key); if (status != PJ_SUCCESS) { app_perror("Error registering other socket", status); return -13; } } else { osd.key = NULL; osd.sock = PJ_INVALID_SOCKET; } /* Init both time duration of testing */ thread_quitting = 0; pj_gettimeofday(&time_to_unregister); time_to_unregister.msec += MSEC; pj_time_val_normalize(&time_to_unregister); end_time = time_to_unregister; end_time.msec += QUIT_MSEC; pj_time_val_normalize(&end_time); /* Create polling thread */ for (i=0; i<WORKER_CNT; ++i) { status = pj_thread_create(test_pool, "unregtest", &worker_thread, ioqueue, 0, 0, &thread[i]); if (status != PJ_SUCCESS) { app_perror("Error creating thread", status); return -20; } } /* Create pair of client/server sockets */ status = app_socketpair(pj_AF_INET(), pj_SOCK_DGRAM(), 0, &sock_data.sock, &sock_data.csock); if (status != PJ_SUCCESS) { app_perror("app_socketpair error", status); return -30; } /* Initialize test data */ sock_data.pool = pj_pool_create(mem, "sd", 1000, 1000, NULL); sock_data.buffer = (char*) pj_pool_alloc(sock_data.pool, 128); sock_data.bufsize = 128; sock_data.op_key = (pj_ioqueue_op_key_t*) pj_pool_alloc(sock_data.pool, sizeof(*sock_data.op_key)); sock_data.received = 0; sock_data.unregistered = 0; pj_ioqueue_op_key_init(sock_data.op_key, sizeof(*sock_data.op_key)); status = pj_mutex_create_simple(sock_data.pool, "sd", &sock_data.mutex); if (status != PJ_SUCCESS) { app_perror("create_mutex() error", status); return -35; } /* Register socket to ioqueue */ pj_bzero(&callback, sizeof(callback)); callback.on_read_complete = &on_read_complete; status = pj_ioqueue_register_sock(sock_data.pool, ioqueue, sock_data.sock, NULL, &callback, &sock_data.key); if (status != PJ_SUCCESS) { app_perror("pj_ioqueue_register error", status); return -40; } /* Bootstrap the first send/receive */ on_read_complete(sock_data.key, sock_data.op_key, 0); /* Loop until test time ends */ for (;;) { pj_time_val now, timeout; pj_gettimeofday(&now); if (test_method == UNREGISTER_IN_APP && PJ_TIME_VAL_GTE(now, time_to_unregister) && sock_data.pool) { pj_mutex_lock(sock_data.mutex); sock_data.unregistered = 1; pj_ioqueue_unregister(sock_data.key); pj_mutex_unlock(sock_data.mutex); pj_mutex_destroy(sock_data.mutex); pj_pool_release(sock_data.pool); sock_data.pool = NULL; } if (PJ_TIME_VAL_GT(now, end_time) && sock_data.unregistered) break; timeout.sec = 0; timeout.msec = 10; pj_ioqueue_poll(ioqueue, &timeout); //pj_thread_sleep(1); } thread_quitting = 1; for (i=0; i<WORKER_CNT; ++i) { pj_thread_join(thread[i]); pj_thread_destroy(thread[i]); } if (other_socket) { pj_ioqueue_unregister(osd.key); } pj_sock_close(sock_data.csock); PJ_LOG(3,(THIS_FILE, "....%s: done (%d KB/s)", title, sock_data.received * 1000 / MSEC / 1000)); return 0; }
/* * GET request scenario 2: using on_complete() to get the * complete data. Server does not reply with content-length. * Request timed out, application sets a longer timeout, then * then restart the request. */ int http_client_test2() { pj_str_t url; pj_http_req_callback hcb; pj_http_req_param param; pj_time_val timeout; char urlbuf[80]; pj_bzero(&hcb, sizeof(hcb)); hcb.on_complete = &on_complete; hcb.on_response = &on_response; pj_http_req_param_default(¶m); /* Create pool, timer, and ioqueue */ pool = pj_pool_create(mem, NULL, 8192, 4096, NULL); if (pj_timer_heap_create(pool, 16, &timer_heap)) return -41; if (pj_ioqueue_create(pool, 16, &ioqueue)) return -42; #ifdef USE_LOCAL_SERVER pj_cstr(&url, "http://127.0.0.1:380"); param.timeout.sec = 0; param.timeout.msec = 2000; thread_quit = PJ_FALSE; g_server.action = ACTION_IGNORE; g_server.send_content_length = PJ_FALSE; g_server.data_size = 4173; g_server.buf_size = 1024; sstatus = pj_sock_socket(pj_AF_INET(), pj_SOCK_STREAM(), 0, &g_server.sock); if (sstatus != PJ_SUCCESS) return -41; pj_sockaddr_in_init(&addr, NULL, 0); sstatus = pj_sock_bind(g_server.sock, &addr, sizeof(addr)); if (sstatus != PJ_SUCCESS) return -43; { pj_sockaddr_in addr; int addr_len = sizeof(addr); sstatus = pj_sock_getsockname(g_server.sock, &addr, &addr_len); if (sstatus != PJ_SUCCESS) return -44; g_server.port = pj_sockaddr_in_get_port(&addr); pj_ansi_snprintf(urlbuf, sizeof(urlbuf), "http://127.0.0.1:%d", g_server.port); url = pj_str(urlbuf); } sstatus = pj_sock_listen(g_server.sock, 8); if (sstatus != PJ_SUCCESS) return -45; sstatus = pj_thread_create(pool, NULL, &server_thread, &g_server, 0, 0, &g_server.thread); if (sstatus != PJ_SUCCESS) return -47; #else pj_cstr(&url, "http://www.google.com.sg"); param.timeout.sec = 0; param.timeout.msec = 50; #endif pj_http_headers_add_elmt2(¶m.headers, (char*)"Accept", (char*)"image/gif, image/x-xbitmap, image/jpeg, " "image/pjpeg, application/x-ms-application," " application/vnd.ms-xpsdocument, " "application/xaml+xml, " "application/x-ms-xbap, " "application/x-shockwave-flash, " "application/vnd.ms-excel, " "application/vnd.ms-powerpoint, " "application/msword, */*"); pj_http_headers_add_elmt2(¶m.headers, (char*)"Accept-Language", (char*)"en-sg"); pj_http_headers_add_elmt2(¶m.headers, (char*)"User-Agent", (char*)"Mozilla/4.0 (compatible; MSIE 7.0; " "Windows NT 6.0; SLCC1; " ".NET CLR 2.0.50727; " ".NET CLR 3.0.04506)"); if (pj_http_req_create(pool, &url, timer_heap, ioqueue, ¶m, &hcb, &http_req)) return -43; if (pj_http_req_start(http_req)) return -45; while (pj_http_req_is_running(http_req)) { pj_time_val delay = {0, 50}; pj_ioqueue_poll(ioqueue, &delay); pj_timer_heap_poll(timer_heap, NULL); } #ifdef USE_LOCAL_SERVER g_server.action = ACTION_REPLY; #endif timeout.sec = 0; timeout.msec = 10000; pj_http_req_set_timeout(http_req, &timeout); if (pj_http_req_start(http_req)) return -47; while (pj_http_req_is_running(http_req)) { pj_time_val delay = {0, 50}; pj_ioqueue_poll(ioqueue, &delay); pj_timer_heap_poll(timer_heap, NULL); } #ifdef USE_LOCAL_SERVER thread_quit = PJ_TRUE; pj_thread_join(g_server.thread); pj_sock_close(g_server.sock); #endif pj_http_req_destroy(http_req); pj_ioqueue_destroy(ioqueue); pj_timer_heap_destroy(timer_heap); pj_pool_release(pool); return PJ_SUCCESS; }
static int tcp_perf_test(void) { enum { COUNT=100000 }; pj_pool_t *pool = NULL; pj_ioqueue_t *ioqueue = NULL; pj_sock_t sock1=PJ_INVALID_SOCKET, sock2=PJ_INVALID_SOCKET; pj_activesock_t *asock1 = NULL, *asock2 = NULL; pj_activesock_cb cb; struct tcp_state *state1, *state2; unsigned i; pj_status_t status; pool = pj_pool_create(mem, "tcpperf", 256, 256, NULL); status = app_socketpair(pj_AF_INET(), pj_SOCK_STREAM(), 0, &sock1, &sock2); if (status != PJ_SUCCESS) { status = -100; goto on_return; } status = pj_ioqueue_create(pool, 4, &ioqueue); if (status != PJ_SUCCESS) { status = -110; goto on_return; } pj_bzero(&cb, sizeof(cb)); cb.on_data_read = &tcp_on_data_read; cb.on_data_sent = &tcp_on_data_sent; state1 = PJ_POOL_ZALLOC_T(pool, struct tcp_state); status = pj_activesock_create(pool, sock1, pj_SOCK_STREAM(), NULL, ioqueue, &cb, state1, &asock1); if (status != PJ_SUCCESS) { status = -120; goto on_return; } state2 = PJ_POOL_ZALLOC_T(pool, struct tcp_state); status = pj_activesock_create(pool, sock2, pj_SOCK_STREAM(), NULL, ioqueue, &cb, state2, &asock2); if (status != PJ_SUCCESS) { status = -130; goto on_return; } status = pj_activesock_start_read(asock1, pool, 1000, 0); if (status != PJ_SUCCESS) { status = -140; goto on_return; } /* Send packet as quickly as possible */ for (i=0; i<COUNT && !state1->err && !state2->err; ++i) { struct tcp_pkt *pkt; struct send_key send_key[2], *op_key; pj_ssize_t len; pkt = (struct tcp_pkt*)state2->pkt; pkt->signature = SIGNATURE; pkt->seq = i; pj_memset(pkt->fill, 'a', sizeof(pkt->fill)); op_key = &send_key[i%2]; pj_ioqueue_op_key_init(&op_key->op_key, sizeof(*op_key)); state2->sent = PJ_FALSE; len = sizeof(*pkt); status = pj_activesock_send(asock2, &op_key->op_key, pkt, &len, 0); if (status == PJ_EPENDING) { do { #if PJ_SYMBIAN pj_symbianos_poll(-1, -1); #else pj_ioqueue_poll(ioqueue, NULL); #endif } while (!state2->sent); } else { #if PJ_SYMBIAN /* The Symbian socket always returns PJ_SUCCESS for TCP send, * eventhough the remote end hasn't received the data yet. * If we continue sending, eventually send() will block, * possibly because the send buffer is full. So we need to * poll the ioqueue periodically, to let receiver gets the * data. */ pj_symbianos_poll(-1, 0); #endif if (status != PJ_SUCCESS) { PJ_LOG(1,("", " err: send status=%d", status)); status = -180; break; } else if (status == PJ_SUCCESS) { if (len != sizeof(*pkt)) { PJ_LOG(1,("", " err: shouldn't report partial sent")); status = -190; break; } } } } /* Wait until everything has been sent/received */ if (state1->next_recv_seq < COUNT) { #ifdef PJ_SYMBIAN while (pj_symbianos_poll(-1, 1000) == PJ_TRUE) ; #else pj_time_val delay = {0, 100}; while (pj_ioqueue_poll(ioqueue, &delay) > 0) ; #endif } if (status == PJ_EPENDING) status = PJ_SUCCESS; if (status != 0) goto on_return; if (state1->err) { status = -183; goto on_return; } if (state2->err) { status = -186; goto on_return; } if (state1->next_recv_seq != COUNT) { PJ_LOG(3,("", " err: only %u packets received, expecting %u", state1->next_recv_seq, COUNT)); status = -195; goto on_return; } on_return: if (asock2) pj_activesock_close(asock2); if (asock1) pj_activesock_close(asock1); if (ioqueue) pj_ioqueue_destroy(ioqueue); if (pool) pj_pool_release(pool); return status; }
/* * Compliance test for failed scenario. * In this case, the client connects to a non-existant service. */ static int compliance_test_1(pj_bool_t allow_concur) { pj_sock_t csock1=PJ_INVALID_SOCKET; pj_sockaddr_in addr; pj_pool_t *pool = NULL; pj_ioqueue_t *ioque = NULL; pj_ioqueue_key_t *ckey1 = NULL; pj_ssize_t status = -1; int pending_op = 0; pj_str_t s; pj_status_t rc; // Create pool. pool = pj_pool_create(mem, NULL, POOL_SIZE, 4000, NULL); // Create I/O Queue. rc = pj_ioqueue_create(pool, PJ_IOQUEUE_MAX_HANDLES, &ioque); if (!ioque) { status=-20; goto on_error; } // Concurrency rc = pj_ioqueue_set_default_concurrency(ioque, allow_concur); if (rc != PJ_SUCCESS) { status=-21; goto on_error; } // Create client socket rc = pj_sock_socket(pj_AF_INET(), pj_SOCK_STREAM(), 0, &csock1); if (rc != PJ_SUCCESS) { app_perror("...ERROR in pj_sock_socket()", rc); status=-1; goto on_error; } // Register client socket. rc = pj_ioqueue_register_sock(pool, ioque, csock1, NULL, &test_cb, &ckey1); if (rc != PJ_SUCCESS) { app_perror("...ERROR in pj_ioqueue_register_sock()", rc); status=-23; goto on_error; } // Initialize remote address. pj_sockaddr_in_init(&addr, pj_cstr(&s, "127.0.0.1"), NON_EXISTANT_PORT); // Client socket connect() status = pj_ioqueue_connect(ckey1, &addr, sizeof(addr)); if (status==PJ_SUCCESS) { // unexpectedly success! status = -30; goto on_error; } if (status != PJ_EPENDING) { // success } else { ++pending_op; } callback_connect_status = -2; callback_connect_key = NULL; // Poll until we've got result while (pending_op) { pj_time_val timeout = {1, 0}; #ifdef PJ_SYMBIAN callback_call_count = 0; pj_symbianos_poll(-1, 1000); status = callback_call_count; #else status = pj_ioqueue_poll(ioque, &timeout); #endif if (status > 0) { if (callback_connect_key==ckey1) { if (callback_connect_status == 0) { // unexpectedly connected! status = -50; goto on_error; } } if (status > pending_op) { PJ_LOG(3,(THIS_FILE, "...error: pj_ioqueue_poll() returned %d " "(only expecting %d)", status, pending_op)); return -552; } pending_op -= status; if (pending_op == 0) { status = 0; } } } // There's no pending operation. // When we poll the ioqueue, there must not be events. if (pending_op == 0) { pj_time_val timeout = {1, 0}; #ifdef PJ_SYMBIAN status = pj_symbianos_poll(-1, 1000); #else status = pj_ioqueue_poll(ioque, &timeout); #endif if (status != 0) { status=-60; goto on_error; } } // Success status = 0; on_error: if (ckey1 != NULL) pj_ioqueue_unregister(ckey1); else if (csock1 != PJ_INVALID_SOCKET) pj_sock_close(csock1); if (ioque != NULL) pj_ioqueue_destroy(ioque); pj_pool_release(pool); return status; }
static pj_status_t krx_ice_handle_events(krx_ice* k, unsigned int maxms, unsigned int* pcount) { if(!k) { printf("Error: krx_ice_handle_events(), invalid krx_ice pointer.\n"); return PJ_FALSE; } printf("lets poll: %p.\n", k); pj_time_val max_timeout = { 0, 0 }; pj_time_val timeout = { 0, 0 }; unsigned int count = 0; unsigned int net_event_count = 0; int c; max_timeout.msec = maxms; timeout.sec = timeout.msec = 0; /* poll the timer to run it and also retrieve earliest entry */ c = pj_timer_heap_poll(k->ice_cfg.stun_cfg.timer_heap, &timeout); if(c > 0) { count += c; } /* timer_heap_poll should never return negative values! */ if(timeout.sec < 0 || timeout.msec < 0) { printf("Error: timer returns negative values. Should never happen.\n"); exit(1); } if(timeout.msec >= 1000) { timeout.msec = 999; } /* use the minimum timeout value */ if(PJ_TIME_VAL_GT(timeout, max_timeout)) { timeout = max_timeout; } /* poll ioqueue */ do { c = pj_ioqueue_poll(k->ice_cfg.stun_cfg.ioqueue, &timeout); if(c < 0) { pj_status_t err = pj_get_netos_error(); pj_thread_sleep(PJ_TIME_VAL_MSEC(timeout)); if(pcount) { *pcount = count; return err; } else if(c == 0) { break; } else { net_event_count += c; timeout.sec = timeout.msec = 0; } } } while(c > 0 && net_event_count < 1 ); count += net_event_count; if(pcount) { *pcount = count; } return PJ_SUCCESS; }
/* * Benchmarking IOQueue */ static int bench_test(pj_bool_t allow_concur, int bufsize, int inactive_sock_count) { pj_sock_t ssock=-1, csock=-1; pj_sockaddr_in addr; pj_pool_t *pool = NULL; pj_sock_t *inactive_sock=NULL; pj_ioqueue_op_key_t *inactive_read_op; char *send_buf, *recv_buf; pj_ioqueue_t *ioque = NULL; pj_ioqueue_key_t *skey, *ckey, *keys[SOCK_INACTIVE_MAX+2]; pj_timestamp t1, t2, t_elapsed; int rc=0, i; /* i must be signed */ pj_str_t temp; char errbuf[PJ_ERR_MSG_SIZE]; TRACE__((THIS_FILE, " bench test %d", inactive_sock_count)); // Create pool. pool = pj_pool_create(mem, NULL, POOL_SIZE, 4000, NULL); // Allocate buffers for send and receive. send_buf = (char*)pj_pool_alloc(pool, bufsize); recv_buf = (char*)pj_pool_alloc(pool, bufsize); // Allocate sockets for sending and receiving. rc = pj_sock_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, &ssock); if (rc == PJ_SUCCESS) { rc = pj_sock_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, &csock); } else csock = PJ_INVALID_SOCKET; if (rc != PJ_SUCCESS) { app_perror("...error: pj_sock_socket()", rc); goto on_error; } // Bind server socket. pj_bzero(&addr, sizeof(addr)); addr.sin_family = pj_AF_INET(); addr.sin_port = pj_htons(PORT); if (pj_sock_bind(ssock, &addr, sizeof(addr))) goto on_error; pj_assert(inactive_sock_count+2 <= PJ_IOQUEUE_MAX_HANDLES); // Create I/O Queue. rc = pj_ioqueue_create(pool, PJ_IOQUEUE_MAX_HANDLES, &ioque); if (rc != PJ_SUCCESS) { app_perror("...error: pj_ioqueue_create()", rc); goto on_error; } // Set concurrency rc = pj_ioqueue_set_default_concurrency(ioque, allow_concur); if (rc != PJ_SUCCESS) { app_perror("...error: pj_ioqueue_set_default_concurrency()", rc); goto on_error; } // Allocate inactive sockets, and bind them to some arbitrary address. // Then register them to the I/O queue, and start a read operation. inactive_sock = (pj_sock_t*)pj_pool_alloc(pool, inactive_sock_count*sizeof(pj_sock_t)); inactive_read_op = (pj_ioqueue_op_key_t*)pj_pool_alloc(pool, inactive_sock_count*sizeof(pj_ioqueue_op_key_t)); pj_bzero(&addr, sizeof(addr)); addr.sin_family = pj_AF_INET(); for (i=0; i<inactive_sock_count; ++i) { pj_ssize_t bytes; rc = pj_sock_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, &inactive_sock[i]); if (rc != PJ_SUCCESS || inactive_sock[i] < 0) { app_perror("...error: pj_sock_socket()", rc); goto on_error; } if ((rc=pj_sock_bind(inactive_sock[i], &addr, sizeof(addr))) != 0) { pj_sock_close(inactive_sock[i]); inactive_sock[i] = PJ_INVALID_SOCKET; app_perror("...error: pj_sock_bind()", rc); goto on_error; } rc = pj_ioqueue_register_sock(pool, ioque, inactive_sock[i], NULL, &test_cb, &keys[i]); if (rc != PJ_SUCCESS) { pj_sock_close(inactive_sock[i]); inactive_sock[i] = PJ_INVALID_SOCKET; app_perror("...error(1): pj_ioqueue_register_sock()", rc); PJ_LOG(3,(THIS_FILE, "....i=%d", i)); goto on_error; } bytes = bufsize; rc = pj_ioqueue_recv(keys[i], &inactive_read_op[i], recv_buf, &bytes, 0); if (rc != PJ_EPENDING) { pj_sock_close(inactive_sock[i]); inactive_sock[i] = PJ_INVALID_SOCKET; app_perror("...error: pj_ioqueue_read()", rc); goto on_error; } } // Register server and client socket. // We put this after inactivity socket, hopefully this can represent the // worst waiting time. rc = pj_ioqueue_register_sock(pool, ioque, ssock, NULL, &test_cb, &skey); if (rc != PJ_SUCCESS) { app_perror("...error(2): pj_ioqueue_register_sock()", rc); goto on_error; } rc = pj_ioqueue_register_sock(pool, ioque, csock, NULL, &test_cb, &ckey); if (rc != PJ_SUCCESS) { app_perror("...error(3): pj_ioqueue_register_sock()", rc); goto on_error; } // Set destination address to send the packet. pj_sockaddr_in_init(&addr, pj_cstr(&temp, "127.0.0.1"), PORT); // Test loop. t_elapsed.u64 = 0; for (i=0; i<LOOP; ++i) { pj_ssize_t bytes; pj_ioqueue_op_key_t read_op, write_op; // Randomize send buffer. pj_create_random_string(send_buf, bufsize); // Start reading on the server side. bytes = bufsize; rc = pj_ioqueue_recv(skey, &read_op, recv_buf, &bytes, 0); if (rc != PJ_EPENDING) { app_perror("...error: pj_ioqueue_read()", rc); break; } // Starts send on the client side. bytes = bufsize; rc = pj_ioqueue_sendto(ckey, &write_op, send_buf, &bytes, 0, &addr, sizeof(addr)); if (rc != PJ_SUCCESS && rc != PJ_EPENDING) { app_perror("...error: pj_ioqueue_write()", rc); break; } if (rc == PJ_SUCCESS) { if (bytes < 0) { app_perror("...error: pj_ioqueue_sendto()",(pj_status_t)-bytes); break; } } // Begin time. pj_get_timestamp(&t1); // Poll the queue until we've got completion event in the server side. callback_read_key = NULL; callback_read_size = 0; TRACE__((THIS_FILE, " waiting for key = %p", skey)); do { pj_time_val timeout = { 1, 0 }; #ifdef PJ_SYMBIAN rc = pj_symbianos_poll(-1, PJ_TIME_VAL_MSEC(timeout)); #else rc = pj_ioqueue_poll(ioque, &timeout); #endif TRACE__((THIS_FILE, " poll rc=%d", rc)); } while (rc >= 0 && callback_read_key != skey); // End time. pj_get_timestamp(&t2); t_elapsed.u64 += (t2.u64 - t1.u64); if (rc < 0) { app_perror(" error: pj_ioqueue_poll", -rc); break; } // Compare recv buffer with send buffer. if (callback_read_size != bufsize || pj_memcmp(send_buf, recv_buf, bufsize)) { rc = -10; PJ_LOG(3,(THIS_FILE, " error: size/buffer mismatch")); break; } // Poll until all events are exhausted, before we start the next loop. do { pj_time_val timeout = { 0, 10 }; #ifdef PJ_SYMBIAN PJ_UNUSED_ARG(timeout); rc = pj_symbianos_poll(-1, 100); #else rc = pj_ioqueue_poll(ioque, &timeout); #endif } while (rc>0); rc = 0; } // Print results if (rc == 0) { pj_timestamp tzero; pj_uint32_t usec_delay; tzero.u32.hi = tzero.u32.lo = 0; usec_delay = pj_elapsed_usec( &tzero, &t_elapsed); PJ_LOG(3, (THIS_FILE, "...%10d %15d % 9d", bufsize, inactive_sock_count, usec_delay)); } else { PJ_LOG(2, (THIS_FILE, "...ERROR rc=%d (buf:%d, fds:%d)", rc, bufsize, inactive_sock_count+2)); } // Cleaning up. for (i=inactive_sock_count-1; i>=0; --i) { pj_ioqueue_unregister(keys[i]); } pj_ioqueue_unregister(skey); pj_ioqueue_unregister(ckey); pj_ioqueue_destroy(ioque); pj_pool_release( pool); return rc; on_error: PJ_LOG(1,(THIS_FILE, "...ERROR: %s", pj_strerror(pj_get_netos_error(), errbuf, sizeof(errbuf)))); if (ssock) pj_sock_close(ssock); if (csock) pj_sock_close(csock); for (i=0; i<inactive_sock_count && inactive_sock && inactive_sock[i]!=PJ_INVALID_SOCKET; ++i) { pj_sock_close(inactive_sock[i]); } if (ioque != NULL) pj_ioqueue_destroy(ioque); pj_pool_release( pool); return -1; }
/* * Repeated connect/accept on the same listener socket. */ static int compliance_test_2(pj_bool_t allow_concur) { #if defined(PJ_SYMBIAN) && PJ_SYMBIAN!=0 enum { MAX_PAIR = 1, TEST_LOOP = 2 }; #else enum { MAX_PAIR = 4, TEST_LOOP = 2 }; #endif struct listener { pj_sock_t sock; pj_ioqueue_key_t *key; pj_sockaddr_in addr; int addr_len; } listener; struct server { pj_sock_t sock; pj_ioqueue_key_t *key; pj_sockaddr_in local_addr; pj_sockaddr_in rem_addr; int rem_addr_len; pj_ioqueue_op_key_t accept_op; } server[MAX_PAIR]; struct client { pj_sock_t sock; pj_ioqueue_key_t *key; } client[MAX_PAIR]; pj_pool_t *pool = NULL; char *send_buf, *recv_buf; pj_ioqueue_t *ioque = NULL; int i, bufsize = BUF_MIN_SIZE; pj_ssize_t status; int test_loop, pending_op = 0; pj_timestamp t_elapsed; pj_str_t s; pj_status_t rc; listener.sock = PJ_INVALID_SOCKET; listener.key = NULL; for (i=0; i<MAX_PAIR; ++i) { server[i].sock = PJ_INVALID_SOCKET; server[i].key = NULL; } for (i=0; i<MAX_PAIR; ++i) { client[i].sock = PJ_INVALID_SOCKET; client[i].key = NULL; } // Create pool. pool = pj_pool_create(mem, NULL, POOL_SIZE, 4000, NULL); // Create I/O Queue. rc = pj_ioqueue_create(pool, PJ_IOQUEUE_MAX_HANDLES, &ioque); if (rc != PJ_SUCCESS) { app_perror("...ERROR in pj_ioqueue_create()", rc); return -10; } // Concurrency rc = pj_ioqueue_set_default_concurrency(ioque, allow_concur); if (rc != PJ_SUCCESS) { app_perror("...ERROR in pj_ioqueue_set_default_concurrency()", rc); return -11; } // Allocate buffers for send and receive. send_buf = (char*)pj_pool_alloc(pool, bufsize); recv_buf = (char*)pj_pool_alloc(pool, bufsize); // Create listener socket rc = pj_sock_socket(pj_AF_INET(), pj_SOCK_STREAM(), 0, &listener.sock); if (rc != PJ_SUCCESS) { app_perror("...error creating socket", rc); status=-20; goto on_error; } // Bind listener socket. pj_sockaddr_in_init(&listener.addr, 0, 0); if ((rc=pj_sock_bind(listener.sock, &listener.addr, sizeof(listener.addr))) != 0 ) { app_perror("...bind error", rc); status=-30; goto on_error; } // Get listener address. listener.addr_len = sizeof(listener.addr); rc = pj_sock_getsockname(listener.sock, &listener.addr, &listener.addr_len); if (rc != PJ_SUCCESS) { app_perror("...ERROR in pj_sock_getsockname()", rc); status=-40; goto on_error; } listener.addr.sin_addr = pj_inet_addr(pj_cstr(&s, "127.0.0.1")); // Register listener socket. rc = pj_ioqueue_register_sock(pool, ioque, listener.sock, NULL, &test_cb, &listener.key); if (rc != PJ_SUCCESS) { app_perror("...ERROR", rc); status=-50; goto on_error; } // Listener socket listen(). if (pj_sock_listen(listener.sock, 5)) { app_perror("...ERROR in pj_sock_listen()", rc); status=-60; goto on_error; } for (test_loop=0; test_loop < TEST_LOOP; ++test_loop) { // Client connect and server accept. for (i=0; i<MAX_PAIR; ++i) { rc = pj_sock_socket(pj_AF_INET(), pj_SOCK_STREAM(), 0, &client[i].sock); if (rc != PJ_SUCCESS) { app_perror("...error creating socket", rc); status=-70; goto on_error; } rc = pj_ioqueue_register_sock(pool, ioque, client[i].sock, NULL, &test_cb, &client[i].key); if (rc != PJ_SUCCESS) { app_perror("...error ", rc); status=-80; goto on_error; } // Server socket accept() pj_ioqueue_op_key_init(&server[i].accept_op, sizeof(server[i].accept_op)); server[i].rem_addr_len = sizeof(pj_sockaddr_in); status = pj_ioqueue_accept(listener.key, &server[i].accept_op, &server[i].sock, &server[i].local_addr, &server[i].rem_addr, &server[i].rem_addr_len); if (status!=PJ_SUCCESS && status != PJ_EPENDING) { app_perror("...ERROR in pj_ioqueue_accept()", rc); status=-90; goto on_error; } if (status==PJ_EPENDING) { ++pending_op; } // Client socket connect() status = pj_ioqueue_connect(client[i].key, &listener.addr, sizeof(listener.addr)); if (status!=PJ_SUCCESS && status != PJ_EPENDING) { app_perror("...ERROR in pj_ioqueue_connect()", rc); status=-100; goto on_error; } if (status==PJ_EPENDING) { ++pending_op; } } // Poll until all connected while (pending_op) { pj_time_val timeout = {1, 0}; #ifdef PJ_SYMBIAN status = pj_symbianos_poll(-1, 1000); #else status = pj_ioqueue_poll(ioque, &timeout); #endif if (status > 0) { if (status > pending_op) { PJ_LOG(3,(THIS_FILE, "...error: pj_ioqueue_poll() returned %d " "(only expecting %d)", status, pending_op)); return -110; } pending_op -= status; if (pending_op == 0) { status = 0; } } } // There's no pending operation. // When we poll the ioqueue, there must not be events. if (pending_op == 0) { pj_time_val timeout = {1, 0}; #ifdef PJ_SYMBIAN status = pj_symbianos_poll(-1, 1000); #else status = pj_ioqueue_poll(ioque, &timeout); #endif if (status != 0) { status=-120; goto on_error; } } for (i=0; i<MAX_PAIR; ++i) { // Check server socket. if (server[i].sock == PJ_INVALID_SOCKET) { status = -130; app_perror("...accept() error", pj_get_os_error()); goto on_error; } // Check addresses if (server[i].local_addr.sin_family != pj_AF_INET() || server[i].local_addr.sin_addr.s_addr == 0 || server[i].local_addr.sin_port == 0) { app_perror("...ERROR address not set", rc); status = -140; goto on_error; } if (server[i].rem_addr.sin_family != pj_AF_INET() || server[i].rem_addr.sin_addr.s_addr == 0 || server[i].rem_addr.sin_port == 0) { app_perror("...ERROR address not set", rc); status = -150; goto on_error; } // Register newly accepted socket. rc = pj_ioqueue_register_sock(pool, ioque, server[i].sock, NULL, &test_cb, &server[i].key); if (rc != PJ_SUCCESS) { app_perror("...ERROR in pj_ioqueue_register_sock", rc); status = -160; goto on_error; } // Test send and receive. t_elapsed.u32.lo = 0; status = send_recv_test(ioque, server[i].key, client[i].key, send_buf, recv_buf, bufsize, &t_elapsed); if (status != 0) { goto on_error; } } // Success status = 0; for (i=0; i<MAX_PAIR; ++i) { if (server[i].key != NULL) { pj_ioqueue_unregister(server[i].key); server[i].key = NULL; server[i].sock = PJ_INVALID_SOCKET; } else if (server[i].sock != PJ_INVALID_SOCKET) { pj_sock_close(server[i].sock); server[i].sock = PJ_INVALID_SOCKET; } if (client[i].key != NULL) { pj_ioqueue_unregister(client[i].key); client[i].key = NULL; client[i].sock = PJ_INVALID_SOCKET; } else if (client[i].sock != PJ_INVALID_SOCKET) { pj_sock_close(client[i].sock); client[i].sock = PJ_INVALID_SOCKET; } } } status = 0; on_error: for (i=0; i<MAX_PAIR; ++i) { if (server[i].key != NULL) { pj_ioqueue_unregister(server[i].key); server[i].key = NULL; server[i].sock = PJ_INVALID_SOCKET; } else if (server[i].sock != PJ_INVALID_SOCKET) { pj_sock_close(server[i].sock); server[i].sock = PJ_INVALID_SOCKET; } if (client[i].key != NULL) { pj_ioqueue_unregister(client[i].key); client[i].key = NULL; server[i].sock = PJ_INVALID_SOCKET; } else if (client[i].sock != PJ_INVALID_SOCKET) { pj_sock_close(client[i].sock); client[i].sock = PJ_INVALID_SOCKET; } } if (listener.key) { pj_ioqueue_unregister(listener.key); listener.key = NULL; } else if (listener.sock != PJ_INVALID_SOCKET) { pj_sock_close(listener.sock); listener.sock = PJ_INVALID_SOCKET; } if (ioque != NULL) pj_ioqueue_destroy(ioque); pj_pool_release(pool); return status; }
static int send_recv_test(pj_ioqueue_t *ioque, pj_ioqueue_key_t *skey, pj_ioqueue_key_t *ckey, void *send_buf, void *recv_buf, pj_ssize_t bufsize, pj_timestamp *t_elapsed) { pj_status_t status; pj_ssize_t bytes; pj_time_val timeout; pj_timestamp t1, t2; int pending_op = 0; pj_ioqueue_op_key_t read_op, write_op; // Start reading on the server side. bytes = bufsize; status = pj_ioqueue_recv(skey, &read_op, recv_buf, &bytes, 0); if (status != PJ_SUCCESS && status != PJ_EPENDING) { app_perror("...pj_ioqueue_recv error", status); return -100; } if (status == PJ_EPENDING) ++pending_op; else { /* Does not expect to return error or immediate data. */ return -115; } // Randomize send buffer. pj_create_random_string((char*)send_buf, bufsize); // Starts send on the client side. bytes = bufsize; status = pj_ioqueue_send(ckey, &write_op, send_buf, &bytes, 0); if (status != PJ_SUCCESS && bytes != PJ_EPENDING) { return -120; } if (status == PJ_EPENDING) { ++pending_op; } // Begin time. pj_get_timestamp(&t1); // Reset indicators callback_read_size = callback_write_size = 0; callback_read_key = callback_write_key = NULL; callback_read_op = callback_write_op = NULL; // Poll the queue until we've got completion event in the server side. status = 0; while (pending_op > 0) { timeout.sec = 1; timeout.msec = 0; #ifdef PJ_SYMBIAN PJ_UNUSED_ARG(ioque); status = pj_symbianos_poll(-1, 1000); #else status = pj_ioqueue_poll(ioque, &timeout); #endif if (status > 0) { if (callback_read_size) { if (callback_read_size != bufsize) return -160; if (callback_read_key != skey) return -161; if (callback_read_op != &read_op) return -162; } if (callback_write_size) { if (callback_write_key != ckey) return -163; if (callback_write_op != &write_op) return -164; } pending_op -= status; } if (status == 0) { PJ_LOG(3,("", "...error: timed out")); } if (status < 0) { return -170; } } // Pending op is zero. // Subsequent poll should yield zero too. timeout.sec = timeout.msec = 0; #ifdef PJ_SYMBIAN status = pj_symbianos_poll(-1, 1); #else status = pj_ioqueue_poll(ioque, &timeout); #endif if (status != 0) return -173; // End time. pj_get_timestamp(&t2); t_elapsed->u32.lo += (t2.u32.lo - t1.u32.lo); // Compare recv buffer with send buffer. if (pj_memcmp(send_buf, recv_buf, bufsize) != 0) { return -180; } // Success return 0; }