summaryrefslogtreecommitdiff
path: root/pjsip/src/pjsip/sip_transport_tcp.c
diff options
context:
space:
mode:
Diffstat (limited to 'pjsip/src/pjsip/sip_transport_tcp.c')
-rw-r--r--pjsip/src/pjsip/sip_transport_tcp.c174
1 files changed, 110 insertions, 64 deletions
diff --git a/pjsip/src/pjsip/sip_transport_tcp.c b/pjsip/src/pjsip/sip_transport_tcp.c
index 141434b..808cee9 100644
--- a/pjsip/src/pjsip/sip_transport_tcp.c
+++ b/pjsip/src/pjsip/sip_transport_tcp.c
@@ -1,4 +1,4 @@
-/* $Id: sip_transport_tcp.c 3553 2011-05-05 06:14:19Z nanang $ */
+/* $Id: sip_transport_tcp.c 4294 2012-11-06 05:02:10Z nanang $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
@@ -57,6 +57,7 @@ struct tcp_listener
pjsip_endpoint *endpt;
pjsip_tpmgr *tpmgr;
pj_activesock_t *asock;
+ pj_sockaddr bound_addr;
pj_qos_type qos_type;
pj_qos_params qos_params;
};
@@ -73,6 +74,7 @@ struct delayed_tdata
{
PJ_DECL_LIST_MEMBER(struct delayed_tdata);
pjsip_tx_data_op_key *tdata_op_key;
+ pj_time_val timeout;
};
@@ -140,8 +142,8 @@ static pj_status_t lis_create_transport(pjsip_tpfactory *factory,
static pj_status_t tcp_create(struct tcp_listener *listener,
pj_pool_t *pool,
pj_sock_t sock, pj_bool_t is_server,
- const pj_sockaddr_in *local,
- const pj_sockaddr_in *remote,
+ const pj_sockaddr *local,
+ const pj_sockaddr *remote,
struct tcp_transport **p_tcp);
@@ -158,10 +160,10 @@ static void tcp_perror(const char *sender, const char *title,
static void sockaddr_to_host_port( pj_pool_t *pool,
pjsip_host_port *host_port,
- const pj_sockaddr_in *addr )
+ const pj_sockaddr *addr )
{
host_port->host.ptr = (char*) pj_pool_alloc(pool, PJ_INET6_ADDRSTRLEN+4);
- pj_sockaddr_print(addr, host_port->host.ptr, PJ_INET6_ADDRSTRLEN+4, 2);
+ pj_sockaddr_print(addr, host_port->host.ptr, PJ_INET6_ADDRSTRLEN+4, 0);
host_port->host.slen = pj_ansi_strlen(host_port->host.ptr);
host_port->port = pj_sockaddr_get_port(addr);
}
@@ -266,17 +268,21 @@ PJ_DEF(pj_status_t) pjsip_tcp_transport_start3(
listener = PJ_POOL_ZALLOC_T(pool, struct tcp_listener);
listener->factory.pool = pool;
- listener->factory.type = PJSIP_TRANSPORT_TCP;
- listener->factory.type_name = "tcp";
+ listener->factory.type = cfg->af==pj_AF_INET() ? PJSIP_TRANSPORT_TCP :
+ PJSIP_TRANSPORT_TCP6;
+ listener->factory.type_name = (char*)
+ pjsip_transport_get_type_name(listener->factory.type);
listener->factory.flag =
- pjsip_transport_get_flag_from_type(PJSIP_TRANSPORT_TCP);
+ pjsip_transport_get_flag_from_type(listener->factory.type);
listener->qos_type = cfg->qos_type;
pj_memcpy(&listener->qos_params, &cfg->qos_params,
sizeof(cfg->qos_params));
pj_ansi_strcpy(listener->factory.obj_name, "tcplis");
+ if (listener->factory.type==PJSIP_TRANSPORT_TCP6)
+ pj_ansi_strcat(listener->factory.obj_name, "6");
- status = pj_lock_create_recursive_mutex(pool, "tcplis",
+ status = pj_lock_create_recursive_mutex(pool, listener->factory.obj_name,
&listener->factory.lock);
if (status != PJ_SUCCESS)
goto on_error;
@@ -292,6 +298,11 @@ PJ_DEF(pj_status_t) pjsip_tcp_transport_start3(
2, listener->factory.obj_name,
"SIP TCP listener socket");
+ /* Bind address may be different than factory.local_addr because
+ * factory.local_addr will be resolved below.
+ */
+ pj_sockaddr_cp(&listener->bound_addr, &cfg->bind_addr);
+
/* Bind socket */
listener_addr = &listener->factory.local_addr;
pj_sockaddr_cp(listener_addr, &cfg->bind_addr);
@@ -326,19 +337,18 @@ PJ_DEF(pj_status_t) pjsip_tcp_transport_start3(
if (!pj_sockaddr_has_addr(listener_addr)) {
pj_sockaddr hostip;
- status = pj_gethostip(pj_AF_INET(), &hostip);
+ status = pj_gethostip(listener->bound_addr.addr.sa_family,
+ &hostip);
if (status != PJ_SUCCESS)
goto on_error;
- pj_memcpy(pj_sockaddr_get_addr(listener_addr),
- pj_sockaddr_get_addr(&hostip),
- pj_sockaddr_get_addr_len(&hostip));
+ pj_sockaddr_copy_addr(listener_addr, &hostip);
}
/* Save the address name */
sockaddr_to_host_port(listener->factory.pool,
&listener->factory.addr_name,
- (pj_sockaddr_in*)listener_addr);
+ listener_addr);
}
/* If port is zero, get the bound port */
@@ -535,8 +545,8 @@ static void tcp_keep_alive_timer(pj_timer_heap_t *th, pj_timer_entry *e);
static pj_status_t tcp_create( struct tcp_listener *listener,
pj_pool_t *pool,
pj_sock_t sock, pj_bool_t is_server,
- const pj_sockaddr_in *local,
- const pj_sockaddr_in *remote,
+ const pj_sockaddr *local,
+ const pj_sockaddr *remote,
struct tcp_transport **p_tcp)
{
struct tcp_transport *tcp;
@@ -544,6 +554,7 @@ static pj_status_t tcp_create( struct tcp_listener *listener,
pj_activesock_cfg asock_cfg;
pj_activesock_cb tcp_callback;
const pj_str_t ka_pkt = PJSIP_TCP_KEEP_ALIVE_DATA;
+ char print_addr[PJ_INET6_ADDRSTRLEN+10];
pj_status_t status;
@@ -579,18 +590,21 @@ static pj_status_t tcp_create( struct tcp_listener *listener,
goto on_error;
}
- tcp->base.key.type = PJSIP_TRANSPORT_TCP;
- pj_memcpy(&tcp->base.key.rem_addr, remote, sizeof(pj_sockaddr_in));
- tcp->base.type_name = "tcp";
- tcp->base.flag = pjsip_transport_get_flag_from_type(PJSIP_TRANSPORT_TCP);
+ tcp->base.key.type = listener->factory.type;
+ pj_sockaddr_cp(&tcp->base.key.rem_addr, remote);
+ tcp->base.type_name = (char*)pjsip_transport_get_type_name(
+ (pjsip_transport_type_e)tcp->base.key.type);
+ tcp->base.flag = pjsip_transport_get_flag_from_type(
+ (pjsip_transport_type_e)tcp->base.key.type);
tcp->base.info = (char*) pj_pool_alloc(pool, 64);
- pj_ansi_snprintf(tcp->base.info, 64, "TCP to %s:%d",
- pj_inet_ntoa(remote->sin_addr),
- (int)pj_ntohs(remote->sin_port));
+ pj_ansi_snprintf(tcp->base.info, 64, "%s to %s",
+ tcp->base.type_name,
+ pj_sockaddr_print(remote, print_addr,
+ sizeof(print_addr), 3));
- tcp->base.addr_len = sizeof(pj_sockaddr_in);
- pj_memcpy(&tcp->base.local_addr, local, sizeof(pj_sockaddr_in));
+ tcp->base.addr_len = pj_sockaddr_get_len(remote);
+ pj_sockaddr_cp(&tcp->base.local_addr, local);
sockaddr_to_host_port(pool, &tcp->base.local_name, local);
sockaddr_to_host_port(pool, &tcp->base.remote_name, remote);
tcp->base.dir = is_server? PJSIP_TP_DIR_INCOMING : PJSIP_TP_DIR_OUTGOING;
@@ -601,7 +615,6 @@ static pj_status_t tcp_create( struct tcp_listener *listener,
tcp->base.do_shutdown = &tcp_shutdown;
tcp->base.destroy = &tcp_destroy_transport;
-
/* Create active socket */
pj_activesock_cfg_default(&asock_cfg);
asock_cfg.async_cnt = 1;
@@ -649,6 +662,9 @@ on_error:
/* Flush all delayed transmision once the socket is connected. */
static void tcp_flush_pending_tx(struct tcp_transport *tcp)
{
+ pj_time_val now;
+
+ pj_gettickcount(&now);
pj_lock_acquire(tcp->base.lock);
while (!pj_list_empty(&tcp->delayed_list)) {
struct delayed_tdata *pending_tx;
@@ -663,12 +679,20 @@ static void tcp_flush_pending_tx(struct tcp_transport *tcp)
tdata = pending_tx->tdata_op_key->tdata;
op_key = (pj_ioqueue_op_key_t*)pending_tx->tdata_op_key;
+ if (pending_tx->timeout.sec > 0 &&
+ PJ_TIME_VAL_GT(now, pending_tx->timeout))
+ {
+ continue;
+ }
+
/* send! */
size = tdata->buf.cur - tdata->buf.start;
status = pj_activesock_send(tcp->asock, op_key, tdata->buf.start,
&size, 0);
if (status != PJ_EPENDING) {
+ pj_lock_release(tcp->base.lock);
on_data_sent(tcp->asock, op_key, size);
+ pj_lock_acquire(tcp->base.lock);
}
}
@@ -791,7 +815,7 @@ static pj_status_t tcp_start_read(struct tcp_transport *tcp)
{
pj_pool_t *pool;
pj_ssize_t size;
- pj_sockaddr_in *rem_addr;
+ pj_sockaddr *rem_addr;
void *readbuf[1];
pj_status_t status;
@@ -814,11 +838,11 @@ static pj_status_t tcp_start_read(struct tcp_transport *tcp)
sizeof(pj_ioqueue_op_key_t));
tcp->rdata.pkt_info.src_addr = tcp->base.key.rem_addr;
- tcp->rdata.pkt_info.src_addr_len = sizeof(pj_sockaddr_in);
- rem_addr = (pj_sockaddr_in*) &tcp->base.key.rem_addr;
- pj_ansi_strcpy(tcp->rdata.pkt_info.src_name,
- pj_inet_ntoa(rem_addr->sin_addr));
- tcp->rdata.pkt_info.src_port = pj_ntohs(rem_addr->sin_port);
+ tcp->rdata.pkt_info.src_addr_len = sizeof(tcp->rdata.pkt_info.src_addr);
+ rem_addr = &tcp->base.key.rem_addr;
+ pj_sockaddr_print(rem_addr, tcp->rdata.pkt_info.src_name,
+ sizeof(tcp->rdata.pkt_info.src_name), 0);
+ tcp->rdata.pkt_info.src_port = pj_sockaddr_get_port(rem_addr);
size = sizeof(tcp->rdata.pkt_info.packet);
readbuf[0] = tcp->rdata.pkt_info.packet;
@@ -848,23 +872,25 @@ static pj_status_t lis_create_transport(pjsip_tpfactory *factory,
struct tcp_listener *listener;
struct tcp_transport *tcp;
pj_sock_t sock;
- pj_sockaddr_in local_addr;
+ pj_sockaddr local_addr;
pj_status_t status;
/* Sanity checks */
PJ_ASSERT_RETURN(factory && mgr && endpt && rem_addr &&
addr_len && p_transport, PJ_EINVAL);
- /* Check that address is a sockaddr_in */
- PJ_ASSERT_RETURN(rem_addr->addr.sa_family == pj_AF_INET() &&
- addr_len == sizeof(pj_sockaddr_in), PJ_EINVAL);
+ /* Check that address is a sockaddr_in or sockaddr_in6*/
+ PJ_ASSERT_RETURN((rem_addr->addr.sa_family == pj_AF_INET() &&
+ addr_len == sizeof(pj_sockaddr_in)) ||
+ (rem_addr->addr.sa_family == pj_AF_INET6() &&
+ addr_len == sizeof(pj_sockaddr_in6)), PJ_EINVAL);
listener = (struct tcp_listener*)factory;
-
/* Create socket */
- status = pj_sock_socket(pj_AF_INET(), pj_SOCK_STREAM(), 0, &sock);
+ status = pj_sock_socket(rem_addr->addr.sa_family, pj_SOCK_STREAM(),
+ 0, &sock);
if (status != PJ_SUCCESS)
return status;
@@ -874,15 +900,20 @@ static pj_status_t lis_create_transport(pjsip_tpfactory *factory,
2, listener->factory.obj_name,
"outgoing SIP TCP socket");
- /* Bind to any port */
- status = pj_sock_bind_in(sock, 0, 0);
+ /* Bind to listener's address and any port */
+ pj_bzero(&local_addr, sizeof(local_addr));
+ pj_sockaddr_cp(&local_addr, &listener->bound_addr);
+ pj_sockaddr_set_port(&local_addr, 0);
+
+ status = pj_sock_bind(sock, &local_addr,
+ pj_sockaddr_get_len(&local_addr));
if (status != PJ_SUCCESS) {
pj_sock_close(sock);
return status;
}
/* Get the local port */
- addr_len = sizeof(pj_sockaddr_in);
+ addr_len = sizeof(local_addr);
status = pj_sock_getsockname(sock, &local_addr, &addr_len);
if (status != PJ_SUCCESS) {
pj_sock_close(sock);
@@ -890,12 +921,13 @@ static pj_status_t lis_create_transport(pjsip_tpfactory *factory,
}
/* Initially set the address from the listener's address */
- local_addr.sin_addr.s_addr =
- ((pj_sockaddr_in*)&listener->factory.local_addr)->sin_addr.s_addr;
+ if (!pj_sockaddr_has_addr(&local_addr)) {
+ pj_sockaddr_copy_addr(&local_addr, &listener->factory.local_addr);
+ }
/* Create the transport descriptor */
status = tcp_create(listener, NULL, sock, PJ_FALSE, &local_addr,
- (pj_sockaddr_in*)rem_addr, &tcp);
+ rem_addr, &tcp);
if (status != PJ_SUCCESS)
return status;
@@ -903,7 +935,7 @@ static pj_status_t lis_create_transport(pjsip_tpfactory *factory,
/* Start asynchronous connect() operation */
tcp->has_pending_connect = PJ_TRUE;
status = pj_activesock_start_connect(tcp->asock, tcp->base.pool, rem_addr,
- sizeof(pj_sockaddr_in));
+ addr_len);
if (status == PJ_SUCCESS) {
on_connect_complete(tcp->asock, PJ_SUCCESS);
} else if (status != PJ_EPENDING) {
@@ -915,18 +947,17 @@ static pj_status_t lis_create_transport(pjsip_tpfactory *factory,
/* Update (again) local address, just in case local address currently
* set is different now that asynchronous connect() is started.
*/
- addr_len = sizeof(pj_sockaddr_in);
+ addr_len = sizeof(local_addr);
if (pj_sock_getsockname(sock, &local_addr, &addr_len)==PJ_SUCCESS) {
- pj_sockaddr_in *tp_addr = (pj_sockaddr_in*)&tcp->base.local_addr;
+ pj_sockaddr *tp_addr = &tcp->base.local_addr;
/* Some systems (like old Win32 perhaps) may not set local address
* properly before socket is fully connected.
*/
- if (tp_addr->sin_addr.s_addr != local_addr.sin_addr.s_addr &&
- local_addr.sin_addr.s_addr != 0)
+ if (pj_sockaddr_cmp(tp_addr, &local_addr) &&
+ pj_sockaddr_get_port(&local_addr) != 0)
{
- tp_addr->sin_addr.s_addr = local_addr.sin_addr.s_addr;
- tp_addr->sin_port = local_addr.sin_port;
+ pj_sockaddr_cp(tp_addr, &local_addr);
sockaddr_to_host_port(tcp->base.pool, &tcp->base.local_name,
&local_addr);
}
@@ -962,6 +993,7 @@ static pj_bool_t on_accept_complete(pj_activesock_t *asock,
struct tcp_transport *tcp;
char addr[PJ_INET6_ADDRSTRLEN+10];
pjsip_tp_state_callback state_cb;
+ pj_sockaddr tmp_src_addr;
pj_status_t status;
PJ_UNUSED_ARG(src_addr_len);
@@ -985,13 +1017,19 @@ static pj_bool_t on_accept_complete(pj_activesock_t *asock,
2, listener->factory.obj_name,
"incoming SIP TCP socket");
+ /* tcp_create() expect pj_sockaddr, so copy src_addr to temporary var,
+ * just in case.
+ */
+ pj_bzero(&tmp_src_addr, sizeof(tmp_src_addr));
+ pj_sockaddr_cp(&tmp_src_addr, src_addr);
+
/*
* Incoming connection!
* Create TCP transport for the new socket.
*/
status = tcp_create( listener, NULL, sock, PJ_TRUE,
- (const pj_sockaddr_in*)&listener->factory.local_addr,
- (const pj_sockaddr_in*)src_addr, &tcp);
+ &listener->factory.local_addr,
+ &tmp_src_addr, &tcp);
if (status == PJ_SUCCESS) {
status = tcp_start_read(tcp);
if (status != PJ_SUCCESS) {
@@ -1095,9 +1133,9 @@ static pj_status_t tcp_send_msg(pjsip_transport *transport,
PJ_ASSERT_RETURN(tdata->op_key.tdata == NULL, PJSIP_EPENDINGTX);
/* Check the address is supported */
- PJ_ASSERT_RETURN(rem_addr && addr_len==sizeof(pj_sockaddr_in), PJ_EINVAL);
-
-
+ PJ_ASSERT_RETURN(rem_addr && (addr_len==sizeof(pj_sockaddr_in) ||
+ addr_len==sizeof(pj_sockaddr_in6)),
+ PJ_EINVAL);
/* Init op key. */
tdata->op_key.tdata = tdata;
@@ -1122,10 +1160,19 @@ static pj_status_t tcp_send_msg(pjsip_transport *transport,
/*
* connect() is still in progress. Put the transmit data to
* the delayed list.
+ * Starting from #1583 (https://trac.pjsip.org/repos/ticket/1583),
+ * we also add timeout value for the transmit data. When the
+ * connect() is completed, the timeout value will be checked to
+ * determine whether the transmit data needs to be sent.
*/
- delayed_tdata = PJ_POOL_ALLOC_T(tdata->pool,
- struct delayed_tdata);
+ delayed_tdata = PJ_POOL_ZALLOC_T(tdata->pool,
+ struct delayed_tdata);
delayed_tdata->tdata_op_key = &tdata->op_key;
+ if (tdata->msg && tdata->msg->type == PJSIP_REQUEST_MSG) {
+ pj_gettickcount(&delayed_tdata->timeout);
+ delayed_tdata->timeout.msec += pjsip_cfg()->tsx.td;
+ pj_time_val_normalize(&delayed_tdata->timeout);
+ }
pj_list_push_back(&tcp->delayed_list, delayed_tdata);
status = PJ_EPENDING;
@@ -1269,7 +1316,7 @@ static pj_bool_t on_connect_complete(pj_activesock_t *asock,
pj_status_t status)
{
struct tcp_transport *tcp;
- pj_sockaddr_in addr;
+ pj_sockaddr addr;
int addrlen;
pjsip_tp_state_callback state_cb;
@@ -1314,15 +1361,14 @@ static pj_bool_t on_connect_complete(pj_activesock_t *asock,
* set is different now that the socket is connected (could happen
* on some systems, like old Win32 probably?).
*/
- addrlen = sizeof(pj_sockaddr_in);
+ addrlen = sizeof(addr);
if (pj_sock_getsockname(tcp->sock, &addr, &addrlen)==PJ_SUCCESS) {
- pj_sockaddr_in *tp_addr = (pj_sockaddr_in*)&tcp->base.local_addr;
+ pj_sockaddr *tp_addr = &tcp->base.local_addr;
if (pj_sockaddr_has_addr(&addr) &&
- tp_addr->sin_addr.s_addr != addr.sin_addr.s_addr)
+ pj_sockaddr_cmp(&addr, tp_addr) != 0)
{
- tp_addr->sin_addr.s_addr = addr.sin_addr.s_addr;
- tp_addr->sin_port = addr.sin_port;
+ pj_sockaddr_cp(tp_addr, &addr);
sockaddr_to_host_port(tcp->base.pool, &tcp->base.local_name,
tp_addr);
}