diff options
Diffstat (limited to 'pjsip/src/test-pjsip')
-rw-r--r-- | pjsip/src/test-pjsip/main.c | 13 | ||||
-rw-r--r-- | pjsip/src/test-pjsip/msg_test.c | 2 | ||||
-rw-r--r-- | pjsip/src/test-pjsip/test.c | 2 | ||||
-rw-r--r-- | pjsip/src/test-pjsip/test.h | 21 | ||||
-rw-r--r-- | pjsip/src/test-pjsip/transport_test.c | 561 | ||||
-rw-r--r-- | pjsip/src/test-pjsip/transport_udp_test.c | 98 | ||||
-rw-r--r-- | pjsip/src/test-pjsip/txdata_test.c | 320 | ||||
-rw-r--r-- | pjsip/src/test-pjsip/uri_test.c | 2 |
8 files changed, 1013 insertions, 6 deletions
diff --git a/pjsip/src/test-pjsip/main.c b/pjsip/src/test-pjsip/main.c index 3e5270b1..3c5f0800 100644 --- a/pjsip/src/test-pjsip/main.c +++ b/pjsip/src/test-pjsip/main.c @@ -17,8 +17,17 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "test.h" +#include <stdio.h> -int main(void) +int main(int argc, char *argv[]) { - return test_main(); + int retval = test_main(); + + if (argc != 1) { + char s[10]; + printf("<Press ENTER to quit>\n"); + fgets(s, sizeof(s), stdin); + } + + return retval; } diff --git a/pjsip/src/test-pjsip/msg_test.c b/pjsip/src/test-pjsip/msg_test.c index 1f6affdd..e3702713 100644 --- a/pjsip/src/test-pjsip/msg_test.c +++ b/pjsip/src/test-pjsip/msg_test.c @@ -664,7 +664,7 @@ static pjsip_msg *create_msg1(pj_pool_t *pool) /*****************************************************************************/ -pj_status_t msg_test(void) +int msg_test(void) { pj_status_t status; pj_pool_t *pool; diff --git a/pjsip/src/test-pjsip/test.c b/pjsip/src/test-pjsip/test.c index 92e0c33a..a8f339c8 100644 --- a/pjsip/src/test-pjsip/test.c +++ b/pjsip/src/test-pjsip/test.c @@ -83,6 +83,8 @@ int test_main(void) DO_TEST(uri_test()); DO_TEST(msg_test()); + DO_TEST(txdata_test()); + DO_TEST(transport_udp_test()); on_return: diff --git a/pjsip/src/test-pjsip/test.h b/pjsip/src/test-pjsip/test.h index aebf6022..686dea07 100644 --- a/pjsip/src/test-pjsip/test.h +++ b/pjsip/src/test-pjsip/test.h @@ -23,10 +23,27 @@ extern pjsip_endpoint *endpt; -pj_status_t uri_test(void); -pj_status_t msg_test(void); +#define TEST_UDP_PORT 15060 +/* The tests */ +int uri_test(void); +int msg_test(void); +int txdata_test(void); +int transport_udp_test(void); + +/* Transport test helpers (transport_test.c). */ +int generic_transport_test(pjsip_transport *tp); +int transport_send_recv_test( pjsip_transport_type_e tp_type, + pjsip_transport *ref_tp, + const pj_sockaddr_in *rem_addr ); +int transport_rt_test( pjsip_transport_type_e tp_type, + pjsip_transport *ref_tp, + const pj_sockaddr_in *rem_addr ); + +/* Test main entry */ int test_main(void); + +/* Test utilities. */ void app_perror(const char *msg, pj_status_t status); diff --git a/pjsip/src/test-pjsip/transport_test.c b/pjsip/src/test-pjsip/transport_test.c new file mode 100644 index 00000000..0d54d42d --- /dev/null +++ b/pjsip/src/test-pjsip/transport_test.c @@ -0,0 +1,561 @@ +/* $Id$ */ +/* + * Copyright (C) 2003-2006 Benny Prijono <benny@prijono.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "test.h" +#include <pjsip_core.h> +#include <pjlib.h> + +/////////////////////////////////////////////////////////////////////////////// +/* + * Generic testing for transport, to make sure that basic + * attributes have been initialized properly. + */ +int generic_transport_test(pjsip_transport *tp) +{ + PJ_LOG(3,("", " structure test...")); + + /* Check that local address name is valid. */ + { + struct pj_in_addr addr; + + /* Note: inet_aton() returns non-zero if addr is valid! */ + if (pj_inet_aton(&tp->local_name.host, &addr) != 0) { + if (addr.s_addr==PJ_INADDR_ANY || addr.s_addr==PJ_INADDR_NONE) { + PJ_LOG(3,("", " Error: invalid address name")); + return -420; + } + } else { + /* It's okay. local_name.host may be a hostname instead of + * IP address. + */ + } + } + + /* Check that port is valid. */ + if (tp->local_name.port <= 0) { + return -430; + } + + /* Check length of address (for now we only check against sockaddr_in). */ + if (tp->addr_len != sizeof(pj_sockaddr_in)) + return -440; + + /* Check type. */ + if (tp->key.type == PJSIP_TRANSPORT_UNSPECIFIED) + return -450; + + /* That's it. */ + return PJ_SUCCESS; +} + +/////////////////////////////////////////////////////////////////////////////// +/* + * Send/receive test. + * + * This test sends a request to loopback address; as soon as request is + * received, response will be sent, and time is recorded. + * + * The main purpose is to test that the basic transport functionalities works, + * before we continue with more complicated tests. + */ +#define FROM_HDR "Bob <sip:bob@example.com>" +#define TO_HDR "Alice <sip:alice@example.com>" +#define CONTACT_HDR "Bob <sip:bob@127.0.0.1>" +#define CALL_ID_HDR "SendRecv-Test" +#define CSEQ_VALUE 100 +#define BODY "Hello World!" + +static pj_bool_t my_on_rx_request(pjsip_rx_data *rdata); +static pj_bool_t my_on_rx_response(pjsip_rx_data *rdata); + +/* Flag to indicate message has been received + * (or failed to send) + */ +#define NO_STATUS -2 +static int send_status = NO_STATUS; +static int recv_status = NO_STATUS; +static pj_timestamp my_send_time, my_recv_time; + +/* Module to receive messages for this test. */ +static pjsip_module my_module = +{ + NULL, NULL, /* prev and next */ + { "Transport-Test", 14}, /* Name. */ + -1, /* Id */ + PJSIP_MOD_PRIORITY_TSX_LAYER-1, /* Priority */ + NULL, /* User data. */ + 0, /* Number of methods supported (=0). */ + { 0 }, /* Array of methods (none) */ + NULL, /* load() */ + NULL, /* start() */ + NULL, /* stop() */ + NULL, /* unload() */ + &my_on_rx_request, /* on_rx_request() */ + &my_on_rx_response, /* on_rx_response() */ + NULL, /* tsx_handler() */ +}; + + +static pj_bool_t my_on_rx_request(pjsip_rx_data *rdata) +{ + /* Check that this is our request. */ + if (pj_strcmp2(&rdata->msg_info.call_id, CALL_ID_HDR) == 0) { + /* It is! */ + /* Send response. */ + pjsip_tx_data *tdata; + pjsip_response_addr res_addr; + pj_status_t status; + + PJ_LOG(4,("test", "Received %d bytes request: --begin-\n" + "%s\n" + "--end--", + rdata->msg_info.len, + rdata->msg_info.msg_buf)); + + + status = pjsip_endpt_create_response( endpt, rdata, 200, NULL, &tdata); + if (status != PJ_SUCCESS) { + recv_status = status; + return PJ_TRUE; + } + status = pjsip_get_response_addr( tdata->pool, rdata, &res_addr); + if (status != PJ_SUCCESS) { + recv_status = status; + pjsip_tx_data_dec_ref(tdata); + return PJ_TRUE; + } + status = pjsip_endpt_send_response( endpt, &res_addr, tdata, NULL, NULL); + if (status != PJ_SUCCESS) { + recv_status = status; + pjsip_tx_data_dec_ref(tdata); + return PJ_TRUE; + } + return PJ_TRUE; + } + + /* Not ours. */ + return PJ_FALSE; +} + +static pj_bool_t my_on_rx_response(pjsip_rx_data *rdata) +{ + if (pj_strcmp2(&rdata->msg_info.call_id, CALL_ID_HDR) == 0) { + PJ_LOG(4,("test", "Received %d bytes response: --begin-\n" + "%s\n" + "--end--", + rdata->msg_info.len, + rdata->msg_info.msg_buf)); + + pj_get_timestamp(&my_recv_time); + recv_status = PJ_SUCCESS; + return PJ_TRUE; + } + return PJ_FALSE; +} + +/* Transport callback. */ +static void send_msg_callback(pjsip_send_state *stateless_data, + pj_ssize_t sent, pj_bool_t *cont) +{ + if (sent < 1) { + /* Obtain the error code. */ + send_status = -sent; + } else { + send_status = PJ_SUCCESS; + } + + /* Don't want to continue. */ + *cont = PJ_FALSE; +} + + +/* Test that we receive loopback message. */ +int transport_send_recv_test( pjsip_transport_type_e tp_type, + pjsip_transport *ref_tp, + const pj_sockaddr_in *rem_addr ) +{ + pj_status_t status; + char target_buf[80]; + pj_str_t target, from, to, contact, call_id, body; + pjsip_method method; + pjsip_tx_data *tdata; + pj_time_val timeout; + + PJ_LOG(3,("", " single message round-trip test...")); + + /* Register out test module to receive the message (if necessary). */ + if (my_module.id == -1) { + status = pjsip_endpt_register_module( endpt, &my_module ); + if (status != PJ_SUCCESS) { + app_perror(" error: unable to register module", status); + return -500; + } + } + + /* Create a request message. */ + pj_sprintf(target_buf, "sip:%s:%d", pj_inet_ntoa(rem_addr->sin_addr), + pj_ntohs(rem_addr->sin_port)); + target = pj_str(target_buf); + from = pj_str(FROM_HDR); + to = pj_str(TO_HDR); + contact = pj_str(CONTACT_HDR); + call_id = pj_str(CALL_ID_HDR); + body = pj_str(BODY); + + pjsip_method_set(&method, PJSIP_OPTIONS_METHOD); + status = pjsip_endpt_create_request( endpt, &method, &target, &from, &to, + &contact, &call_id, CSEQ_VALUE, + &body, &tdata ); + if (status != PJ_SUCCESS) { + app_perror(" error: unable to create request", status); + return -510; + } + + /* Reset statuses */ + send_status = recv_status = NO_STATUS; + + /* Start time. */ + pj_get_timestamp(&my_send_time); + + /* Send the message (statelessly). */ + status = pjsip_endpt_send_request_stateless( endpt, tdata, NULL, + &send_msg_callback); + if (status != PJ_SUCCESS) { + /* Immediate error! */ + pjsip_tx_data_dec_ref(tdata); + send_status = status; + } + + /* Set the timeout (1 second from now) */ + pj_gettimeofday(&timeout); + timeout.sec += 1; + + /* Loop handling events until we get status */ + do { + pj_time_val now; + pj_time_val poll_interval = { 0, 10 }; + + pj_gettimeofday(&now); + if (PJ_TIME_VAL_GTE(now, timeout)) { + PJ_LOG(3,("", " error: timeout in send/recv test")); + status = -540; + goto on_return; + } + + if (send_status!=NO_STATUS && send_status!=PJ_SUCCESS) { + app_perror(" error sending message", send_status); + status = -550; + goto on_return; + } + + if (recv_status!=NO_STATUS && recv_status!=PJ_SUCCESS) { + app_perror(" error receiving message", recv_status); + status = -560; + goto on_return; + } + + if (send_status!=NO_STATUS && recv_status!=NO_STATUS) { + /* Success! */ + break; + } + + pjsip_endpt_handle_events(endpt, &poll_interval); + + } while (1); + + if (status == PJ_SUCCESS) { + unsigned usec_rt; + usec_rt = pj_elapsed_usec(&my_send_time, &my_recv_time); + PJ_LOG(3,("", " round-trip = %d usec", usec_rt)); + } + + status = PJ_SUCCESS; + +on_return: + return status; +} + + +/////////////////////////////////////////////////////////////////////////////// +/* + * Multithreaded round-trip test + * + * This test will spawn multiple threads, each of them send a request. As soon + * as request is received, response will be sent, and time is recorded. + * + * The main purpose of this test is to ensure there's no crash when multiple + * threads are sending/receiving messages. + * + */ +static pj_bool_t rt_on_rx_request(pjsip_rx_data *rdata); +static pj_bool_t rt_on_rx_response(pjsip_rx_data *rdata); + +static pjsip_module rt_module = +{ + NULL, NULL, /* prev and next */ + { "Transport-RT-Test", 17}, /* Name. */ + -1, /* Id */ + PJSIP_MOD_PRIORITY_TSX_LAYER-1, /* Priority */ + NULL, /* User data. */ + 0, /* Number of methods supported (=0). */ + { 0 }, /* Array of methods (none) */ + NULL, /* load() */ + NULL, /* start() */ + NULL, /* stop() */ + NULL, /* unload() */ + &rt_on_rx_request, /* on_rx_request() */ + &rt_on_rx_response, /* on_rx_response() */ + NULL, /* tsx_handler() */ +}; + +static struct +{ + pj_thread_t *thread; + pj_timestamp send_time; + pj_timestamp total_rt_time; + int sent_request_count, recv_response_count; + pj_str_t call_id; +} rt_test_data[16]; + +static char rt_target_uri[32]; +static pj_bool_t rt_stop; +static pj_str_t rt_call_id; + +static pj_bool_t rt_on_rx_request(pjsip_rx_data *rdata) +{ + if (!pj_strncmp(&rdata->msg_info.call_id, &rt_call_id, rt_call_id.slen)) { + char *pos = pj_strchr(&rdata->msg_info.call_id, '/'); + int thread_id = (*pos - '0'); + + pjsip_tx_data *tdata; + pjsip_response_addr res_addr; + pj_status_t status; + + status = pjsip_endpt_create_response( endpt, rdata, 200, NULL, &tdata); + if (status != PJ_SUCCESS) { + return PJ_TRUE; + } + status = pjsip_get_response_addr( tdata->pool, rdata, &res_addr); + if (status != PJ_SUCCESS) { + pjsip_tx_data_dec_ref(tdata); + return PJ_TRUE; + } + status = pjsip_endpt_send_response( endpt, &res_addr, tdata, NULL, NULL); + if (status != PJ_SUCCESS) { + pjsip_tx_data_dec_ref(tdata); + return PJ_TRUE; + } + return PJ_TRUE; + + } + return PJ_FALSE; +} + +static pj_status_t rt_send_request(int thread_id) +{ + pj_status_t status; + pj_str_t target, from, to, contact, call_id; + pjsip_tx_data *tdata; + + /* Create a request message. */ + target = pj_str(rt_target_uri); + from = pj_str(FROM_HDR); + to = pj_str(TO_HDR); + contact = pj_str(CONTACT_HDR); + call_id = rt_test_data[thread_id].call_id; + + status = pjsip_endpt_create_request( endpt, &pjsip_options_method, + &target, &from, &to, + &contact, &call_id, -1, + NULL, &tdata ); + if (status != PJ_SUCCESS) { + app_perror(" error: unable to create request", status); + return -610; + } + + /* Start time. */ + pj_get_timestamp(&rt_test_data[thread_id].send_time); + + /* Send the message (statelessly). */ + status = pjsip_endpt_send_request_stateless( endpt, tdata, NULL, NULL); + if (status != PJ_SUCCESS) { + /* Immediate error! */ + app_perror(" error: send request", status); + pjsip_tx_data_dec_ref(tdata); + return -620; + } + + /* Update counter. */ + rt_test_data[thread_id].sent_request_count++; + + return PJ_SUCCESS; +} + +static pj_bool_t rt_on_rx_response(pjsip_rx_data *rdata) +{ + if (!pj_strncmp(&rdata->msg_info.call_id, &rt_call_id, rt_call_id.slen)) { + char *pos = pj_strchr(&rdata->msg_info.call_id, '/')+1; + int thread_id = (*pos - '0'); + pj_timestamp recv_time; + + /* Update counter and end-time. */ + rt_test_data[thread_id].recv_response_count++; + pj_get_timestamp(&recv_time); + + pj_sub_timestamp(&recv_time, &rt_test_data[thread_id].send_time); + pj_add_timestamp(&rt_test_data[thread_id].total_rt_time, &recv_time); + + if (!rt_stop) + rt_send_request(thread_id); + return PJ_TRUE; + } + return PJ_FALSE; +} + +static int rt_thread(void *arg) +{ + int thread_id = (int)arg; + pj_time_val poll_delay = { 0, 10 }; + + /* Sleep to allow main threads to run. */ + pj_thread_sleep(10); + + /* Send the first request. */ + if (rt_send_request(thread_id) != PJ_SUCCESS) + return -1; + + while (!rt_stop) { + pjsip_endpt_handle_events(endpt, &poll_delay); + } + return 0; +} + +int transport_rt_test( pjsip_transport_type_e tp_type, + pjsip_transport *ref_tp, + const pj_sockaddr_in *rem_addr ) +{ + enum { THREADS = 4, INTERVAL = 10 }; + int i; + pj_status_t status; + pj_pool_t *pool; + pj_bool_t is_reliable; + + pj_timestamp zero_time, total_time; + unsigned usec_rt; + unsigned total_sent; + unsigned total_recv; + + + PJ_LOG(3,("", " multithreaded round-trip test (%d threads)...", + THREADS)); + PJ_LOG(3,("", " this will take approx %d seconds, please wait..", INTERVAL)); + + is_reliable = (pjsip_transport_get_flag_from_type(tp_type) & PJSIP_TRANSPORT_RELIABLE); + + /* Register module (if not yet registered) */ + if (rt_module.id == -1) { + status = pjsip_endpt_register_module( endpt, &rt_module ); + if (status != PJ_SUCCESS) { + app_perror(" error: unable to register module", status); + return -600; + } + } + + /* Create pool for this test. */ + pool = pjsip_endpt_create_pool(endpt, NULL, 4000, 4000); + if (!pool) + return -610; + + /* Initialize static test data. */ + pj_sprintf(rt_target_uri, "sip:%s:%d", pj_inet_ntoa(rem_addr->sin_addr), + pj_ntohs(rem_addr->sin_port)); + rt_call_id = pj_str("RT-Call-Id/"); + rt_stop = PJ_FALSE; + + /* Initialize thread data. */ + for (i=0; i<THREADS; ++i) { + char buf[1]; + pj_str_t str_id = { buf, 1 }; + + pj_memset(&rt_test_data[i], 0, sizeof(rt_test_data[i])); + + /* Generate Call-ID for each thread. */ + rt_test_data[i].call_id.ptr = pj_pool_alloc(pool, rt_call_id.slen+1); + pj_strcpy(&rt_test_data[i].call_id, &rt_call_id); + buf[0] = '0' + i; + pj_strcat(&rt_test_data[i].call_id, &str_id); + + /* Create thread, suspended. */ + status = pj_thread_create(pool, "rttest%p", &rt_thread, (void*)i, 0, + PJ_THREAD_SUSPENDED, &rt_test_data[i].thread); + if (status != PJ_SUCCESS) { + app_perror(" error: unable to create thread", status); + return -620; + } + } + + /* Start threads! */ + for (i=0; i<THREADS; ++i) { + pj_thread_resume(rt_test_data[i].thread); + } + + /* Sleep for some time. */ + pj_thread_sleep(INTERVAL * 1000); + + /* Signal thread to stop. */ + rt_stop = PJ_TRUE; + + /* Wait threads to complete. */ + for (i=0; i<THREADS; ++i) { + pj_thread_join(rt_test_data[i].thread); + pj_thread_destroy(rt_test_data[i].thread); + } + + /* Gather statistics. */ + pj_memset(&total_time, 0, sizeof(total_time)); + pj_memset(&zero_time, 0, sizeof(zero_time)); + usec_rt = total_sent = total_recv = 0; + for (i=0; i<THREADS; ++i) { + total_sent += rt_test_data[i].sent_request_count; + total_recv += rt_test_data[i].recv_response_count; + pj_add_timestamp(&total_time, &rt_test_data[i].total_rt_time); + } + + /* Display statistics. */ + if (total_recv) + total_time.u64 = total_time.u64/total_recv; + else + total_time.u64 = 0; + usec_rt = pj_elapsed_usec(&zero_time, &total_time); + PJ_LOG(3,("", " done.")); + PJ_LOG(3,("", " total %d messages sent", total_sent)); + if (total_sent-total_recv) + PJ_LOG(2,("", " total %d messages LOST", total_sent-total_recv)); + else + PJ_LOG(3,("", " no message was lost")); + PJ_LOG(3,("", " average round-trip=%d usec", usec_rt)); + + pjsip_endpt_destroy_pool(endpt, pool); + + if (is_reliable && (total_sent != total_recv)) { + PJ_LOG(3,("", " error: %d messages lost", total_sent-total_recv)); + return -650; + } + return 0; +} diff --git a/pjsip/src/test-pjsip/transport_udp_test.c b/pjsip/src/test-pjsip/transport_udp_test.c new file mode 100644 index 00000000..1af74ed0 --- /dev/null +++ b/pjsip/src/test-pjsip/transport_udp_test.c @@ -0,0 +1,98 @@ +/* $Id$ */ +/* + * Copyright (C) 2003-2006 Benny Prijono <benny@prijono.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "test.h" +#include <pjsip_core.h> +#include <pjlib.h> + + +/* + * UDP transport test. + */ +int transport_udp_test(void) +{ + enum { SEND_RECV_LOOP = 2 }; + pjsip_transport *udp_tp, *tp; + pj_sockaddr_in addr, rem_addr; + pj_str_t s; + pj_status_t status; + int i; + + pj_sockaddr_in_init(&addr, NULL, TEST_UDP_PORT); + + /* Start UDP transport. */ + status = pjsip_udp_transport_start( endpt, &addr, NULL, 1, &udp_tp); + if (status != PJ_SUCCESS) { + app_perror(" Error: unable to start UDP transport", status); + return -10; + } + + /* UDP transport must have initial reference counter set to 1. */ + if (pj_atomic_get(udp_tp->ref_cnt) != 1) + return -20; + + /* Test basic transport attributes */ + status = generic_transport_test(udp_tp); + if (status != PJ_SUCCESS) + return status; + + /* Test that transport manager is returning the correct + * transport. + */ + pj_sockaddr_in_init(&rem_addr, pj_cstr(&s, "1.1.1.1"), 80); + status = pjsip_endpt_acquire_transport(endpt, PJSIP_TRANSPORT_UDP, + &rem_addr, sizeof(rem_addr), + &tp); + if (status != PJ_SUCCESS) + return -50; + if (tp != udp_tp) + return -60; + + /* pjsip_endpt_acquire_transport() adds reference, so we need + * to decrement it. + */ + pjsip_transport_dec_ref(tp); + + /* Check again that reference counter is 1. */ + if (pj_atomic_get(udp_tp->ref_cnt) != 1) + return -70; + + /* Basic transport's send/receive loopback test. */ + pj_sockaddr_in_init(&rem_addr, pj_cstr(&s, "127.0.0.1"), TEST_UDP_PORT); + for (i=0; i<SEND_RECV_LOOP; ++i) { + status = transport_send_recv_test(PJSIP_TRANSPORT_UDP, tp, &rem_addr); + if (status != 0) + return status; + } + + /* Multi-threaded round-trip test. */ + status = transport_rt_test(PJSIP_TRANSPORT_UDP, tp, &rem_addr); + if (status != 0) + return status; + + /* Check again that reference counter is 1. */ + if (pj_atomic_get(udp_tp->ref_cnt) != 1) + return -80; + + /* Destroy this transport. */ + pjsip_transport_dec_ref(udp_tp); + + /* Done */ + return 0; +} diff --git a/pjsip/src/test-pjsip/txdata_test.c b/pjsip/src/test-pjsip/txdata_test.c new file mode 100644 index 00000000..08cad024 --- /dev/null +++ b/pjsip/src/test-pjsip/txdata_test.c @@ -0,0 +1,320 @@ +/* $Id$ */ +/* + * Copyright (C) 2003-2006 Benny Prijono <benny@prijono.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "test.h" +#include <pjsip_core.h> +#include <pjlib.h> + +#define HFIND(msg,h,H) ((pjsip_##h##_hdr*) pjsip_msg_find_hdr(msg, PJSIP_H_##H, NULL)) + +/* + * This tests various core message creation functions. + */ +int txdata_test(void) +{ + pj_status_t status; + pj_str_t target, from, to, contact, body; + pjsip_rx_data dummy_rdata; + pjsip_tx_data *invite, *invite2, *cancel, *response, *ack; + + /* Create INVITE request. */ + target = pj_str("tel:+1"); + from = pj_str("tel:+0"); + to = pj_str("tel:+1"); + contact = pj_str("Bob <sip:+0@example.com;user=phone>"); + body = pj_str("Hello world!"); + + status = pjsip_endpt_create_request( endpt, &pjsip_invite_method, &target, + &from, &to, &contact, NULL, 10, &body, + &invite); + if (status != PJ_SUCCESS) { + app_perror(" error: unable to create request", status); + return -10; + } + + /* Buffer must be invalid. */ + if (pjsip_tx_data_is_valid(invite) != 0) { + PJ_LOG(3,("", " error: buffer must be invalid")); + return -14; + } + /* Reference counter must be set to 1. */ + if (pj_atomic_get(invite->ref_cnt) != 1) { + PJ_LOG(3,("", " error: invalid reference counter")); + return -15; + } + /* Check message type. */ + if (invite->msg->type != PJSIP_REQUEST_MSG) + return -16; + /* Check method. */ + if (invite->msg->line.req.method.id != PJSIP_INVITE_METHOD) + return -17; + + /* Check that mandatory headers are present. */ + if (HFIND(invite->msg, from, FROM) == 0) + return -20; + if (HFIND(invite->msg, to, TO) == 0) + return -21; + if (HFIND(invite->msg, contact, CONTACT) == 0) + return -22; + if (HFIND(invite->msg, cid, CALL_ID) == 0) + return -23; + if (HFIND(invite->msg, cseq, CSEQ) == 0) + return -24; + do { + pjsip_via_hdr *via = HFIND(invite->msg, via, VIA); + if (via == NULL) + return -25; + /* Branch param must be empty. */ + if (via->branch_param.slen != 0) + return -26; + } while (0); + if (invite->msg->body == NULL) + return -28; + + /* Create another INVITE request from first request. */ + status = pjsip_endpt_create_request_from_hdr( endpt, &pjsip_invite_method, + invite->msg->line.req.uri, + HFIND(invite->msg,from,FROM), + HFIND(invite->msg,to,TO), + HFIND(invite->msg,contact,CONTACT), + HFIND(invite->msg,cid,CALL_ID), + 10, &body, &invite2); + if (status != PJ_SUCCESS) { + app_perror(" error: create second request failed", status); + return -30; + } + + /* Buffer must be invalid. */ + if (pjsip_tx_data_is_valid(invite2) != 0) { + PJ_LOG(3,("", " error: buffer must be invalid")); + return -34; + } + /* Reference counter must be set to 1. */ + if (pj_atomic_get(invite2->ref_cnt) != 1) { + PJ_LOG(3,("", " error: invalid reference counter")); + return -35; + } + /* Check message type. */ + if (invite2->msg->type != PJSIP_REQUEST_MSG) + return -36; + /* Check method. */ + if (invite2->msg->line.req.method.id != PJSIP_INVITE_METHOD) + return -37; + + /* Check that mandatory headers are again present. */ + if (HFIND(invite2->msg, from, FROM) == 0) + return -40; + if (HFIND(invite2->msg, to, TO) == 0) + return -41; + if (HFIND(invite2->msg, contact, CONTACT) == 0) + return -42; + if (HFIND(invite2->msg, cid, CALL_ID) == 0) + return -43; + if (HFIND(invite2->msg, cseq, CSEQ) == 0) + return -44; + if (HFIND(invite2->msg, via, VIA) == 0) + return -45; + /* + if (HFIND(invite2->msg, ctype, CONTENT_TYPE) == 0) + return -46; + if (HFIND(invite2->msg, clen, CONTENT_LENGTH) == 0) + return -47; + */ + if (invite2->msg->body == NULL) + return -48; + + /* Done checking invite2. We can delete this. */ + if (pjsip_tx_data_dec_ref(invite2) != PJSIP_EBUFDESTROYED) { + PJ_LOG(3,("", " error: request buffer not destroyed!")); + return -49; + } + + /* Initialize dummy rdata (to simulate receiving a request) + * We should never do this in real application, as there are many + * many more fields need to be initialized!! + */ + dummy_rdata.msg_info.call_id = (HFIND(invite->msg, cid, CALL_ID))->id; + dummy_rdata.msg_info.clen = NULL; + dummy_rdata.msg_info.cseq = HFIND(invite->msg, cseq, CSEQ); + dummy_rdata.msg_info.ctype = NULL; + dummy_rdata.msg_info.from = HFIND(invite->msg, from, FROM); + dummy_rdata.msg_info.max_fwd = NULL; + dummy_rdata.msg_info.msg = invite->msg; + dummy_rdata.msg_info.record_route = NULL; + dummy_rdata.msg_info.require = NULL; + dummy_rdata.msg_info.route = NULL; + dummy_rdata.msg_info.to = HFIND(invite->msg, to, TO); + dummy_rdata.msg_info.via = HFIND(invite->msg, via, VIA); + + /* Create a response message for the request. */ + status = pjsip_endpt_create_response( endpt, &dummy_rdata, 301, NULL, + &response); + if (status != PJ_SUCCESS) { + app_perror(" error: unable to create response", status); + return -50; + } + + /* Buffer must be invalid. */ + if (pjsip_tx_data_is_valid(response) != 0) { + PJ_LOG(3,("", " error: buffer must be invalid")); + return -54; + } + /* Check reference counter. */ + if (pj_atomic_get(response->ref_cnt) != 1) { + PJ_LOG(3,("", " error: invalid ref count in response")); + return -55; + } + /* Check message type. */ + if (response->msg->type != PJSIP_RESPONSE_MSG) + return -56; + /* Check correct status is set. */ + if (response->msg->line.status.code != 301) + return -57; + + /* Check that mandatory headers are again present. */ + if (HFIND(response->msg, from, FROM) == 0) + return -60; + if (HFIND(response->msg, to, TO) == 0) + return -61; + /* + if (HFIND(response->msg, contact, CONTACT) == 0) + return -62; + */ + if (HFIND(response->msg, cid, CALL_ID) == 0) + return -63; + if (HFIND(response->msg, cseq, CSEQ) == 0) + return -64; + if (HFIND(response->msg, via, VIA) == 0) + return -65; + + /* This response message will be used later when creating ACK */ + + /* Create CANCEL request for the original request. */ + status = pjsip_endpt_create_cancel( endpt, invite, &cancel); + if (status != PJ_SUCCESS) { + app_perror(" error: unable to create CANCEL request", status); + return -80; + } + + /* Buffer must be invalid. */ + if (pjsip_tx_data_is_valid(cancel) != 0) { + PJ_LOG(3,("", " error: buffer must be invalid")); + return -84; + } + /* Check reference counter. */ + if (pj_atomic_get(cancel->ref_cnt) != 1) { + PJ_LOG(3,("", " error: invalid ref count in CANCEL request")); + return -85; + } + /* Check message type. */ + if (cancel->msg->type != PJSIP_REQUEST_MSG) + return -86; + /* Check method. */ + if (cancel->msg->line.req.method.id != PJSIP_CANCEL_METHOD) + return -87; + + /* Check that mandatory headers are again present. */ + if (HFIND(cancel->msg, from, FROM) == 0) + return -90; + if (HFIND(cancel->msg, to, TO) == 0) + return -91; + /* + if (HFIND(cancel->msg, contact, CONTACT) == 0) + return -92; + */ + if (HFIND(cancel->msg, cid, CALL_ID) == 0) + return -93; + if (HFIND(cancel->msg, cseq, CSEQ) == 0) + return -94; + if (HFIND(cancel->msg, via, VIA) == 0) + return -95; + + /* Done checking CANCEL request. */ + if (pjsip_tx_data_dec_ref(cancel) != PJSIP_EBUFDESTROYED) { + PJ_LOG(3,("", " error: response buffer not destroyed!")); + return -99; + } + + /* Modify dummy_rdata to simulate receiving response. */ + pj_memset(&dummy_rdata, 0, sizeof(dummy_rdata)); + dummy_rdata.msg_info.msg = response->msg; + dummy_rdata.msg_info.to = HFIND(response->msg, to, TO); + + /* Create ACK request */ + status = pjsip_endpt_create_ack( endpt, invite, &dummy_rdata, &ack ); + if (status != PJ_SUCCESS) { + PJ_LOG(3,("", " error: unable to create ACK")); + return -100; + } + /* Buffer must be invalid. */ + if (pjsip_tx_data_is_valid(ack) != 0) { + PJ_LOG(3,("", " error: buffer must be invalid")); + return -104; + } + /* Check reference counter. */ + if (pj_atomic_get(ack->ref_cnt) != 1) { + PJ_LOG(3,("", " error: invalid ref count in ACK request")); + return -105; + } + /* Check message type. */ + if (ack->msg->type != PJSIP_REQUEST_MSG) + return -106; + /* Check method. */ + if (ack->msg->line.req.method.id != PJSIP_ACK_METHOD) + return -107; + /* Check Request-URI is present. */ + if (ack->msg->line.req.uri == NULL) + return -108; + + /* Check that mandatory headers are again present. */ + if (HFIND(ack->msg, from, FROM) == 0) + return -110; + if (HFIND(ack->msg, to, TO) == 0) + return -111; + if (HFIND(ack->msg, cid, CALL_ID) == 0) + return -112; + if (HFIND(ack->msg, cseq, CSEQ) == 0) + return -113; + if (HFIND(ack->msg, via, VIA) == 0) + return -114; + if (ack->msg->body != NULL) + return -115; + + /* Done checking invite message. */ + if (pjsip_tx_data_dec_ref(invite) != PJSIP_EBUFDESTROYED) { + PJ_LOG(3,("", " error: response buffer not destroyed!")); + return -120; + } + + /* Done checking response message. */ + if (pjsip_tx_data_dec_ref(response) != PJSIP_EBUFDESTROYED) { + PJ_LOG(3,("", " error: response buffer not destroyed!")); + return -130; + } + + /* Done checking ack message. */ + if (pjsip_tx_data_dec_ref(ack) != PJSIP_EBUFDESTROYED) { + PJ_LOG(3,("", " error: response buffer not destroyed!")); + return -140; + } + + /* Done. */ + return 0; +} + diff --git a/pjsip/src/test-pjsip/uri_test.c b/pjsip/src/test-pjsip/uri_test.c index 29a16dd5..647397a2 100644 --- a/pjsip/src/test-pjsip/uri_test.c +++ b/pjsip/src/test-pjsip/uri_test.c @@ -783,7 +783,7 @@ on_return: return status; } -pj_status_t uri_test() +int uri_test() { unsigned i, loop; pj_pool_t *pool; |