summaryrefslogtreecommitdiff
path: root/pjsip/src/test-pjsip
diff options
context:
space:
mode:
authorBenny Prijono <bennylp@teluu.com>2005-12-30 23:50:15 +0000
committerBenny Prijono <bennylp@teluu.com>2005-12-30 23:50:15 +0000
commit944562492d0c16b9e44ec4e1cc97657846d82cd0 (patch)
tree6e6c2e65e95e479384faeeaab4f525fa91cc7f27 /pjsip/src/test-pjsip
parent9b86a2145e18cb843e69167b10f3c7414c11c634 (diff)
Basic module, transport, and sending messages
git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@106 74dad513-b988-da41-8d7b-12977e46ad98
Diffstat (limited to 'pjsip/src/test-pjsip')
-rw-r--r--pjsip/src/test-pjsip/main.c13
-rw-r--r--pjsip/src/test-pjsip/msg_test.c2
-rw-r--r--pjsip/src/test-pjsip/test.c2
-rw-r--r--pjsip/src/test-pjsip/test.h21
-rw-r--r--pjsip/src/test-pjsip/transport_test.c561
-rw-r--r--pjsip/src/test-pjsip/transport_udp_test.c98
-rw-r--r--pjsip/src/test-pjsip/txdata_test.c320
-rw-r--r--pjsip/src/test-pjsip/uri_test.c2
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;