diff options
Diffstat (limited to 'pjsip/src/pjsip/sip_transport.c')
-rw-r--r-- | pjsip/src/pjsip/sip_transport.c | 3096 |
1 files changed, 1559 insertions, 1537 deletions
diff --git a/pjsip/src/pjsip/sip_transport.c b/pjsip/src/pjsip/sip_transport.c index 09eb6cfb..477ddf20 100644 --- a/pjsip/src/pjsip/sip_transport.c +++ b/pjsip/src/pjsip/sip_transport.c @@ -1,1667 +1,1689 @@ -/* $Id$ - */ -#include <pjsip/sip_transport.h> -#include <pjsip/sip_endpoint.h> -#include <pjsip/sip_parser.h> -#include <pjsip/sip_msg.h> -#include <pjsip/sip_private.h> +/* $Id$
+ */
+/*
+ * PJSIP - SIP Stack
+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>
+ *
+ * Author:
+ * Benny Prijono <bennylp@bulukucing.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+#include <pjsip/sip_transport.h>
+#include <pjsip/sip_endpoint.h>
+#include <pjsip/sip_parser.h>
+#include <pjsip/sip_msg.h>
+#include <pjsip/sip_private.h>
#include <pjsip/sip_errno.h>
-#include <pj/os.h> -#include <pj/log.h> -#include <pj/ioqueue.h> -#include <pj/hash.h> -#include <pj/string.h> -#include <pj/pool.h> +#include <pj/os.h>
+#include <pj/log.h>
+#include <pj/ioqueue.h>
+#include <pj/hash.h>
+#include <pj/string.h>
+#include <pj/pool.h>
#include <pj/assert.h>
- -#define MGR_IDLE_CHECK_INTERVAL 30 -#define MGR_HASH_TABLE_SIZE PJSIP_MAX_DIALOG_COUNT -#define BACKLOG 5 -#define DEFAULT_SO_SNDBUF (8 * 1024 * 1024) -#define DEFAULT_SO_RCVBUF (8 * 1024 * 1024) - -#define LOG_TRANSPORT_MGR "trmgr" -#define THIS_FILE "sip_transport" - -static void destroy_transport( pjsip_transport_mgr *mgr, pjsip_transport_t *tr ); - - -/** - * New TCP socket for accept. - */ -typedef struct incoming_socket_rec -{ - pj_sock_t sock; - pj_sockaddr_in remote; - pj_sockaddr_in local; - int addrlen; -} incoming_socket_rec; - -/** - * SIP Transport. - */ -struct pjsip_transport_t -{ - /** Standard list members, for chaining the transport in the - * listener list. - */ - PJ_DECL_LIST_MEMBER(struct pjsip_transport_t); - - /** Transport's pool. */ - pj_pool_t *pool; - - /** Mutex */ - pj_mutex_t *tr_mutex; - - /** Transport name for logging purpose */ - char obj_name[PJ_MAX_OBJ_NAME]; - - /** Socket handle */ - pj_sock_t sock; - - /** Transport type. */ - pjsip_transport_type_e type; - - /** Flags to keep various states (see pjsip_transport_flags_e). */ - pj_uint32_t flag; - - /** I/O Queue key */ - pj_ioqueue_key_t *key; +
+#define MGR_IDLE_CHECK_INTERVAL 30
+#define MGR_HASH_TABLE_SIZE PJSIP_MAX_DIALOG_COUNT
+#define BACKLOG 5
+#define DEFAULT_SO_SNDBUF (8 * 1024 * 1024)
+#define DEFAULT_SO_RCVBUF (8 * 1024 * 1024)
+
+#define LOG_TRANSPORT_MGR "trmgr"
+#define THIS_FILE "sip_transport"
+
+static void destroy_transport( pjsip_transport_mgr *mgr, pjsip_transport_t *tr );
+
+
+/**
+ * New TCP socket for accept.
+ */
+typedef struct incoming_socket_rec
+{
+ pj_sock_t sock;
+ pj_sockaddr_in remote;
+ pj_sockaddr_in local;
+ int addrlen;
+} incoming_socket_rec;
+
+/**
+ * SIP Transport.
+ */
+struct pjsip_transport_t
+{
+ /** Standard list members, for chaining the transport in the
+ * listener list.
+ */
+ PJ_DECL_LIST_MEMBER(struct pjsip_transport_t);
+
+ /** Transport's pool. */
+ pj_pool_t *pool;
+
+ /** Mutex */
+ pj_mutex_t *tr_mutex;
+
+ /** Transport name for logging purpose */
+ char obj_name[PJ_MAX_OBJ_NAME];
+
+ /** Socket handle */
+ pj_sock_t sock;
+
+ /** Transport type. */
+ pjsip_transport_type_e type;
+
+ /** Flags to keep various states (see pjsip_transport_flags_e). */
+ pj_uint32_t flag;
+
+ /** I/O Queue key */
+ pj_ioqueue_key_t *key;
/** Accept key. */
pj_ioqueue_op_key_t accept_op;
- /** Receive data buffer */ - pjsip_rx_data *rdata; -
- /** Pointer to transport manager */ - pjsip_transport_mgr *mgr; - - /** Reference counter, to prevent this transport from being closed while - * it's being used. - */ - pj_atomic_t *ref_cnt; - - /** Local address. */ - pj_sockaddr_in local_addr; - - /** Address name (what to put in Via address field). */ - pj_sockaddr_in addr_name; - - /** Remote address (can be zero for UDP and for listeners). UDP listener - * bound to local loopback interface (127.0.0.1) has remote address set - * to 127.0.0.1 to prevent client from using it to send to remote hosts, - * because remote host then will receive 127.0.0.1 as the packet's - * source address. - */ - pj_sockaddr_in remote_addr; - - /** Struct to save incoming socket information. */ - incoming_socket_rec accept_data; - - /** When this transport should be closed. */ - pj_time_val close_time; - - /** List of callbacks to be called when client attempt to use this - * transport while it's not connected (i.e. still connecting). - */ - pj_list cb_list; -}; - - -/* - * Transport manager. - */ -struct pjsip_transport_mgr -{ - pj_hash_table_t *transport_table; - pj_mutex_t *mutex; - pjsip_endpoint *endpt; - pj_ioqueue_t *ioqueue; + /** Receive data buffer */
+ pjsip_rx_data *rdata;
+
+ /** Pointer to transport manager */
+ pjsip_transport_mgr *mgr;
+
+ /** Reference counter, to prevent this transport from being closed while
+ * it's being used.
+ */
+ pj_atomic_t *ref_cnt;
+
+ /** Local address. */
+ pj_sockaddr_in local_addr;
+
+ /** Address name (what to put in Via address field). */
+ pj_sockaddr_in addr_name;
+
+ /** Remote address (can be zero for UDP and for listeners). UDP listener
+ * bound to local loopback interface (127.0.0.1) has remote address set
+ * to 127.0.0.1 to prevent client from using it to send to remote hosts,
+ * because remote host then will receive 127.0.0.1 as the packet's
+ * source address.
+ */
+ pj_sockaddr_in remote_addr;
+
+ /** Struct to save incoming socket information. */
+ incoming_socket_rec accept_data;
+
+ /** When this transport should be closed. */
+ pj_time_val close_time;
+
+ /** List of callbacks to be called when client attempt to use this
+ * transport while it's not connected (i.e. still connecting).
+ */
+ pj_list cb_list;
+};
+
+
+/*
+ * Transport manager.
+ */
+struct pjsip_transport_mgr
+{
+ pj_hash_table_t *transport_table;
+ pj_mutex_t *mutex;
+ pjsip_endpoint *endpt;
+ pj_ioqueue_t *ioqueue;
pj_time_val next_idle_check;
pj_size_t send_buf_size;
- pj_size_t recv_buf_size; - void (*message_callback)(pjsip_endpoint*, pjsip_rx_data *rdata); -}; - -/* - * Transport role. - */ -typedef enum transport_role_e -{ - TRANSPORT_ROLE_LISTENER, - TRANSPORT_ROLE_TRANSPORT, -} transport_role_e; - -/* - * Transport key for indexing in the hash table. - * WATCH OUT FOR ALIGNMENT PROBLEM HERE! - */ -typedef struct transport_key -{ - pj_uint8_t type; - pj_uint8_t zero; - pj_uint16_t port; - pj_uint32_t addr; -} transport_key; - -/* - * Transport callback. - */ -struct transport_callback -{ - PJ_DECL_LIST_MEMBER(struct transport_callback); - - /** User defined token to be passed to the callback. */ - void *token; - - /** The callback function. */ - void (*cb)(pjsip_transport_t *tr, void *token, pj_status_t status); - -}; - -/* - * Transport names. - */ -const struct -{ - pjsip_transport_type_e type; - pj_uint16_t port; - pj_str_t name; -} transport_names[] = -{ - { PJSIP_TRANSPORT_UNSPECIFIED, 0, {NULL, 0}}, - { PJSIP_TRANSPORT_UDP, 5060, {"UDP", 3}}, -#if PJ_HAS_TCP - { PJSIP_TRANSPORT_TCP, 5060, {"TCP", 3}}, - { PJSIP_TRANSPORT_TLS, 5061, {"TLS", 3}}, - { PJSIP_TRANSPORT_SCTP, 5060, {"SCTP", 4}} -#endif -}; - + pj_size_t recv_buf_size;
+ void (*message_callback)(pjsip_endpoint*, pjsip_rx_data *rdata);
+};
+
+/*
+ * Transport role.
+ */
+typedef enum transport_role_e
+{
+ TRANSPORT_ROLE_LISTENER,
+ TRANSPORT_ROLE_TRANSPORT,
+} transport_role_e;
+
+/*
+ * Transport key for indexing in the hash table.
+ * WATCH OUT FOR ALIGNMENT PROBLEM HERE!
+ */
+typedef struct transport_key
+{
+ pj_uint8_t type;
+ pj_uint8_t zero;
+ pj_uint16_t port;
+ pj_uint32_t addr;
+} transport_key;
+
+/*
+ * Transport callback.
+ */
+struct transport_callback
+{
+ PJ_DECL_LIST_MEMBER(struct transport_callback);
+
+ /** User defined token to be passed to the callback. */
+ void *token;
+
+ /** The callback function. */
+ void (*cb)(pjsip_transport_t *tr, void *token, pj_status_t status);
+
+};
+
+/*
+ * Transport names.
+ */
+const struct
+{
+ pjsip_transport_type_e type;
+ pj_uint16_t port;
+ pj_str_t name;
+} transport_names[] =
+{
+ { PJSIP_TRANSPORT_UNSPECIFIED, 0, {NULL, 0}},
+ { PJSIP_TRANSPORT_UDP, 5060, {"UDP", 3}},
+#if PJ_HAS_TCP
+ { PJSIP_TRANSPORT_TCP, 5060, {"TCP", 3}},
+ { PJSIP_TRANSPORT_TLS, 5061, {"TLS", 3}},
+ { PJSIP_TRANSPORT_SCTP, 5060, {"SCTP", 4}}
+#endif
+};
+
static void on_ioqueue_read(pj_ioqueue_key_t *key,
pj_ioqueue_op_key_t *op_key,
- pj_ssize_t bytes_read); + pj_ssize_t bytes_read);
static void on_ioqueue_write(pj_ioqueue_key_t *key,
pj_ioqueue_op_key_t *op_key,
- pj_ssize_t bytes_sent); + pj_ssize_t bytes_sent);
static void on_ioqueue_accept(pj_ioqueue_key_t *key,
pj_ioqueue_op_key_t *op_key,
pj_sock_t newsock,
- int status); + int status);
static void on_ioqueue_connect(pj_ioqueue_key_t *key,
- int status); - -static pj_ioqueue_callback ioqueue_transport_callback = -{ - &on_ioqueue_read, - &on_ioqueue_write, - &on_ioqueue_accept, - &on_ioqueue_connect -}; - -static void init_key_from_transport(transport_key *key, - const pjsip_transport_t *tr) -{ - /* This is to detect alignment problems. */ - pj_assert(sizeof(transport_key) == 8); - - key->type = (pj_uint8_t)tr->type; - key->zero = 0; - key->addr = pj_sockaddr_in_get_addr(&tr->remote_addr).s_addr; - key->port = pj_sockaddr_in_get_port(&tr->remote_addr); - /* - if (key->port == 0) { - key->port = pj_sockaddr_in_get_port(&tr->local_addr); - } - */ -} - -#if PJ_HAS_TCP -static void init_tcp_key(transport_key *key, pjsip_transport_type_e type, - const pj_sockaddr_in *addr) -{ - /* This is to detect alignment problems. */ - pj_assert(sizeof(transport_key) == 8); - - key->type = (pj_uint8_t)type; - key->zero = 0; - key->addr = pj_sockaddr_in_get_addr(addr).s_addr; - key->port = pj_sockaddr_in_get_port(addr); -} -#endif - -static void init_udp_key(transport_key *key, pjsip_transport_type_e type, - const pj_sockaddr_in *addr) -{ - PJ_UNUSED_ARG(addr); - - /* This is to detect alignment problems. */ - pj_assert(sizeof(transport_key) == 8); - - pj_memset(key, 0, sizeof(*key)); - key->type = (pj_uint8_t)type; - -#if 0 /* Not sure why we need to make 127.0.0.1 a special case */ - if (addr->sin_addr.s_addr == inet_addr("127.0.0.1")) { - /* This looks more complicated than it is because key->addr uses - * the host version of the address (i.e. converted with ntohl()). - */ - pj_str_t localaddr = pj_str("127.0.0.1"); - pj_sockaddr_in addr; - pj_sockaddr_set_str_addr(&addr, &localaddr); - key->addr = pj_sockaddr_in_get_addr(&addr); - } -#endif -} - -/* - * Get type format name (for pool name). - */ -static const char *transport_get_name_format( int type ) -{ - switch (type) { - case PJSIP_TRANSPORT_UDP: - return " udp%p"; -#if PJ_HAS_TCP - case PJSIP_TRANSPORT_TCP: - return " tcp%p"; - case PJSIP_TRANSPORT_TLS: - return " tls%p"; - case PJSIP_TRANSPORT_SCTP: - return "sctp%p"; -#endif - } - pj_assert(0); - return 0; -} - -/* - * Get the default SIP port number for the specified type. - */ -PJ_DEF(int) pjsip_transport_get_default_port_for_type(pjsip_transport_type_e type) -{ - return transport_names[type].port; -} - -/* - * Get transport name. - */ -static const char *get_type_name(int type) -{ - return transport_names[type].name.ptr; -} - -/* - * Get transport type from name. - */ -PJ_DEF(pjsip_transport_type_e) -pjsip_transport_get_type_from_name(const pj_str_t *name) -{ - unsigned i; - - for (i=0; i<PJ_ARRAY_SIZE(transport_names); ++i) { - if (pj_stricmp(name, &transport_names[i].name) == 0) { - return transport_names[i].type; - } - } - return PJSIP_TRANSPORT_UNSPECIFIED; -} - -/* - * Create new transmit buffer. - */ + int status);
+
+static pj_ioqueue_callback ioqueue_transport_callback =
+{
+ &on_ioqueue_read,
+ &on_ioqueue_write,
+ &on_ioqueue_accept,
+ &on_ioqueue_connect
+};
+
+static void init_key_from_transport(transport_key *key,
+ const pjsip_transport_t *tr)
+{
+ /* This is to detect alignment problems. */
+ pj_assert(sizeof(transport_key) == 8);
+
+ key->type = (pj_uint8_t)tr->type;
+ key->zero = 0;
+ key->addr = pj_sockaddr_in_get_addr(&tr->remote_addr).s_addr;
+ key->port = pj_sockaddr_in_get_port(&tr->remote_addr);
+ /*
+ if (key->port == 0) {
+ key->port = pj_sockaddr_in_get_port(&tr->local_addr);
+ }
+ */
+}
+
+#if PJ_HAS_TCP
+static void init_tcp_key(transport_key *key, pjsip_transport_type_e type,
+ const pj_sockaddr_in *addr)
+{
+ /* This is to detect alignment problems. */
+ pj_assert(sizeof(transport_key) == 8);
+
+ key->type = (pj_uint8_t)type;
+ key->zero = 0;
+ key->addr = pj_sockaddr_in_get_addr(addr).s_addr;
+ key->port = pj_sockaddr_in_get_port(addr);
+}
+#endif
+
+static void init_udp_key(transport_key *key, pjsip_transport_type_e type,
+ const pj_sockaddr_in *addr)
+{
+ PJ_UNUSED_ARG(addr);
+
+ /* This is to detect alignment problems. */
+ pj_assert(sizeof(transport_key) == 8);
+
+ pj_memset(key, 0, sizeof(*key));
+ key->type = (pj_uint8_t)type;
+
+#if 0 /* Not sure why we need to make 127.0.0.1 a special case */
+ if (addr->sin_addr.s_addr == inet_addr("127.0.0.1")) {
+ /* This looks more complicated than it is because key->addr uses
+ * the host version of the address (i.e. converted with ntohl()).
+ */
+ pj_str_t localaddr = pj_str("127.0.0.1");
+ pj_sockaddr_in addr;
+ pj_sockaddr_set_str_addr(&addr, &localaddr);
+ key->addr = pj_sockaddr_in_get_addr(&addr);
+ }
+#endif
+}
+
+/*
+ * Get type format name (for pool name).
+ */
+static const char *transport_get_name_format( int type )
+{
+ switch (type) {
+ case PJSIP_TRANSPORT_UDP:
+ return " udp%p";
+#if PJ_HAS_TCP
+ case PJSIP_TRANSPORT_TCP:
+ return " tcp%p";
+ case PJSIP_TRANSPORT_TLS:
+ return " tls%p";
+ case PJSIP_TRANSPORT_SCTP:
+ return "sctp%p";
+#endif
+ }
+ pj_assert(0);
+ return 0;
+}
+
+/*
+ * Get the default SIP port number for the specified type.
+ */
+PJ_DEF(int) pjsip_transport_get_default_port_for_type(pjsip_transport_type_e type)
+{
+ return transport_names[type].port;
+}
+
+/*
+ * Get transport name.
+ */
+static const char *get_type_name(int type)
+{
+ return transport_names[type].name.ptr;
+}
+
+/*
+ * Get transport type from name.
+ */
+PJ_DEF(pjsip_transport_type_e)
+pjsip_transport_get_type_from_name(const pj_str_t *name)
+{
+ unsigned i;
+
+ for (i=0; i<PJ_ARRAY_SIZE(transport_names); ++i) {
+ if (pj_stricmp(name, &transport_names[i].name) == 0) {
+ return transport_names[i].type;
+ }
+ }
+ return PJSIP_TRANSPORT_UNSPECIFIED;
+}
+
+/*
+ * Create new transmit buffer.
+ */
pj_status_t pjsip_tx_data_create( pjsip_transport_mgr *mgr,
- pjsip_tx_data **p_tdata ) -{ - pj_pool_t *pool; - pjsip_tx_data *tdata; + pjsip_tx_data **p_tdata )
+{
+ pj_pool_t *pool;
+ pjsip_tx_data *tdata;
pj_status_t status;
- - PJ_LOG(5, ("", "pjsip_tx_data_create")); +
+ PJ_LOG(5, ("", "pjsip_tx_data_create"));
PJ_ASSERT_RETURN(mgr && p_tdata, PJ_EINVAL);
- - pool = pjsip_endpt_create_pool( mgr->endpt, "ptdt%p", - PJSIP_POOL_LEN_TDATA, - PJSIP_POOL_INC_TDATA ); - if (!pool) { - return PJ_ENOMEM; - } - tdata = pj_pool_calloc(pool, 1, sizeof(pjsip_tx_data)); - tdata->pool = pool; - tdata->mgr = mgr; - pj_sprintf(tdata->obj_name,"txd%p", tdata); - - status = pj_atomic_create(tdata->pool, 0, &tdata->ref_cnt); - if (status != PJ_SUCCESS) { - pjsip_endpt_destroy_pool( mgr->endpt, tdata->pool ); - return status; - } +
+ pool = pjsip_endpt_create_pool( mgr->endpt, "ptdt%p",
+ PJSIP_POOL_LEN_TDATA,
+ PJSIP_POOL_INC_TDATA );
+ if (!pool) {
+ return PJ_ENOMEM;
+ }
+ tdata = pj_pool_calloc(pool, 1, sizeof(pjsip_tx_data));
+ tdata->pool = pool;
+ tdata->mgr = mgr;
+ pj_sprintf(tdata->obj_name,"txd%p", tdata);
+
+ status = pj_atomic_create(tdata->pool, 0, &tdata->ref_cnt);
+ if (status != PJ_SUCCESS) {
+ pjsip_endpt_destroy_pool( mgr->endpt, tdata->pool );
+ return status;
+ }
- *p_tdata = tdata; - return PJ_SUCCESS; -} - -/* - * Add reference to tx buffer. - */ -PJ_DEF(void) pjsip_tx_data_add_ref( pjsip_tx_data *tdata ) -{ - pj_atomic_inc(tdata->ref_cnt); -} - -/* - * Decrease transport data reference, destroy it when the reference count - * reaches zero. - */ -PJ_DEF(void) 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(6,(tdata->obj_name, "destroying txdata")); - pj_atomic_destroy( tdata->ref_cnt ); - pjsip_endpt_destroy_pool( tdata->mgr->endpt, tdata->pool ); - } -} - -/* - * Invalidate the content of the print buffer to force the message to be - * re-printed when sent. - */ -PJ_DEF(void) pjsip_tx_data_invalidate_msg( pjsip_tx_data *tdata ) -{ - tdata->buf.cur = tdata->buf.start; -} - -/* - * Get the transport type. - */ -PJ_DEF(pjsip_transport_type_e) pjsip_transport_get_type( const pjsip_transport_t * tr) -{ - return tr->type; -} - -/* - * Get transport type from transport flag. - */ -PJ_DEF(pjsip_transport_type_e) pjsip_get_transport_type_from_flag(unsigned flag) -{ -#if PJ_HAS_TCP - if (flag & PJSIP_TRANSPORT_SECURE) { - return PJSIP_TRANSPORT_TLS; - } else if (flag & PJSIP_TRANSPORT_RELIABLE) { - return PJSIP_TRANSPORT_TCP; - } else -#else - PJ_UNUSED_ARG(flag); -#endif - { - return PJSIP_TRANSPORT_UDP; - } -} - -/* - * Get the transport type name. - */ -PJ_DEF(const char *) pjsip_transport_get_type_name( const pjsip_transport_t * tr) -{ - return get_type_name(tr->type); -} - -/* - * Get the transport's object name. - */ -PJ_DEF(const char*) pjsip_transport_get_obj_name( const pjsip_transport_t *tr ) -{ - return tr->obj_name; -} - -/* - * Get the transport's reference counter. - */ -PJ_DEF(int) pjsip_transport_get_ref_cnt( const pjsip_transport_t *tr ) -{ - return pj_atomic_get(tr->ref_cnt); -} - -/* - * Get transport local address. - */ -PJ_DEF(const pj_sockaddr_in*) pjsip_transport_get_local_addr( pjsip_transport_t *tr ) -{ - return &tr->local_addr; -} - -/* - * Get address name. - */ -PJ_DEF(const pj_sockaddr_in*) pjsip_transport_get_addr_name (pjsip_transport_t *tr) -{ - return &tr->addr_name; -} - -/* - * Get transport remote address. - */ -PJ_DEF(const pj_sockaddr_in*) pjsip_transport_get_remote_addr( const pjsip_transport_t *tr ) -{ - return &tr->remote_addr; -} - -/* - * Get transport flag. - */ -PJ_DEF(unsigned) pjsip_transport_get_flag( const pjsip_transport_t * tr ) -{ - return tr->flag; -} - -/* - * Add reference to the specified transport. - */ -PJ_DEF(void) pjsip_transport_add_ref( pjsip_transport_t * tr ) -{ - pj_atomic_inc(tr->ref_cnt); -} - -/* - * Decrease the reference time of the transport. - */ -PJ_DEF(void) pjsip_transport_dec_ref( pjsip_transport_t *tr ) -{ - pj_assert(tr->ref_cnt > 0); - if (pj_atomic_dec_and_get(tr->ref_cnt) == 0) { - pj_gettimeofday(&tr->close_time); - tr->close_time.sec += PJSIP_TRANSPORT_CLOSE_TIMEOUT; - } -} - -/* - * Open the underlying transport. - */ -static pj_status_t create_socket( pjsip_transport_type_e type, + *p_tdata = tdata;
+ return PJ_SUCCESS;
+}
+
+/*
+ * Add reference to tx buffer.
+ */
+PJ_DEF(void) pjsip_tx_data_add_ref( pjsip_tx_data *tdata )
+{
+ pj_atomic_inc(tdata->ref_cnt);
+}
+
+/*
+ * Decrease transport data reference, destroy it when the reference count
+ * reaches zero.
+ */
+PJ_DEF(void) 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(6,(tdata->obj_name, "destroying txdata"));
+ pj_atomic_destroy( tdata->ref_cnt );
+ pjsip_endpt_destroy_pool( tdata->mgr->endpt, tdata->pool );
+ }
+}
+
+/*
+ * Invalidate the content of the print buffer to force the message to be
+ * re-printed when sent.
+ */
+PJ_DEF(void) pjsip_tx_data_invalidate_msg( pjsip_tx_data *tdata )
+{
+ tdata->buf.cur = tdata->buf.start;
+}
+
+/*
+ * Get the transport type.
+ */
+PJ_DEF(pjsip_transport_type_e) pjsip_transport_get_type( const pjsip_transport_t * tr)
+{
+ return tr->type;
+}
+
+/*
+ * Get transport type from transport flag.
+ */
+PJ_DEF(pjsip_transport_type_e) pjsip_get_transport_type_from_flag(unsigned flag)
+{
+#if PJ_HAS_TCP
+ if (flag & PJSIP_TRANSPORT_SECURE) {
+ return PJSIP_TRANSPORT_TLS;
+ } else if (flag & PJSIP_TRANSPORT_RELIABLE) {
+ return PJSIP_TRANSPORT_TCP;
+ } else
+#else
+ PJ_UNUSED_ARG(flag);
+#endif
+ {
+ return PJSIP_TRANSPORT_UDP;
+ }
+}
+
+/*
+ * Get the transport type name.
+ */
+PJ_DEF(const char *) pjsip_transport_get_type_name( const pjsip_transport_t * tr)
+{
+ return get_type_name(tr->type);
+}
+
+/*
+ * Get the transport's object name.
+ */
+PJ_DEF(const char*) pjsip_transport_get_obj_name( const pjsip_transport_t *tr )
+{
+ return tr->obj_name;
+}
+
+/*
+ * Get the transport's reference counter.
+ */
+PJ_DEF(int) pjsip_transport_get_ref_cnt( const pjsip_transport_t *tr )
+{
+ return pj_atomic_get(tr->ref_cnt);
+}
+
+/*
+ * Get transport local address.
+ */
+PJ_DEF(const pj_sockaddr_in*) pjsip_transport_get_local_addr( pjsip_transport_t *tr )
+{
+ return &tr->local_addr;
+}
+
+/*
+ * Get address name.
+ */
+PJ_DEF(const pj_sockaddr_in*) pjsip_transport_get_addr_name (pjsip_transport_t *tr)
+{
+ return &tr->addr_name;
+}
+
+/*
+ * Get transport remote address.
+ */
+PJ_DEF(const pj_sockaddr_in*) pjsip_transport_get_remote_addr( const pjsip_transport_t *tr )
+{
+ return &tr->remote_addr;
+}
+
+/*
+ * Get transport flag.
+ */
+PJ_DEF(unsigned) pjsip_transport_get_flag( const pjsip_transport_t * tr )
+{
+ return tr->flag;
+}
+
+/*
+ * Add reference to the specified transport.
+ */
+PJ_DEF(void) pjsip_transport_add_ref( pjsip_transport_t * tr )
+{
+ pj_atomic_inc(tr->ref_cnt);
+}
+
+/*
+ * Decrease the reference time of the transport.
+ */
+PJ_DEF(void) pjsip_transport_dec_ref( pjsip_transport_t *tr )
+{
+ pj_assert(tr->ref_cnt > 0);
+ if (pj_atomic_dec_and_get(tr->ref_cnt) == 0) {
+ pj_gettimeofday(&tr->close_time);
+ tr->close_time.sec += PJSIP_TRANSPORT_CLOSE_TIMEOUT;
+ }
+}
+
+/*
+ * Open the underlying transport.
+ */
+static pj_status_t create_socket( pjsip_transport_type_e type,
pj_sockaddr_in *local,
- pj_sock_t *p_sock) -{ - int sock_family; - int sock_type; - int sock_proto; + pj_sock_t *p_sock)
+{
+ int sock_family;
+ int sock_type;
+ int sock_proto;
int len;
- pj_status_t status; - pj_sock_t sock; - - /* Set socket parameters */ - if (type == PJSIP_TRANSPORT_UDP) { - sock_family = PJ_AF_INET; - sock_type = PJ_SOCK_DGRAM; - sock_proto = 0; - -#if PJ_HAS_TCP - } else if (type == PJSIP_TRANSPORT_TCP) { - sock_family = PJ_AF_INET; - sock_type = PJ_SOCK_STREAM; - sock_proto = 0; -#endif - } else { - return PJ_EINVAL; - } - - /* Create socket. */ - status = pj_sock_socket( sock_family, sock_type, sock_proto, &sock); - if (status != PJ_SUCCESS) - return status; - - /* Bind the socket to the requested address, or if no address is - * specified, let the operating system chooses the address. - */ - if (/*local->sin_addr.s_addr != 0 &&*/ local->sin_port != 0) { + pj_status_t status;
+ pj_sock_t sock;
+
+ /* Set socket parameters */
+ if (type == PJSIP_TRANSPORT_UDP) {
+ sock_family = PJ_AF_INET;
+ sock_type = PJ_SOCK_DGRAM;
+ sock_proto = 0;
+
+#if PJ_HAS_TCP
+ } else if (type == PJSIP_TRANSPORT_TCP) {
+ sock_family = PJ_AF_INET;
+ sock_type = PJ_SOCK_STREAM;
+ sock_proto = 0;
+#endif
+ } else {
+ return PJ_EINVAL;
+ }
+
+ /* Create socket. */
+ status = pj_sock_socket( sock_family, sock_type, sock_proto, &sock);
+ if (status != PJ_SUCCESS)
+ return status;
+
+ /* Bind the socket to the requested address, or if no address is
+ * specified, let the operating system chooses the address.
+ */
+ if (/*local->sin_addr.s_addr != 0 &&*/ local->sin_port != 0) {
/* Bind to the requested address. */
- status = pj_sock_bind(sock, local, sizeof(*local)); - if (status != PJ_SUCCESS) { - pj_sock_close(sock); - return status; - } - } else if (type == PJSIP_TRANSPORT_UDP) { - /* Only for UDP sockets: bind to any address so that the operating - * system allocates the port for us. For TCP, let the OS implicitly - * bind the socket with connect() syscall (if we bind now, then we'll - * get 0.0.0.0 as local address). - */ - pj_memset(local, 0, sizeof(*local)); + status = pj_sock_bind(sock, local, sizeof(*local));
+ if (status != PJ_SUCCESS) {
+ pj_sock_close(sock);
+ return status;
+ }
+ } else if (type == PJSIP_TRANSPORT_UDP) {
+ /* Only for UDP sockets: bind to any address so that the operating
+ * system allocates the port for us. For TCP, let the OS implicitly
+ * bind the socket with connect() syscall (if we bind now, then we'll
+ * get 0.0.0.0 as local address).
+ */
+ pj_memset(local, 0, sizeof(*local));
local->sin_family = PJ_AF_INET;
- status = pj_sock_bind(sock, local, sizeof(*local)); - if (status != PJ_SUCCESS) { - pj_sock_close(sock); - return status; - } - - /* Get the local address. */ + status = pj_sock_bind(sock, local, sizeof(*local));
+ if (status != PJ_SUCCESS) {
+ pj_sock_close(sock);
+ return status;
+ }
+
+ /* Get the local address. */
len = sizeof(pj_sockaddr_in);
- status = pj_sock_getsockname(sock, local, &len); - if (status != PJ_SUCCESS) { - pj_sock_close(sock); - return status; - } - } -
- *p_sock = sock; - return PJ_SUCCESS; -} - -/* - * Close the transport. - */ -static void destroy_socket( pjsip_transport_t * tr) -{ - pj_assert( pj_atomic_get(tr->ref_cnt) == 0); - pj_sock_close(tr->sock); - tr->sock = -1; -} - -/* - * Create a new transport object. - */ -static pj_status_t create_transport( pjsip_transport_mgr *mgr, - pjsip_transport_type_e type, - pj_sock_t sock_hnd, - const pj_sockaddr_in *local_addr, + status = pj_sock_getsockname(sock, local, &len);
+ if (status != PJ_SUCCESS) {
+ pj_sock_close(sock);
+ return status;
+ }
+ }
+
+ *p_sock = sock;
+ return PJ_SUCCESS;
+}
+
+/*
+ * Close the transport.
+ */
+static void destroy_socket( pjsip_transport_t * tr)
+{
+ pj_assert( pj_atomic_get(tr->ref_cnt) == 0);
+ pj_sock_close(tr->sock);
+ tr->sock = -1;
+}
+
+/*
+ * Create a new transport object.
+ */
+static pj_status_t create_transport( pjsip_transport_mgr *mgr,
+ pjsip_transport_type_e type,
+ pj_sock_t sock_hnd,
+ const pj_sockaddr_in *local_addr,
const pj_sockaddr_in *addr_name,
- pjsip_transport_t **p_transport ) -{ - pj_pool_t *tr_pool=NULL, *rdata_pool=NULL; + pjsip_transport_t **p_transport )
+{
+ pj_pool_t *tr_pool=NULL, *rdata_pool=NULL;
pjsip_transport_t *tr = NULL;
- pj_status_t status; - - /* Allocate pool for transport from endpoint. */ - tr_pool = pjsip_endpt_create_pool( mgr->endpt, - transport_get_name_format(type), - PJSIP_POOL_LEN_TRANSPORT, - PJSIP_POOL_INC_TRANSPORT ); + pj_status_t status;
+
+ /* Allocate pool for transport from endpoint. */
+ tr_pool = pjsip_endpt_create_pool( mgr->endpt,
+ transport_get_name_format(type),
+ PJSIP_POOL_LEN_TRANSPORT,
+ PJSIP_POOL_INC_TRANSPORT );
if (!tr_pool) {
- status = PJ_ENOMEM; - goto on_error; - } - - /* Allocate pool for rdata from endpoint. */ - rdata_pool = pjsip_endpt_create_pool( mgr->endpt, - "prdt%p", - PJSIP_POOL_LEN_RDATA, - PJSIP_POOL_INC_RDATA ); + status = PJ_ENOMEM;
+ goto on_error;
+ }
+
+ /* Allocate pool for rdata from endpoint. */
+ rdata_pool = pjsip_endpt_create_pool( mgr->endpt,
+ "prdt%p",
+ PJSIP_POOL_LEN_RDATA,
+ PJSIP_POOL_INC_RDATA );
if (!rdata_pool) {
- status = PJ_ENOMEM; - goto on_error; - } - - /* Allocate and initialize the transport. */ - tr = pj_pool_calloc(tr_pool, 1, sizeof(*tr)); - tr->pool = tr_pool; - tr->type = type; - tr->mgr = mgr; - tr->sock = sock_hnd; - pj_memcpy(&tr->local_addr, local_addr, sizeof(pj_sockaddr_in)); - pj_list_init(&tr->cb_list); - pj_sprintf(tr->obj_name, transport_get_name_format(type), tr); - - if (type != PJSIP_TRANSPORT_UDP) { - tr->flag |= PJSIP_TRANSPORT_RELIABLE; - } - - /* Address name. */ - if (addr_name == NULL) { - addr_name = &tr->local_addr; - } - pj_memcpy(&tr->addr_name, addr_name, sizeof(*addr_name)); - + status = PJ_ENOMEM;
+ goto on_error;
+ }
+
+ /* Allocate and initialize the transport. */
+ tr = pj_pool_calloc(tr_pool, 1, sizeof(*tr));
+ tr->pool = tr_pool;
+ tr->type = type;
+ tr->mgr = mgr;
+ tr->sock = sock_hnd;
+ pj_memcpy(&tr->local_addr, local_addr, sizeof(pj_sockaddr_in));
+ pj_list_init(&tr->cb_list);
+ pj_sprintf(tr->obj_name, transport_get_name_format(type), tr);
+
+ if (type != PJSIP_TRANSPORT_UDP) {
+ tr->flag |= PJSIP_TRANSPORT_RELIABLE;
+ }
+
+ /* Address name. */
+ if (addr_name == NULL) {
+ addr_name = &tr->local_addr;
+ }
+ pj_memcpy(&tr->addr_name, addr_name, sizeof(*addr_name));
+
/* Create atomic */
- status = pj_atomic_create(tr_pool, 0, &tr->ref_cnt); - if (status != PJ_SUCCESS) - goto on_error; - - /* Init rdata in the transport. */ - tr->rdata = pj_pool_alloc(rdata_pool, sizeof(*tr->rdata)); - tr->rdata->pool = rdata_pool; - tr->rdata->len = 0; - tr->rdata->transport = tr; - - /* Init transport mutex. */ - status = pj_mutex_create_recursive(tr_pool, "mtr%p", &tr->tr_mutex); - if (status != PJ_SUCCESS) - goto on_error; - - /* Register to I/O Queue */ - status = pj_ioqueue_register_sock( tr_pool, mgr->ioqueue, - tr->sock, tr, + status = pj_atomic_create(tr_pool, 0, &tr->ref_cnt);
+ if (status != PJ_SUCCESS)
+ goto on_error;
+
+ /* Init rdata in the transport. */
+ tr->rdata = pj_pool_alloc(rdata_pool, sizeof(*tr->rdata));
+ tr->rdata->pool = rdata_pool;
+ tr->rdata->len = 0;
+ tr->rdata->transport = tr;
+
+ /* Init transport mutex. */
+ status = pj_mutex_create_recursive(tr_pool, "mtr%p", &tr->tr_mutex);
+ if (status != PJ_SUCCESS)
+ goto on_error;
+
+ /* Register to I/O Queue */
+ status = pj_ioqueue_register_sock( tr_pool, mgr->ioqueue,
+ tr->sock, tr,
&ioqueue_transport_callback,
- &tr->key); - if (status != PJ_SUCCESS) - goto on_error; -
- *p_transport = tr; - return PJ_SUCCESS; - -on_error: - if (tr && tr->tr_mutex) { - pj_mutex_destroy(tr->tr_mutex); - } - if (tr_pool) { - pjsip_endpt_destroy_pool(mgr->endpt, tr_pool); - } - if (rdata_pool) { - pjsip_endpt_destroy_pool(mgr->endpt, rdata_pool); - } - return status; -} - -/* - * Destroy transport. - */ -static void destroy_transport( pjsip_transport_mgr *mgr, pjsip_transport_t *tr) -{ - transport_key hash_key; - - /* Remove from I/O queue. */ - pj_ioqueue_unregister( tr->key ); - - /* Remove from hash table */ - init_key_from_transport(&hash_key, tr); - pj_hash_set(NULL, mgr->transport_table, &hash_key, sizeof(hash_key), NULL); - - /* Close transport. */ - destroy_socket(tr); - - /* Destroy the transport mutex. */ - pj_mutex_destroy(tr->tr_mutex); - - /* Destroy atomic */ - pj_atomic_destroy( tr->ref_cnt ); - - /* Release the pool associated with the rdata. */ - pjsip_endpt_destroy_pool(mgr->endpt, tr->rdata->pool ); - - /* Release the pool associated with the transport. */ - pjsip_endpt_destroy_pool(mgr->endpt, tr->pool ); -} - - + &tr->key);
+ if (status != PJ_SUCCESS)
+ goto on_error;
+
+ *p_transport = tr;
+ return PJ_SUCCESS;
+
+on_error:
+ if (tr && tr->tr_mutex) {
+ pj_mutex_destroy(tr->tr_mutex);
+ }
+ if (tr_pool) {
+ pjsip_endpt_destroy_pool(mgr->endpt, tr_pool);
+ }
+ if (rdata_pool) {
+ pjsip_endpt_destroy_pool(mgr->endpt, rdata_pool);
+ }
+ return status;
+}
+
+/*
+ * Destroy transport.
+ */
+static void destroy_transport( pjsip_transport_mgr *mgr, pjsip_transport_t *tr)
+{
+ transport_key hash_key;
+
+ /* Remove from I/O queue. */
+ pj_ioqueue_unregister( tr->key );
+
+ /* Remove from hash table */
+ init_key_from_transport(&hash_key, tr);
+ pj_hash_set(NULL, mgr->transport_table, &hash_key, sizeof(hash_key), NULL);
+
+ /* Close transport. */
+ destroy_socket(tr);
+
+ /* Destroy the transport mutex. */
+ pj_mutex_destroy(tr->tr_mutex);
+
+ /* Destroy atomic */
+ pj_atomic_destroy( tr->ref_cnt );
+
+ /* Release the pool associated with the rdata. */
+ pjsip_endpt_destroy_pool(mgr->endpt, tr->rdata->pool );
+
+ /* Release the pool associated with the transport. */
+ pjsip_endpt_destroy_pool(mgr->endpt, tr->pool );
+}
+
+
static pj_status_t transport_send_msg( pjsip_transport_t *tr,
- pjsip_tx_data *tdata, + pjsip_tx_data *tdata,
const pj_sockaddr_in *addr,
- pj_ssize_t *p_sent) -{ - const char *buf = tdata->buf.start; - pj_ssize_t size; - pj_status_t status; + pj_ssize_t *p_sent)
+{
+ const char *buf = tdata->buf.start;
+ pj_ssize_t size;
+ pj_status_t status;
/* Can only send if tdata is not being sent! */
if (pj_ioqueue_is_pending(tr->key, &tdata->op_key))
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; - } - - /* Print the message if it's not printed */ - if (tdata->buf.cur <= tdata->buf.start) { - size = pjsip_msg_print( tdata->msg, tdata->buf.start, - tdata->buf.end - tdata->buf.start); +
+ /* 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;
+ }
+
+ /* Print the message if it's not printed */
+ if (tdata->buf.cur <= tdata->buf.start) {
+ size = pjsip_msg_print( tdata->msg, tdata->buf.start,
+ tdata->buf.end - tdata->buf.start);
if (size < 0) {
- return PJSIP_EMSGTOOLONG; + return PJSIP_EMSGTOOLONG;
}
- pj_assert(size != 0); - tdata->buf.cur += size; - tdata->buf.cur[size] = '\0'; - } - - /* Send the message. */ - buf = tdata->buf.start; - size = tdata->buf.cur - tdata->buf.start; - - if (tr->type == PJSIP_TRANSPORT_UDP) { - PJ_LOG(4,(tr->obj_name, "sendto %s:%d, %d bytes, data:\n" - "----------- begin msg ------------\n" - "%s" - "------------ end msg -------------", - pj_inet_ntoa(addr->sin_addr), - pj_sockaddr_in_get_port(addr), - size, buf)); -
- status = pj_ioqueue_sendto( tr->key, &tdata->op_key, - buf, &size, 0, addr, sizeof(*addr)); - } -#if PJ_HAS_TCP - else { - PJ_LOG(4,(tr->obj_name, "sending %d bytes, data:\n" - "----------- begin msg ------------\n" - "%s" - "------------ end msg -------------", - size, buf)); - - status = pj_ioqueue_send(tr->key, &tdata->op_key, buf, &size, 0); - } -#else - else { + pj_assert(size != 0);
+ tdata->buf.cur += size;
+ tdata->buf.cur[size] = '\0';
+ }
+
+ /* Send the message. */
+ buf = tdata->buf.start;
+ size = tdata->buf.cur - tdata->buf.start;
+
+ if (tr->type == PJSIP_TRANSPORT_UDP) {
+ PJ_LOG(4,(tr->obj_name, "sendto %s:%d, %d bytes, data:\n"
+ "----------- begin msg ------------\n"
+ "%s"
+ "------------ end msg -------------",
+ pj_inet_ntoa(addr->sin_addr),
+ pj_sockaddr_in_get_port(addr),
+ size, buf));
+
+ status = pj_ioqueue_sendto( tr->key, &tdata->op_key,
+ buf, &size, 0, addr, sizeof(*addr));
+ }
+#if PJ_HAS_TCP
+ else {
+ PJ_LOG(4,(tr->obj_name, "sending %d bytes, data:\n"
+ "----------- begin msg ------------\n"
+ "%s"
+ "------------ end msg -------------",
+ size, buf));
+
+ status = pj_ioqueue_send(tr->key, &tdata->op_key, buf, &size, 0);
+ }
+#else
+ else {
pj_assert(!"Unsupported transport");
- status = PJSIP_EUNSUPTRANSPORT; - } -#endif -
- *p_sent = size; - return status; -} - -/* - * Send a SIP message using the specified transport, to the address specified - * in the outgoing data. - */ -PJ_DEF(pj_status_t) pjsip_transport_send_msg( pjsip_transport_t *tr, - pjsip_tx_data *tdata, + status = PJSIP_EUNSUPTRANSPORT;
+ }
+#endif
+
+ *p_sent = size;
+ return status;
+}
+
+/*
+ * Send a SIP message using the specified transport, to the address specified
+ * in the outgoing data.
+ */
+PJ_DEF(pj_status_t) pjsip_transport_send_msg( pjsip_transport_t *tr,
+ pjsip_tx_data *tdata,
const pj_sockaddr_in *addr,
- pj_ssize_t *sent) -{ - PJ_LOG(5, (tr->obj_name, "pjsip_transport_send_msg(tdata=%s)", tdata->obj_name)); - - return transport_send_msg(tr, tdata, addr, sent ); -} - -/////////////////////////////////////////////////////////////////////////////// - -/* - * Create a new transport manager. - */ -PJ_DEF(pj_status_t) pjsip_transport_mgr_create( pj_pool_t *pool, - pjsip_endpoint * endpt, + pj_ssize_t *sent)
+{
+ PJ_LOG(5, (tr->obj_name, "pjsip_transport_send_msg(tdata=%s)", tdata->obj_name));
+
+ return transport_send_msg(tr, tdata, addr, sent );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+/*
+ * Create a new transport manager.
+ */
+PJ_DEF(pj_status_t) pjsip_transport_mgr_create( pj_pool_t *pool,
+ pjsip_endpoint * endpt,
void (*cb)(pjsip_endpoint*,
pjsip_rx_data *),
- pjsip_transport_mgr **p_mgr) -{ - pjsip_transport_mgr *mgr; + pjsip_transport_mgr **p_mgr)
+{
+ pjsip_transport_mgr *mgr;
pj_status_t status;
- - PJ_LOG(5, (LOG_TRANSPORT_MGR, "pjsip_transport_mgr_create()")); - - mgr = pj_pool_alloc(pool, sizeof(*mgr)); - mgr->endpt = endpt; - mgr->message_callback = cb; +
+ PJ_LOG(5, (LOG_TRANSPORT_MGR, "pjsip_transport_mgr_create()"));
+
+ mgr = pj_pool_alloc(pool, sizeof(*mgr));
+ mgr->endpt = endpt;
+ mgr->message_callback = cb;
mgr->send_buf_size = DEFAULT_SO_SNDBUF;
mgr->recv_buf_size = DEFAULT_SO_RCVBUF;
- - mgr->transport_table = pj_hash_create(pool, MGR_HASH_TABLE_SIZE); - if (!mgr->transport_table) { - return PJ_ENOMEM; - } - status = pj_ioqueue_create(pool, PJSIP_MAX_TRANSPORTS, &mgr->ioqueue); - if (status != PJ_SUCCESS) { - return status; - } - status = pj_mutex_create_recursive(pool, "tmgr%p", &mgr->mutex); - if (status != PJ_SUCCESS) { - pj_ioqueue_destroy(mgr->ioqueue); - return status; - } - pj_gettimeofday(&mgr->next_idle_check); +
+ mgr->transport_table = pj_hash_create(pool, MGR_HASH_TABLE_SIZE);
+ if (!mgr->transport_table) {
+ return PJ_ENOMEM;
+ }
+ status = pj_ioqueue_create(pool, PJSIP_MAX_TRANSPORTS, &mgr->ioqueue);
+ if (status != PJ_SUCCESS) {
+ return status;
+ }
+ status = pj_mutex_create_recursive(pool, "tmgr%p", &mgr->mutex);
+ if (status != PJ_SUCCESS) {
+ pj_ioqueue_destroy(mgr->ioqueue);
+ return status;
+ }
+ pj_gettimeofday(&mgr->next_idle_check);
mgr->next_idle_check.sec += MGR_IDLE_CHECK_INTERVAL;
- *p_mgr = mgr; - return status; -} - -/* - * Destroy transport manager. - */ -PJ_DEF(pj_status_t) pjsip_transport_mgr_destroy( pjsip_transport_mgr *mgr ) -{ - pj_hash_iterator_t itr_val; - pj_hash_iterator_t *itr; - - PJ_LOG(5, (LOG_TRANSPORT_MGR, "pjsip_transport_mgr_destroy()")); - - pj_mutex_lock(mgr->mutex); - - itr = pjsip_transport_first(mgr, &itr_val); - while (itr != NULL) { - pj_hash_iterator_t *next; - pjsip_transport_t *transport; - - transport = pjsip_transport_this(mgr, itr); - - next = pjsip_transport_next(mgr, itr); - - pj_atomic_set(transport->ref_cnt, 0); - destroy_transport( mgr, transport); - - itr = next; - } - pj_ioqueue_destroy(mgr->ioqueue); - + *p_mgr = mgr;
+ return status;
+}
+
+/*
+ * Destroy transport manager.
+ */
+PJ_DEF(pj_status_t) pjsip_transport_mgr_destroy( pjsip_transport_mgr *mgr )
+{
+ pj_hash_iterator_t itr_val;
+ pj_hash_iterator_t *itr;
+
+ PJ_LOG(5, (LOG_TRANSPORT_MGR, "pjsip_transport_mgr_destroy()"));
+
+ pj_mutex_lock(mgr->mutex);
+
+ itr = pjsip_transport_first(mgr, &itr_val);
+ while (itr != NULL) {
+ pj_hash_iterator_t *next;
+ pjsip_transport_t *transport;
+
+ transport = pjsip_transport_this(mgr, itr);
+
+ next = pjsip_transport_next(mgr, itr);
+
+ pj_atomic_set(transport->ref_cnt, 0);
+ destroy_transport( mgr, transport);
+
+ itr = next;
+ }
+ pj_ioqueue_destroy(mgr->ioqueue);
+
pj_mutex_unlock(mgr->mutex);
- return PJ_SUCCESS; -} - -/* - * Create listener - */ -static pj_status_t create_listener( pjsip_transport_mgr *mgr, - pjsip_transport_type_e type, - pj_sock_t sock_hnd, - pj_sockaddr_in *local_addr, - const pj_sockaddr_in *addr_name) -{ - pjsip_transport_t *tr; + return PJ_SUCCESS;
+}
+
+/*
+ * Create listener
+ */
+static pj_status_t create_listener( pjsip_transport_mgr *mgr,
+ pjsip_transport_type_e type,
+ pj_sock_t sock_hnd,
+ pj_sockaddr_in *local_addr,
+ const pj_sockaddr_in *addr_name)
+{
+ pjsip_transport_t *tr;
struct transport_key *hash_key;
- const pj_str_t loopback_addr = { "127.0.0.1", 9 }; - pj_status_t status; + const pj_str_t loopback_addr = { "127.0.0.1", 9 };
+ pj_status_t status;
- if (mgr->send_buf_size != 0) { + if (mgr->send_buf_size != 0) {
int opt_val = mgr->send_buf_size;
status = pj_sock_setsockopt( sock_hnd, PJ_SOL_SOCKET,
PJ_SO_SNDBUF,
&opt_val, sizeof(opt_val));
- - if (status != PJ_SUCCESS) { - return status; +
+ if (status != PJ_SUCCESS) {
+ return status;
}
- } + }
- if (mgr->recv_buf_size != 0) { + if (mgr->recv_buf_size != 0) {
int opt_val = mgr->recv_buf_size;
status = pj_sock_setsockopt( sock_hnd, PJ_SOL_SOCKET,
PJ_SO_RCVBUF,
- &opt_val, sizeof(opt_val)); - if (status != PJ_SUCCESS) { - return status; + &opt_val, sizeof(opt_val));
+ if (status != PJ_SUCCESS) {
+ return status;
}
- } - - status = create_transport(mgr, type, sock_hnd, local_addr, addr_name, &tr); - if (status != PJ_SUCCESS) { - pj_sock_close(sock_hnd); - return status; - } -#if PJ_HAS_TCP - if (type == PJSIP_TRANSPORT_TCP) { -
- status = pj_sock_listen(tr->sock, BACKLOG); - if (status != 0) { - destroy_transport(mgr, tr); - return status; - } + }
+
+ status = create_transport(mgr, type, sock_hnd, local_addr, addr_name, &tr);
+ if (status != PJ_SUCCESS) {
+ pj_sock_close(sock_hnd);
+ return status;
+ }
+#if PJ_HAS_TCP
+ if (type == PJSIP_TRANSPORT_TCP) {
+
+ status = pj_sock_listen(tr->sock, BACKLOG);
+ if (status != 0) {
+ destroy_transport(mgr, tr);
+ return status;
+ }
/* Discard immediate connections. */
do {
- tr->accept_data.addrlen = sizeof(tr->accept_data.local); - status = pj_ioqueue_accept(tr->key, &tr->accept_op, - &tr->accept_data.sock, - &tr->accept_data.local, - &tr->accept_data.remote, + tr->accept_data.addrlen = sizeof(tr->accept_data.local);
+ status = pj_ioqueue_accept(tr->key, &tr->accept_op,
+ &tr->accept_data.sock,
+ &tr->accept_data.local,
+ &tr->accept_data.remote,
&tr->accept_data.addrlen);
if (status==PJ_SUCCESS) {
pj_sock_close(tr->accept_data.sock);
- } else if (status != PJ_EPENDING) { - destroy_transport(mgr, tr); - return status; + } else if (status != PJ_EPENDING) {
+ destroy_transport(mgr, tr);
+ return status;
}
- } while (status==PJ_SUCCESS); - - } else -#endif + } while (status==PJ_SUCCESS);
+
+ } else
+#endif
if (type == PJSIP_TRANSPORT_UDP) {
pj_ssize_t bytes;
/* Discard immediate data. */
- do { + do {
tr->rdata->addr_len = sizeof(tr->rdata->addr);
- bytes = PJSIP_MAX_PKT_LEN; - status = pj_ioqueue_recvfrom( tr->key, &tr->rdata->op_key, - tr->rdata->packet, &bytes, 0, - &tr->rdata->addr, + bytes = PJSIP_MAX_PKT_LEN;
+ status = pj_ioqueue_recvfrom( tr->key, &tr->rdata->op_key,
+ tr->rdata->packet, &bytes, 0,
+ &tr->rdata->addr,
&tr->rdata->addr_len);
if (status == PJ_SUCCESS) {
- ; - } else if (status != PJ_EPENDING) { - destroy_transport(mgr, tr); - return status; + ;
+ } else if (status != PJ_EPENDING) {
+ destroy_transport(mgr, tr);
+ return status;
}
- } while (status == PJ_SUCCESS); - } - - pj_atomic_set(tr->ref_cnt, 1); - - /* Listeners normally have no remote address */ - pj_memset(&tr->remote_addr, 0, sizeof(tr->remote_addr)); - - /* Set remote address to 127.0.0.1 for UDP socket bound to 127.0.0.1. - * See further comments on struct pjsip_transport_t definition. + } while (status == PJ_SUCCESS);
+ }
+
+ pj_atomic_set(tr->ref_cnt, 1);
+
+ /* Listeners normally have no remote address */
+ pj_memset(&tr->remote_addr, 0, sizeof(tr->remote_addr));
+
+ /* Set remote address to 127.0.0.1 for UDP socket bound to 127.0.0.1.
+ * See further comments on struct pjsip_transport_t definition.
*/
if (type == PJSIP_TRANSPORT_UDP &&
local_addr->sin_addr.s_addr == pj_inet_addr(&loopback_addr).s_addr)
- { - pj_str_t localaddr = pj_str("127.0.0.1"); - pj_sockaddr_in_set_str_addr( &tr->remote_addr, &localaddr); - } - hash_key = pj_pool_alloc(tr->pool, sizeof(transport_key)); - init_key_from_transport(hash_key, tr); - - pj_mutex_lock(mgr->mutex); + {
+ pj_str_t localaddr = pj_str("127.0.0.1");
+ pj_sockaddr_in_set_str_addr( &tr->remote_addr, &localaddr);
+ }
+ hash_key = pj_pool_alloc(tr->pool, sizeof(transport_key));
+ init_key_from_transport(hash_key, tr);
+
+ pj_mutex_lock(mgr->mutex);
pj_hash_set(tr->pool, mgr->transport_table,
- hash_key, sizeof(transport_key), tr); - pj_mutex_unlock(mgr->mutex); - - PJ_LOG(4,(tr->obj_name, "Listening at %s %s:%d", - get_type_name(tr->type), - pj_inet_ntoa(tr->local_addr.sin_addr), - pj_sockaddr_in_get_port(&tr->local_addr))); - PJ_LOG(4,(tr->obj_name, "Listener public address is at %s %s:%d", - get_type_name(tr->type), - pj_inet_ntoa(tr->addr_name.sin_addr), - pj_sockaddr_in_get_port(&tr->addr_name))); - return PJ_SUCCESS; -} - -/* - * Create listener. - */ -PJ_DEF(pj_status_t) pjsip_create_listener( pjsip_transport_mgr *mgr, - pjsip_transport_type_e type, - pj_sockaddr_in *local_addr, - const pj_sockaddr_in *addr_name) -{ - pj_sock_t sock_hnd; + hash_key, sizeof(transport_key), tr);
+ pj_mutex_unlock(mgr->mutex);
+
+ PJ_LOG(4,(tr->obj_name, "Listening at %s %s:%d",
+ get_type_name(tr->type),
+ pj_inet_ntoa(tr->local_addr.sin_addr),
+ pj_sockaddr_in_get_port(&tr->local_addr)));
+ PJ_LOG(4,(tr->obj_name, "Listener public address is at %s %s:%d",
+ get_type_name(tr->type),
+ pj_inet_ntoa(tr->addr_name.sin_addr),
+ pj_sockaddr_in_get_port(&tr->addr_name)));
+ return PJ_SUCCESS;
+}
+
+/*
+ * Create listener.
+ */
+PJ_DEF(pj_status_t) pjsip_create_listener( pjsip_transport_mgr *mgr,
+ pjsip_transport_type_e type,
+ pj_sockaddr_in *local_addr,
+ const pj_sockaddr_in *addr_name)
+{
+ pj_sock_t sock_hnd;
pj_status_t status;
- - PJ_LOG(5, (LOG_TRANSPORT_MGR, "pjsip_create_listener(type=%d)", type)); - - status = create_socket(type, local_addr, &sock_hnd); - if (status != PJ_SUCCESS) { - return status; - } - - return create_listener(mgr, type, sock_hnd, local_addr, addr_name); -} - -/* - * Create UDP listener. - */ -PJ_DEF(pj_status_t) pjsip_create_udp_listener( pjsip_transport_mgr *mgr, - pj_sock_t sock, - const pj_sockaddr_in *addr_name) -{ +
+ PJ_LOG(5, (LOG_TRANSPORT_MGR, "pjsip_create_listener(type=%d)", type));
+
+ status = create_socket(type, local_addr, &sock_hnd);
+ if (status != PJ_SUCCESS) {
+ return status;
+ }
+
+ return create_listener(mgr, type, sock_hnd, local_addr, addr_name);
+}
+
+/*
+ * Create UDP listener.
+ */
+PJ_DEF(pj_status_t) pjsip_create_udp_listener( pjsip_transport_mgr *mgr,
+ pj_sock_t sock,
+ const pj_sockaddr_in *addr_name)
+{
pj_sockaddr_in local_addr;
- pj_status_t status; - int addrlen = sizeof(local_addr); + pj_status_t status;
+ int addrlen = sizeof(local_addr);
+
+ status = pj_sock_getsockname(sock, (pj_sockaddr_t*)&local_addr, &addrlen);
+ if (status != PJ_SUCCESS)
+ return status;
- status = pj_sock_getsockname(sock, (pj_sockaddr_t*)&local_addr, &addrlen); - if (status != PJ_SUCCESS) - return status; - return create_listener(mgr, PJSIP_TRANSPORT_UDP, sock,
- &local_addr, addr_name); -} - -/* - * Find transport to be used to send message to remote destination. If no - * suitable transport is found, a new one will be created. - */ -PJ_DEF(void) pjsip_transport_get( pjsip_transport_mgr *mgr, - pj_pool_t *pool, - pjsip_transport_type_e type, - const pj_sockaddr_in *remote, - void *token, - pjsip_transport_completion_callback *cb) -{ - transport_key search_key, *hash_key; - pjsip_transport_t *tr; - pj_sockaddr_in local; - pj_sock_t sock_hnd; - pj_status_t status; - struct transport_callback *cb_rec; - - PJ_LOG(5, (LOG_TRANSPORT_MGR, "pjsip_transport_get()")); - - /* Create the callback record. - */ - cb_rec = pj_pool_calloc(pool, 1, sizeof(*cb_rec)); - cb_rec->token = token; - cb_rec->cb = cb; - - /* Create key for hash table look-up. - * The key creation is different for TCP and UDP. - */ -#if PJ_HAS_TCP - if (type==PJSIP_TRANSPORT_TCP) { - init_tcp_key(&search_key, type, remote); - } else -#endif - if (type==PJSIP_TRANSPORT_UDP) { - init_udp_key(&search_key, type, remote); - } - - /* Start lock the manager. */ - pj_mutex_lock(mgr->mutex); - - /* Lookup the transport in the hash table. */ - tr = pj_hash_get(mgr->transport_table, &search_key, sizeof(transport_key)); - - if (tr) { - /* Transport found. If the transport is still busy (i.e. connecting - * is in progress), then just register the callback. Otherwise - * report via the callback if callback is specified. - */ - pj_mutex_unlock(mgr->mutex); - pj_mutex_lock(tr->tr_mutex); - - if (tr->flag & PJSIP_TRANSPORT_IOQUEUE_BUSY) { - /* Transport is busy. Just register the callback. */ - pj_list_insert_before(&tr->cb_list, cb_rec); - - } else { - /* Transport is ready. Call callback now. - */ - (*cb_rec->cb)(tr, cb_rec->token, PJ_SUCCESS); - } - pj_mutex_unlock(tr->tr_mutex); - - return; - } - - - /* Transport not found. Create new one. */ - pj_memset(&local, 0, sizeof(local)); - local.sin_family = PJ_AF_INET; - status = create_socket(type, &local, &sock_hnd); - if (status != PJ_SUCCESS) { - pj_mutex_unlock(mgr->mutex); - (*cb_rec->cb)(NULL, cb_rec->token, status); - return; - } - status = create_transport(mgr, type, sock_hnd, &local, NULL, &tr); - if (status != PJ_SUCCESS) { - pj_mutex_unlock(mgr->mutex); - (*cb_rec->cb)(NULL, cb_rec->token, status); - return; - } - -#if PJ_HAS_TCP - if (type == PJSIP_TRANSPORT_TCP) { - pj_memcpy(&tr->remote_addr, remote, sizeof(pj_sockaddr_in)); + &local_addr, addr_name);
+}
+
+/*
+ * Find transport to be used to send message to remote destination. If no
+ * suitable transport is found, a new one will be created.
+ */
+PJ_DEF(void) pjsip_transport_get( pjsip_transport_mgr *mgr,
+ pj_pool_t *pool,
+ pjsip_transport_type_e type,
+ const pj_sockaddr_in *remote,
+ void *token,
+ pjsip_transport_completion_callback *cb)
+{
+ transport_key search_key, *hash_key;
+ pjsip_transport_t *tr;
+ pj_sockaddr_in local;
+ pj_sock_t sock_hnd;
+ pj_status_t status;
+ struct transport_callback *cb_rec;
+
+ PJ_LOG(5, (LOG_TRANSPORT_MGR, "pjsip_transport_get()"));
+
+ /* Create the callback record.
+ */
+ cb_rec = pj_pool_calloc(pool, 1, sizeof(*cb_rec));
+ cb_rec->token = token;
+ cb_rec->cb = cb;
+
+ /* Create key for hash table look-up.
+ * The key creation is different for TCP and UDP.
+ */
+#if PJ_HAS_TCP
+ if (type==PJSIP_TRANSPORT_TCP) {
+ init_tcp_key(&search_key, type, remote);
+ } else
+#endif
+ if (type==PJSIP_TRANSPORT_UDP) {
+ init_udp_key(&search_key, type, remote);
+ }
+
+ /* Start lock the manager. */
+ pj_mutex_lock(mgr->mutex);
+
+ /* Lookup the transport in the hash table. */
+ tr = pj_hash_get(mgr->transport_table, &search_key, sizeof(transport_key));
+
+ if (tr) {
+ /* Transport found. If the transport is still busy (i.e. connecting
+ * is in progress), then just register the callback. Otherwise
+ * report via the callback if callback is specified.
+ */
+ pj_mutex_unlock(mgr->mutex);
+ pj_mutex_lock(tr->tr_mutex);
+
+ if (tr->flag & PJSIP_TRANSPORT_IOQUEUE_BUSY) {
+ /* Transport is busy. Just register the callback. */
+ pj_list_insert_before(&tr->cb_list, cb_rec);
+
+ } else {
+ /* Transport is ready. Call callback now.
+ */
+ (*cb_rec->cb)(tr, cb_rec->token, PJ_SUCCESS);
+ }
+ pj_mutex_unlock(tr->tr_mutex);
+
+ return;
+ }
+
+
+ /* Transport not found. Create new one. */
+ pj_memset(&local, 0, sizeof(local));
+ local.sin_family = PJ_AF_INET;
+ status = create_socket(type, &local, &sock_hnd);
+ if (status != PJ_SUCCESS) {
+ pj_mutex_unlock(mgr->mutex);
+ (*cb_rec->cb)(NULL, cb_rec->token, status);
+ return;
+ }
+ status = create_transport(mgr, type, sock_hnd, &local, NULL, &tr);
+ if (status != PJ_SUCCESS) {
+ pj_mutex_unlock(mgr->mutex);
+ (*cb_rec->cb)(NULL, cb_rec->token, status);
+ return;
+ }
+
+#if PJ_HAS_TCP
+ if (type == PJSIP_TRANSPORT_TCP) {
+ pj_memcpy(&tr->remote_addr, remote, sizeof(pj_sockaddr_in));
status = pj_ioqueue_connect(tr->key, &tr->remote_addr,
- sizeof(pj_sockaddr_in)); - pj_assert(status != 0); + sizeof(pj_sockaddr_in));
+ pj_assert(status != 0);
if (status != PJ_EPENDING) {
- PJ_TODO(HANDLE_IMMEDIATE_CONNECT); - destroy_transport(mgr, tr); - pj_mutex_unlock(mgr->mutex); - (*cb_rec->cb)(NULL, cb_rec->token, status); - return; - } - } else -#endif - if (type == PJSIP_TRANSPORT_UDP) { - pj_ssize_t size; - - do { + PJ_TODO(HANDLE_IMMEDIATE_CONNECT);
+ destroy_transport(mgr, tr);
+ pj_mutex_unlock(mgr->mutex);
+ (*cb_rec->cb)(NULL, cb_rec->token, status);
+ return;
+ }
+ } else
+#endif
+ if (type == PJSIP_TRANSPORT_UDP) {
+ pj_ssize_t size;
+
+ do {
tr->rdata->addr_len = sizeof(tr->rdata->addr);
- size = PJSIP_MAX_PKT_LEN; - status = pj_ioqueue_recvfrom( tr->key, &tr->rdata->op_key, - tr->rdata->packet, &size, 0, - &tr->rdata->addr, + size = PJSIP_MAX_PKT_LEN;
+ status = pj_ioqueue_recvfrom( tr->key, &tr->rdata->op_key,
+ tr->rdata->packet, &size, 0,
+ &tr->rdata->addr,
&tr->rdata->addr_len);
if (status == PJ_SUCCESS)
- ; - else if (status != PJ_EPENDING) { - destroy_transport(mgr, tr); - pj_mutex_unlock(mgr->mutex); - (*cb_rec->cb)(NULL, cb_rec->token, status); - return; - } - - /* Bug here. - * If data is immediately available, although not likely, it will - * be dropped because we don't expect to have data right after - * the socket is created, do we ?! - */ - PJ_TODO(FIXED_BUG_ON_IMMEDIATE_TRANSPORT_DATA); - - } while (status == PJ_SUCCESS); - - //Bug: cb will never be called! - // Must force status to PJ_SUCCESS; - //status = PJ_IOQUEUE_PENDING; - - status = PJ_SUCCESS; - - } else { - pj_mutex_unlock(mgr->mutex); - (*cb_rec->cb)(NULL, cb_rec->token, PJSIP_EUNSUPTRANSPORT); - return; - } - - pj_assert(status==PJ_EPENDING || status==PJ_SUCCESS); - pj_mutex_lock(tr->tr_mutex); - hash_key = pj_pool_alloc(tr->pool, sizeof(transport_key)); - pj_memcpy(hash_key, &search_key, sizeof(transport_key)); + ;
+ else if (status != PJ_EPENDING) {
+ destroy_transport(mgr, tr);
+ pj_mutex_unlock(mgr->mutex);
+ (*cb_rec->cb)(NULL, cb_rec->token, status);
+ return;
+ }
+
+ /* Bug here.
+ * If data is immediately available, although not likely, it will
+ * be dropped because we don't expect to have data right after
+ * the socket is created, do we ?!
+ */
+ PJ_TODO(FIXED_BUG_ON_IMMEDIATE_TRANSPORT_DATA);
+
+ } while (status == PJ_SUCCESS);
+
+ //Bug: cb will never be called!
+ // Must force status to PJ_SUCCESS;
+ //status = PJ_IOQUEUE_PENDING;
+
+ status = PJ_SUCCESS;
+
+ } else {
+ pj_mutex_unlock(mgr->mutex);
+ (*cb_rec->cb)(NULL, cb_rec->token, PJSIP_EUNSUPTRANSPORT);
+ return;
+ }
+
+ pj_assert(status==PJ_EPENDING || status==PJ_SUCCESS);
+ pj_mutex_lock(tr->tr_mutex);
+ hash_key = pj_pool_alloc(tr->pool, sizeof(transport_key));
+ pj_memcpy(hash_key, &search_key, sizeof(transport_key));
pj_hash_set(tr->pool, mgr->transport_table,
- hash_key, sizeof(transport_key), tr); - if (status == PJ_SUCCESS) { - pj_mutex_unlock(tr->tr_mutex); - pj_mutex_unlock(mgr->mutex); - (*cb_rec->cb)(tr, cb_rec->token, PJ_SUCCESS); - } else { - pj_list_insert_before(&tr->cb_list, cb_rec); - pj_mutex_unlock(tr->tr_mutex); - pj_mutex_unlock(mgr->mutex); - } - -} - -#if PJ_HAS_TCP -/* - * Handle completion of asynchronous accept() operation. - * This function is called by handle_events() function. - */ -static void handle_new_connection( pjsip_transport_mgr *mgr, - pjsip_transport_t *listener, - pj_status_t status ) -{ - pjsip_transport_t *tr; + hash_key, sizeof(transport_key), tr);
+ if (status == PJ_SUCCESS) {
+ pj_mutex_unlock(tr->tr_mutex);
+ pj_mutex_unlock(mgr->mutex);
+ (*cb_rec->cb)(tr, cb_rec->token, PJ_SUCCESS);
+ } else {
+ pj_list_insert_before(&tr->cb_list, cb_rec);
+ pj_mutex_unlock(tr->tr_mutex);
+ pj_mutex_unlock(mgr->mutex);
+ }
+
+}
+
+#if PJ_HAS_TCP
+/*
+ * Handle completion of asynchronous accept() operation.
+ * This function is called by handle_events() function.
+ */
+static void handle_new_connection( pjsip_transport_mgr *mgr,
+ pjsip_transport_t *listener,
+ pj_status_t status )
+{
+ pjsip_transport_t *tr;
transport_key *hash_key;
pj_ssize_t size;
- - pj_assert (listener->type == PJSIP_TRANSPORT_TCP); - - if (status != PJ_SUCCESS) { +
+ pj_assert (listener->type == PJSIP_TRANSPORT_TCP);
+
+ if (status != PJ_SUCCESS) {
PJSIP_ENDPT_LOG_ERROR((mgr->endpt, listener->obj_name, status,
"Error in accept() completion"));
- goto on_return; - } - - PJ_LOG(4,(listener->obj_name, "incoming tcp connection from %s:%d", - pj_inet_ntoa(listener->accept_data.remote.sin_addr), - pj_sockaddr_in_get_port(&listener->accept_data.remote))); - - status = create_transport(mgr, listener->type, - listener->accept_data.sock, - &listener->accept_data.local, - NULL, &tr); - if (status != PJ_SUCCESS) { + goto on_return;
+ }
+
+ PJ_LOG(4,(listener->obj_name, "incoming tcp connection from %s:%d",
+ pj_inet_ntoa(listener->accept_data.remote.sin_addr),
+ pj_sockaddr_in_get_port(&listener->accept_data.remote)));
+
+ status = create_transport(mgr, listener->type,
+ listener->accept_data.sock,
+ &listener->accept_data.local,
+ NULL, &tr);
+ if (status != PJ_SUCCESS) {
PJSIP_ENDPT_LOG_ERROR((mgr->endpt, listener->obj_name, status,
"Error in creating new incoming TCP"));
- goto on_return; - } - - /* - tr->rdata->addr_len = sizeof(tr->rdata->addr); - status = pj_ioqueue_recvfrom( mgr->ioqueue, tr->key, - tr->rdata->packet, PJSIP_MAX_PKT_LEN, - &tr->rdata->addr, - &tr->rdata->addr_len); - */ - tr->rdata->addr = listener->accept_data.remote; - tr->rdata->addr_len = listener->accept_data.addrlen; -
- size = PJSIP_MAX_PKT_LEN; + goto on_return;
+ }
+
+ /*
+ tr->rdata->addr_len = sizeof(tr->rdata->addr);
+ status = pj_ioqueue_recvfrom( mgr->ioqueue, tr->key,
+ tr->rdata->packet, PJSIP_MAX_PKT_LEN,
+ &tr->rdata->addr,
+ &tr->rdata->addr_len);
+ */
+ tr->rdata->addr = listener->accept_data.remote;
+ tr->rdata->addr_len = listener->accept_data.addrlen;
+
+ size = PJSIP_MAX_PKT_LEN;
status = pj_ioqueue_recv(tr->key, &tr->rdata->op_key,
- tr->rdata->packet, &size, 0); - if (status != PJ_EPENDING) { + tr->rdata->packet, &size, 0);
+ if (status != PJ_EPENDING) {
PJSIP_ENDPT_LOG_ERROR((mgr->endpt, listener->obj_name, status,
"Error in receiving data"));
- PJ_TODO(IMMEDIATE_DATA); - destroy_transport(mgr, tr); - goto on_return; - } - + PJ_TODO(IMMEDIATE_DATA);
+ destroy_transport(mgr, tr);
+ goto on_return;
+ }
+
pj_memcpy(&tr->remote_addr, &listener->accept_data.remote,
- listener->accept_data.addrlen); - hash_key = pj_pool_alloc(tr->pool, sizeof(transport_key)); - init_key_from_transport(hash_key, tr); - - pj_mutex_lock(mgr->mutex); + listener->accept_data.addrlen);
+ hash_key = pj_pool_alloc(tr->pool, sizeof(transport_key));
+ init_key_from_transport(hash_key, tr);
+
+ pj_mutex_lock(mgr->mutex);
pj_hash_set(tr->pool, mgr->transport_table, hash_key,
- sizeof(transport_key), tr); - pj_mutex_unlock(mgr->mutex); - -on_return: - /* Re-initiate asynchronous accept() */ - listener->accept_data.addrlen = sizeof(listener->accept_data.local); - status = pj_ioqueue_accept(listener->key, &listener->accept_op, - &listener->accept_data.sock, - &listener->accept_data.local, - &listener->accept_data.remote, - &listener->accept_data.addrlen); - if (status != PJ_EPENDING) { + sizeof(transport_key), tr);
+ pj_mutex_unlock(mgr->mutex);
+
+on_return:
+ /* Re-initiate asynchronous accept() */
+ listener->accept_data.addrlen = sizeof(listener->accept_data.local);
+ status = pj_ioqueue_accept(listener->key, &listener->accept_op,
+ &listener->accept_data.sock,
+ &listener->accept_data.local,
+ &listener->accept_data.remote,
+ &listener->accept_data.addrlen);
+ if (status != PJ_EPENDING) {
PJSIP_ENDPT_LOG_ERROR((mgr->endpt, listener->obj_name, status,
"Error in receiving data"));
- PJ_TODO(IMMEDIATE_ACCEPT); - return; - } -} - -/* - * Handle completion of asynchronous connect() function. - * This function is called by the handle_events() function. - */ -static void handle_connect_completion( pjsip_transport_mgr *mgr, - pjsip_transport_t *tr, - pj_status_t status ) -{ - struct transport_callback new_list; - struct transport_callback *cb_rec; + PJ_TODO(IMMEDIATE_ACCEPT);
+ return;
+ }
+}
+
+/*
+ * Handle completion of asynchronous connect() function.
+ * This function is called by the handle_events() function.
+ */
+static void handle_connect_completion( pjsip_transport_mgr *mgr,
+ pjsip_transport_t *tr,
+ pj_status_t status )
+{
+ struct transport_callback new_list;
+ struct transport_callback *cb_rec;
pj_ssize_t recv_size;
- - PJ_UNUSED_ARG(mgr); - - /* On connect completion, we must call all registered callbacks in - * the transport. - */ - - /* Initialize new list. */ - pj_list_init(&new_list); - - /* Hold transport's mutex. We don't want other thread to register a - * callback while we're dealing with it. - */ - pj_mutex_lock(tr->tr_mutex); - - /* Copy callback list to new list so that we can call the callbacks - * without holding the mutex. - */ - pj_list_merge_last(&new_list, &tr->cb_list); - - /* Clear transport's busy flag. */ - tr->flag &= ~PJSIP_TRANSPORT_IOQUEUE_BUSY; - - /* If success, update local address. - * Local address is only available after connect() has returned. - */ - if (status == PJ_SUCCESS) { - int addrlen = sizeof(tr->local_addr); +
+ PJ_UNUSED_ARG(mgr);
+
+ /* On connect completion, we must call all registered callbacks in
+ * the transport.
+ */
+
+ /* Initialize new list. */
+ pj_list_init(&new_list);
+
+ /* Hold transport's mutex. We don't want other thread to register a
+ * callback while we're dealing with it.
+ */
+ pj_mutex_lock(tr->tr_mutex);
+
+ /* Copy callback list to new list so that we can call the callbacks
+ * without holding the mutex.
+ */
+ pj_list_merge_last(&new_list, &tr->cb_list);
+
+ /* Clear transport's busy flag. */
+ tr->flag &= ~PJSIP_TRANSPORT_IOQUEUE_BUSY;
+
+ /* If success, update local address.
+ * Local address is only available after connect() has returned.
+ */
+ if (status == PJ_SUCCESS) {
+ int addrlen = sizeof(tr->local_addr);
status = pj_sock_getsockname(tr->sock,
(pj_sockaddr_t*)&tr->local_addr,
- &addrlen); - if (status == PJ_SUCCESS) { - pj_memcpy(&tr->addr_name, &tr->local_addr, sizeof(tr->addr_name)); - } - } - - /* Unlock mutex. */ - pj_mutex_unlock(tr->tr_mutex); - - /* Call all registered callbacks. */ - cb_rec = new_list.next; - while (cb_rec != &new_list) { - struct transport_callback *next; - next = cb_rec->next; - (*cb_rec->cb)(tr, cb_rec->token, status); - cb_rec = next; - } - - /* Success? */ - if (status != PJ_SUCCESS) { + &addrlen);
+ if (status == PJ_SUCCESS) {
+ pj_memcpy(&tr->addr_name, &tr->local_addr, sizeof(tr->addr_name));
+ }
+ }
+
+ /* Unlock mutex. */
+ pj_mutex_unlock(tr->tr_mutex);
+
+ /* Call all registered callbacks. */
+ cb_rec = new_list.next;
+ while (cb_rec != &new_list) {
+ struct transport_callback *next;
+ next = cb_rec->next;
+ (*cb_rec->cb)(tr, cb_rec->token, status);
+ cb_rec = next;
+ }
+
+ /* Success? */
+ if (status != PJ_SUCCESS) {
destroy_transport(mgr, tr);
- PJ_TODO(WTF); - return; - } - + PJ_TODO(WTF);
+ return;
+ }
+
/* Initiate read operation to socket. */
- recv_size = PJSIP_MAX_PKT_LEN; + recv_size = PJSIP_MAX_PKT_LEN;
status = pj_ioqueue_recv( tr->key, &tr->rdata->op_key, tr->rdata->packet,
- &recv_size, 0); - if (status != PJ_EPENDING) { + &recv_size, 0);
+ if (status != PJ_EPENDING) {
destroy_transport(mgr, tr);
- PJ_TODO(IMMEDIATE_DATA); - return; - } -} -#endif /* PJ_HAS_TCP */ - -/* - * Handle incoming data. - * This function is called when the transport manager receives 'notification' - * from the I/O Queue that the receive operation has completed. - * This function will then attempt to parse the message, and hands over the - * message to the endpoint. - */ -static void handle_received_data( pjsip_transport_mgr *mgr, - pjsip_transport_t *tr, - pj_ssize_t size ) -{ - pjsip_msg *msg; - pjsip_rx_data *rdata = tr->rdata; - pj_pool_t *rdata_pool; - pjsip_hdr *hdr; - pj_str_t s; - char *src_addr; - int src_port; - pj_size_t msg_fragment_size = 0; - - /* Check size. */ - if (size < 1) { - if (tr->type != PJSIP_TRANSPORT_UDP) { - /* zero bytes indicates transport has been closed for TCP. - * But alas, we can't destroy it now since transactions may still - * have reference to it. In that case, just do nothing, the - * transaction will receive error when it tries to send anything. - * But alas!! UAC transactions wont send anything!!. - * So this is a bug! - */ - if (pj_atomic_get(tr->ref_cnt)==0) { - PJ_LOG(4,(tr->obj_name, "connection closed")); - destroy_transport(mgr, tr); - } else { - PJ_TODO(HANDLE_TCP_TRANSPORT_CLOSED); - //PJ_TODO(SIGNAL_TRANSACTIONS_ON_TRANSPORT_CLOSED); - } - return; - } else { - /* On Windows machines, UDP recv() will return zero upon receiving - * ICMP port unreachable message. - */ - PJ_LOG(4,(tr->obj_name, "Ignored zero length UDP packet (port unreachable?)")); - goto on_return; - } - } - - /* Save received time. */ - pj_gettimeofday(&rdata->timestamp); - - /* Update length. */ - rdata->len += size; - - /* Null terminate packet, this is the requirement of the parser. */ - rdata->packet[rdata->len] = '\0'; - - /* Get source address and port for logging purpose. */ - src_addr = pj_inet_ntoa(rdata->addr.sin_addr); - src_port = pj_sockaddr_in_get_port(&rdata->addr); - - /* Print the whole data to the log. */ - PJ_LOG(4,(tr->obj_name, "%d bytes recvfrom %s:%d:\n" - "----------- begin msg ------------\n" - "%s" - "------------ end msg -------------", - rdata->len, src_addr, src_port, rdata->packet)); - - - /* Process all message fragments. */ - while (rdata->len > 0) { - - msg_fragment_size = rdata->len; -#if PJ_HAS_TCP - /* For TCP transport, check if the whole message has been received. */ - if (tr->type != PJSIP_TRANSPORT_UDP) { - pj_status_t msg_status; + PJ_TODO(IMMEDIATE_DATA);
+ return;
+ }
+}
+#endif /* PJ_HAS_TCP */
+
+/*
+ * Handle incoming data.
+ * This function is called when the transport manager receives 'notification'
+ * from the I/O Queue that the receive operation has completed.
+ * This function will then attempt to parse the message, and hands over the
+ * message to the endpoint.
+ */
+static void handle_received_data( pjsip_transport_mgr *mgr,
+ pjsip_transport_t *tr,
+ pj_ssize_t size )
+{
+ pjsip_msg *msg;
+ pjsip_rx_data *rdata = tr->rdata;
+ pj_pool_t *rdata_pool;
+ pjsip_hdr *hdr;
+ pj_str_t s;
+ char *src_addr;
+ int src_port;
+ pj_size_t msg_fragment_size = 0;
+
+ /* Check size. */
+ if (size < 1) {
+ if (tr->type != PJSIP_TRANSPORT_UDP) {
+ /* zero bytes indicates transport has been closed for TCP.
+ * But alas, we can't destroy it now since transactions may still
+ * have reference to it. In that case, just do nothing, the
+ * transaction will receive error when it tries to send anything.
+ * But alas!! UAC transactions wont send anything!!.
+ * So this is a bug!
+ */
+ if (pj_atomic_get(tr->ref_cnt)==0) {
+ PJ_LOG(4,(tr->obj_name, "connection closed"));
+ destroy_transport(mgr, tr);
+ } else {
+ PJ_TODO(HANDLE_TCP_TRANSPORT_CLOSED);
+ //PJ_TODO(SIGNAL_TRANSACTIONS_ON_TRANSPORT_CLOSED);
+ }
+ return;
+ } else {
+ /* On Windows machines, UDP recv() will return zero upon receiving
+ * ICMP port unreachable message.
+ */
+ PJ_LOG(4,(tr->obj_name, "Ignored zero length UDP packet (port unreachable?)"));
+ goto on_return;
+ }
+ }
+
+ /* Save received time. */
+ pj_gettimeofday(&rdata->timestamp);
+
+ /* Update length. */
+ rdata->len += size;
+
+ /* Null terminate packet, this is the requirement of the parser. */
+ rdata->packet[rdata->len] = '\0';
+
+ /* Get source address and port for logging purpose. */
+ src_addr = pj_inet_ntoa(rdata->addr.sin_addr);
+ src_port = pj_sockaddr_in_get_port(&rdata->addr);
+
+ /* Print the whole data to the log. */
+ PJ_LOG(4,(tr->obj_name, "%d bytes recvfrom %s:%d:\n"
+ "----------- begin msg ------------\n"
+ "%s"
+ "------------ end msg -------------",
+ rdata->len, src_addr, src_port, rdata->packet));
+
+
+ /* Process all message fragments. */
+ while (rdata->len > 0) {
+
+ msg_fragment_size = rdata->len;
+#if PJ_HAS_TCP
+ /* For TCP transport, check if the whole message has been received. */
+ if (tr->type != PJSIP_TRANSPORT_UDP) {
+ pj_status_t msg_status;
msg_status = pjsip_find_msg(rdata->packet, rdata->len, PJ_FALSE,
- &msg_fragment_size); - if (msg_status != PJ_SUCCESS) { + &msg_fragment_size);
+ if (msg_status != PJ_SUCCESS) {
if (rdata->len == PJSIP_MAX_PKT_LEN) {
PJSIP_ENDPT_LOG_ERROR((mgr->endpt, tr->obj_name,
PJSIP_EOVERFLOW,
- "Buffer discarded for %s:%d", - src_addr, src_port)); - goto on_return; - } else { - goto tcp_read_packet; - } - } - } -#endif - - /* Clear parser error report */ - pj_list_init(&rdata->parse_err); - - /* Parse the message. */ - PJ_LOG(5,(tr->obj_name, "Parsing %d bytes from %s:%d", msg_fragment_size, - src_addr, src_port)); - - msg = pjsip_parse_rdata( rdata->packet, msg_fragment_size, rdata); - if (msg == NULL) { - PJ_LOG(3,(tr->obj_name, "Bad message (%d bytes from %s:%d)", msg_fragment_size, - src_addr, src_port)); - goto finish_process_fragment; - } -
- /* Perform basic header checking. */ + "Buffer discarded for %s:%d",
+ src_addr, src_port));
+ goto on_return;
+ } else {
+ goto tcp_read_packet;
+ }
+ }
+ }
+#endif
+
+ /* Clear parser error report */
+ pj_list_init(&rdata->parse_err);
+
+ /* Parse the message. */
+ PJ_LOG(5,(tr->obj_name, "Parsing %d bytes from %s:%d", msg_fragment_size,
+ src_addr, src_port));
+
+ msg = pjsip_parse_rdata( rdata->packet, msg_fragment_size, rdata);
+ if (msg == NULL) {
+ PJ_LOG(3,(tr->obj_name, "Bad message (%d bytes from %s:%d)", msg_fragment_size,
+ src_addr, src_port));
+ goto finish_process_fragment;
+ }
+
+ /* Perform basic header checking. */
if (rdata->call_id.ptr == NULL || rdata->from == NULL ||
- rdata->to == NULL || rdata->via == NULL || rdata->cseq == NULL) - { - PJ_LOG(3,(tr->obj_name, "Bad message from %s:%d: missing some header", - src_addr, src_port)); - goto finish_process_fragment; - } - - /* If message is received from address that's different from the sent-by, - * MUST add received parameter to the via. - * In our case, we add Via receive param for EVERY received message, - * because it saves us from resolving the host HERE in case sent-by is in - * FQDN format. And it doesn't hurt either. - */ - s = pj_str(src_addr); - pj_strdup(rdata->pool, &rdata->via->recvd_param, &s); - - /* RFC 3581: - * If message contains "rport" param, put the received port there. - */ - if (rdata->via->rport_param == 0) { - rdata->via->rport_param = pj_sockaddr_in_get_port(&rdata->addr); - } - - /* Drop response message if it has more than one Via. - */ - if (msg->type == PJSIP_RESPONSE_MSG) { - hdr = (pjsip_hdr*)rdata->via->next; - if (hdr != &rdata->msg->hdr) { - hdr = pjsip_msg_find_hdr(msg, PJSIP_H_VIA, hdr); - if (hdr) { - PJ_LOG(3,(tr->obj_name, "Bad message from %s:%d: " - "multiple Via in response message", - src_addr, src_port)); - goto finish_process_fragment; - } - } - } - - /* Call the transport manager's upstream message callback. - */ - (*mgr->message_callback)(mgr->endpt, rdata); - -finish_process_fragment: - rdata->len -= msg_fragment_size; - if (rdata->len > 0) { - pj_memmove(rdata->packet, rdata->packet+msg_fragment_size, rdata->len); - PJ_LOG(4,(tr->obj_name, "Processing next fragment, size=%d bytes", rdata->len)); - } - - } /* while (rdata->len > 0) */ - -on_return: - /* Reset the pool and rdata */ - rdata_pool = rdata->pool; - pj_pool_reset(rdata_pool); - rdata = pj_pool_alloc( rdata_pool, sizeof(*rdata) ); - rdata->len = 0; - rdata->transport = tr; - rdata->pool = rdata_pool; - tr->rdata = rdata; - - /* Read the next packet. */ - rdata->addr_len = sizeof(rdata->addr); + rdata->to == NULL || rdata->via == NULL || rdata->cseq == NULL)
+ {
+ PJ_LOG(3,(tr->obj_name, "Bad message from %s:%d: missing some header",
+ src_addr, src_port));
+ goto finish_process_fragment;
+ }
+
+ /* If message is received from address that's different from the sent-by,
+ * MUST add received parameter to the via.
+ * In our case, we add Via receive param for EVERY received message,
+ * because it saves us from resolving the host HERE in case sent-by is in
+ * FQDN format. And it doesn't hurt either.
+ */
+ s = pj_str(src_addr);
+ pj_strdup(rdata->pool, &rdata->via->recvd_param, &s);
+
+ /* RFC 3581:
+ * If message contains "rport" param, put the received port there.
+ */
+ if (rdata->via->rport_param == 0) {
+ rdata->via->rport_param = pj_sockaddr_in_get_port(&rdata->addr);
+ }
+
+ /* Drop response message if it has more than one Via.
+ */
+ if (msg->type == PJSIP_RESPONSE_MSG) {
+ hdr = (pjsip_hdr*)rdata->via->next;
+ if (hdr != &rdata->msg->hdr) {
+ hdr = pjsip_msg_find_hdr(msg, PJSIP_H_VIA, hdr);
+ if (hdr) {
+ PJ_LOG(3,(tr->obj_name, "Bad message from %s:%d: "
+ "multiple Via in response message",
+ src_addr, src_port));
+ goto finish_process_fragment;
+ }
+ }
+ }
+
+ /* Call the transport manager's upstream message callback.
+ */
+ (*mgr->message_callback)(mgr->endpt, rdata);
+
+finish_process_fragment:
+ rdata->len -= msg_fragment_size;
+ if (rdata->len > 0) {
+ pj_memmove(rdata->packet, rdata->packet+msg_fragment_size, rdata->len);
+ PJ_LOG(4,(tr->obj_name, "Processing next fragment, size=%d bytes", rdata->len));
+ }
+
+ } /* while (rdata->len > 0) */
+
+on_return:
+ /* Reset the pool and rdata */
+ rdata_pool = rdata->pool;
+ pj_pool_reset(rdata_pool);
+ rdata = pj_pool_alloc( rdata_pool, sizeof(*rdata) );
+ rdata->len = 0;
+ rdata->transport = tr;
+ rdata->pool = rdata_pool;
+ tr->rdata = rdata;
+
+ /* Read the next packet. */
+ rdata->addr_len = sizeof(rdata->addr);
if (tr->type == PJSIP_TRANSPORT_UDP) {
- pj_ssize_t size = PJSIP_MAX_PKT_LEN; - pj_ioqueue_recvfrom(tr->key, &tr->rdata->op_key, - tr->rdata->packet, &size, 0, + pj_ssize_t size = PJSIP_MAX_PKT_LEN;
+ pj_ioqueue_recvfrom(tr->key, &tr->rdata->op_key,
+ tr->rdata->packet, &size, 0,
&rdata->addr, &rdata->addr_len);
- PJ_TODO(HANDLE_IMMEDIATE_DATA); - } - -#if PJ_HAS_TCP - /* The next 'if' should have been 'else if', but we need to put the - label inside the '#if PJ_HAS_TCP' block to avoid 'unreferenced label' warning. - */ -tcp_read_packet: + PJ_TODO(HANDLE_IMMEDIATE_DATA);
+ }
+
+#if PJ_HAS_TCP
+ /* The next 'if' should have been 'else if', but we need to put the
+ label inside the '#if PJ_HAS_TCP' block to avoid 'unreferenced label' warning.
+ */
+tcp_read_packet:
if (tr->type == PJSIP_TRANSPORT_TCP) {
pj_ssize_t size = PJSIP_MAX_PKT_LEN - tr->rdata->len;
- pj_ioqueue_recv( tr->key, &tr->rdata->op_key, - tr->rdata->packet + tr->rdata->len, + pj_ioqueue_recv( tr->key, &tr->rdata->op_key,
+ tr->rdata->packet + tr->rdata->len,
&size, 0);
- PJ_TODO(HANDLE_IMMEDIATE_DATA_1); - } -#endif -} - -static void transport_mgr_on_idle( pjsip_transport_mgr *mgr ) -{ - pj_time_val now; - pj_hash_iterator_t itr_val; - pj_hash_iterator_t *itr; - - - /* Get time for comparing transport's close time. */ - pj_gettimeofday(&now); - if (now.sec < mgr->next_idle_check.sec) { - return; - } - - /* Acquire transport manager's lock. */ - pj_mutex_lock(mgr->mutex); - - /* Update next idle check. */ - mgr->next_idle_check.sec += MGR_IDLE_CHECK_INTERVAL; - - /* Iterate all transports, and close transports that are not used for - some periods. - */ - itr = pjsip_transport_first(mgr, &itr_val); - while (itr != NULL) { - pj_hash_iterator_t *next; - pjsip_transport_t *transport; - - transport = pjsip_transport_this(mgr, itr); - - next = pjsip_transport_next(mgr, itr); - - if (pj_atomic_get(transport->ref_cnt)==0 && - PJ_TIME_VAL_LTE(transport->close_time, now)) - { - destroy_transport(mgr, transport); - } - - itr = next; - } - - /* Release transport manager's lock. */ - pj_mutex_unlock(mgr->mutex); -} - + PJ_TODO(HANDLE_IMMEDIATE_DATA_1);
+ }
+#endif
+}
+
+static void transport_mgr_on_idle( pjsip_transport_mgr *mgr )
+{
+ pj_time_val now;
+ pj_hash_iterator_t itr_val;
+ pj_hash_iterator_t *itr;
+
+
+ /* Get time for comparing transport's close time. */
+ pj_gettimeofday(&now);
+ if (now.sec < mgr->next_idle_check.sec) {
+ return;
+ }
+
+ /* Acquire transport manager's lock. */
+ pj_mutex_lock(mgr->mutex);
+
+ /* Update next idle check. */
+ mgr->next_idle_check.sec += MGR_IDLE_CHECK_INTERVAL;
+
+ /* Iterate all transports, and close transports that are not used for
+ some periods.
+ */
+ itr = pjsip_transport_first(mgr, &itr_val);
+ while (itr != NULL) {
+ pj_hash_iterator_t *next;
+ pjsip_transport_t *transport;
+
+ transport = pjsip_transport_this(mgr, itr);
+
+ next = pjsip_transport_next(mgr, itr);
+
+ if (pj_atomic_get(transport->ref_cnt)==0 &&
+ PJ_TIME_VAL_LTE(transport->close_time, now))
+ {
+ destroy_transport(mgr, transport);
+ }
+
+ itr = next;
+ }
+
+ /* Release transport manager's lock. */
+ pj_mutex_unlock(mgr->mutex);
+}
+
static void on_ioqueue_read(pj_ioqueue_key_t *key,
pj_ioqueue_op_key_t *op_key,
- pj_ssize_t bytes_read) -{ - pjsip_transport_t *t; - t = pj_ioqueue_get_user_data(key); - - handle_received_data( t->mgr, t, bytes_read ); -} - + pj_ssize_t bytes_read)
+{
+ pjsip_transport_t *t;
+ t = pj_ioqueue_get_user_data(key);
+
+ handle_received_data( t->mgr, t, bytes_read );
+}
+
static void on_ioqueue_write(pj_ioqueue_key_t *key,
pj_ioqueue_op_key_t *op_key,
- pj_ssize_t bytes_sent) -{ - PJ_UNUSED_ARG(key); - PJ_UNUSED_ARG(bytes_sent); - - /* Completion of write operation. - * Do nothing. - */ -} - + pj_ssize_t bytes_sent)
+{
+ PJ_UNUSED_ARG(key);
+ PJ_UNUSED_ARG(bytes_sent);
+
+ /* Completion of write operation.
+ * Do nothing.
+ */
+}
+
static void on_ioqueue_accept(pj_ioqueue_key_t *key,
pj_ioqueue_op_key_t *op_key,
pj_sock_t newsock,
- int status) -{ -#if PJ_HAS_TCP - pjsip_transport_t *t; - t = pj_ioqueue_get_user_data(key); - - handle_new_connection( t->mgr, t, status ); -#else - PJ_UNUSED_ARG(key); - PJ_UNUSED_ARG(status); -#endif -} - -static void on_ioqueue_connect(pj_ioqueue_key_t *key, int status) -{ -#if PJ_HAS_TCP - pjsip_transport_t *t; - t = pj_ioqueue_get_user_data(key); - - handle_connect_completion( t->mgr, t, status); -#else - PJ_UNUSED_ARG(key); - PJ_UNUSED_ARG(status); -#endif -} - - -/* - * Poll for events. - */ -PJ_DEF(int) pjsip_transport_mgr_handle_events( pjsip_transport_mgr *mgr, - const pj_time_val *req_timeout ) -{ - int event_count; - int break_loop; - int result; - pj_time_val timeout; - - PJ_LOG(5, (LOG_TRANSPORT_MGR, "pjsip_transport_mgr_handle_events()")); - - event_count = 0; - break_loop = 0; - timeout = *req_timeout; - do { - result = pj_ioqueue_poll( mgr->ioqueue, &timeout); - if (result == 1) { - ++event_count; - - /* Break the loop. */ - //if (timeout.msec==0 && timeout.sec==0) { - break_loop = 1; - //} - - } else { - /* On idle, cleanup transport. */ - transport_mgr_on_idle(mgr); - - break_loop = 1; - } - timeout.sec = timeout.msec = 0; - } while (!break_loop); - - return event_count; -} - - -PJ_DEF(pj_hash_iterator_t*) pjsip_transport_first( pjsip_transport_mgr *mgr, - pj_hash_iterator_t *it ) -{ - return pj_hash_first(mgr->transport_table, it); -} - -PJ_DEF(pj_hash_iterator_t*) pjsip_transport_next( pjsip_transport_mgr *mgr, - pj_hash_iterator_t *itr ) -{ - return pj_hash_next(mgr->transport_table, itr); -} - -PJ_DEF(pjsip_transport_t*) pjsip_transport_this( pjsip_transport_mgr *mgr, - pj_hash_iterator_t *itr ) -{ - return pj_hash_this(mgr->transport_table, itr); -} + int status)
+{
+#if PJ_HAS_TCP
+ pjsip_transport_t *t;
+ t = pj_ioqueue_get_user_data(key);
+
+ handle_new_connection( t->mgr, t, status );
+#else
+ PJ_UNUSED_ARG(key);
+ PJ_UNUSED_ARG(status);
+#endif
+}
+
+static void on_ioqueue_connect(pj_ioqueue_key_t *key, int status)
+{
+#if PJ_HAS_TCP
+ pjsip_transport_t *t;
+ t = pj_ioqueue_get_user_data(key);
+
+ handle_connect_completion( t->mgr, t, status);
+#else
+ PJ_UNUSED_ARG(key);
+ PJ_UNUSED_ARG(status);
+#endif
+}
+
+
+/*
+ * Poll for events.
+ */
+PJ_DEF(int) pjsip_transport_mgr_handle_events( pjsip_transport_mgr *mgr,
+ const pj_time_val *req_timeout )
+{
+ int event_count;
+ int break_loop;
+ int result;
+ pj_time_val timeout;
+
+ PJ_LOG(5, (LOG_TRANSPORT_MGR, "pjsip_transport_mgr_handle_events()"));
+
+ event_count = 0;
+ break_loop = 0;
+ timeout = *req_timeout;
+ do {
+ result = pj_ioqueue_poll( mgr->ioqueue, &timeout);
+ if (result == 1) {
+ ++event_count;
+
+ /* Break the loop. */
+ //if (timeout.msec==0 && timeout.sec==0) {
+ break_loop = 1;
+ //}
+
+ } else {
+ /* On idle, cleanup transport. */
+ transport_mgr_on_idle(mgr);
+
+ break_loop = 1;
+ }
+ timeout.sec = timeout.msec = 0;
+ } while (!break_loop);
+
+ return event_count;
+}
+
+
+PJ_DEF(pj_hash_iterator_t*) pjsip_transport_first( pjsip_transport_mgr *mgr,
+ pj_hash_iterator_t *it )
+{
+ return pj_hash_first(mgr->transport_table, it);
+}
+
+PJ_DEF(pj_hash_iterator_t*) pjsip_transport_next( pjsip_transport_mgr *mgr,
+ pj_hash_iterator_t *itr )
+{
+ return pj_hash_next(mgr->transport_table, itr);
+}
+
+PJ_DEF(pjsip_transport_t*) pjsip_transport_this( pjsip_transport_mgr *mgr,
+ pj_hash_iterator_t *itr )
+{
+ return pj_hash_this(mgr->transport_table, itr);
+}
|