Fix #1603: reinit UDP socket of DNS resolver when sendto() returning EPIPE.
git-svn-id: https://svn.pjsip.org/repos/pjproject/trunk@4317 74dad513-b988-da41-8d7b-12977e46ad98
This commit is contained in:
parent
d7636bd4ab
commit
bf7b3a14b4
|
@ -223,6 +223,62 @@ static pj_status_t select_nameservers(pj_dns_resolver *resolver,
|
|||
unsigned servers[]);
|
||||
|
||||
|
||||
/* Close UDP socket */
|
||||
static void close_sock(pj_dns_resolver *resv)
|
||||
{
|
||||
/* Close existing socket */
|
||||
if (resv->udp_key != NULL) {
|
||||
pj_ioqueue_unregister(resv->udp_key);
|
||||
resv->udp_key = NULL;
|
||||
resv->udp_sock = PJ_INVALID_SOCKET;
|
||||
} else if (resv->udp_sock != PJ_INVALID_SOCKET) {
|
||||
pj_sock_close(resv->udp_sock);
|
||||
resv->udp_sock = PJ_INVALID_SOCKET;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Initialize UDP socket */
|
||||
static pj_status_t init_sock(pj_dns_resolver *resv)
|
||||
{
|
||||
pj_ioqueue_callback socket_cb;
|
||||
pj_status_t status;
|
||||
|
||||
/* Create the UDP socket */
|
||||
status = pj_sock_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, &resv->udp_sock);
|
||||
if (status != PJ_SUCCESS)
|
||||
return status;
|
||||
|
||||
/* Bind to any address/port */
|
||||
status = pj_sock_bind_in(resv->udp_sock, 0, 0);
|
||||
if (status != PJ_SUCCESS)
|
||||
return status;
|
||||
|
||||
/* Register to ioqueue */
|
||||
pj_bzero(&socket_cb, sizeof(socket_cb));
|
||||
socket_cb.on_read_complete = &on_read_complete;
|
||||
status = pj_ioqueue_register_sock(resv->pool, resv->ioqueue,
|
||||
resv->udp_sock, resv, &socket_cb,
|
||||
&resv->udp_key);
|
||||
if (status != PJ_SUCCESS)
|
||||
return status;
|
||||
|
||||
pj_ioqueue_op_key_init(&resv->udp_op_key, sizeof(resv->udp_op_key));
|
||||
|
||||
/* Start asynchronous read to the UDP socket */
|
||||
resv->udp_len = sizeof(resv->udp_rx_pkt);
|
||||
resv->udp_addr_len = sizeof(resv->udp_src_addr);
|
||||
status = pj_ioqueue_recvfrom(resv->udp_key, &resv->udp_op_key,
|
||||
resv->udp_rx_pkt, &resv->udp_len,
|
||||
PJ_IOQUEUE_ALWAYS_ASYNC,
|
||||
&resv->udp_src_addr, &resv->udp_addr_len);
|
||||
if (status != PJ_EPENDING)
|
||||
return status;
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/* Initialize DNS settings with default values */
|
||||
PJ_DEF(void) pj_dns_settings_default(pj_dns_settings *s)
|
||||
{
|
||||
|
@ -247,7 +303,6 @@ PJ_DEF(pj_status_t) pj_dns_resolver_create( pj_pool_factory *pf,
|
|||
{
|
||||
pj_pool_t *pool;
|
||||
pj_dns_resolver *resv;
|
||||
pj_ioqueue_callback socket_cb;
|
||||
pj_status_t status;
|
||||
|
||||
/* Sanity check */
|
||||
|
@ -302,37 +357,11 @@ PJ_DEF(pj_status_t) pj_dns_resolver_create( pj_pool_factory *pf,
|
|||
resv->hquerybyres = pj_hash_create(pool, Q_HASH_TABLE_SIZE);
|
||||
pj_list_init(&resv->query_free_nodes);
|
||||
|
||||
/* Create the UDP socket */
|
||||
status = pj_sock_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, &resv->udp_sock);
|
||||
/* Initialize the UDP socket */
|
||||
status = init_sock(resv);
|
||||
if (status != PJ_SUCCESS)
|
||||
goto on_error;
|
||||
|
||||
/* Bind to any address/port */
|
||||
status = pj_sock_bind_in(resv->udp_sock, 0, 0);
|
||||
if (status != PJ_SUCCESS)
|
||||
goto on_error;
|
||||
|
||||
/* Register to ioqueue */
|
||||
pj_bzero(&socket_cb, sizeof(socket_cb));
|
||||
socket_cb.on_read_complete = &on_read_complete;
|
||||
status = pj_ioqueue_register_sock(pool, resv->ioqueue, resv->udp_sock,
|
||||
resv, &socket_cb, &resv->udp_key);
|
||||
if (status != PJ_SUCCESS)
|
||||
goto on_error;
|
||||
|
||||
pj_ioqueue_op_key_init(&resv->udp_op_key, sizeof(resv->udp_op_key));
|
||||
|
||||
/* Start asynchronous read to the UDP socket */
|
||||
resv->udp_len = sizeof(resv->udp_rx_pkt);
|
||||
resv->udp_addr_len = sizeof(resv->udp_src_addr);
|
||||
status = pj_ioqueue_recvfrom(resv->udp_key, &resv->udp_op_key,
|
||||
resv->udp_rx_pkt, &resv->udp_len,
|
||||
PJ_IOQUEUE_ALWAYS_ASYNC,
|
||||
&resv->udp_src_addr, &resv->udp_addr_len);
|
||||
if (status != PJ_EPENDING)
|
||||
goto on_error;
|
||||
|
||||
|
||||
/* Looks like everything is okay */
|
||||
*p_resolver = resv;
|
||||
return PJ_SUCCESS;
|
||||
|
@ -392,14 +421,7 @@ PJ_DEF(pj_status_t) pj_dns_resolver_destroy( pj_dns_resolver *resolver,
|
|||
resolver->timer = NULL;
|
||||
}
|
||||
|
||||
if (resolver->udp_key != NULL) {
|
||||
pj_ioqueue_unregister(resolver->udp_key);
|
||||
resolver->udp_key = NULL;
|
||||
resolver->udp_sock = PJ_INVALID_SOCKET;
|
||||
} else if (resolver->udp_sock != PJ_INVALID_SOCKET) {
|
||||
pj_sock_close(resolver->udp_sock);
|
||||
resolver->udp_sock = PJ_INVALID_SOCKET;
|
||||
}
|
||||
close_sock(resolver);
|
||||
|
||||
if (resolver->own_ioqueue && resolver->ioqueue) {
|
||||
pj_ioqueue_destroy(resolver->ioqueue);
|
||||
|
@ -603,13 +625,36 @@ static pj_status_t transmit_query(pj_dns_resolver *resolver,
|
|||
pj_ssize_t sent = (pj_ssize_t) pkt_size;
|
||||
struct nameserver *ns = &resolver->ns[servers[i]];
|
||||
|
||||
pj_sock_sendto(resolver->udp_sock, resolver->udp_tx_pkt, &sent, 0,
|
||||
&resolver->ns[servers[i]].addr, sizeof(pj_sockaddr_in));
|
||||
status = pj_sock_sendto(resolver->udp_sock, resolver->udp_tx_pkt,
|
||||
&sent, 0, &resolver->ns[servers[i]].addr,
|
||||
sizeof(pj_sockaddr_in));
|
||||
|
||||
PJ_LOG(4,(resolver->name.ptr,
|
||||
#if defined(PJ_IPHONE_OS_HAS_MULTITASKING_SUPPORT) && \
|
||||
PJ_IPHONE_OS_HAS_MULTITASKING_SUPPORT!=0
|
||||
/* Re-init dead UDP sockets, see ticket #1107 & #1603.
|
||||
* Note: PJ_STATUS_FROM_OS(EPIPE) == PJ_ERRNO_START_SYS + 32.
|
||||
*/
|
||||
if (status == PJ_ERRNO_START_SYS + 32) {
|
||||
close_sock(resolver);
|
||||
status = init_sock(resolver);
|
||||
if (status != PJ_SUCCESS) {
|
||||
PJ_PERROR(1,(THIS_FILE, status, "Error reinit UDP socket"));
|
||||
return status;
|
||||
}
|
||||
|
||||
PJ_LOG(3,(THIS_FILE, "UDP socket reinitialized."));
|
||||
|
||||
/* Try to send again */
|
||||
status = pj_sock_sendto(resolver->udp_sock, resolver->udp_tx_pkt,
|
||||
&sent, 0, &resolver->ns[servers[i]].addr,
|
||||
sizeof(pj_sockaddr_in));
|
||||
}
|
||||
#endif
|
||||
|
||||
PJ_PERROR(4,(resolver->name.ptr, status,
|
||||
"%s %d bytes to NS %d (%s:%d): DNS %s query for %s",
|
||||
(q->transmit_cnt==0? "Transmitting":"Re-transmitting"),
|
||||
(int)sent, servers[i],
|
||||
(int)pkt_size, servers[i],
|
||||
pj_inet_ntoa(ns->addr.sin_addr),
|
||||
(int)pj_ntohs(ns->addr.sin_port),
|
||||
pj_dns_get_type_name(q->key.qtype),
|
||||
|
|
Loading…
Reference in New Issue