summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenny Prijono <bennylp@teluu.com>2005-11-18 22:43:42 +0000
committerBenny Prijono <bennylp@teluu.com>2005-11-18 22:43:42 +0000
commit9e1924d579a65c21db21e76d227582bb9474bb57 (patch)
treea6a4a50056d13a9256ebdaed79b34a0b58bbc314
parent4f18a7f712fdb4cfb90b2c0813b93c95927ccd75 (diff)
The BIG transport modifications
git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@54 74dad513-b988-da41-8d7b-12977e46ad98
-rw-r--r--pjsip/include/pjsip/sip_config.h9
-rw-r--r--pjsip/include/pjsip/sip_endpoint.h47
-rw-r--r--pjsip/include/pjsip/sip_errno.h21
-rw-r--r--pjsip/include/pjsip/sip_misc.h2
-rw-r--r--pjsip/include/pjsip/sip_private.h55
-rw-r--r--pjsip/include/pjsip/sip_transaction.h2
-rw-r--r--pjsip/include/pjsip/sip_transport.h645
-rw-r--r--pjsip/include/pjsip/sip_types.h6
-rw-r--r--pjsip/src/pjsip-ua/sip_dialog.c1
-rw-r--r--pjsip/src/pjsip/sip_auth.c30
-rw-r--r--pjsip/src/pjsip/sip_endpoint.c165
-rw-r--r--pjsip/src/pjsip/sip_misc.c26
-rw-r--r--pjsip/src/pjsip/sip_parser.c38
-rw-r--r--pjsip/src/pjsip/sip_transaction.c72
-rw-r--r--pjsip/src/pjsip/sip_transport.c1814
15 files changed, 1066 insertions, 1867 deletions
diff --git a/pjsip/include/pjsip/sip_config.h b/pjsip/include/pjsip/sip_config.h
index 67c00551..5620c33b 100644
--- a/pjsip/include/pjsip/sip_config.h
+++ b/pjsip/include/pjsip/sip_config.h
@@ -63,6 +63,15 @@
#define PJSIP_POOL_LEN_DIALOG 1200
#define PJSIP_POOL_INC_DIALOG 512
+/* Transport manager hash table size (must be 2^n-1). */
+#define PJSIP_TPMGR_HTABLE_SIZE 31
+
+/* Transport idle timeout before it's destroyed. */
+#define PJSIP_TRANSPORT_IDLE_TIME 30
+
+/* Max entries to process in timer heap per poll. */
+#define PJSIP_MAX_TIMED_OUT_ENTRIES 10
+
/* Module related constants. */
#define PJSIP_MAX_MODULE 8
diff --git a/pjsip/include/pjsip/sip_endpoint.h b/pjsip/include/pjsip/sip_endpoint.h
index e92775cd..24eca24f 100644
--- a/pjsip/include/pjsip/sip_endpoint.h
+++ b/pjsip/include/pjsip/sip_endpoint.h
@@ -259,51 +259,10 @@ PJ_DECL(void) pjsip_endpt_resolve( pjsip_endpoint *endpt,
*
* @see pjsip_transport_get
*/
-PJ_DECL(void) pjsip_endpt_get_transport( pjsip_endpoint *endpt,
- pj_pool_t *pool,
- pjsip_transport_type_e type,
- const pj_sockaddr_in *remote,
- void *token,
- pjsip_transport_completion_callback *cb);
-
-/**
- * Create listener a new transport listener. A listener is transport object
- * that is capable of receiving SIP messages. For UDP listener, normally
- * application should use #pjsip_endpt_create_udp_listener instead if the
- * application has already created the socket.
- * This function, like all other endpoint functions, is thread safe.
- *
- * @param endpt The endpoint instance.
- * @param type Transport type (eg. UDP, TCP, etc.)
- * @param addr The bound address of the transport.
- * @param addr_name The address to be advertised in SIP messages. For example,
- * the bound address can be 0.0.0.0, but the advertised address
- * normally will be the IP address of the host.
- *
- * @return Zero if listener is created successfully.
- */
-PJ_DECL(pj_status_t) pjsip_endpt_create_listener( pjsip_endpoint *endpt,
+PJ_DECL(pj_status_t) pjsip_endpt_alloc_transport( pjsip_endpoint *endpt,
pjsip_transport_type_e type,
- pj_sockaddr_in *addr,
- const pj_sockaddr_in *addr_name);
-
-/**
- * Create UDP listener. For UDP, normally the application would create the
- * socket by itself (for STUN purpose), then it can register the socket as
- * listener by calling this function.
- * This function, like all other endpoint functions, is thread safe.
- *
- * @param endpt The endpoint instance.
- * @param sock The socket handle.
- * @param addr_name The address to be advertised in SIP message. If the socket
- * has been resolved with STUN, then application may specify
- * the mapped address in this parameter.
- *
- * @return Zero if listener is created successfully.
- */
-PJ_DECL(pj_status_t) pjsip_endpt_create_udp_listener( pjsip_endpoint *endpt,
- pj_sock_t sock,
- const pj_sockaddr_in *addr_name);
+ const pj_sockaddr_in *remote,
+ pjsip_transport **p_transport);
/**
* Get additional headers to be put in outgoing request message.
diff --git a/pjsip/include/pjsip/sip_errno.h b/pjsip/include/pjsip/sip_errno.h
index 1d777e42..5473f362 100644
--- a/pjsip/include/pjsip/sip_errno.h
+++ b/pjsip/include/pjsip/sip_errno.h
@@ -54,6 +54,11 @@
/**
* @hideinitializer
+ * Invalid message (syntax error)
+ */
+#define PJSIP_EINVALIDMSG (PJSIP_ERRNO_START_PJSIP + 0)
+/**
+ * @hideinitializer
* Missing required header(s).
*/
#define PJSIP_EMISSINGHDR (PJSIP_ERRNO_START_PJSIP + 1)
@@ -97,6 +102,22 @@
* Invalid Via header in response (sent-by, etc).
*/
#define PJSIP_EINVALIDVIA (PJSIP_ERRNO_START_PJSIP + 9)
+/**
+ * @hideinitializer
+ * Multiple Via headers in response.
+ */
+#define PJSIP_EMULTIPLEVIA (PJSIP_ERRNO_START_PJSIP + 9)
+/**
+ * @hideinitializer
+ * SIP object is busy.
+ */
+#define PJSIP_EBUSY (PJSIP_ERRNO_START_PJSIP + 10)
+/**
+ * @hideinitializer
+ * SIP object with the same type already exists.
+ */
+#define PJSIP_ETYPEEXISTS (PJSIP_ERRNO_START_PJSIP + 11)
+
#endif /* __PJSIP_SIP_ERRNO_H__ */
diff --git a/pjsip/include/pjsip/sip_misc.h b/pjsip/include/pjsip/sip_misc.h
index 0217e36e..f8685e54 100644
--- a/pjsip/include/pjsip/sip_misc.h
+++ b/pjsip/include/pjsip/sip_misc.h
@@ -178,7 +178,7 @@ PJ_DECL(pj_status_t) pjsip_endpt_create_cancel( pjsip_endpoint *endpt,
* @return zero (PJ_OK) if successfull.
*/
PJ_DECL(pj_status_t) pjsip_get_response_addr(pj_pool_t *pool,
- const pjsip_transport_t *tr,
+ const pjsip_transport *tr,
const pjsip_via_hdr *via,
pjsip_host_port *addr);
diff --git a/pjsip/include/pjsip/sip_private.h b/pjsip/include/pjsip/sip_private.h
index 9e2ccc9b..1c14e607 100644
--- a/pjsip/include/pjsip/sip_private.h
+++ b/pjsip/include/pjsip/sip_private.h
@@ -35,61 +35,6 @@ PJ_BEGIN_DECL
*/
-/**
- * Create a new transport manager.
- * @param pool The pool
- * @param endpt The endpoint
- * @param cb Callback to be called to receive messages from transport.
- */
-PJ_DECL(pj_status_t) pjsip_transport_mgr_create( pj_pool_t *pool,
- pjsip_endpoint *endpt,
- void (*cb)(pjsip_endpoint *,
- pjsip_rx_data *),
- pjsip_transport_mgr **);
-
-
-/**
- * Destroy transport manager and release all transports.
- * @param mgr Transport manager to be destroyed.
- */
-PJ_DECL(pj_status_t) pjsip_transport_mgr_destroy( pjsip_transport_mgr *mgr );
-
-/**
- * Poll for transport events.
- * Incoming messages will be parsed by the transport manager, and the callback
- * will be called for each of this message.
- * @param endpt The endpoint.
- * @param timeout Timeout value, or NULL to wait forever.
- */
-PJ_DECL(int) pjsip_transport_mgr_handle_events( pjsip_transport_mgr *mgr,
- const pj_time_val *timeout );
-
-/**
- * Get the pointer to the first transport iterator.
- * @param mgr The transport manager.
- * @param it The iterator used for iterating the hash element.
- * @return the iterator to the first transport, or NULL.
- */
-PJ_DECL(pj_hash_iterator_t*) pjsip_transport_first( pjsip_transport_mgr *mgr,
- pj_hash_iterator_t *it );
-
-
-/**
- * Get the next transport iterator.
- * @param itr the iterator to the transport.
- * @return the iterator pointed to the next transport, or NULL.
- */
-PJ_DECL(pj_hash_iterator_t*) pjsip_transport_next( pjsip_transport_mgr *mgr,
- pj_hash_iterator_t *itr );
-
-/**
- * Get the value of transport iterator.
- * @param mgr the transport manager.
- * @param itr the transport iterator.
- * @return the transport associated with the iterator.
- */
-PJ_DECL(pjsip_transport_t*) pjsip_transport_this( pjsip_transport_mgr *mgr,
- pj_hash_iterator_t *itr );
/**
* @}
diff --git a/pjsip/include/pjsip/sip_transaction.h b/pjsip/include/pjsip/sip_transaction.h
index 8a653222..4090ca4c 100644
--- a/pjsip/include/pjsip/sip_transaction.h
+++ b/pjsip/include/pjsip/sip_transaction.h
@@ -111,7 +111,7 @@ struct pjsip_transaction
pjsip_server_addresses remote_addr; /**< Addresses resolved. */
int current_addr; /**< Address currently used. */
- pjsip_transport_t *transport; /**< Transport to use. */
+ pjsip_transport *transport; /**< Transport to use. */
/*
* Messages and timer.
diff --git a/pjsip/include/pjsip/sip_transport.h b/pjsip/include/pjsip/sip_transport.h
index 950ee5cf..36cf863e 100644
--- a/pjsip/include/pjsip/sip_transport.h
+++ b/pjsip/include/pjsip/sip_transport.h
@@ -29,6 +29,7 @@
#include <pj/sock.h>
#include <pj/list.h>
#include <pj/ioqueue.h>
+#include <pj/timer.h>
PJ_BEGIN_DECL
@@ -43,6 +44,78 @@ PJ_BEGIN_DECL
* @{
*/
+/*****************************************************************************
+ *
+ * GENERAL TRANSPORT (NAMES, TYPES, ETC.)
+ *
+ *****************************************************************************/
+
+/**
+ * Flags for SIP transports.
+ */
+enum pjsip_transport_flags_e
+{
+ PJSIP_TRANSPORT_RELIABLE = 1, /**< Transport is reliable. */
+ PJSIP_TRANSPORT_SECURE = 2, /**< Transport is secure. */
+ PJSIP_TRANSPORT_DATAGRAM = 4, /**< Datagram based transport. */
+};
+
+/**
+ * Check if transport tp is reliable.
+ */
+#define PJSIP_TRANSPORT_IS_RELIABLE(tp) \
+ ((tp)->flag & PJSIP_TRANSPORT_RELIABLE)
+
+/**
+ * Get the transport type from the transport name.
+ *
+ * @param name Transport name, such as "TCP", or "UDP".
+ *
+ * @return The transport type, or PJSIP_TRANSPORT_UNSPECIFIED if
+ * the name is not recognized as the name of supported
+ * transport.
+ */
+PJ_DECL(pjsip_transport_type_e)
+pjsip_transport_get_type_from_name(const pj_str_t *name);
+
+/**
+ * Get the transport type for the specified flags.
+ *
+ * @param flag The transport flag.
+ *
+ * @return Transport type.
+ */
+PJ_DECL(pjsip_transport_type_e)
+pjsip_transport_get_type_from_flag(unsigned flag);
+
+/**
+ * Get transport flag from type.
+ *
+ * @param type Transport type.
+ *
+ * @return Transport flags.
+ */
+PJ_DECL(unsigned)
+pjsip_transport_get_flag_from_type( pjsip_transport_type_e type );
+
+/**
+ * Get the default SIP port number for the specified type.
+ *
+ * @param type Transport type.
+ *
+ * @return The port number, which is the default SIP port number for
+ * the specified type.
+ */
+PJ_DECL(int)
+pjsip_transport_get_default_port_for_type(pjsip_transport_type_e type);
+
+
+/*****************************************************************************
+ *
+ * RECEIVE DATA BUFFER.
+ *
+ *****************************************************************************/
+
/**
* Incoming message buffer.
* This structure keep all the information regarding the received message. This
@@ -52,78 +125,130 @@ PJ_BEGIN_DECL
*/
struct pjsip_rx_data
{
- //PJ_DECL_LIST_MEMBER(struct pjsip_rx_data);
- /** Memory pool for this buffer. */
- pj_pool_t *pool;
+ /**
+ * tp_info is part of rdata that remains static for the duration of the
+ * buffer. It is initialized when the buffer was created by transport.
+ */
+ struct
+ {
+ /** Memory pool for this buffer. */
+ pj_pool_t *pool;
- /** Ioqueue op key. */
- pj_ioqueue_op_key_t op_key;
+ /** The transport object which received this packet. */
+ pjsip_transport *transport;
+
+ /** Ioqueue key. */
+ pj_ioqueue_op_key_t op_key;
- /** Time when the message was received. */
- pj_time_val timestamp;
+ } tp_info;
- /** The packet buffer. */
- char packet[PJSIP_MAX_PKT_LEN];
- /** The length of the packet received. */
- int len;
+ /**
+ * pkt_info is initialized by transport when it receives an incoming
+ * packet.
+ */
+ struct
+ {
+ /** Time when the message was received. */
+ pj_time_val timestamp;
+
+ /** Pointer to the original packet. */
+ char packet[PJSIP_MAX_PKT_LEN];
+
+ /** Zero termination for the packet. */
+ pj_uint32_t zero;
- /** The source address from which the packet was received. */
- pj_sockaddr_in addr;
+ /** The length of the packet received. */
+ int len;
- /** The length of the source address. */
- int addr_len;
+ /** The source address from which the packet was received. */
+ pj_sockaddr_in addr;
- /** The transport object which received this packet. */
- pjsip_transport_t *transport;
+ /** The length of the source address. */
+ int addr_len;
- /** The parsed message, if any. */
- pjsip_msg *msg;
+ } pkt_info;
- /** This the transaction key generated from the message. This key is only
- * available after the rdata has reached the endpoint.
+
+ /**
+ * msg_info is initialized by transport mgr (tpmgr) before this buffer
+ * is passed to endpoint.
*/
- pj_str_t key;
+ struct
+ {
+ /** Start of msg buffer. */
+ char *msg_buf;
+
+ /** Length fo message. */
+ int len;
+
+ /** The parsed message, if any. */
+ pjsip_msg *msg;
- /** The Call-ID header as found in the message. */
- pj_str_t call_id;
+ /** The Call-ID header as found in the message. */
+ pj_str_t call_id;
- /** The From header as found in the message. */
- pjsip_from_hdr *from;
+ /** The From header as found in the message. */
+ pjsip_from_hdr *from;
- /** The To header as found in the message. */
- pjsip_to_hdr *to;
+ /** The To header as found in the message. */
+ pjsip_to_hdr *to;
- /** The topmost Via header as found in the message. */
- pjsip_via_hdr *via;
+ /** The topmost Via header as found in the message. */
+ pjsip_via_hdr *via;
- /** The CSeq header as found in the message. */
- pjsip_cseq_hdr *cseq;
+ /** The CSeq header as found in the message. */
+ pjsip_cseq_hdr *cseq;
- /** Max forwards header. */
- pjsip_max_forwards_hdr *max_fwd;
+ /** Max forwards header. */
+ pjsip_max_forwards_hdr *max_fwd;
- /** The first route header. */
- pjsip_route_hdr *route;
+ /** The first route header. */
+ pjsip_route_hdr *route;
- /** The first record-route header. */
- pjsip_rr_hdr *record_route;
+ /** The first record-route header. */
+ pjsip_rr_hdr *record_route;
- /** Content-type header. */
- pjsip_ctype_hdr *ctype;
+ /** Content-type header. */
+ pjsip_ctype_hdr *ctype;
- /** Content-length header. */
- pjsip_clen_hdr *clen;
+ /** Content-length header. */
+ pjsip_clen_hdr *clen;
+
+ /** The first Require header. */
+ pjsip_require_hdr *require;
+
+ /** The list of error generated by the parser when parsing
+ this message.
+ */
+ pjsip_parser_err_report parse_err;
+
+ } msg_info;
+
+
+ /**
+ * endpt_info is initialized by endpoint after this buffer reaches
+ * endpoint.
+ */
+ struct
+ {
+ /**
+ * This the transaction key generated for the message.
+ */
+ pj_str_t key;
- /** The first Require header. */
- pjsip_require_hdr *require;
+ } endpt_info;
- /** The list of error generated by the parser when parsing this message. */
- pjsip_parser_err_report parse_err;
};
+/*****************************************************************************
+ *
+ * TRANSMIT DATA BUFFER MANIPULATION.
+ *
+ *****************************************************************************/
+
/**
* Data structure for sending outgoing message. Application normally creates
* this buffer by calling #pjsip_endpt_create_tdata.
@@ -156,11 +281,14 @@ struct pjsip_tx_data
pj_time_val rx_timestamp;
/** The transport manager for this buffer. */
- pjsip_transport_mgr *mgr;
+ pjsip_tpmgr *mgr;
/** Ioqueue asynchronous operation key. */
pj_ioqueue_op_key_t op_key;
+ /** Lock object. */
+ pj_lock_t *lock;
+
/** The message in this buffer. */
pjsip_msg *msg;
@@ -174,10 +302,31 @@ struct pjsip_tx_data
/** Reference counter. */
pj_atomic_t *ref_cnt;
+
+ /** Being sent? */
+ int is_pending;
+
+ /** Transport internal. */
+ void *token;
+ void (*cb)(void*, pjsip_tx_data*, pj_status_t);
};
/**
+ * Create a new, blank transmit buffer. The reference count is initialized
+ * to zero.
+ *
+ * @param mgr The transport manager.
+ * @param tdata Pointer to receive transmit data.
+ *
+ * @return PJ_SUCCESS, or the appropriate error code.
+ *
+ * @see pjsip_endpt_create_tdata
+ */
+pj_status_t pjsip_tx_data_create( pjsip_tpmgr *mgr,
+ pjsip_tx_data **tdata );
+
+/**
* Add reference counter to the transmit buffer. The reference counter controls
* the life time of the buffer, ie. when the counter reaches zero, then it
* will be destroyed.
@@ -195,6 +344,13 @@ PJ_DECL(void) pjsip_tx_data_add_ref( pjsip_tx_data *tdata );
PJ_DECL(void) pjsip_tx_data_dec_ref( pjsip_tx_data *tdata );
/**
+ * Check if transmit data buffer contains a valid message.
+ *
+ * @param tdata The transmit buffer.
+ */
+PJ_DECL(pj_bool_t) pjsip_tx_data_is_valid( pjsip_tx_data *tdata );
+
+/**
* Invalidate the print buffer to force message to be re-printed. Call
* when the message has changed after it has been printed to buffer. The
* message is printed to buffer normally by transport when it is about to be
@@ -207,288 +363,251 @@ PJ_DECL(void) pjsip_tx_data_dec_ref( pjsip_tx_data *tdata );
PJ_DECL(void) pjsip_tx_data_invalidate_msg( pjsip_tx_data *tdata );
-/**
- * Flags for SIP transports.
- */
-enum pjsip_transport_flags_e
-{
- PJSIP_TRANSPORT_RELIABLE = 1, /**< Transport is reliable. */
- PJSIP_TRANSPORT_SECURE = 2, /**< Transport is secure. */
- PJSIP_TRANSPORT_IOQUEUE_BUSY = 4, /**< WTH?? */
-};
-
-/**
- * Get the transport type from the transport name.
+/*****************************************************************************
*
- * @param name Transport name, such as "TCP", or "UDP".
+ * TRANSPORT
*
- * @return The transport type, or PJSIP_TRANSPORT_UNSPECIFIED if
- * the name is not recognized as the name of supported
- * transport.
- */
-PJ_DECL(pjsip_transport_type_e)
-pjsip_transport_get_type_from_name(const pj_str_t *name);
+ *****************************************************************************/
/**
- * Get the transport type for the specified flags.
- *
- * @param flag The transport flag.
- *
- * @return Transport type.
+ * This structure represent the "public" interface of a SIP transport.
+ * Applications normally extend this structure to include transport
+ * specific members.
*/
-PJ_DECL(pjsip_transport_type_e)
-pjsip_transport_get_type_from_flag(unsigned flag);
+typedef struct pjsip_transport
+{
+ char obj_name[PJ_MAX_OBJ_NAME]; /**< Name. */
+
+ pj_pool_t *pool; /**< Pool used by transport. */
+ pj_atomic_t *ref_cnt; /**< Reference counter. */
+ pj_lock_t *lock; /**< Lock object. */
+ int tracing; /**< Tracing enabled? */
+
+ pjsip_transport_type_e type; /**< Transport type. */
+ char type_name[8]; /**< Type name. */
+ unsigned flag; /**< #pjsip_transport_flags_e */
+
+ pj_sockaddr_in local_addr; /**< Bound address. */
+ pj_sockaddr_in public_addr; /**< STUN addres. */
+ pj_sockaddr_in rem_addr; /**< Remote addr (zero for UDP) */
+
+ pjsip_tpmgr *tpmgr; /**< Transport manager. */
+ pj_timer_entry idle_timer; /**< Timer when ref cnt is zero.*/
+
+ /**
+ * Function to be called by transport manager to send SIP message.
+ *
+ * @param transport The transport to send the message.
+ * @param packet The buffer to send.
+ * @param length The length of the buffer to send.
+ * @param op_key Completion token, which will be supplied to
+ * caller when pending send operation completes.
+ * @param rem_addr The remote destination address.
+ * @param callback If supplied, the callback will be called
+ * once a pending transmission has completed. If
+ * the function completes immediately (i.e. return
+ * code is not PJ_EPENDING), the callback will not
+ * be called.
+ *
+ * @return Should return PJ_SUCCESS only if data has been
+ * succesfully queued to operating system for
+ * transmission. Otherwise it may return PJ_EPENDING
+ * if the underlying transport can not send the
+ * data immediately and will send it later, which in
+ * this case caller doesn't have to do anything
+ * except wait the calback to be called, if it
+ * supplies one.
+ * Other return values indicate the error code.
+ */
+ pj_status_t (*send_msg)(pjsip_transport *transport,
+ const void *packet,
+ pj_size_t length,
+ pj_ioqueue_op_key_t *op_key,
+ const pj_sockaddr_in *rem_addr,
+ void *token,
+ void (*callback)(pjsip_transport *transport,
+ void *token,
+ pj_status_t status));
+
+ /**
+ * Destroy this transport.
+ */
+ pj_status_t (*destroy)(pjsip_transport *transport);
+
+ /*
+ * Application may extend this structure..
+ */
+} pjsip_transport;
+
/**
- * Get the default SIP port number for the specified type.
- *
- * @param type Transport type.
- *
- * @return The port number, which is the default SIP port number for
- * the specified type.
+ * Register a transport.
*/
-PJ_DECL(int)
-pjsip_transport_get_default_port_for_type(pjsip_transport_type_e type);
+PJ_DECL(pj_status_t) pjsip_transport_register( pjsip_tpmgr *mgr,
+ pjsip_transport *tp );
/**
- * Add reference to transport.
- * Transactions or dialogs that uses a particular transport must call this
- * function to indicate that the transport is being used, thus preventing the
- * transport from being closed.
- *
- * @param transport The transport.
+ * Unregister transport. This will eventually call the transport to
+ * destroy itself.
*/
-PJ_DECL(void)
-pjsip_transport_add_ref( pjsip_transport_t *transport );
+PJ_DECL(pj_status_t) pjsip_transport_unregister( pjsip_tpmgr *mgr,
+ pjsip_transport *tp);
/**
- * Decrease reference to transport.
- * When the transport reference counter becomes zero, a timer will be started
- * and when this timer expires and the reference counter is still zero, the
- * transport will be released.
- *
- * @param transport The transport
+ * Add ref.
*/
-PJ_DECL(void)
-pjsip_transport_dec_ref( pjsip_transport_t *transport );
-
+PJ_DECL(pj_status_t) pjsip_transport_add_ref( pjsip_transport *tp );
/**
- * Macro to check whether the transport is reliable.
- *
- * @param transport The transport
- *
- * @return non-zero (not necessarily 1) if transport is reliable.
+ * Dec ref.
*/
-#define PJSIP_TRANSPORT_IS_RELIABLE(transport) \
- (pjsip_transport_get_flag(transport) & PJSIP_TRANSPORT_RELIABLE)
+PJ_DECL(pj_status_t) pjsip_transport_dec_ref( pjsip_transport *tp );
/**
- * Macro to check whether the transport is secure.
- *
- * @param transport The transport
- *
- * @return non-zero (not necessarily one) if transport is secure.
+ * Call for incoming message.
*/
-#define PJSIP_TRANSPORT_IS_SECURE(transport) \
- (pjsip_transport_get_flag(transport) & PJSIP_TRANSPORT_SECURE)
+PJ_DECL(pj_ssize_t) pjsip_tpmgr_receive_packet(pjsip_tpmgr *mgr,
+ pjsip_rx_data *rdata);
-/**
- * Get the transport type.
+
+/*****************************************************************************
*
- * @param tr The transport.
+ * TRANSPORT FACTORY
*
- * @return Transport type.
- */
-PJ_DECL(pjsip_transport_type_e)
-pjsip_transport_get_type( const pjsip_transport_t * tr);
+ *****************************************************************************/
-/**
- * Get the transport type name (ie "UDP", or "TCP").
- *
- * @param tr The transport.
- * @return The string type.
- */
-PJ_DECL(const char *)
-pjsip_transport_get_type_name( const pjsip_transport_t * tr);
/**
- * Get the transport's object name.
- *
- * @param tr The transport.
- * @return The object name.
+ * Transport factory.
*/
-PJ_DECL(const char*)
-pjsip_transport_get_obj_name( const pjsip_transport_t *tr );
+typedef struct pjsip_tpfactory pjsip_tpfactory;
/**
- * Get the transport's reference counter.
- *
- * @param tr The transport.
- * @return The reference count value.
+ * Transport factory.
*/
-PJ_DECL(int)
-pjsip_transport_get_ref_cnt( const pjsip_transport_t *tr );
+struct pjsip_tpfactory
+{
+ /* This list is managed by transport manager. */
+ PJ_DECL_LIST_MEMBER(struct pjsip_tpfactory);
+
+ pj_pool_t *pool;
+ pj_lock_t *lock;
+
+ pjsip_transport_type_e type;
+ char type_name[8];
+ unsigned flag;
+
+ pj_sockaddr_in local_addr;
+ pj_sockaddr_in public_addr;
+
+ /**
+ * Create new outbound connection.
+ */
+ pj_status_t (*create_transport)(pjsip_tpfactory *factory,
+ pjsip_tpmgr *mgr,
+ pjsip_endpoint *endpt,
+ pj_ioqueue_t *ioqueue,
+ const pj_sockaddr_in *rem_addr,
+ pjsip_transport **transport);
+
+ /*
+ * Application may extend this structure..
+ */
+};
+
-/**
- * Get transport flag.
- *
- * @param tr The transport.
- * @return Transport flag.
- */
-PJ_DECL(unsigned)
-pjsip_transport_get_flag( const pjsip_transport_t * tr );
/**
- * Get the local address of the transport, ie. the address which the socket
- * is bound.
+ * Register a transport factory.
*
- * @param tr The transport.
- * @return The address.
+ * @param mgr The transport manager.
+ * @param factory Transport factory.
+ *
+ * @return PJ_SUCCESS if listener was successfully created.
*/
-PJ_DECL(const pj_sockaddr_in *)
-pjsip_transport_get_local_addr( pjsip_transport_t * tr );
+PJ_DECL(pj_status_t) pjsip_tpmgr_register_tpfactory(pjsip_tpmgr *mgr,
+ pjsip_tpfactory *tpf);
/**
- * Get the address name of the transport. Address name can be an arbitrary
- * address assigned to a transport. This is usefull for example when STUN
- * is used, then the address name of an UDP transport can specify the public
- * address of the transport. When the address name is not set, then value
- * will be equal to the local/bound address. Application should normally
- * prefer to use the address name instead of the local address.
- *
- * @param tr The transport.
- * @return The address name.
+ * Unregister factory.
*/
-PJ_DECL(const pj_sockaddr_in*)
-pjsip_transport_get_addr_name (pjsip_transport_t *tr);
+PJ_DECL(pj_status_t) pjsip_tpmgr_unregister_tpfactory(pjsip_tpmgr *mgr,
+ pjsip_tpfactory *tpf);
-/**
- * Get the remote address of the transport. Not all transports will have
- * a valid remote address. UDP transports, for example, will likely to have
- * zero has their remote address, because UDP transport can be used to send
- * and receive messages from multiple destinations.
+
+/*****************************************************************************
*
- * @param tr The transport.
- * @return The address.
- */
-PJ_DECL(const pj_sockaddr_in *)
-pjsip_transport_get_remote_addr( const pjsip_transport_t * tr );
+ * TRANSPORT MANAGER
+ *
+ *****************************************************************************/
/**
- * Send a SIP message using the specified transport, to the address specified
- * in the outgoing data. This function is only usefull for application when it
- * wants to handle the message statelessly, because otherwise it should create
- * a transaction and let the transaction handles the transmission of the
- * message.
- *
- * This function will send the message immediately, so application must be
- * sure that the transport is ready to do so before calling this function.
+ * Create a new transport manager.
*
- * @param tr The transport to send the message.
- * @param tdata The outgoing message buffer.
- * @param addr The remote address.
- * @param sent If not null, it will be filled up with the length of
- * data sent.
+ * @param pool Pool.
+ * @param endpt Endpoint instance.
+ * @param cb Callback to receive incoming message.
+ * @param p_mgr Pointer to receive the new transport manager.
*
- * @return PJ_SUCCESS on success, or the appropriate error code.
+ * @return PJ_SUCCESS or the appropriate error code on error.
*/
-PJ_DECL(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_DECL(pj_status_t) pjsip_tpmgr_create( pj_pool_t *pool,
+ pjsip_endpoint * endpt,
+ pj_ioqueue_t *ioqueue,
+ pj_timer_heap_t *timer_heap,
+ void (*cb)(pjsip_endpoint*,
+ pj_status_t,
+ pjsip_rx_data *),
+ pjsip_tpmgr **p_mgr);
/**
- * @}
+ * Destroy transport manager.
*/
+PJ_DECL(pj_status_t) pjsip_tpmgr_destroy(pjsip_tpmgr *mgr);
-/*
- * PRIVATE FUNCTIONS!!!
- *
- * These functions are normally to be used by endpoint. Application should
- * use the variant provided by the endpoint instance.
- *
- * Application normally wouldn't be able to call these functions because it
- * has no reference of the transport manager (the instance of the transport
- * manager is hidden by endpoint!).
- */
-/*
- * Create a new transmit buffer.
- *
- * @param mgr The transport manager.
- * @return The transmit buffer data, or NULL on error.
+/**
+ * Dump transport info.
*/
-pj_status_t pjsip_tx_data_create( pjsip_transport_mgr *mgr,
- pjsip_tx_data **tdata );
+PJ_DECL(void) pjsip_tpmgr_dump_transports(pjsip_tpmgr *mgr);
-/**
- * Create listener.
+/*****************************************************************************
*
- * @param mgr The transport manager.
- * @param type Transport type.
- * @param local_addr The address to bind.
- * @param addr_name If not null, sets the address name. If NULL,
- * then the local address will be used.
+ * PUBLIC API
*
- * @return PJ_SUCCESS if listener was successfully created.
- */
-PJ_DECL(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);
+ *****************************************************************************/
/**
- * Create UDP listener.
- *
- * @param mgr The transport manager.
- * @param sock The UDP socket.
- * @param addr_name If not null, sets the address name. If NULL,
- * then the local address will be used.
- *
- * @return PJ_SUCCESS if listener was successfully created.
+ * Find transport to be used to send message to remote destination. If no
+ * suitable transport is found, a new one will be created.
*/
-PJ_DECL(pj_status_t) pjsip_create_udp_listener( pjsip_transport_mgr *mgr,
- pj_sock_t sock,
- const pj_sockaddr_in *addr_name);
+PJ_DECL(pj_status_t) pjsip_tpmgr_alloc_transport( pjsip_tpmgr *mgr,
+ pjsip_transport_type_e type,
+ const pj_sockaddr_in *remote,
+ pjsip_transport **p_transport );
-/**
- * Type of function to receive asynchronous transport completion for
- * pjsip_transport_get() operation.
- *
- * @param tr The transport.
- * @param token Token registered previously.
- * @param status Status of operation.
+
+/**
+ * Send a SIP message using the specified transport.
*/
-typedef void pjsip_transport_completion_callback(pjsip_transport_t *tr,
- void *token,
- pj_status_t status);
+PJ_DECL(pj_status_t) pjsip_transport_send( pjsip_transport *tr,
+ pjsip_tx_data *tdata,
+ const pj_sockaddr_in *addr,
+ void *token,
+ void (*cb)(void *token,
+ pjsip_tx_data *tdata,
+ pj_status_t));
+
/**
- * Find transport to be used to send message to remote destination. If no
- * suitable transport is found, a new one will be created. If transport
- * can not be available immediately (for example, an outgoing TCP connec()),
- * then the caller will be notified later via the callback.
- *
- * @param mgr The transport manager.
- * @param pool Pool to allocate asychronous job (if required).
- * @param type The transport type.
- * @param remote The remote address.
- * @param token The token that will be passed to the callback.
- * @param cb The callback to be called to report the completion of
- * the operation.
- */
-PJ_DECL(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);
+ * @}
+ */
+
PJ_END_DECL
diff --git a/pjsip/include/pjsip/sip_types.h b/pjsip/include/pjsip/sip_types.h
index 7ac2044e..6554b4ce 100644
--- a/pjsip/include/pjsip/sip_types.h
+++ b/pjsip/include/pjsip/sip_types.h
@@ -25,12 +25,12 @@
/**
* Opaque data structure for transports (sip_transport.h).
*/
-typedef struct pjsip_transport_t pjsip_transport_t;
+typedef struct pjsip_transport pjsip_transport;
/**
* Opaque data type for transport manager (sip_transport.h).
*/
-typedef struct pjsip_transport_mgr pjsip_transport_mgr;
+typedef struct pjsip_tpmgr pjsip_tpmgr;
/**
* Transport types.
@@ -43,7 +43,6 @@ typedef enum pjsip_transport_type_e
/** UDP. */
PJSIP_TRANSPORT_UDP,
-#if PJ_HAS_TCP
/** TCP. */
PJSIP_TRANSPORT_TCP,
@@ -52,7 +51,6 @@ typedef enum pjsip_transport_type_e
/** SCTP. */
PJSIP_TRANSPORT_SCTP,
-#endif
} pjsip_transport_type_e;
diff --git a/pjsip/src/pjsip-ua/sip_dialog.c b/pjsip/src/pjsip-ua/sip_dialog.c
index 64762eea..1b23bc42 100644
--- a/pjsip/src/pjsip-ua/sip_dialog.c
+++ b/pjsip/src/pjsip-ua/sip_dialog.c
@@ -1079,6 +1079,7 @@ PJ_DEF(pjsip_tx_data*) pjsip_dlg_answer( pjsip_dlg *dlg, int code )
/* Get transmit data and the message.
* We will rewrite the message with a new status code.
*/
+ only if tdata is not pending!!!
tdata = dlg->invite_tsx->last_tx;
msg = tdata->msg;
diff --git a/pjsip/src/pjsip/sip_auth.c b/pjsip/src/pjsip/sip_auth.c
index 6cd5ae9d..b3375867 100644
--- a/pjsip/src/pjsip/sip_auth.c
+++ b/pjsip/src/pjsip/sip_auth.c
@@ -35,7 +35,7 @@
#define MAX_TEMP 128
/* A macro just to get rid of type mismatch between char and unsigned char */
-#define MD5_APPEND(pms,buf,len) md5_append(pms, (const unsigned char*)buf, len)
+#define MD5_APPEND(pms,buf,len) pj_md5_update(pms, (const pj_uint8_t*)buf, len)
/* Logging. */
#define THIS_FILE "sip_auth.c"
@@ -80,7 +80,7 @@ static void create_digest( pj_str_t *result,
char ha1[MD5STRLEN];
char ha2[MD5STRLEN];
unsigned char digest[16];
- md5_state_t pms;
+ pj_md5_context pms;
pj_assert(result->slen >= MD5STRLEN);
@@ -90,13 +90,13 @@ static void create_digest( pj_str_t *result,
/***
*** ha1 = MD5(username ":" realm ":" password)
***/
- md5_init(&pms);
+ pj_md5_init(&pms);
MD5_APPEND( &pms, cred_info->username.ptr, cred_info->username.slen);
MD5_APPEND( &pms, ":", 1);
MD5_APPEND( &pms, cred_info->realm.ptr, cred_info->realm.slen);
MD5_APPEND( &pms, ":", 1);
MD5_APPEND( &pms, cred_info->data.ptr, cred_info->data.slen);
- md5_finish(&pms, digest);
+ pj_md5_final(&pms, digest);
digest2str(digest, ha1);
@@ -110,11 +110,11 @@ static void create_digest( pj_str_t *result,
/***
*** ha2 = MD5(method ":" req_uri)
***/
- md5_init(&pms);
+ pj_md5_init(&pms);
MD5_APPEND( &pms, method->ptr, method->slen);
MD5_APPEND( &pms, ":", 1);
MD5_APPEND( &pms, uri->ptr, uri->slen);
- md5_finish(&pms, digest);
+ pj_md5_final(&pms, digest);
digest2str(digest, ha2);
AUTH_TRACE_((THIS_FILE, " ha2=%.32s", ha2));
@@ -126,7 +126,7 @@ static void create_digest( pj_str_t *result,
*** When qop=auth is used:
*** response = MD5(ha1 ":" nonce ":" nc ":" cnonce ":" qop ":" ha2)
***/
- md5_init(&pms);
+ pj_md5_init(&pms);
MD5_APPEND( &pms, ha1, MD5STRLEN);
MD5_APPEND( &pms, ":", 1);
MD5_APPEND( &pms, nonce->ptr, nonce->slen);
@@ -142,7 +142,7 @@ static void create_digest( pj_str_t *result,
MD5_APPEND( &pms, ha2, MD5STRLEN);
/* This is the final response digest. */
- md5_finish(&pms, digest);
+ pj_md5_final(&pms, digest);
/* Convert digest to string and store in chal->response. */
result->slen = MD5STRLEN;
@@ -734,15 +734,15 @@ PJ_DEF(pjsip_tx_data*) pjsip_auth_reinit_req( pjsip_endpoint *endpt,
PJ_UNUSED_ARG(endpt);
- pj_assert(rdata->msg->type == PJSIP_RESPONSE_MSG);
- pj_assert(rdata->msg->line.status.code == 401 ||
- rdata->msg->line.status.code == 407 );
+ pj_assert(rdata->msg_info.msg->type == PJSIP_RESPONSE_MSG);
+ pj_assert(rdata->msg_info.msg->line.status.code == 401 ||
+ rdata->msg_info.msg->line.status.code == 407 );
/*
* Respond to each authentication challenge.
*/
- hdr = rdata->msg->hdr.next;
- while (hdr != &rdata->msg->hdr) {
+ hdr = rdata->msg_info.msg->hdr.next;
+ while (hdr != &rdata->msg_info.msg->hdr) {
pjsip_auth_session *sess;
const pjsip_www_authenticate_hdr *hchal;
pjsip_authorization_hdr *hauth;
@@ -750,11 +750,11 @@ PJ_DEF(pjsip_tx_data*) pjsip_auth_reinit_req( pjsip_endpoint *endpt,
/* Find WWW-Authenticate or Proxy-Authenticate header. */
while (hdr->type != PJSIP_H_WWW_AUTHENTICATE &&
hdr->type != PJSIP_H_PROXY_AUTHENTICATE &&
- hdr != &rdata->msg->hdr)
+ hdr != &rdata->msg_info.msg->hdr)
{
hdr = hdr->next;
}
- if (hdr == &rdata->msg->hdr)
+ if (hdr == &rdata->msg_info.msg->hdr)
break;
hchal = (const pjsip_www_authenticate_hdr*) hdr;
diff --git a/pjsip/src/pjsip/sip_endpoint.c b/pjsip/src/pjsip/sip_endpoint.c
index e8ec2324..398c1c55 100644
--- a/pjsip/src/pjsip/sip_endpoint.c
+++ b/pjsip/src/pjsip/sip_endpoint.c
@@ -32,7 +32,7 @@
#include <pj/hash.h>
#include <pj/assert.h>
#include <pj/errno.h>
-
+#include <pj/lock.h>
#define PJSIP_EX_NO_MEMORY PJ_NO_MEMORY_EXCEPTION
#define THIS_FILE "endpoint"
@@ -63,7 +63,10 @@ struct pjsip_endpoint
pj_timer_heap_t *timer_heap;
/** Transport manager. */
- pjsip_transport_mgr *transport_mgr;
+ pjsip_tpmgr *transport_mgr;
+
+ /** Ioqueue. */
+ pj_ioqueue_t *ioqueue;
/** DNS Resolver. */
pjsip_resolver_t *resolver;
@@ -95,7 +98,8 @@ struct pjsip_endpoint
/*
* Prototypes.
*/
-static void endpt_transport_callback( pjsip_endpoint *, pjsip_rx_data *rdata );
+static void endpt_transport_callback(pjsip_endpoint*,
+ pj_status_t, pjsip_rx_data*);
/*
@@ -354,6 +358,7 @@ PJ_DEF(pj_status_t) pjsip_endpt_create(pj_pool_factory *pf,
pj_pool_t *pool;
pjsip_endpoint *endpt;
pjsip_max_forwards_hdr *mf_hdr;
+ pj_lock_t *lock = NULL;
PJ_LOG(5, (THIS_FILE, "pjsip_endpt_create()"));
@@ -398,11 +403,28 @@ PJ_DEF(pj_status_t) pjsip_endpt_create(pj_pool_factory *pf,
goto on_error;
}
+ /* Set recursive lock for the timer heap. */
+ status = pj_lock_create_recursive_mutex( endpt->pool, "edpt%p", &lock);
+ if (status != PJ_SUCCESS) {
+ goto on_error;
+ }
+ pj_timer_heap_set_lock(endpt->timer_heap, lock, PJ_TRUE);
+
+ /* Set maximum timed out entries to process in a single poll. */
+ pj_timer_heap_set_max_timed_out_per_poll(endpt->timer_heap,
+ PJSIP_MAX_TIMED_OUT_ENTRIES);
+
+ /* Create ioqueue. */
+ status = pj_ioqueue_create( endpt->pool, PJSIP_MAX_TRANSPORTS, &endpt->ioqueue);
+ if (status != PJ_SUCCESS) {
+ goto on_error;
+ }
+
/* Create transport manager. */
- status = pjsip_transport_mgr_create( endpt->pool,
- endpt,
- &endpt_transport_callback,
- &endpt->transport_mgr);
+ status = pjsip_tpmgr_create( endpt->pool, endpt,
+ endpt->ioqueue, endpt->timer_heap,
+ &endpt_transport_callback,
+ &endpt->transport_mgr);
if (status != PJ_SUCCESS) {
goto on_error;
}
@@ -445,7 +467,7 @@ PJ_DEF(pj_status_t) pjsip_endpt_create(pj_pool_factory *pf,
on_error:
if (endpt->transport_mgr) {
- pjsip_transport_mgr_destroy(endpt->transport_mgr);
+ pjsip_tpmgr_destroy(endpt->transport_mgr);
endpt->transport_mgr = NULL;
}
if (endpt->mutex) {
@@ -470,7 +492,7 @@ PJ_DEF(void) pjsip_endpt_destroy(pjsip_endpoint *endpt)
PJ_LOG(5, (THIS_FILE, "pjsip_endpt_destroy()"));
/* Shutdown and destroy all transports. */
- pjsip_transport_mgr_destroy(endpt->transport_mgr);
+ pjsip_tpmgr_destroy(endpt->transport_mgr);
/* Delete endpoint mutex. */
pj_mutex_destroy(endpt->mutex);
@@ -532,20 +554,16 @@ PJ_DEF(void) pjsip_endpt_destroy_pool( pjsip_endpoint *endpt, pj_pool_t *pool )
PJ_DEF(void) pjsip_endpt_handle_events( pjsip_endpoint *endpt,
const pj_time_val *max_timeout)
{
- pj_time_val timeout;
- int i;
+ /* timeout is 'out' var. This just to make compiler happy. */
+ pj_time_val timeout = { 0, 0};
PJ_LOG(5, (THIS_FILE, "pjsip_endpt_handle_events()"));
/* Poll the timer. The timer heap has its own mutex for better
- * granularity, so we don't need to lock end endpoint. We also keep
- * polling the timer while we have events.
+ * granularity, so we don't need to lock end endpoint.
*/
- timeout.sec = timeout.msec = 0; /* timeout is 'out' var. This just to make compiler happy. */
- for (i=0; i<10; ++i) {
- if (pj_timer_heap_poll( endpt->timer_heap, &timeout ) < 1)
- break;
- }
+ timeout.sec = timeout.msec = 0;
+ pj_timer_heap_poll( endpt->timer_heap, &timeout );
/* If caller specifies maximum time to wait, then compare the value with
* the timeout to wait from timer, and use the minimum value.
@@ -554,8 +572,8 @@ PJ_DEF(void) pjsip_endpt_handle_events( pjsip_endpoint *endpt,
timeout = *max_timeout;
}
- /* Poll events in the transport manager. */
- pjsip_transport_mgr_handle_events( endpt->transport_mgr, &timeout);
+ /* Poll ioqueue. */
+ pj_ioqueue_poll( endpt->ioqueue, &timeout);
}
/*
@@ -658,13 +676,13 @@ PJ_DECL(pjsip_transaction*) pjsip_endpt_find_tsx( pjsip_endpoint *endpt,
static void rdata_create_key( pjsip_rx_data *rdata)
{
pjsip_role_e role;
- if (rdata->msg->type == PJSIP_REQUEST_MSG) {
+ if (rdata->msg_info.msg->type == PJSIP_REQUEST_MSG) {
role = PJSIP_ROLE_UAS;
} else {
role = PJSIP_ROLE_UAC;
}
- pjsip_tsx_create_key(rdata->pool, &rdata->key, role,
- &rdata->cseq->method, rdata);
+ pjsip_tsx_create_key(rdata->tp_info.pool, &rdata->endpt_info.key, role,
+ &rdata->msg_info.cseq->method, rdata);
}
/*
@@ -672,14 +690,26 @@ static void rdata_create_key( pjsip_rx_data *rdata)
* receives a message from the network.
*/
static void endpt_transport_callback( pjsip_endpoint *endpt,
+ pj_status_t status,
pjsip_rx_data *rdata )
{
- pjsip_msg *msg = rdata->msg;
+ pjsip_msg *msg = rdata->msg_info.msg;
pjsip_transaction *tsx;
pj_bool_t a_new_transaction_just_been_created = PJ_FALSE;
PJ_LOG(5, (THIS_FILE, "endpt_transport_callback(rdata=%p)", rdata));
+ if (status != PJ_SUCCESS) {
+ const char *src_addr = pj_inet_ntoa(rdata->pkt_info.addr.sin_addr);
+ int port = pj_ntohs(rdata->pkt_info.addr.sin_port);
+ PJSIP_ENDPT_LOG_ERROR((endpt, "transport", status,
+ "Src.addr=%s:%d, packet:--\n"
+ "%s\n"
+ "-- end of packet. Error",
+ src_addr, port, rdata->msg_info.msg_buf));
+ return;
+ }
+
/* For response, check that the value in Via sent-by match the transport.
* If not matched, silently drop the response.
* Ref: RFC3261 Section 18.1.2 Receiving Response
@@ -687,16 +717,16 @@ static void endpt_transport_callback( pjsip_endpoint *endpt,
if (msg->type == PJSIP_RESPONSE_MSG) {
const pj_sockaddr_in *addr;
const char *addr_addr;
- int port = rdata->via->sent_by.port;
+ int port = rdata->msg_info.via->sent_by.port;
pj_bool_t mismatch = PJ_FALSE;
if (port == 0) {
int type;
- type = pjsip_transport_get_type(rdata->transport);
+ type = rdata->tp_info.transport->type;
port = pjsip_transport_get_default_port_for_type(type);
}
- addr = pjsip_transport_get_addr_name(rdata->transport);
+ addr = &rdata->tp_info.transport->public_addr;
addr_addr = pj_inet_ntoa(addr->sin_addr);
- if (pj_strcmp2(&rdata->via->sent_by.host, addr_addr) != 0)
+ if (pj_strcmp2(&rdata->msg_info.via->sent_by.host, addr_addr) != 0)
mismatch = PJ_TRUE;
else if (port != pj_ntohs(addr->sin_port)) {
/* Port or address mismatch, we should discard response */
@@ -706,7 +736,7 @@ static void endpt_transport_callback( pjsip_endpoint *endpt,
* So we discard the response only if the port doesn't match
* both the port in sent-by and rport. We try to be lenient here!
*/
- if (rdata->via->rport_param != pj_sockaddr_in_get_port(addr))
+ if (rdata->msg_info.via->rport_param != pj_sockaddr_in_get_port(addr))
mismatch = PJ_TRUE;
else {
PJ_LOG(4,(THIS_FILE, "Response %p has mismatch port in sent-by"
@@ -729,13 +759,13 @@ static void endpt_transport_callback( pjsip_endpoint *endpt,
/* Find the transaction for the received message. */
PJ_LOG(5, (THIS_FILE, "finding tsx with key=%.*s",
- rdata->key.slen, rdata->key.ptr));
+ rdata->endpt_info.key.slen, rdata->endpt_info.key.ptr));
/* Start lock mutex in the endpoint. */
pj_mutex_lock(endpt->tsx_table_mutex);
/* Find the transaction in the hash table. */
- tsx = pj_hash_get( endpt->tsx_table, rdata->key.ptr, rdata->key.slen );
+ tsx = pj_hash_get( endpt->tsx_table, rdata->endpt_info.key.ptr, rdata->endpt_info.key.slen );
/* Unlock mutex. */
pj_mutex_unlock(endpt->tsx_table_mutex);
@@ -752,7 +782,7 @@ static void endpt_transport_callback( pjsip_endpoint *endpt,
/* Inform TU about the 200 message, only if it's INVITE. */
if (PJSIP_IS_STATUS_IN_CLASS(msg->line.status.code, 200) &&
- rdata->cseq->method.id == PJSIP_INVITE_METHOD)
+ rdata->msg_info.cseq->method.id == PJSIP_INVITE_METHOD)
{
pjsip_event e;
@@ -776,7 +806,7 @@ static void endpt_transport_callback( pjsip_endpoint *endpt,
/*
* For non-ACK request message, create a new transaction.
*/
- } else if (rdata->msg->line.req.method.id != PJSIP_ACK_METHOD) {
+ } else if (rdata->msg_info.msg->line.req.method.id != PJSIP_ACK_METHOD) {
pj_status_t status;
@@ -805,7 +835,7 @@ static void endpt_transport_callback( pjsip_endpoint *endpt,
/* Dispatch message to transaction. */
pjsip_tsx_on_rx_msg( tsx, rdata );
- } else if (rdata->msg->line.req.method.id == PJSIP_ACK_METHOD) {
+ } else if (rdata->msg_info.msg->line.req.method.id == PJSIP_ACK_METHOD) {
/*
* This is an ACK message, but the INVITE transaction could not
* be found (possibly because the branch parameter in Via in ACK msg
@@ -914,42 +944,21 @@ PJ_DEF(void) pjsip_endpt_resolve( pjsip_endpoint *endpt,
/*
* Find/create transport.
*/
-PJ_DEF(void) pjsip_endpt_get_transport( pjsip_endpoint *endpt,
- pj_pool_t *pool,
- pjsip_transport_type_e type,
- const pj_sockaddr_in *remote,
- void *token,
- pjsip_transport_completion_callback *cb)
+PJ_DECL(pj_status_t) pjsip_endpt_alloc_transport( pjsip_endpoint *endpt,
+ pjsip_transport_type_e type,
+ const pj_sockaddr_in *remote,
+ pjsip_transport **p_transport)
{
- PJ_LOG(5, (THIS_FILE, "pjsip_endpt_get_transport()"));
- pjsip_transport_get( endpt->transport_mgr, pool, type,
- remote, token, cb);
+ PJ_LOG(5, (THIS_FILE, "pjsip_endpt_alloc_transport()"));
+ return pjsip_tpmgr_alloc_transport( endpt->transport_mgr, type, remote,
+ p_transport);
}
-PJ_DEF(pj_status_t) pjsip_endpt_create_listener( pjsip_endpoint *endpt,
- pjsip_transport_type_e type,
- pj_sockaddr_in *addr,
- const pj_sockaddr_in *addr_name)
-{
- PJ_LOG(5, (THIS_FILE, "pjsip_endpt_create_listener()"));
- return pjsip_create_listener( endpt->transport_mgr, type, addr, addr_name );
-}
-
-PJ_DEF(pj_status_t) pjsip_endpt_create_udp_listener( pjsip_endpoint *endpt,
- pj_sock_t sock,
- const pj_sockaddr_in *addr_name)
-{
- PJ_LOG(5, (THIS_FILE, "pjsip_endpt_create_udp_listener()"));
- return pjsip_create_udp_listener( endpt->transport_mgr, sock, addr_name );
-}
-
PJ_DEF(void) pjsip_endpt_dump( pjsip_endpoint *endpt, pj_bool_t detail )
{
#if PJ_LOG_MAX_LEVEL >= 3
unsigned count;
- pj_hash_iterator_t itr_val;
- pj_hash_iterator_t *itr;
PJ_LOG(5, (THIS_FILE, "pjsip_endpt_dump()"));
@@ -1014,38 +1023,8 @@ PJ_DEF(void) pjsip_endpt_dump( pjsip_endpoint *endpt, pj_bool_t detail )
}
/* Transports.
- * Note: transport is not properly locked in this function.
- * See pjsip_transport_first, pjsip_transport_next.
*/
- itr = pjsip_transport_first( endpt->transport_mgr, &itr_val );
- if (itr) {
- PJ_LOG(3, (THIS_FILE, " Dumping transports:"));
-
- do {
- char src_addr[128], dst_addr[128];
- int src_port, dst_port;
- const pj_sockaddr_in *addr;
- pjsip_transport_t *t;
-
- t = pjsip_transport_this(endpt->transport_mgr, itr);
- addr = pjsip_transport_get_local_addr(t);
- pj_native_strcpy(src_addr, pj_inet_ntoa(addr->sin_addr));
- src_port = pj_ntohs(addr->sin_port);
-
- addr = pjsip_transport_get_remote_addr(t);
- pj_native_strcpy(dst_addr, pj_inet_ntoa(addr->sin_addr));
- dst_port = pj_ntohs(addr->sin_port);
-
- PJ_LOG(3, (THIS_FILE, " %s %s %s:%d --> %s:%d (refcnt=%d)",
- pjsip_transport_get_type_name(t),
- pjsip_transport_get_obj_name(t),
- src_addr, src_port,
- dst_addr, dst_port,
- pjsip_transport_get_ref_cnt(t)));
-
- itr = pjsip_transport_next(endpt->transport_mgr, itr);
- } while (itr);
- }
+ pjsip_tpmgr_dump_transports( endpt->transport_mgr );
/* Timer. */
PJ_LOG(3,(THIS_FILE, " Timer heap has %u entries",
diff --git a/pjsip/src/pjsip/sip_misc.c b/pjsip/src/pjsip/sip_misc.c
index 8f87b2ad..c134da88 100644
--- a/pjsip/src/pjsip/sip_misc.c
+++ b/pjsip/src/pjsip/sip_misc.c
@@ -429,7 +429,7 @@ PJ_DEF(pj_status_t) pjsip_endpt_create_response( pjsip_endpoint *endpt,
pj_status_t status;
/* rdata must be a request message. */
- req_msg = rdata->msg;
+ req_msg = rdata->msg_info.msg;
pj_assert(req_msg->type == PJSIP_REQUEST_MSG);
/* Log this action. */
@@ -449,10 +449,10 @@ PJ_DEF(pj_status_t) pjsip_endpt_create_response( pjsip_endpoint *endpt,
msg->line.status.reason = *pjsip_get_status_text(code);
/* Set TX data attributes. */
- tdata->rx_timestamp = rdata->timestamp;
+ tdata->rx_timestamp = rdata->pkt_info.timestamp;
/* Copy all the via headers, in order. */
- via = rdata->via;
+ via = rdata->msg_info.via;
while (via) {
pjsip_msg_add_hdr( msg, pjsip_hdr_clone(tdata->pool, via));
via = via->next;
@@ -478,15 +478,15 @@ PJ_DEF(pj_status_t) pjsip_endpt_create_response( pjsip_endpoint *endpt,
pjsip_msg_add_hdr(msg, pjsip_hdr_clone(tdata->pool, hdr));
/* Copy From header. */
- hdr = pjsip_hdr_clone(tdata->pool, rdata->from);
+ hdr = pjsip_hdr_clone(tdata->pool, rdata->msg_info.from);
pjsip_msg_add_hdr( msg, hdr);
/* Copy To header. */
- hdr = pjsip_hdr_clone(tdata->pool, rdata->to);
+ hdr = pjsip_hdr_clone(tdata->pool, rdata->msg_info.to);
pjsip_msg_add_hdr( msg, hdr);
/* Copy CSeq header. */
- hdr = pjsip_hdr_clone(tdata->pool, rdata->cseq);
+ hdr = pjsip_hdr_clone(tdata->pool, rdata->msg_info.cseq);
pjsip_msg_add_hdr( msg, hdr);
/* All done. */
@@ -514,8 +514,8 @@ PJ_DEF(void) pjsip_endpt_create_ack(pjsip_endpoint *endpt,
PJ_UNUSED_ARG(endpt);
/* rdata must be a final response. */
- pj_assert(rdata->msg->type==PJSIP_RESPONSE_MSG &&
- rdata->msg->line.status.code >= 300);
+ pj_assert(rdata->msg_info.msg->type==PJSIP_RESPONSE_MSG &&
+ rdata->msg_info.msg->line.status.code >= 300);
/* Log this action. */
PJ_LOG(5,(THIS_FILE, "pjsip_endpt_create_ack(rdata=%p)", rdata));
@@ -542,7 +542,7 @@ PJ_DEF(void) pjsip_endpt_create_ack(pjsip_endpoint *endpt,
/* Copy To header from the original INVITE. */
to = (pjsip_to_hdr*)pjsip_msg_find_remove_hdr( invite_msg,
PJSIP_H_TO, NULL);
- pj_strdup(tdata->pool, &to->tag, &rdata->to->tag);
+ pj_strdup(tdata->pool, &to->tag, &rdata->msg_info.to->tag);
pjsip_msg_add_hdr( ack_msg, (pjsip_hdr*)to );
/* Must contain single Via, just as the original INVITE. */
@@ -674,7 +674,7 @@ PJ_DEF(pj_status_t) pjsip_endpt_create_cancel( pjsip_endpoint *endpt,
* response.
*/
PJ_DEF(pj_status_t) pjsip_get_response_addr(pj_pool_t *pool,
- const pjsip_transport_t *req_transport,
+ const pjsip_transport *req_transport,
const pjsip_via_hdr *via,
pjsip_host_port *send_addr)
{
@@ -687,12 +687,12 @@ PJ_DEF(pj_status_t) pjsip_get_response_addr(pj_pool_t *pool,
* - otherwise if received parameter is present, set to this address.
* - otherwise send to the address in sent-by.
*/
- send_addr->flag = pjsip_transport_get_flag(req_transport);
- send_addr->type = pjsip_transport_get_type(req_transport);
+ send_addr->flag = req_transport->flag;
+ send_addr->type = req_transport->type;
if (PJSIP_TRANSPORT_IS_RELIABLE(req_transport)) {
const pj_sockaddr_in *remote_addr;
- remote_addr = pjsip_transport_get_remote_addr(req_transport);
+ remote_addr = &req_transport->rem_addr;
pj_strdup2(pool, &send_addr->host,
pj_inet_ntoa(remote_addr->sin_addr));
send_addr->port = pj_sockaddr_in_get_port(remote_addr);
diff --git a/pjsip/src/pjsip/sip_parser.c b/pjsip/src/pjsip/sip_parser.c
index 0e16d7db..01013363 100644
--- a/pjsip/src/pjsip/sip_parser.c
+++ b/pjsip/src/pjsip/sip_parser.c
@@ -558,19 +558,19 @@ PJ_DEF(pjsip_msg *) pjsip_parse_rdata( char *buf, pj_size_t size,
&on_syntax_error);
context.scanner = &scanner;
- context.pool = rdata->pool;
+ context.pool = rdata->tp_info.pool;
context.rdata = rdata;
PJ_TRY {
- rdata->msg = int_parse_msg(&context, &rdata->parse_err);
+ rdata->msg_info.msg = int_parse_msg(&context, &rdata->msg_info.parse_err);
}
PJ_DEFAULT {
- rdata->msg = NULL;
+ rdata->msg_info.msg = NULL;
}
PJ_END
pj_scan_fini(&scanner);
- return rdata->msg;
+ return rdata->msg_info.msg;
}
/* Determine if a message has been received. */
@@ -1258,7 +1258,7 @@ static pjsip_hdr* parse_hdr_call_id(pjsip_parse_ctx *ctx)
parse_hdr_end(ctx->scanner);
if (ctx->rdata)
- ctx->rdata->call_id = hdr->id;
+ ctx->rdata->msg_info.call_id = hdr->id;
return (pjsip_hdr*)hdr;
}
@@ -1339,7 +1339,7 @@ static pjsip_hdr* parse_hdr_content_len( pjsip_parse_ctx *ctx )
parse_hdr_end(ctx->scanner);
if (ctx->rdata)
- ctx->rdata->clen = hdr;
+ ctx->rdata->msg_info.clen = hdr;
return (pjsip_hdr*)hdr;
}
@@ -1367,7 +1367,7 @@ static pjsip_hdr* parse_hdr_content_type( pjsip_parse_ctx *ctx )
parse_hdr_end(ctx->scanner);
if (ctx->rdata)
- ctx->rdata->ctype = hdr;
+ ctx->rdata->msg_info.ctype = hdr;
return (pjsip_hdr*)hdr;
}
@@ -1388,7 +1388,7 @@ static pjsip_hdr* parse_hdr_cseq( pjsip_parse_ctx *ctx )
parse_hdr_end( ctx->scanner );
if (ctx->rdata)
- ctx->rdata->cseq = hdr;
+ ctx->rdata->msg_info.cseq = hdr;
return (pjsip_hdr*)hdr;
}
@@ -1432,7 +1432,7 @@ static pjsip_hdr* parse_hdr_from( pjsip_parse_ctx *ctx )
pjsip_from_hdr *hdr = pjsip_from_hdr_create(ctx->pool);
parse_hdr_fromto(ctx->scanner, ctx->pool, hdr);
if (ctx->rdata)
- ctx->rdata->from = hdr;
+ ctx->rdata->msg_info.from = hdr;
return (pjsip_hdr*)hdr;
}
@@ -1443,8 +1443,8 @@ static pjsip_hdr* parse_hdr_require( pjsip_parse_ctx *ctx )
pjsip_require_hdr *hdr = pjsip_require_hdr_create(ctx->pool);
parse_generic_array_hdr(hdr, ctx->scanner);
- if (ctx->rdata && ctx->rdata->require == NULL)
- ctx->rdata->require = hdr;
+ if (ctx->rdata && ctx->rdata->msg_info.require == NULL)
+ ctx->rdata->msg_info.require = hdr;
return (pjsip_hdr*)hdr;
}
@@ -1474,7 +1474,7 @@ static pjsip_hdr* parse_hdr_to( pjsip_parse_ctx *ctx )
parse_hdr_fromto(ctx->scanner, ctx->pool, hdr);
if (ctx->rdata)
- ctx->rdata->to = hdr;
+ ctx->rdata->msg_info.to = hdr;
return (pjsip_hdr*)hdr;
}
@@ -1528,7 +1528,7 @@ static pjsip_hdr* parse_hdr_max_forwards( pjsip_parse_ctx *ctx )
parse_generic_int_hdr(hdr, ctx->scanner);
if (ctx->rdata)
- ctx->rdata->max_fwd = hdr;
+ ctx->rdata->msg_info.max_fwd = hdr;
return (pjsip_hdr*)hdr;
}
@@ -1578,8 +1578,8 @@ static pjsip_hdr* parse_hdr_rr( pjsip_parse_ctx *ctx)
} while (1);
parse_hdr_end(scanner);
- if (ctx->rdata && ctx->rdata->record_route==NULL)
- ctx->rdata->record_route = first;
+ if (ctx->rdata && ctx->rdata->msg_info.record_route==NULL)
+ ctx->rdata->msg_info.record_route = first;
return (pjsip_hdr*)first;
}
@@ -1606,8 +1606,8 @@ static pjsip_hdr* parse_hdr_route( pjsip_parse_ctx *ctx )
} while (1);
parse_hdr_end(scanner);
- if (ctx->rdata && ctx->rdata->route==NULL)
- ctx->rdata->route = first;
+ if (ctx->rdata && ctx->rdata->msg_info.route==NULL)
+ ctx->rdata->msg_info.route = first;
return (pjsip_hdr*)first;
}
@@ -1659,8 +1659,8 @@ static pjsip_hdr* parse_hdr_via( pjsip_parse_ctx *ctx )
parse_hdr_end(scanner);
- if (ctx->rdata && ctx->rdata->via == NULL)
- ctx->rdata->via = first;
+ if (ctx->rdata && ctx->rdata->msg_info.via == NULL)
+ ctx->rdata->msg_info.via = first;
return (pjsip_hdr*)first;
}
diff --git a/pjsip/src/pjsip/sip_transaction.c b/pjsip/src/pjsip/sip_transaction.c
index 3e078e0d..f186f28a 100644
--- a/pjsip/src/pjsip/sip_transaction.c
+++ b/pjsip/src/pjsip/sip_transaction.c
@@ -192,18 +192,18 @@ static pj_status_t create_tsx_key_2543( pj_pool_t *pool,
pj_str_t *host;
PJ_ASSERT_RETURN(pool && str && method && rdata, PJ_EINVAL);
- PJ_ASSERT_RETURN(rdata->msg, PJ_EINVAL);
- PJ_ASSERT_RETURN(rdata->via, PJSIP_EMISSINGHDR);
- PJ_ASSERT_RETURN(rdata->cseq, PJSIP_EMISSINGHDR);
- PJ_ASSERT_RETURN(rdata->from, PJSIP_EMISSINGHDR);
+ PJ_ASSERT_RETURN(rdata->msg_info.msg, PJ_EINVAL);
+ PJ_ASSERT_RETURN(rdata->msg_info.via, PJSIP_EMISSINGHDR);
+ PJ_ASSERT_RETURN(rdata->msg_info.cseq, PJSIP_EMISSINGHDR);
+ PJ_ASSERT_RETURN(rdata->msg_info.from, PJSIP_EMISSINGHDR);
- host = &rdata->via->sent_by.host;
- req_uri = (pjsip_uri*)rdata->msg->line.req.uri;
+ host = &rdata->msg_info.via->sent_by.host;
+ req_uri = (pjsip_uri*)rdata->msg_info.msg->line.req.uri;
/* Calculate length required. */
len_required = 9 + /* CSeq number */
- rdata->from->tag.slen + /* From tag. */
- rdata->call_id.slen + /* Call-ID */
+ rdata->msg_info.from->tag.slen + /* From tag. */
+ rdata->msg_info.call_id.slen + /* Call-ID */
host->slen + /* Via host. */
9 + /* Via port. */
16; /* Separator+Allowance. */
@@ -231,19 +231,19 @@ static pj_status_t create_tsx_key_2543( pj_pool_t *pool,
}
/* Add CSeq (only the number). */
- len = pj_utoa(rdata->cseq->cseq, p);
+ len = pj_utoa(rdata->msg_info.cseq->cseq, p);
p += len;
*p++ = SEPARATOR;
/* Add From tag. */
- len = rdata->from->tag.slen;
- pj_memcpy( p, rdata->from->tag.ptr, len);
+ len = rdata->msg_info.from->tag.slen;
+ pj_memcpy( p, rdata->msg_info.from->tag.ptr, len);
p += len;
*p++ = SEPARATOR;
/* Add Call-ID. */
- len = rdata->call_id.slen;
- pj_memcpy( p, rdata->call_id.ptr, len );
+ len = rdata->msg_info.call_id.slen;
+ pj_memcpy( p, rdata->msg_info.call_id.ptr, len );
p += len;
*p++ = SEPARATOR;
@@ -257,7 +257,7 @@ static pj_status_t create_tsx_key_2543( pj_pool_t *pool,
p += host->slen;
*p++ = ':';
- len = pj_utoa(rdata->via->sent_by.port, p);
+ len = pj_utoa(rdata->msg_info.via->sent_by.port, p);
p += len;
*p++ = SEPARATOR;
@@ -324,7 +324,7 @@ PJ_DEF(pj_status_t) pjsip_tsx_create_key( pj_pool_t *pool, pj_str_t *key,
* generated by agent compliant with RFC3261. Otherwise, it will be
* handled as RFC2543.
*/
- const pj_str_t *branch = &rdata->via->branch_param;
+ const pj_str_t *branch = &rdata->msg_info.via->branch_param;
if (pj_strncmp(branch,&rfc3261_branch,PJSIP_RFC3261_BRANCH_LEN)==0) {
@@ -642,7 +642,7 @@ static pj_status_t tsx_process_route( pjsip_transaction *tsx,
* This callback is called when asychronous transport connect() operation
* has completed, with or without error.
*/
-static void tsx_transport_callback(pjsip_transport_t *tr,
+static void tsx_transport_callback(pjsip_transport *tr,
void *token,
pj_status_t status)
{
@@ -656,11 +656,11 @@ static void tsx_transport_callback(pjsip_transport_t *tr,
if (status == PJ_SUCCESS) {
PJ_LOG(4, (tsx->obj_name, "%s connected to %s:%d",
- pjsip_transport_get_type_name(tr),
+ tr->type_name,
addr, tsx->dest_name.port));
} else {
PJ_LOG(4, (tsx->obj_name, "%s unable to connect to %s:%d, status=%d",
- pjsip_transport_get_type_name(tr),
+ tr->type_name,
addr, tsx->dest_name.port, status));
}
@@ -877,7 +877,7 @@ PJ_DEF(pj_status_t) pjsip_tsx_init_uac( pjsip_transaction *tsx,
PJ_DEF(pj_status_t) pjsip_tsx_init_uas( pjsip_transaction *tsx,
pjsip_rx_data *rdata)
{
- pjsip_msg *msg = rdata->msg;
+ pjsip_msg *msg = rdata->msg_info.msg;
pj_str_t *branch;
pjsip_cseq_hdr *cseq;
pj_status_t status;
@@ -889,7 +889,7 @@ PJ_DEF(pj_status_t) pjsip_tsx_init_uas( pjsip_transaction *tsx,
lock_tsx(tsx, &lck);
/* Keep shortcut to message */
- msg = rdata->msg;
+ msg = rdata->msg_info.msg;
/* Role is UAS */
tsx->role = PJSIP_ROLE_UAS;
@@ -908,14 +908,14 @@ PJ_DEF(pj_status_t) pjsip_tsx_init_uas( pjsip_transaction *tsx,
}
/* Duplicate branch parameter for transaction. */
- branch = &rdata->via->branch_param;
+ branch = &rdata->msg_info.via->branch_param;
pj_strdup(tsx->pool, &tsx->branch, branch);
PJ_LOG(6, (tsx->obj_name, "tsx_key=%.*s", tsx->transaction_key.slen,
tsx->transaction_key.ptr));
/* Save CSeq */
- cseq = rdata->cseq;
+ cseq = rdata->msg_info.cseq;
tsx->cseq = cseq->cseq;
/* Begin with state NULL
@@ -931,10 +931,10 @@ PJ_DEF(pj_status_t) pjsip_tsx_init_uas( pjsip_transaction *tsx,
/* In addition, RFC 3581 says, if Via has "rport" parameter specified,
* then return the response using the same transport.
*/
- if (PJSIP_TRANSPORT_IS_RELIABLE(rdata->transport) ||
- rdata->via->rport_param >= 0)
+ if (PJSIP_TRANSPORT_IS_RELIABLE(rdata->tp_info.transport) ||
+ rdata->msg_info.via->rport_param >= 0)
{
- tsx->transport = rdata->transport;
+ tsx->transport = rdata->tp_info.transport;
pjsip_transport_add_ref(tsx->transport);
tsx->transport_state = PJSIP_TSX_TRANSPORT_STATE_FINAL;
@@ -943,13 +943,13 @@ PJ_DEF(pj_status_t) pjsip_tsx_init_uas( pjsip_transaction *tsx,
tsx->remote_addr.entry[0].type =
pjsip_transport_get_type(tsx->transport);
pj_memcpy(&tsx->remote_addr.entry[0].addr,
- &rdata->addr, rdata->addr_len);
+ &rdata->pkt_info.addr, rdata->pkt_info.addr_len);
} else {
pj_status_t status;
- status = pjsip_get_response_addr(tsx->pool, rdata->transport,
- rdata->via, &tsx->dest_name);
+ status = pjsip_get_response_addr(tsx->pool, rdata->tp_info.transport,
+ rdata->msg_info.via, &tsx->dest_name);
if (status != PJ_SUCCESS) {
tsx->transport_state = PJSIP_TSX_TRANSPORT_STATE_FINAL;
tsx->status_code = PJSIP_SC_TSX_TRANSPORT_ERROR;
@@ -1212,9 +1212,9 @@ static pj_status_t tsx_send_msg( pjsip_transaction *tsx,
/* Don't update Via sent-by on retransmission. */
if (via->sent_by.host.slen == 0) {
- addr_name = pjsip_transport_get_addr_name(tsx->transport);
+ addr_name = &tsx->transport->public_addr;
pj_strdup2(tdata->pool, &via->transport,
- pjsip_transport_get_type_name(tsx->transport));
+ tsx->transport->type_name);
pj_strdup2(tdata->pool, &via->sent_by.host,
pj_inet_ntoa(addr_name->sin_addr));
via->sent_by.port = pj_ntohs(addr_name->sin_port);
@@ -1396,7 +1396,7 @@ static pj_status_t pjsip_tsx_on_state_calling( pjsip_transaction *tsx,
* the final response.
*/
/* Keep last_tx for authorization. */
- code = event->body.rx_msg.rdata->msg->line.status.code;
+ code = event->body.rx_msg.rdata->msg_info.msg->line.status.code;
if (tsx->method.id != PJSIP_INVITE_METHOD && code!=401 && code!=407) {
pjsip_tx_data_dec_ref(tsx->last_tx);
tsx->last_tx = NULL;
@@ -1665,7 +1665,7 @@ static pj_status_t pjsip_tsx_on_state_proceeding_uac(pjsip_transaction *tsx,
return PJ_EINVALIDOP;
}
- tsx->status_code = event->body.rx_msg.rdata->msg->line.status.code;
+ tsx->status_code = event->body.rx_msg.rdata->msg_info.msg->line.status.code;
} else {
tsx->status_code = PJSIP_SC_TSX_TIMEOUT;
}
@@ -1762,7 +1762,7 @@ static pj_status_t pjsip_tsx_on_state_completed_uas( pjsip_transaction *tsx,
pj_assert(tsx->state == PJSIP_TSX_STATE_COMPLETED);
if (event->type == PJSIP_EVENT_RX_MSG) {
- pjsip_msg *msg = event->body.rx_msg.rdata->msg;
+ pjsip_msg *msg = event->body.rx_msg.rdata->msg_info.msg;
pjsip_cseq_hdr *cseq = pjsip_msg_find_hdr( msg, PJSIP_H_CSEQ, NULL );
/* On receive request retransmission, retransmit last response. */
@@ -1855,7 +1855,7 @@ static pj_status_t pjsip_tsx_on_state_completed_uac( pjsip_transaction *tsx,
/* On received of final response retransmission, retransmit the ACK.
* TU doesn't need to be informed.
*/
- pjsip_msg *msg = event->body.rx_msg.rdata->msg;
+ pjsip_msg *msg = event->body.rx_msg.rdata->msg_info.msg;
pj_assert(msg->type == PJSIP_RESPONSE_MSG);
if (msg->type==PJSIP_RESPONSE_MSG &&
msg->line.status.code >= 200)
@@ -1921,10 +1921,10 @@ static pj_status_t pjsip_tsx_on_state_confirmed( pjsip_transaction *tsx,
if (event->type == PJSIP_EVENT_RX_MSG) {
pjsip_method_e method_id =
- event->body.rx_msg.rdata->msg->line.req.method.id;
+ event->body.rx_msg.rdata->msg_info.msg->line.req.method.id;
/* Must be a request message. */
- pj_assert(event->body.rx_msg.rdata->msg->type == PJSIP_REQUEST_MSG);
+ pj_assert(event->body.rx_msg.rdata->msg_info.msg->type == PJSIP_REQUEST_MSG);
/* Must be an ACK request or a late INVITE retransmission. */
pj_assert(method_id == PJSIP_ACK_METHOD ||
diff --git a/pjsip/src/pjsip/sip_transport.c b/pjsip/src/pjsip/sip_transport.c
index b78037a5..cd9b564f 100644
--- a/pjsip/src/pjsip/sip_transport.c
+++ b/pjsip/src/pjsip/sip_transport.c
@@ -29,152 +29,32 @@
#include <pj/string.h>
#include <pj/pool.h>
#include <pj/assert.h>
+#include <pj/lock.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;
-
- /** 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;
-};
+#define THIS_FILE "transport"
/*
* Transport manager.
*/
-struct pjsip_transport_mgr
+struct pjsip_tpmgr
{
- pj_hash_table_t *transport_table;
- pj_mutex_t *mutex;
+ pj_hash_table_t *table;
+ pj_lock_t *lock;
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);
+ pj_timer_heap_t *timer_heap;
+ pjsip_tpfactory factory_list;
+ void (*msg_cb)(pjsip_endpoint*, pj_status_t, pjsip_rx_data*);
};
-/*
- * 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);
-};
+/*****************************************************************************
+ *
+ * GENERAL TRANSPORT (NAMES, TYPES, ETC.)
+ *
+ *****************************************************************************/
/*
* Transport names.
@@ -184,170 +64,102 @@ const struct
pjsip_transport_type_e type;
pj_uint16_t port;
pj_str_t name;
+ unsigned flag;
} 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
+ { PJSIP_TRANSPORT_UNSPECIFIED, 0, {NULL, 0}, 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},
+ { PJSIP_TRANSPORT_SCTP, 5060, {"SCTP", 4}, PJSIP_TRANSPORT_RELIABLE}
};
-static void on_ioqueue_read(pj_ioqueue_key_t *key,
- pj_ioqueue_op_key_t *op_key,
- 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);
-static void on_ioqueue_accept(pj_ioqueue_key_t *key,
- pj_ioqueue_op_key_t *op_key,
- pj_sock_t newsock,
- 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)
+/*
+ * Get transport type from name.
+ */
+PJ_DEF(pjsip_transport_type_e)
+pjsip_transport_get_type_from_name(const pj_str_t *name)
{
- /* This is to detect alignment problems. */
- pj_assert(sizeof(transport_key) == 8);
+ unsigned i;
- 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);
+ for (i=0; i<PJ_ARRAY_SIZE(transport_names); ++i) {
+ if (pj_stricmp(name, &transport_names[i].name) == 0) {
+ return transport_names[i].type;
+ }
}
- */
-}
-
-#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);
+ pj_assert(!"Invalid transport name");
+ return PJSIP_TRANSPORT_UNSPECIFIED;
}
-#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).
+ * Get the transport type for the specified flags.
*/
-static const char *transport_get_name_format( int type )
+PJ_DEF(pjsip_transport_type_e)
+pjsip_transport_get_type_from_flag(unsigned flag)
{
- 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
+ unsigned i;
+
+ for (i=0; i<PJ_ARRAY_SIZE(transport_names); ++i) {
+ if (transport_names[i].flag == flag) {
+ return transport_names[i].type;
+ }
}
- pj_assert(0);
- return 0;
+
+ pj_assert(!"Invalid transport type");
+ return PJSIP_TRANSPORT_UNSPECIFIED;
}
-/*
- * 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)
+PJ_DEF(unsigned)
+pjsip_transport_get_flag_from_type( pjsip_transport_type_e type )
{
- return transport_names[type].port;
+ PJ_ASSERT_RETURN(type < PJ_ARRAY_SIZE(transport_names), 0);
+ return transport_names[type].flag;
}
/*
- * Get transport name.
+ * Get the default SIP port number for the specified type.
*/
-static const char *get_type_name(int type)
+PJ_DEF(int)
+pjsip_transport_get_default_port_for_type(pjsip_transport_type_e type)
{
- return transport_names[type].name.ptr;
+ PJ_ASSERT_RETURN(type < PJ_ARRAY_SIZE(transport_names), 5060);
+ return transport_names[type].port;
}
-/*
- * 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;
-}
+/*****************************************************************************
+ *
+ * TRANSMIT DATA BUFFER MANIPULATION.
+ *
+ *****************************************************************************/
/*
* Create new transmit buffer.
*/
-pj_status_t pjsip_tx_data_create( pjsip_transport_mgr *mgr,
- pjsip_tx_data **p_tdata )
+PJ_DEF(pj_status_t) pjsip_tx_data_create( pjsip_tpmgr *mgr,
+ 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_ASSERT_RETURN(mgr && p_tdata, PJ_EINVAL);
- pool = pjsip_endpt_create_pool( mgr->endpt, "ptdt%p",
+ PJ_LOG(5, ("", "pjsip_tx_data_create"));
+
+ pool = pjsip_endpt_create_pool( mgr->endpt, "tdta%p",
PJSIP_POOL_LEN_TDATA,
PJSIP_POOL_INC_TDATA );
- if (!pool) {
+ if (!pool)
return PJ_ENOMEM;
- }
- tdata = pj_pool_calloc(pool, 1, sizeof(pjsip_tx_data));
+
+ tdata = pj_pool_zalloc(pool, sizeof(pjsip_tx_data));
tdata->pool = pool;
tdata->mgr = mgr;
- pj_sprintf(tdata->obj_name,"txd%p", tdata);
+ pj_snprintf(tdata->obj_name, PJ_MAX_OBJ_NAME, "tdta%p", tdata);
status = pj_atomic_create(tdata->pool, 0, &tdata->ref_cnt);
if (status != PJ_SUCCESS) {
@@ -355,10 +167,20 @@ pj_status_t pjsip_tx_data_create( pjsip_transport_mgr *mgr,
return status;
}
+ //status = pj_lock_create_simple_mutex(pool, "tdta%p", &tdata->lock);
+ status = pj_lock_create_null_mutex(pool, "tdta%p", &tdata->lock);
+ if (status != PJ_SUCCESS) {
+ pjsip_endpt_destroy_pool( mgr->endpt, tdata->pool );
+ return status;
+ }
+
+ pj_ioqueue_op_key_init(&tdata->op_key, sizeof(tdata->op_key));
+
*p_tdata = tdata;
return PJ_SUCCESS;
}
+
/*
* Add reference to tx buffer.
*/
@@ -375,8 +197,9 @@ 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_LOG(5,(tdata->obj_name, "destroying txdata"));
pj_atomic_destroy( tdata->ref_cnt );
+ pj_lock_destroy( tdata->lock );
pjsip_endpt_destroy_pool( tdata->mgr->endpt, tdata->pool );
}
}
@@ -390,328 +213,79 @@ 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)
+PJ_DEF(pj_bool_t) pjsip_tx_data_is_valid( pjsip_tx_data *tdata )
{
- return tr->type;
+ return tdata->buf.cur != tdata->buf.start;
}
-/*
- * 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;
-}
+/*****************************************************************************
+ *
+ * TRANSPORT KEY
+ *
+ *****************************************************************************/
/*
- * Get transport flag.
+ * Transport key for indexing in the hash table.
*/
-PJ_DEF(unsigned) pjsip_transport_get_flag( const pjsip_transport_t * tr )
+typedef struct transport_key
{
- return tr->flag;
-}
+ pj_uint8_t type;
+ pj_uint8_t zero;
+ pj_uint16_t port;
+ pj_uint32_t addr;
+} transport_key;
-/*
- * 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;
- }
-}
+/*****************************************************************************
+ *
+ * TRANSPORT
+ *
+ *****************************************************************************/
-/*
- * Open the underlying transport.
- */
-static pj_status_t create_socket( pjsip_transport_type_e type,
- pj_sockaddr_in *local,
- pj_sock_t *p_sock)
+static void transport_send_callback(pjsip_transport *transport,
+ void *token,
+ pj_status_t status)
{
- 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;
- }
+ pjsip_tx_data *tdata = token;
- /* Create socket. */
- status = pj_sock_socket( sock_family, sock_type, sock_proto, &sock);
- if (status != PJ_SUCCESS)
- return status;
+ PJ_UNUSED_ARG(transport);
- /* Bind the socket to the requested address, or if no address is
- * specified, let the operating system chooses the address.
+ /* Mark pending off so that app can resend/reuse txdata from inside
+ * the callback.
*/
- 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));
- local->sin_family = PJ_AF_INET;
- status = pj_sock_bind(sock, local, sizeof(*local));
- if (status != PJ_SUCCESS) {
- pj_sock_close(sock);
- return status;
- }
+ tdata->is_pending = 0;
- /* 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;
- }
+ /* Call callback, if any. */
+ if (tdata->cb) {
+ (*tdata->cb)(tdata->token, tdata, 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;
+ /* Decrement reference count. */
+ pjsip_tx_data_dec_ref(tdata);
}
/*
- * Create a new transport object.
+ * Send a SIP message using the specified transport.
*/
-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_DEF(pj_status_t) pjsip_transport_send( pjsip_transport *tr,
+ pjsip_tx_data *tdata,
+ const pj_sockaddr_in *addr,
+ void *token,
+ void (*cb)(void *token,
+ pjsip_tx_data *tdata,
+ pj_status_t))
{
- 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 );
- 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 );
- 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));
-
- /* 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,
- &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 );
+ PJ_ASSERT_RETURN(tr && tdata && addr, PJ_EINVAL);
- /* 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,
- const pj_sockaddr_in *addr,
- 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))
+ /* Is it currently being sent? */
+ if (tdata->is_pending) {
+ pj_assert(!"Invalid operation step!");
return PJSIP_EPENDINGTX;
+ }
/* Allocate buffer if necessary. */
if (tdata->buf.start == NULL) {
@@ -720,8 +294,10 @@ static pj_status_t transport_send_msg( pjsip_transport_t *tr,
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) {
+ /* 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) {
@@ -732,952 +308,544 @@ static pj_status_t transport_send_msg( pjsip_transport_t *tr,
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;
+ /* Save callback data. */
+ tdata->token = token;
+ tdata->cb = cb;
+
+ /* Add reference counter. */
+ pjsip_tx_data_add_ref(tdata);
+
+ /* Mark as pending. */
+ tdata->is_pending = 1;
+
+ /* Send to transport. */
+ status = (*tr->send_msg)(tr, tdata->buf.start,
+ tdata->buf.cur - tdata->buf.start,
+ &tdata->op_key,
+ addr, tdata, &transport_send_callback);
+
+ if (status != PJ_EPENDING) {
+ tdata->is_pending = 0;
+ pjsip_tx_data_dec_ref(tdata);
}
-#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)
+static void transport_idle_callback(pj_timer_heap_t *timer_heap,
+ struct pj_timer_entry *entry)
{
- PJ_LOG(5, (tr->obj_name, "pjsip_transport_send_msg(tdata=%s)", tdata->obj_name));
+ pjsip_transport *tp = entry->user_data;
+ pj_assert(tp != NULL);
- return transport_send_msg(tr, tdata, addr, sent );
-}
+ PJ_UNUSED_ARG(timer_heap);
-///////////////////////////////////////////////////////////////////////////////
+ entry->id = PJ_FALSE;
+ pjsip_transport_unregister(tp->tpmgr, tp);
+}
/*
- * Create a new transport manager.
+ * Add ref.
*/
-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)
+PJ_DEF(pj_status_t) pjsip_transport_add_ref( pjsip_transport *tp )
{
- pjsip_transport_mgr *mgr;
- pj_status_t status;
+ PJ_ASSERT_RETURN(tp != NULL, PJ_EINVAL);
- 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;
+ if (pj_atomic_inc_and_get(tp->ref_cnt) == 1) {
+ pj_lock_acquire(tp->tpmgr->lock);
+ /* Verify again. */
+ if (pj_atomic_get(tp->ref_cnt) == 1) {
+ if (tp->idle_timer.id != PJ_FALSE) {
+ pj_timer_heap_cancel(tp->tpmgr->timer_heap, &tp->idle_timer);
+ tp->idle_timer.id = PJ_FALSE;
+ }
+ }
+ pj_lock_release(tp->tpmgr->lock);
}
- pj_gettimeofday(&mgr->next_idle_check);
- mgr->next_idle_check.sec += MGR_IDLE_CHECK_INTERVAL;
- *p_mgr = mgr;
- return status;
+ return PJ_SUCCESS;
}
/*
- * Destroy transport manager.
+ * Dec ref.
*/
-PJ_DEF(pj_status_t) pjsip_transport_mgr_destroy( pjsip_transport_mgr *mgr )
+PJ_DEF(pj_status_t) pjsip_transport_dec_ref( pjsip_transport *tp )
{
- pj_hash_iterator_t itr_val;
- pj_hash_iterator_t *itr;
-
- PJ_LOG(5, (LOG_TRANSPORT_MGR, "pjsip_transport_mgr_destroy()"));
+ PJ_ASSERT_RETURN(tp != NULL, PJ_EINVAL);
- pj_mutex_lock(mgr->mutex);
+ pj_assert(pj_atomic_get(tp->ref_cnt) > 0);
- 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_dec_and_get(tp->ref_cnt) == 0) {
+ pj_lock_acquire(tp->tpmgr->lock);
+ /* Verify again. */
+ if (pj_atomic_get(tp->ref_cnt) == 0) {
+ pj_time_val delay = { PJSIP_TRANSPORT_IDLE_TIME, 0 };
- pj_atomic_set(transport->ref_cnt, 0);
- destroy_transport( mgr, transport);
-
- itr = next;
+ pj_assert(tp->idle_timer.id == 0);
+ tp->idle_timer.id = PJ_TRUE;
+ pj_timer_heap_schedule(tp->tpmgr->timer_heap, &tp->idle_timer, &delay);
+ }
+ pj_lock_release(tp->tpmgr->lock);
}
- pj_ioqueue_destroy(mgr->ioqueue);
-
- pj_mutex_unlock(mgr->mutex);
return PJ_SUCCESS;
}
-/*
- * Create listener
+
+/**
+ * Register a transport.
*/
-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)
+PJ_DEF(pj_status_t) pjsip_transport_register( pjsip_tpmgr *mgr,
+ pjsip_transport *tp )
{
- pjsip_transport_t *tr;
- struct transport_key *hash_key;
- const pj_str_t loopback_addr = { "127.0.0.1", 9 };
- pj_status_t status;
-
- 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));
+ transport_key key;
- if (status != PJ_SUCCESS) {
- return status;
- }
- }
-
- 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;
- }
- }
-
- 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) {
+ /* Init. */
+ tp->tpmgr = mgr;
+ pj_memset(&tp->idle_timer, 0, sizeof(tp->idle_timer));
+ tp->idle_timer.user_data = tp;
+ tp->idle_timer.cb = &transport_idle_callback;
- 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);
- if (status==PJ_SUCCESS) {
- pj_sock_close(tr->accept_data.sock);
- } else if (status != PJ_EPENDING) {
- destroy_transport(mgr, tr);
- return status;
- }
- } while (status==PJ_SUCCESS);
-
- } else
-#endif
- if (type == PJSIP_TRANSPORT_UDP) {
- pj_ssize_t bytes;
-
- /* Discard immediate data. */
- 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,
- &tr->rdata->addr_len);
- if (status == PJ_SUCCESS) {
- ;
- } else if (status != PJ_EPENDING) {
- destroy_transport(mgr, tr);
- return status;
- }
- } while (status == PJ_SUCCESS);
- }
-
- pj_atomic_set(tr->ref_cnt, 1);
+ /*
+ * Register to hash table.
+ */
+ key.type = (pj_uint8_t)tp->type;
+ key.zero = 0;
+ key.addr = pj_ntohl(tp->rem_addr.sin_addr.s_addr);
+ key.port = pj_ntohs(tp->rem_addr.sin_port);
- /* Listeners normally have no remote address */
- pj_memset(&tr->remote_addr, 0, sizeof(tr->remote_addr));
+ pj_lock_acquire(mgr->lock);
+ pj_hash_set(tp->pool, mgr->table, &key, sizeof(key), tp);
+ pj_lock_release(mgr->lock);
- /* 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_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.
+
+/**
+ * Unregister transport.
*/
-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_DEF(pj_status_t) pjsip_transport_unregister( pjsip_tpmgr *mgr,
+ pjsip_transport *tp)
{
- pj_sock_t sock_hnd;
- pj_status_t status;
+ transport_key key;
- PJ_LOG(5, (LOG_TRANSPORT_MGR, "pjsip_create_listener(type=%d)", type));
+ PJ_ASSERT_RETURN(pj_atomic_get(tp->ref_cnt) == 0, PJSIP_EBUSY);
- status = create_socket(type, local_addr, &sock_hnd);
- if (status != PJ_SUCCESS) {
- return status;
+ pj_lock_acquire(tp->lock);
+ pj_lock_acquire(mgr->lock);
+
+ /*
+ * Unregister timer, if any.
+ */
+ pj_assert(tp->idle_timer.id == PJ_FALSE);
+ if (tp->idle_timer.id != PJ_FALSE) {
+ pj_timer_heap_cancel(mgr->timer_heap, &tp->idle_timer);
+ tp->idle_timer.id = PJ_FALSE;
}
- return create_listener(mgr, type, sock_hnd, local_addr, addr_name);
-}
+ /*
+ * Unregister from hash table.
+ */
+ key.type = (pj_uint8_t)tp->type;
+ key.zero = 0;
+ key.addr = pj_ntohl(tp->rem_addr.sin_addr.s_addr);
+ key.port = pj_ntohs(tp->rem_addr.sin_port);
-/*
- * 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_hash_set(tp->pool, mgr->table, &key, sizeof(key), NULL);
- status = pj_sock_getsockname(sock, (pj_sockaddr_t*)&local_addr, &addrlen);
- if (status != PJ_SUCCESS)
- return status;
+ pj_lock_release(mgr->lock);
- return create_listener(mgr, PJSIP_TRANSPORT_UDP, sock,
- &local_addr, addr_name);
+ /* Destroy. */
+ return tp->destroy(tp);
}
-/*
- * 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);
+/*****************************************************************************
+ *
+ * TRANSPORT FACTORY
+ *
+ *****************************************************************************/
- /* 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);
+PJ_DEF(pj_status_t) pjsip_tpmgr_register_tpfactory( pjsip_tpmgr *mgr,
+ pjsip_tpfactory *tpf)
+{
+ pjsip_tpfactory *p;
+ pj_status_t status;
- if (tr->flag & PJSIP_TRANSPORT_IOQUEUE_BUSY) {
- /* Transport is busy. Just register the callback. */
- pj_list_insert_before(&tr->cb_list, cb_rec);
+ pj_lock_acquire(mgr->lock);
- } else {
- /* Transport is ready. Call callback now.
- */
- (*cb_rec->cb)(tr, cb_rec->token, PJ_SUCCESS);
+ /* Check that no factory with the same type has been registered. */
+ status = PJ_SUCCESS;
+ for (p=mgr->factory_list.next; p!=&mgr->factory_list; p=p->next) {
+ if (p->type == tpf->type) {
+ status = PJSIP_ETYPEEXISTS;
+ break;
+ }
+ if (p == tpf) {
+ status = PJ_EEXISTS;
+ break;
}
- 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;
+ pj_lock_release(mgr->lock);
+ return status;
}
-#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);
- 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 {
- 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,
- &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;
- }
+ pj_list_insert_before(&mgr->factory_list, tpf);
- /* 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);
+ pj_lock_release(mgr->lock);
- } while (status == PJ_SUCCESS);
+ return PJ_SUCCESS;
+}
- //Bug: cb will never be called!
- // Must force status to PJ_SUCCESS;
- //status = PJ_IOQUEUE_PENDING;
- status = PJ_SUCCESS;
+/**
+ * Unregister factory.
+ */
+PJ_DEF(pj_status_t) pjsip_tpmgr_unregister_tpfactory( pjsip_tpmgr *mgr,
+ pjsip_tpfactory *tpf)
+{
+ pj_lock_acquire(mgr->lock);
- } else {
- pj_mutex_unlock(mgr->mutex);
- (*cb_rec->cb)(NULL, cb_rec->token, PJSIP_EUNSUPTRANSPORT);
- return;
- }
+ pj_assert(pj_list_find_node(&mgr->factory_list, tpf) == tpf);
+ pj_list_erase(tpf);
- 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);
- }
+ pj_lock_release(mgr->lock);
+ return PJ_SUCCESS;
}
-#if PJ_HAS_TCP
+
+/*****************************************************************************
+ *
+ * TRANSPORT MANAGER
+ *
+ *****************************************************************************/
+
/*
- * Handle completion of asynchronous accept() operation.
- * This function is called by handle_events() function.
+ * Create a new transport manager.
*/
-static void handle_new_connection( pjsip_transport_mgr *mgr,
- pjsip_transport_t *listener,
- pj_status_t status )
+PJ_DEF(pj_status_t) pjsip_tpmgr_create( pj_pool_t *pool,
+ pjsip_endpoint *endpt,
+ pj_ioqueue_t *ioqueue,
+ pj_timer_heap_t *timer_heap,
+ void (*cb)(pjsip_endpoint*,
+ pj_status_t,
+ pjsip_rx_data *),
+ pjsip_tpmgr **p_mgr)
{
- pjsip_transport_t *tr;
- transport_key *hash_key;
- pj_ssize_t size;
+ pjsip_tpmgr *mgr;
+ pj_status_t status;
- pj_assert (listener->type == PJSIP_TRANSPORT_TCP);
+ PJ_ASSERT_RETURN(pool && endpt && cb && p_mgr, PJ_EINVAL);
- if (status != PJ_SUCCESS) {
- PJSIP_ENDPT_LOG_ERROR((mgr->endpt, listener->obj_name, status,
- "Error in accept() completion"));
- goto on_return;
- }
+ PJ_LOG(5, (THIS_FILE, "pjsip_tpmgr_create()"));
- 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)));
+ mgr = pj_pool_zalloc(pool, sizeof(*mgr));
+ mgr->endpt = endpt;
+ mgr->msg_cb = cb;
+ mgr->ioqueue = ioqueue;
+ mgr->timer_heap = timer_heap;
+ pj_list_init(&mgr->factory_list);
- 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;
- }
+ mgr->table = pj_hash_create(pool, PJSIP_TPMGR_HTABLE_SIZE);
+ if (!mgr->table)
+ return PJ_ENOMEM;
- /*
- 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) {
- 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;
- }
+ status = pj_lock_create_recursive_mutex(pool, "tmgr%p", &mgr->lock);
+ if (status != PJ_SUCCESS)
+ return status;
- 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);
- 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) {
- PJSIP_ENDPT_LOG_ERROR((mgr->endpt, listener->obj_name, status,
- "Error in receiving data"));
- PJ_TODO(IMMEDIATE_ACCEPT);
- return;
- }
+ *p_mgr = mgr;
+ return PJ_SUCCESS;
}
/*
- * Handle completion of asynchronous connect() function.
- * This function is called by the handle_events() function.
+ * pjsip_tpmgr_destroy()
+ *
+ * Destroy transport manager.
*/
-static void handle_connect_completion( pjsip_transport_mgr *mgr,
- pjsip_transport_t *tr,
- pj_status_t status )
+PJ_DEF(pj_status_t) pjsip_tpmgr_destroy( pjsip_tpmgr *mgr )
{
- 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);
+ pj_hash_iterator_t itr_val;
+ pj_hash_iterator_t *itr;
+
+ PJ_LOG(5, (THIS_FILE, "pjsip_tpmgr_destroy()"));
- /* Clear transport's busy flag. */
- tr->flag &= ~PJSIP_TRANSPORT_IOQUEUE_BUSY;
+ pj_lock_acquire(mgr->lock);
- /* If success, update local address.
- * Local address is only available after connect() has returned.
- */
- if (status == PJ_SUCCESS) {
- int addrlen = sizeof(tr->local_addr);
+ itr = pj_hash_first(mgr->table, &itr_val);
+ while (itr != NULL) {
+ pj_hash_iterator_t *next;
+ pjsip_transport *transport;
- 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));
- }
- }
+ transport = pj_hash_this(mgr->table, itr);
- /* Unlock mutex. */
- pj_mutex_unlock(tr->tr_mutex);
+ next = pj_hash_next(mgr->table, itr);
- /* 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;
- }
+ pj_atomic_set(transport->ref_cnt, 0);
+ pjsip_transport_unregister(mgr, transport);
- /* Success? */
- if (status != PJ_SUCCESS) {
- destroy_transport(mgr, tr);
- PJ_TODO(WTF);
- return;
+ itr = next;
}
+ pj_ioqueue_destroy(mgr->ioqueue);
- /* Initiate read operation to socket. */
- 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) {
- destroy_transport(mgr, tr);
- PJ_TODO(IMMEDIATE_DATA);
- return;
- }
+ pj_lock_release(mgr->lock);
+
+ return PJ_SUCCESS;
}
-#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.
+ * pjsip_tpmgr_receive_packet()
+ *
+ * Called by tranports when they receive a new packet.
*/
-static void handle_received_data( pjsip_transport_mgr *mgr,
- pjsip_transport_t *tr,
- pj_ssize_t size )
+PJ_DEF(pj_ssize_t) pjsip_tpmgr_receive_packet( pjsip_tpmgr *mgr,
+ pjsip_rx_data *rdata)
{
- pjsip_msg *msg;
- pjsip_rx_data *rdata = tr->rdata;
- pj_pool_t *rdata_pool;
- pjsip_hdr *hdr;
+ pjsip_transport *tr = rdata->tp_info.transport;
pj_str_t s;
- char *src_addr;
- int src_port;
- pj_size_t msg_fragment_size = 0;
+
+ char *current_pkt;
+ pj_size_t remaining_len;
+ pj_size_t total_processed = 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;
- }
- }
+ pj_assert(rdata->pkt_info.len > 0);
+ if (rdata->pkt_info.len <= 0)
+ return -1;
- /* Save received time. */
- pj_gettimeofday(&rdata->timestamp);
+ current_pkt = rdata->pkt_info.packet;
+ remaining_len = rdata->pkt_info.len;
- /* Update length. */
- rdata->len += size;
+ /* Must NULL terminate buffer. This is the requirement of the
+ * parser etc.
+ */
+ current_pkt[remaining_len] = '\0';
- /* Null terminate packet, this is the requirement of the parser. */
- rdata->packet[rdata->len] = '\0';
+ /* Process all message fragments. */
+ while (total_processed < remaining_len) {
- /* 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);
+ pjsip_msg *msg;
+ pj_size_t msg_fragment_size = 0;
- /* 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));
+ /* Initialize default fragment size. */
+ msg_fragment_size = remaining_len;
+ /* Null terminate packet. */
- /* Process all message fragments. */
- while (rdata->len > 0) {
+ /* Clear and init msg_info in rdata.
+ * Endpoint might inspect the values there when we call the callback
+ * to report some errors.
+ */
+ pj_memset(&rdata->msg_info, 0, sizeof(rdata->msg_info));
+ pj_list_init(&rdata->msg_info.parse_err);
+ rdata->msg_info.msg_buf = current_pkt;
+ rdata->msg_info.len = remaining_len;
- 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) {
+ if ((tr->flag & PJSIP_TRANSPORT_DATAGRAM) == 0) {
pj_status_t msg_status;
- msg_status = pjsip_find_msg(rdata->packet, rdata->len, PJ_FALSE,
+ msg_status = pjsip_find_msg(current_pkt, remaining_len, PJ_FALSE,
&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;
+ if (remaining_len == PJSIP_MAX_PKT_LEN) {
+ mgr->msg_cb(mgr->endpt, PJSIP_EOVERFLOW, rdata);
+ /* Exhaust all data. */
+ return rdata->pkt_info.len;
} else {
- goto tcp_read_packet;
+ /* Not enough data in packet. */
+ return total_processed;
}
}
}
-#endif
- /* Clear parser error report */
- pj_list_init(&rdata->parse_err);
+ /* Update msg_info. */
+ rdata->msg_info.len = msg_fragment_size;
/* 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);
+ rdata->msg_info.msg = msg =
+ pjsip_parse_rdata( current_pkt, 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));
+ mgr->msg_cb(mgr->endpt, PJSIP_EINVALIDMSG, rdata);
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)
+ if (rdata->msg_info.call_id.ptr == NULL ||
+ rdata->msg_info.from == NULL ||
+ rdata->msg_info.to == NULL ||
+ rdata->msg_info.via == NULL ||
+ rdata->msg_info.cseq == NULL)
{
- PJ_LOG(3,(tr->obj_name, "Bad message from %s:%d: missing some header",
- src_addr, src_port));
+ mgr->msg_cb(mgr->endpt, PJSIP_EMISSINGHDR, rdata);
goto finish_process_fragment;
}
- /* If message is received from address that's different from the sent-by,
+ /* If message is received from address that's different from 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);
+ s = pj_str(pj_inet_ntoa(rdata->pkt_info.addr.sin_addr));
+ if (pj_strcmp(&s, &rdata->msg_info.via->sent_by.host) != 0) {
+ pj_strdup(rdata->tp_info.pool,
+ &rdata->msg_info.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);
+ if (rdata->msg_info.via->rport_param == 0) {
+ rdata->msg_info.via->rport_param =
+ pj_ntohs(rdata->pkt_info.addr.sin_port);
}
/* 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) {
+ pjsip_hdr *hdr;
+ hdr = (pjsip_hdr*)rdata->msg_info.via->next;
+ if (hdr != &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));
+ mgr->msg_cb(mgr->endpt, PJSIP_EMULTIPLEVIA, rdata);
goto finish_process_fragment;
}
}
}
/* Call the transport manager's upstream message callback.
- */
- (*mgr->message_callback)(mgr->endpt, rdata);
+ */
+ mgr->msg_cb(mgr->endpt, PJ_SUCCESS, 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));
- }
+ total_processed += msg_fragment_size;
+ current_pkt += msg_fragment_size;
+ remaining_len -= msg_fragment_size;
- } /* 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,
- &rdata->addr, &rdata->addr_len);
- PJ_TODO(HANDLE_IMMEDIATE_DATA);
- }
+ } /* while (rdata->pkt_info.len > 0) */
-#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,
- &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;
+ return total_processed;
+}
- /* Get time for comparing transport's close time. */
- pj_gettimeofday(&now);
- if (now.sec < mgr->next_idle_check.sec) {
- return;
- }
+/*
+ * pjsip_tpmgr_alloc_transport()
+ *
+ * Get transport suitable to communicate to remote. Create a new one
+ * if necessary.
+ */
+PJ_DEF(pj_status_t) pjsip_tpmgr_alloc_transport( pjsip_tpmgr *mgr,
+ pjsip_transport_type_e type,
+ const pj_sockaddr_in *remote,
+ pjsip_transport **p_transport)
+{
+ transport_key key;
+ pjsip_transport *transport;
+ pjsip_tpfactory *factory;
+ pj_status_t status;
- /* Acquire transport manager's lock. */
- pj_mutex_lock(mgr->mutex);
+ pj_lock_acquire(mgr->lock);
- /* Update next idle check. */
- mgr->next_idle_check.sec += MGR_IDLE_CHECK_INTERVAL;
+ /* First try to get exact destination. */
+ key.type = (pj_uint8_t)type;
+ key.zero = 0;
+ key.addr = pj_ntohl(remote->sin_addr.s_addr);
+ key.port = pj_ntohs(remote->sin_port);
- /* 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 = pj_hash_get(mgr->table, &key, sizeof(key));
+ if (transport != NULL) {
+ unsigned flag = pjsip_transport_get_flag_from_type(type);
- transport = pjsip_transport_this(mgr, itr);
+ /* For datagram transports, try lookup with zero address. */
+ if (flag & PJSIP_TRANSPORT_DATAGRAM) {
+ key.addr = 0;
+ key.port = 0;
- 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);
+ transport = pj_hash_get(mgr->table, &key, sizeof(key));
}
+ }
+
+ if (transport != NULL) {
+ /*
+ * Transport found!
+ */
+ pjsip_transport_add_ref(transport);
+ pj_lock_release(mgr->lock);
+ *p_transport = transport;
+ return PJ_SUCCESS;
+ }
- itr = next;
+ /*
+ * Transport not found!
+ * Find factory that can create such transport.
+ */
+ factory = mgr->factory_list.next;
+ while (factory != &mgr->factory_list) {
+ if (factory->type == type)
+ break;
+ factory = factory->next;
}
- /* Release transport manager's lock. */
- pj_mutex_unlock(mgr->mutex);
-}
+ if (factory == &mgr->factory_list) {
+ /* No factory can create the transport! */
+ pj_lock_release(mgr->lock);
+ return PJSIP_EUNSUPTRANSPORT;
+ }
-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);
+ /* Request factory to create transport. */
+ status = factory->create_transport(factory, mgr, mgr->endpt,
+ mgr->ioqueue, remote, p_transport);
- handle_received_data( t->mgr, t, bytes_read );
+ pj_lock_release(mgr->lock);
+ return status;
}
-static void on_ioqueue_write(pj_ioqueue_key_t *key,
- pj_ioqueue_op_key_t *op_key,
- pj_ssize_t bytes_sent)
+/**
+ * Dump transport info.
+ */
+PJ_DEF(void) pjsip_tpmgr_dump_transports(pjsip_tpmgr *mgr)
{
- PJ_UNUSED_ARG(key);
- PJ_UNUSED_ARG(bytes_sent);
-
- /* Completion of write operation.
- * Do nothing.
- */
-}
+#if PJ_LOG_MAX_LEVEL >= 3
+ pj_hash_iterator_t itr_val;
+ pj_hash_iterator_t *itr;
-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
-}
+ pj_lock_acquire(mgr->lock);
-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
-}
+ itr = pj_hash_first(mgr->table, &itr_val);
+ if (itr) {
+ PJ_LOG(3, (THIS_FILE, " Dumping transports:"));
+ do {
+ char src_addr[128], dst_addr[128];
+ int src_port, dst_port;
+ pjsip_transport *t;
-/*
- * 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);
+ t = pj_hash_this(mgr->table, itr);
+ pj_native_strcpy(src_addr, pj_inet_ntoa(t->local_addr.sin_addr));
+ src_port = pj_ntohs(t->local_addr.sin_port);
- return event_count;
-}
+ pj_native_strcpy(dst_addr, pj_inet_ntoa(t->rem_addr.sin_addr));
+ dst_port = pj_ntohs(t->rem_addr.sin_port);
+ PJ_LOG(3, (THIS_FILE, " %s %s %s:%d --> %s:%d (refcnt=%d)",
+ t->type_name,
+ t->obj_name,
+ src_addr, src_port,
+ dst_addr, dst_port,
+ pj_atomic_get(t->ref_cnt)));
-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);
-}
+ itr = pj_hash_next(mgr->table, itr);
+ } while (itr);
+ }
-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_lock_release(mgr->lock);
+#endif
}
-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);
-}