From c157bc02e842ad3b6eb84fc841d07504fbb423ec Mon Sep 17 00:00:00 2001 From: Nanang Izzuddin Date: Tue, 15 Jan 2013 14:21:07 +0000 Subject: Fix #1603: reinit UDP socket of DNS resolver when sendto() returning EPIPE. git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@4317 74dad513-b988-da41-8d7b-12977e46ad98 --- pjlib-util/src/pjlib-util/resolver.c | 127 ++++++++++++++++++++++++----------- 1 file changed, 86 insertions(+), 41 deletions(-) (limited to 'pjlib-util') diff --git a/pjlib-util/src/pjlib-util/resolver.c b/pjlib-util/src/pjlib-util/resolver.c index b80fd2e5..0a55eada 100644 --- a/pjlib-util/src/pjlib-util/resolver.c +++ b/pjlib-util/src/pjlib-util/resolver.c @@ -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); - 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); + /* Initialize the UDP socket */ + status = init_sock(resv); 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), -- cgit v1.2.3