/* DNS resolver callback */ static void dns_srv_resolver_cb(void *user_data, pj_status_t status, const pj_dns_srv_record *rec) { pj_stun_sock *stun_sock = (pj_stun_sock*) user_data; /* Clear query */ stun_sock->q = NULL; /* Handle error */ if (status != PJ_SUCCESS) { sess_fail(stun_sock, PJ_STUN_SOCK_DNS_OP, status); return; } pj_assert(rec->count); pj_assert(rec->entry[0].server.addr_count); PJ_TODO(SUPPORT_IPV6_IN_RESOLVER); pj_assert(stun_sock->af == pj_AF_INET()); /* Set the address */ pj_sockaddr_in_init(&stun_sock->srv_addr.ipv4, NULL, rec->entry[0].port); stun_sock->srv_addr.ipv4.sin_addr = rec->entry[0].server.addr[0]; /* Start sending Binding request */ get_mapped_addr(stun_sock); }
/* Start socket. */ PJ_DEF(pj_status_t) pj_stun_sock_start( pj_stun_sock *stun_sock, const pj_str_t *domain, pj_uint16_t default_port, pj_dns_resolver *resolver) { pj_status_t status; PJ_ASSERT_RETURN(stun_sock && domain && default_port, PJ_EINVAL); /* Check whether the domain contains IP address */ stun_sock->srv_addr.addr.sa_family = (pj_uint16_t)stun_sock->af; status = pj_inet_pton(stun_sock->af, domain, pj_sockaddr_get_addr(&stun_sock->srv_addr)); if (status != PJ_SUCCESS) { stun_sock->srv_addr.addr.sa_family = (pj_uint16_t)0; } /* If resolver is set, try to resolve with DNS SRV first. It * will fallback to DNS A/AAAA when no SRV record is found. */ if (status != PJ_SUCCESS && resolver) { const pj_str_t res_name = pj_str("_stun._udp."); unsigned opt; pj_assert(stun_sock->q == NULL); opt = PJ_DNS_SRV_FALLBACK_A; if (stun_sock->af == pj_AF_INET6()) { opt |= (PJ_DNS_SRV_RESOLVE_AAAA | PJ_DNS_SRV_FALLBACK_AAAA); } status = pj_dns_srv_resolve(domain, &res_name, default_port, stun_sock->pool, resolver, opt, stun_sock, &dns_srv_resolver_cb, &stun_sock->q); /* Processing will resume when the DNS SRV callback is called */ return status; } else { if (status != PJ_SUCCESS) { pj_addrinfo ai; unsigned cnt = 1; status = pj_getaddrinfo(stun_sock->af, domain, &cnt, &ai); if (status != PJ_SUCCESS) return status; pj_sockaddr_cp(&stun_sock->srv_addr, &ai.ai_addr); } pj_sockaddr_set_port(&stun_sock->srv_addr, (pj_uint16_t)default_port); /* Start sending Binding request */ return get_mapped_addr(stun_sock); } }
/* Keep-alive timer callback */ static void ka_timer_cb(pj_timer_heap_t *th, pj_timer_entry *te) { pj_stun_sock *stun_sock; stun_sock = (pj_stun_sock *) te->user_data; PJ_UNUSED_ARG(th); /* Time to send STUN Binding request */ if (get_mapped_addr(stun_sock) != PJ_SUCCESS) return; /* Next keep-alive timer will be scheduled once the request * is complete. */ }
/* DNS resolver callback */ static void dns_srv_resolver_cb(void *user_data, pj_status_t status, const pj_dns_srv_record *rec) { pj_stun_sock *stun_sock = (pj_stun_sock*) user_data; pj_grp_lock_acquire(stun_sock->grp_lock); /* Clear query */ stun_sock->q = NULL; /* Handle error */ if (status != PJ_SUCCESS) { sess_fail(stun_sock, PJ_STUN_SOCK_DNS_OP, status); pj_grp_lock_release(stun_sock->grp_lock); return; } pj_assert(rec->count); pj_assert(rec->entry[0].server.addr_count); pj_assert(rec->entry[0].server.addr[0].af == stun_sock->af); /* Set the address */ pj_sockaddr_init(stun_sock->af, &stun_sock->srv_addr, NULL, rec->entry[0].port); if (stun_sock->af == pj_AF_INET6()) { stun_sock->srv_addr.ipv6.sin6_addr = rec->entry[0].server.addr[0].ip.v6; } else { stun_sock->srv_addr.ipv4.sin_addr = rec->entry[0].server.addr[0].ip.v4; } /* Start sending Binding request */ get_mapped_addr(stun_sock); pj_grp_lock_release(stun_sock->grp_lock); }