diff options
Diffstat (limited to 'pjsip/src/pjsip/sip_transport.c')
-rw-r--r-- | pjsip/src/pjsip/sip_transport.c | 288 |
1 files changed, 233 insertions, 55 deletions
diff --git a/pjsip/src/pjsip/sip_transport.c b/pjsip/src/pjsip/sip_transport.c index 4823feb9..742cf9e1 100644 --- a/pjsip/src/pjsip/sip_transport.c +++ b/pjsip/src/pjsip/sip_transport.c @@ -22,6 +22,7 @@ #include <pjsip/sip_msg.h> #include <pjsip/sip_private.h> #include <pjsip/sip_errno.h> +#include <pjsip/sip_module.h> #include <pj/os.h> #include <pj/log.h> #include <pj/ioqueue.h> @@ -32,7 +33,33 @@ #include <pj/lock.h> -#define THIS_FILE "transport" +#define THIS_FILE "sip_transport.c" + +/* Prototype. */ +static pj_status_t mod_on_tx_msg(pjsip_tx_data *tdata); + +/* This module has sole purpose to print transmit data to contigous buffer + * before actually transmitted to the wire. + */ +static pjsip_module mod_msg_print = +{ + NULL, NULL, /* prev and next */ + { "mod-msg-print", 13}, /* Name. */ + -1, /* Id */ + PJSIP_MOD_PRIORITY_TRANSPORT_LAYER, /* Priority */ + NULL, /* User data. */ + 0, /* Number of methods supported (=0). */ + { 0 }, /* Array of methods (none) */ + NULL, /* load() */ + NULL, /* start() */ + NULL, /* stop() */ + NULL, /* unload() */ + NULL, /* on_rx_request() */ + NULL, /* on_rx_response() */ + &mod_on_tx_msg, /* on_tx_request() */ + &mod_on_tx_msg, /* on_tx_response() */ + NULL, /* on_tsx_state() */ +}; /* * Transport manager. @@ -46,7 +73,8 @@ struct pjsip_tpmgr #if defined(PJ_DEBUG) && PJ_DEBUG!=0 pj_atomic_t *tdata_counter; #endif - void (*msg_cb)(pjsip_endpoint*, pj_status_t, pjsip_rx_data*); + void (*on_rx_msg)(pjsip_endpoint*, pj_status_t, pjsip_rx_data*); + pj_status_t (*on_tx_msg)(pjsip_endpoint*, pjsip_tx_data*); }; /***************************************************************************** @@ -66,7 +94,7 @@ const struct unsigned flag; } transport_names[] = { - { PJSIP_TRANSPORT_UNSPECIFIED, 0, {NULL, 0}, 0}, + { PJSIP_TRANSPORT_UNSPECIFIED, 0, {"Unspecified", 11}, 0}, { PJSIP_TRANSPORT_UDP, 5060, {"UDP", 3}, PJSIP_TRANSPORT_DATAGRAM}, { PJSIP_TRANSPORT_TCP, 5060, {"TCP", 3}, PJSIP_TRANSPORT_RELIABLE}, { PJSIP_TRANSPORT_TLS, 5061, {"TLS", 3}, PJSIP_TRANSPORT_RELIABLE | PJSIP_TRANSPORT_SECURE}, @@ -90,6 +118,9 @@ pjsip_transport_get_type_from_name(const pj_str_t *name) PJ_ASSERT_RETURN(transport_names[PJSIP_TRANSPORT_UDP].type == PJSIP_TRANSPORT_UDP, PJSIP_TRANSPORT_UNSPECIFIED); + if (name->slen == 0) + return PJSIP_TRANSPORT_UNSPECIFIED; + /* Get transport type from name. */ for (i=0; i<PJ_ARRAY_SIZE(transport_names); ++i) { if (pj_stricmp(name, &transport_names[i].name) == 0) { @@ -162,6 +193,23 @@ pjsip_transport_get_default_port_for_type(pjsip_transport_type_e type) return transport_names[type].port; } +/* + * Get transport name. + */ +PJ_DEF(const char*) pjsip_transport_get_type_name(pjsip_transport_type_e type) +{ + /* Sanity check. + * Check that transport_names[] are indexed on transport type. + */ + PJ_ASSERT_RETURN(transport_names[PJSIP_TRANSPORT_UDP].type == + PJSIP_TRANSPORT_UDP, "Unknown"); + + /* Check that argument is valid. */ + PJ_ASSERT_RETURN(type < PJ_ARRAY_SIZE(transport_names), "Unknown"); + + /* Return the port. */ + return transport_names[type].name.ptr; +} /***************************************************************************** * @@ -181,8 +229,6 @@ PJ_DEF(pj_status_t) pjsip_tx_data_create( pjsip_tpmgr *mgr, PJ_ASSERT_RETURN(mgr && p_tdata, PJ_EINVAL); - PJ_LOG(5, ("", "pjsip_tx_data_create")); - pool = pjsip_endpt_create_pool( mgr->endpt, "tdta%p", PJSIP_POOL_LEN_TDATA, PJSIP_POOL_INC_TDATA ); @@ -234,7 +280,8 @@ PJ_DEF(pj_status_t) pjsip_tx_data_dec_ref( pjsip_tx_data *tdata ) { pj_assert( pj_atomic_get(tdata->ref_cnt) > 0); if (pj_atomic_dec_and_get(tdata->ref_cnt) <= 0) { - PJ_LOG(5,(tdata->obj_name, "destroying txdata")); + PJ_LOG(5,(tdata->obj_name, "Destroying txdata %s", + pjsip_tx_data_get_info(tdata))); #if defined(PJ_DEBUG) && PJ_DEBUG!=0 pj_atomic_dec( tdata->mgr->tdata_counter ); #endif @@ -254,6 +301,7 @@ PJ_DEF(pj_status_t) pjsip_tx_data_dec_ref( pjsip_tx_data *tdata ) PJ_DEF(void) pjsip_tx_data_invalidate_msg( pjsip_tx_data *tdata ) { tdata->buf.cur = tdata->buf.start; + tdata->info = NULL; } PJ_DEF(pj_bool_t) pjsip_tx_data_is_valid( pjsip_tx_data *tdata ) @@ -261,7 +309,72 @@ PJ_DEF(pj_bool_t) pjsip_tx_data_is_valid( pjsip_tx_data *tdata ) return tdata->buf.cur != tdata->buf.start; } +static char *get_msg_info(pj_pool_t *pool, const char *obj_name, + const pjsip_msg *msg) +{ + char info_buf[128], *info; + const pjsip_cseq_hdr *cseq; + int len; + + cseq = pjsip_msg_find_hdr(msg, PJSIP_H_CSEQ, NULL); + PJ_ASSERT_RETURN(cseq != NULL, "INVALID MSG"); + + if (msg->type == PJSIP_REQUEST_MSG) { + len = pj_snprintf(info_buf, sizeof(info_buf), + "Request msg %.*s/cseq=%d (%s)", + msg->line.req.method.name.slen, + msg->line.req.method.name.ptr, + cseq->cseq, obj_name); + } else { + len = pj_snprintf(info_buf, sizeof(info_buf), + "Response msg %d/%.*s/cseq=%d (%s)", + msg->line.status.code, + cseq->method.name.slen, + cseq->method.name.ptr, + cseq->cseq, obj_name); + } + + if (len < 1 || len >= sizeof(info_buf)) { + return (char*)obj_name; + } + + info = pj_pool_alloc(pool, len+1); + pj_memcpy(info, info_buf, len+1); + + return info; +} + +PJ_DEF(char*) pjsip_tx_data_get_info( pjsip_tx_data *tdata ) +{ + + PJ_ASSERT_RETURN(tdata && tdata->msg, "INVALID MSG"); + + if (tdata->info) + return tdata->info; + + pj_lock_acquire(tdata->lock); + tdata->info = get_msg_info(tdata->pool, tdata->obj_name, tdata->msg); + pj_lock_release(tdata->lock); + + return tdata->info; +} + +PJ_DEF(char*) pjsip_rx_data_get_info(pjsip_rx_data *rdata) +{ + char obj_name[16]; + + PJ_ASSERT_RETURN(rdata->msg_info.msg, "INVALID MSG"); + + if (rdata->msg_info.info) + return rdata->msg_info.info; + pj_native_strcpy(obj_name, "rdata"); + pj_sprintf(obj_name+5, "%p", rdata); + + rdata->msg_info.info = get_msg_info(rdata->tp_info.pool, obj_name, + rdata->msg_info.msg); + return rdata->msg_info.info; +} /***************************************************************************** * @@ -298,6 +411,35 @@ static void transport_send_callback(pjsip_transport *transport, pjsip_tx_data_dec_ref(tdata); } +/* This function is called by endpoint for on_tx_request() and on_tx_response() + * notification. + */ +static pj_status_t mod_on_tx_msg(pjsip_tx_data *tdata) +{ + /* Allocate buffer if necessary. */ + if (tdata->buf.start == NULL) { + tdata->buf.start = pj_pool_alloc( tdata->pool, PJSIP_MAX_PKT_LEN); + tdata->buf.cur = tdata->buf.start; + tdata->buf.end = tdata->buf.start + PJSIP_MAX_PKT_LEN; + } + + /* Do we need to reprint? */ + if (!pjsip_tx_data_is_valid(tdata)) { + pj_ssize_t size; + + size = pjsip_msg_print( tdata->msg, tdata->buf.start, + tdata->buf.end - tdata->buf.start); + if (size < 0) { + return PJSIP_EMSGTOOLONG; + } + pj_assert(size != 0); + tdata->buf.cur += size; + tdata->buf.cur[size] = '\0'; + } + + return PJ_SUCCESS; +} + /* * Send a SIP message using the specified transport. */ @@ -320,25 +462,28 @@ PJ_DEF(pj_status_t) pjsip_transport_send( pjsip_transport *tr, return PJSIP_EPENDINGTX; } - /* Allocate buffer if necessary. */ - if (tdata->buf.start == NULL) { - tdata->buf.start = pj_pool_alloc( tdata->pool, PJSIP_MAX_PKT_LEN); - tdata->buf.cur = tdata->buf.start; - tdata->buf.end = tdata->buf.start + PJSIP_MAX_PKT_LEN; + /* Fill in tp_info. */ + tdata->tp_info.transport = tr; + pj_memcpy(&tdata->tp_info.dst_addr, addr, addr_len); + tdata->tp_info.dst_addr_len = addr_len; + if (addr->sa_family == PJ_AF_INET) { + const char *str_addr; + str_addr = pj_inet_ntoa(((pj_sockaddr_in*)addr)->sin_addr); + pj_native_strcpy(tdata->tp_info.dst_name, str_addr); + tdata->tp_info.dst_port = pj_ntohs(((pj_sockaddr_in*)addr)->sin_port); + } else { + pj_native_strcpy(tdata->tp_info.dst_name, "<unknown>"); + tdata->tp_info.dst_port = 0; } - /* Do we need to reprint? */ - if (!pjsip_tx_data_is_valid(tdata)) { - pj_ssize_t size; - - size = pjsip_msg_print( tdata->msg, tdata->buf.start, - tdata->buf.end - tdata->buf.start); - if (size < 0) { - return PJSIP_EMSGTOOLONG; - } - pj_assert(size != 0); - tdata->buf.cur += size; - tdata->buf.cur[size] = '\0'; + /* Distribute to modules. + * When the message reach mod_msg_print, the contents of the message will + * be "printed" to contiguous buffer. + */ + if (tr->tpmgr->on_tx_msg) { + status = (*tr->tpmgr->on_tx_msg)(tr->endpt, tdata); + if (status != PJ_SUCCESS) + return status; } /* Save callback data. */ @@ -449,18 +594,12 @@ PJ_DEF(pj_status_t) pjsip_transport_register( pjsip_tpmgr *mgr, return PJ_SUCCESS; } - -/** - * Unregister transport. - */ -PJ_DEF(pj_status_t) pjsip_transport_unregister( pjsip_tpmgr *mgr, - pjsip_transport *tp) +/* Force destroy transport (e.g. during transport manager shutdown. */ +static pj_status_t destroy_transport( pjsip_tpmgr *mgr, + pjsip_transport *tp ) { int key_len; - /* Must have no user. */ - PJ_ASSERT_RETURN(pj_atomic_get(tp->ref_cnt) == 0, PJSIP_EBUSY); - pj_lock_acquire(tp->lock); pj_lock_acquire(mgr->lock); @@ -485,6 +624,19 @@ PJ_DEF(pj_status_t) pjsip_transport_unregister( pjsip_tpmgr *mgr, return tp->destroy(tp); } +/** + * Unregister transport. + */ +PJ_DEF(pj_status_t) pjsip_transport_unregister( pjsip_tpmgr *mgr, + pjsip_transport *tp) +{ + /* Must have no user. */ + PJ_ASSERT_RETURN(pj_atomic_get(tp->ref_cnt) == 0, PJSIP_EBUSY); + + /* Destroy. */ + return destroy_transport(mgr, tp); +} + /***************************************************************************** @@ -556,21 +708,28 @@ PJ_DEF(pj_status_t) pjsip_tpmgr_unregister_tpfactory( pjsip_tpmgr *mgr, */ PJ_DEF(pj_status_t) pjsip_tpmgr_create( pj_pool_t *pool, pjsip_endpoint *endpt, - void (*cb)(pjsip_endpoint*, - pj_status_t, - pjsip_rx_data *), + void (*rx_cb)(pjsip_endpoint*, + pj_status_t, + pjsip_rx_data *), + pj_status_t (*tx_cb)(pjsip_endpoint*, + pjsip_tx_data*), pjsip_tpmgr **p_mgr) { pjsip_tpmgr *mgr; pj_status_t status; - PJ_ASSERT_RETURN(pool && endpt && cb && p_mgr, PJ_EINVAL); + PJ_ASSERT_RETURN(pool && endpt && rx_cb && p_mgr, PJ_EINVAL); - PJ_LOG(5, (THIS_FILE, "pjsip_tpmgr_create()")); + /* Register mod_msg_print module. */ + status = pjsip_endpt_register_module(endpt, &mod_msg_print); + if (status != PJ_SUCCESS) + return status; + /* Create and initialize transport manager. */ mgr = pj_pool_zalloc(pool, sizeof(*mgr)); mgr->endpt = endpt; - mgr->msg_cb = cb; + mgr->on_rx_msg = rx_cb; + mgr->on_tx_msg = tx_cb; pj_list_init(&mgr->factory_list); mgr->table = pj_hash_create(pool, PJSIP_TPMGR_HTABLE_SIZE); @@ -587,6 +746,8 @@ PJ_DEF(pj_status_t) pjsip_tpmgr_create( pj_pool_t *pool, return status; #endif + PJ_LOG(5, (THIS_FILE, "Transport manager created.")); + *p_mgr = mgr; return PJ_SUCCESS; } @@ -600,12 +761,9 @@ PJ_DEF(pj_status_t) pjsip_tpmgr_destroy( pjsip_tpmgr *mgr ) { pj_hash_iterator_t itr_val; pj_hash_iterator_t *itr; + pjsip_endpoint *endpt = mgr->endpt; - PJ_LOG(5, (THIS_FILE, "pjsip_tpmgr_destroy()")); - -#if defined(PJ_DEBUG) && PJ_DEBUG!=0 - pj_assert(pj_atomic_get(mgr->tdata_counter) == 0); -#endif + PJ_LOG(5, (THIS_FILE, "Destroying transport manager")); pj_lock_acquire(mgr->lock); @@ -618,8 +776,7 @@ PJ_DEF(pj_status_t) pjsip_tpmgr_destroy( pjsip_tpmgr *mgr ) next = pj_hash_next(mgr->table, itr); - pj_atomic_set(transport->ref_cnt, 0); - pjsip_transport_unregister(mgr, transport); + destroy_transport(mgr, transport); itr = next; } @@ -627,6 +784,19 @@ PJ_DEF(pj_status_t) pjsip_tpmgr_destroy( pjsip_tpmgr *mgr ) pj_lock_release(mgr->lock); pj_lock_destroy(mgr->lock); + /* Unregister mod_msg_print. */ + if (mod_msg_print.id != -1) { + pjsip_endpt_unregister_module(endpt, &mod_msg_print); + } + +#if defined(PJ_DEBUG) && PJ_DEBUG!=0 + /* If you encounter assert error on this line, it means there are + * leakings in transmit data (i.e. some transmit data have not been + * destroyed). + */ + pj_assert(pj_atomic_get(mgr->tdata_counter) == 0); +#endif + return PJ_SUCCESS; } @@ -685,7 +855,7 @@ PJ_DEF(pj_ssize_t) pjsip_tpmgr_receive_packet( pjsip_tpmgr *mgr, &msg_fragment_size); if (msg_status != PJ_SUCCESS) { if (remaining_len == PJSIP_MAX_PKT_LEN) { - mgr->msg_cb(mgr->endpt, PJSIP_ERXOVERFLOW, rdata); + mgr->on_rx_msg(mgr->endpt, PJSIP_ERXOVERFLOW, rdata); /* Exhaust all data. */ return rdata->pkt_info.len; } else { @@ -702,7 +872,7 @@ PJ_DEF(pj_ssize_t) pjsip_tpmgr_receive_packet( pjsip_tpmgr *mgr, rdata->msg_info.msg = msg = pjsip_parse_rdata( current_pkt, msg_fragment_size, rdata); if (msg == NULL) { - mgr->msg_cb(mgr->endpt, PJSIP_EINVALIDMSG, rdata); + mgr->on_rx_msg(mgr->endpt, PJSIP_EINVALIDMSG, rdata); goto finish_process_fragment; } @@ -713,7 +883,7 @@ PJ_DEF(pj_ssize_t) pjsip_tpmgr_receive_packet( pjsip_tpmgr *mgr, rdata->msg_info.via == NULL || rdata->msg_info.cseq == NULL) { - mgr->msg_cb(mgr->endpt, PJSIP_EMISSINGHDR, rdata); + mgr->on_rx_msg(mgr->endpt, PJSIP_EMISSINGHDR, rdata); goto finish_process_fragment; } @@ -737,7 +907,7 @@ PJ_DEF(pj_ssize_t) pjsip_tpmgr_receive_packet( pjsip_tpmgr *mgr, if (hdr != &msg->hdr) { hdr = pjsip_msg_find_hdr(msg, PJSIP_H_VIA, hdr); if (hdr) { - mgr->msg_cb(mgr->endpt, PJSIP_EMULTIPLEVIA, rdata); + mgr->on_rx_msg(mgr->endpt, PJSIP_EMULTIPLEVIA, rdata); goto finish_process_fragment; } } @@ -745,7 +915,7 @@ PJ_DEF(pj_ssize_t) pjsip_tpmgr_receive_packet( pjsip_tpmgr *mgr, /* Call the transport manager's upstream message callback. */ - mgr->msg_cb(mgr->endpt, PJ_SUCCESS, rdata); + mgr->on_rx_msg(mgr->endpt, PJ_SUCCESS, rdata); finish_process_fragment: @@ -795,17 +965,25 @@ PJ_DEF(pj_status_t) pjsip_tpmgr_acquire_transport(pjsip_tpmgr *mgr, unsigned flag = pjsip_transport_get_flag_from_type(type); const pj_sockaddr *remote_addr = (const pj_sockaddr*)remote; - /* For datagram transports, try lookup with zero address. + /* Ignore address for loop transports. */ + if (type == PJSIP_TRANSPORT_LOOP || + type == PJSIP_TRANSPORT_LOOP_DGRAM) + { + pj_sockaddr_in *addr = (pj_sockaddr_in*)&key.addr; + + pj_memset(addr, 0, sizeof(pj_sockaddr_in)); + key_len = sizeof(key.type) + sizeof(pj_sockaddr_in); + transport = pj_hash_get(mgr->table, &key, key_len); + } + /* For datagram INET transports, try lookup with zero address. */ - if ( (flag & PJSIP_TRANSPORT_DATAGRAM) && - (remote_addr->sa_family == PJ_AF_INET)) + else if ((flag & PJSIP_TRANSPORT_DATAGRAM) && + (remote_addr->sa_family == PJ_AF_INET)) { pj_sockaddr_in *addr = (pj_sockaddr_in*)&key.addr; pj_memset(addr, 0, sizeof(pj_sockaddr_in)); addr->sin_family = PJ_AF_INET; - addr->sin_addr.s_addr = 0; - addr->sin_port = 0; key_len = sizeof(key.type) + sizeof(pj_sockaddr_in); transport = pj_hash_get(mgr->table, &key, key_len); |