📄 sip_transport_udp.c
字号:
/* Unregister from ioqueue. */
if (tp->key) {
pj_ioqueue_unregister(tp->key);
tp->key = NULL;
} else {
/* Close socket. */
if (tp->sock && tp->sock != PJ_INVALID_SOCKET) {
pj_sock_close(tp->sock);
tp->sock = PJ_INVALID_SOCKET;
}
}
/* Must poll ioqueue because IOCP calls the callback when socket
* is closed. We poll the ioqueue until all pending callbacks
* have been called.
*/
for (i=0; i<50 && tp->is_closing < 1+tp->rdata_cnt; ++i) {
int cnt;
pj_time_val timeout = {0, 1};
cnt = pj_ioqueue_poll(pjsip_endpt_get_ioqueue(transport->endpt),
&timeout);
if (cnt == 0)
break;
}
/* Destroy rdata */
for (i=0; i<tp->rdata_cnt; ++i) {
pj_pool_release(tp->rdata[i]->tp_info.pool);
}
/* Destroy reference counter. */
if (tp->base.ref_cnt)
pj_atomic_destroy(tp->base.ref_cnt);
/* Destroy lock */
if (tp->base.lock)
pj_lock_destroy(tp->base.lock);
/* Destroy pool. */
pjsip_endpt_release_pool(tp->base.endpt, tp->base.pool);
return PJ_SUCCESS;
}
/*
* udp_shutdown()
*
* Start graceful UDP shutdown.
*/
static pj_status_t udp_shutdown(pjsip_transport *transport)
{
return pjsip_transport_dec_ref(transport);
}
/*
* pjsip_udp_transport_attach()
*
* Attach UDP socket and start transport.
*/
PJ_DEF(pj_status_t) pjsip_udp_transport_attach( pjsip_endpoint *endpt,
pj_sock_t sock,
const pjsip_host_port *a_name,
unsigned async_cnt,
pjsip_transport **p_transport)
{
enum { M = 80 };
pj_pool_t *pool;
struct udp_transport *tp;
pj_ioqueue_t *ioqueue;
pj_ioqueue_callback ioqueue_cb;
long sobuf_size;
unsigned i;
pj_status_t status;
PJ_ASSERT_RETURN(endpt && sock!=PJ_INVALID_SOCKET && a_name && async_cnt>0,
PJ_EINVAL);
/* Adjust socket rcvbuf size */
sobuf_size = PJSIP_UDP_SO_RCVBUF_SIZE;
status = pj_sock_setsockopt(sock, PJ_SOL_SOCKET, PJ_SO_RCVBUF,
&sobuf_size, sizeof(sobuf_size));
if (status != PJ_SUCCESS) {
char errmsg[PJ_ERR_MSG_SIZE];
pj_strerror(status, errmsg, sizeof(errmsg));
PJ_LOG(4,(THIS_FILE, "Error setting SO_RCVBUF: %s [%d]", errmsg,
status));
}
/* Adjust socket sndbuf size */
sobuf_size = PJSIP_UDP_SO_SNDBUF_SIZE;
status = pj_sock_setsockopt(sock, PJ_SOL_SOCKET, PJ_SO_SNDBUF,
&sobuf_size, sizeof(sobuf_size));
if (status != PJ_SUCCESS) {
char errmsg[PJ_ERR_MSG_SIZE];
pj_strerror(status, errmsg, sizeof(errmsg));
PJ_LOG(4,(THIS_FILE, "Error setting SO_SNDBUF: %s [%d]", errmsg,
status));
}
/* Create pool. */
pool = pjsip_endpt_create_pool(endpt, "udp%p", PJSIP_POOL_LEN_TRANSPORT,
PJSIP_POOL_INC_TRANSPORT);
if (!pool)
return PJ_ENOMEM;
/* Create the UDP transport object. */
tp = pj_pool_zalloc(pool, sizeof(struct udp_transport));
/* Save pool. */
tp->base.pool = pool;
/* Object name. */
pj_ansi_snprintf(tp->base.obj_name, sizeof(tp->base.obj_name),
"udp%p", tp);
/* Init reference counter. */
status = pj_atomic_create(pool, 0, &tp->base.ref_cnt);
if (status != PJ_SUCCESS)
goto on_error;
/* Init lock. */
status = pj_lock_create_recursive_mutex(pool, "udp%p", &tp->base.lock);
if (status != PJ_SUCCESS)
goto on_error;
/* Set type. */
tp->base.key.type = PJSIP_TRANSPORT_UDP;
/* Remote address is left zero (except the family) */
tp->base.key.rem_addr.sa_family = PJ_AF_INET;
/* Type name. */
tp->base.type_name = "UDP";
/* Transport flag */
tp->base.flag = pjsip_transport_get_flag_from_type(PJSIP_TRANSPORT_UDP);
/* Length of addressess. */
tp->base.addr_len = sizeof(pj_sockaddr_in);
/* Init local address. */
status = pj_sock_getsockname(sock, &tp->base.local_addr,
&tp->base.addr_len);
if (status != PJ_SUCCESS)
goto on_error;
/* Init address name (published address) */
pj_strdup_with_null(pool, &tp->base.local_name.host, &a_name->host);
tp->base.local_name.port = a_name->port;
/* Init remote name. */
tp->base.remote_name.host = pj_str("0.0.0.0");
tp->base.remote_name.port = 0;
/* Transport info. */
tp->base.info = pj_pool_alloc(pool, M);
pj_ansi_snprintf(
tp->base.info, M, "udp %s:%d [published as %s:%d]",
pj_inet_ntoa(((pj_sockaddr_in*)&tp->base.local_addr)->sin_addr),
pj_ntohs(((pj_sockaddr_in*)&tp->base.local_addr)->sin_port),
tp->base.local_name.host.ptr,
tp->base.local_name.port);
/* Set endpoint. */
tp->base.endpt = endpt;
/* Transport manager and timer will be initialized by tpmgr */
/* Attach socket. */
tp->sock = sock;
/* Register to ioqueue. */
ioqueue = pjsip_endpt_get_ioqueue(endpt);
pj_memset(&ioqueue_cb, 0, sizeof(ioqueue_cb));
ioqueue_cb.on_read_complete = &udp_on_read_complete;
ioqueue_cb.on_write_complete = &udp_on_write_complete;
status = pj_ioqueue_register_sock(pool, ioqueue, tp->sock, tp,
&ioqueue_cb, &tp->key);
if (status != PJ_SUCCESS)
goto on_error;
/* Set functions. */
tp->base.send_msg = &udp_send_msg;
tp->base.do_shutdown = &udp_shutdown;
tp->base.destroy = &udp_destroy;
/* This is a permanent transport, so we initialize the ref count
* to one so that transport manager don't destroy this transport
* when there's no user!
*/
pj_atomic_inc(tp->base.ref_cnt);
/* Register to transport manager. */
tp->base.tpmgr = pjsip_endpt_get_tpmgr(endpt);
status = pjsip_transport_register( tp->base.tpmgr, (pjsip_transport*)tp);
if (status != PJ_SUCCESS)
goto on_error;
/* Create rdata and put it in the array. */
tp->rdata_cnt = 0;
tp->rdata = pj_pool_calloc(tp->base.pool, async_cnt,
sizeof(pjsip_rx_data*));
for (i=0; i<async_cnt; ++i) {
pj_pool_t *rdata_pool = pjsip_endpt_create_pool(endpt, "rtd%p",
PJSIP_POOL_RDATA_LEN,
PJSIP_POOL_RDATA_INC);
if (!rdata_pool) {
pj_atomic_set(tp->base.ref_cnt, 0);
pjsip_transport_destroy(&tp->base);
return PJ_ENOMEM;
}
init_rdata(tp, i, rdata_pool, NULL);
tp->rdata_cnt++;
}
/* Start reading the ioqueue. */
for (i=0; i<async_cnt; ++i) {
pj_ssize_t size;
size = sizeof(tp->rdata[i]->pkt_info.packet);
tp->rdata[i]->pkt_info.src_addr_len = sizeof(tp->rdata[i]->pkt_info.src_addr);
status = pj_ioqueue_recvfrom(tp->key,
&tp->rdata[i]->tp_info.op_key.op_key,
tp->rdata[i]->pkt_info.packet,
&size, PJ_IOQUEUE_ALWAYS_ASYNC,
&tp->rdata[i]->pkt_info.src_addr,
&tp->rdata[i]->pkt_info.src_addr_len);
if (status == PJ_SUCCESS) {
pj_assert(!"Shouldn't happen because PJ_IOQUEUE_ALWAYS_ASYNC!");
udp_on_read_complete(tp->key, &tp->rdata[i]->tp_info.op_key.op_key,
size);
} else if (status != PJ_EPENDING) {
/* Error! */
pjsip_transport_destroy(&tp->base);
return status;
}
}
/* Done. */
if (p_transport)
*p_transport = &tp->base;
PJ_LOG(4,(tp->base.obj_name,
"SIP UDP transport started, published address is %.*s:%d",
(int)tp->base.local_name.host.slen,
tp->base.local_name.host.ptr,
tp->base.local_name.port));
return PJ_SUCCESS;
on_error:
udp_destroy((pjsip_transport*)tp);
return status;
}
/*
* pjsip_udp_transport_start()
*
* Create a UDP socket in the specified address and start a transport.
*/
PJ_DEF(pj_status_t) pjsip_udp_transport_start( pjsip_endpoint *endpt,
const pj_sockaddr_in *local_a,
const pjsip_host_port *a_name,
unsigned async_cnt,
pjsip_transport **p_transport)
{
pj_sock_t sock;
pj_status_t status;
char addr_buf[16];
pj_sockaddr_in tmp_addr;
pjsip_host_port bound_name;
PJ_ASSERT_RETURN(endpt && async_cnt, PJ_EINVAL);
status = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &sock);
if (status != PJ_SUCCESS)
return status;
if (local_a == NULL) {
pj_sockaddr_in_init(&tmp_addr, NULL, 0);
local_a = &tmp_addr;
}
status = pj_sock_bind(sock, local_a, sizeof(*local_a));
if (status != PJ_SUCCESS) {
pj_sock_close(sock);
return status;
}
if (a_name == NULL) {
/* Address name is not specified.
* Build a name based on bound address.
*/
int addr_len;
addr_len = sizeof(tmp_addr);
status = pj_sock_getsockname(sock, &tmp_addr, &addr_len);
if (status != PJ_SUCCESS) {
pj_sock_close(sock);
return status;
}
a_name = &bound_name;
bound_name.host.ptr = addr_buf;
bound_name.port = pj_ntohs(tmp_addr.sin_port);
/* If bound address specifies "0.0.0.0", get the IP address
* of local hostname.
*/
if (tmp_addr.sin_addr.s_addr == PJ_INADDR_ANY) {
pj_in_addr hostip;
status = pj_gethostip(&hostip);
if (status != PJ_SUCCESS)
return status;
pj_strcpy2(&bound_name.host, pj_inet_ntoa(hostip));
} else {
/* Otherwise use bound address. */
pj_strcpy2(&bound_name.host, pj_inet_ntoa(tmp_addr.sin_addr));
}
}
return pjsip_udp_transport_attach( endpt, sock, a_name, async_cnt,
p_transport );
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -