Author: file Date: Sat Apr 4 14:46:19 2015 New Revision: 433993 URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=433993 Log: Simplify code, reduce memory usage, and restrict queries based on what transports are available.
Modified: team/group/dns_pjsip/include/asterisk/dns_core.h team/group/dns_pjsip/main/dns_core.c team/group/dns_pjsip/res/res_pjsip.c team/group/dns_pjsip/res/res_pjsip/pjsip_resolver.c Modified: team/group/dns_pjsip/include/asterisk/dns_core.h URL: http://svnview.digium.com/svn/asterisk/team/group/dns_pjsip/include/asterisk/dns_core.h?view=diff&rev=433993&r1=433992&r2=433993 ============================================================================== --- team/group/dns_pjsip/include/asterisk/dns_core.h (original) +++ team/group/dns_pjsip/include/asterisk/dns_core.h Sat Apr 4 14:46:19 2015 @@ -205,6 +205,15 @@ const char *ast_dns_record_get_data(const struct ast_dns_record *record); /*! + * \brief Retrieve the size of the raw DNS record + * + * \param record The DNS record + * + * \return the size of the raw DNS record + */ +size_t ast_dns_record_get_data_size(const struct ast_dns_record *record); + +/*! * \brief Get the next DNS record * * \param record The current DNS record Modified: team/group/dns_pjsip/main/dns_core.c URL: http://svnview.digium.com/svn/asterisk/team/group/dns_pjsip/main/dns_core.c?view=diff&rev=433993&r1=433992&r2=433993 ============================================================================== --- team/group/dns_pjsip/main/dns_core.c (original) +++ team/group/dns_pjsip/main/dns_core.c Sat Apr 4 14:46:19 2015 @@ -163,6 +163,11 @@ return record->data_ptr; } +size_t ast_dns_record_get_data_size(const struct ast_dns_record *record) +{ + return record->data_len; +} + const struct ast_dns_record *ast_dns_record_get_next(const struct ast_dns_record *record) { return AST_LIST_NEXT(record, list); Modified: team/group/dns_pjsip/res/res_pjsip.c URL: http://svnview.digium.com/svn/asterisk/team/group/dns_pjsip/res/res_pjsip.c?view=diff&rev=433993&r1=433992&r2=433993 ============================================================================== --- team/group/dns_pjsip/res/res_pjsip.c (original) +++ team/group/dns_pjsip/res/res_pjsip.c Sat Apr 4 14:46:19 2015 @@ -3441,8 +3441,6 @@ return AST_MODULE_LOAD_DECLINE; } - ast_sip_initialize_resolver(); - pjsip_tsx_layer_init_module(ast_pjsip_endpoint); pjsip_ua_init_module(ast_pjsip_endpoint, NULL); @@ -3474,6 +3472,9 @@ pj_caching_pool_destroy(&caching_pool); return AST_MODULE_LOAD_DECLINE; } + + ast_sip_initialize_resolver(); + ast_sip_initialize_dns(); if (ast_sip_initialize_distributor()) { ast_log(LOG_ERROR, "Failed to register distributor module. Aborting load\n"); Modified: team/group/dns_pjsip/res/res_pjsip/pjsip_resolver.c URL: http://svnview.digium.com/svn/asterisk/team/group/dns_pjsip/res/res_pjsip/pjsip_resolver.c?view=diff&rev=433993&r1=433992&r2=433993 ============================================================================== --- team/group/dns_pjsip/res/res_pjsip/pjsip_resolver.c (original) +++ team/group/dns_pjsip/res/res_pjsip/pjsip_resolver.c Sat Apr 4 14:46:19 2015 @@ -29,48 +29,57 @@ #include "asterisk/res_pjsip.h" #include "include/res_pjsip_private.h" -/*! \brief Structure which contains resolved target information */ -struct sip_resolved_target { - /*! \brief The record type that this target originated from */ +/*! \brief Structure which contains transport+port information for an active query */ +struct sip_target { /*! \brief The transport to be used */ pjsip_transport_type_e transport; /*! \brief The port */ int port; - /*! \brief Resulting addresses */ - pjsip_server_addresses addresses; }; -/*! \brief The vector used for addresses */ -AST_VECTOR(addresses, struct sip_resolved_target); +/*! \brief The vector used for current targets */ +AST_VECTOR(targets, struct sip_target); /*! \brief Structure which keeps track of resolution */ struct sip_resolve { /*! \brief Addresses currently being resolved, indexed based on index of queries in query set */ - struct addresses resolving; - /*! \brief Addresses that have been resolved, to ensure proper sorting go from back to front */ - struct addresses resolved; + struct targets resolving; /*! \brief Active queries */ struct ast_dns_query_set *queries; + /*! \brief Current viable server addresses */ + pjsip_server_addresses addresses; /*! \brief Callback to invoke upon completion */ pjsip_resolver_callback *callback; /*! \brief User provided data */ void *token; }; +/*! \brief Available transports on the system */ +static int sip_available_transports[] = { + /* This is a list of transports understood by the resolver, with whether they are + * available as a valid transport stored + */ + [PJSIP_TRANSPORT_UDP] = 0, + [PJSIP_TRANSPORT_TCP] = 0, + [PJSIP_TRANSPORT_TLS] = 0, + [PJSIP_TRANSPORT_UDP6] = 0, + [PJSIP_TRANSPORT_TCP6] = 0, + [PJSIP_TRANSPORT_TLS6] = 0, +}; + /*! \brief Destructor for resolution data */ static void sip_resolve_destroy(void *data) { struct sip_resolve *resolve = data; AST_VECTOR_FREE(&resolve->resolving); - AST_VECTOR_FREE(&resolve->resolved); ao2_cleanup(resolve->queries); } /*! \brief Perform resolution but keep transport and port information */ static int sip_resolve_add(struct sip_resolve *resolve, const char *name, int rr_type, int rr_class, pjsip_transport_type_e transport, int port) { - struct sip_resolved_target target = { + struct sip_target target = { .transport = transport, .port = port, }; @@ -101,31 +110,18 @@ static int sip_resolve_invoke_user_callback(void *data) { struct sip_resolve *resolve = data; - pjsip_server_addresses addresses = { - .count = 0, - }; int idx; - /* We start from the end because the records with the highest preference are there */ - for (idx = AST_VECTOR_SIZE(&resolve->resolved) - 1; idx >= 0; --idx) { - struct sip_resolved_target *target = AST_VECTOR_GET_ADDR(&resolve->resolved, idx); - int address_pos; - char addr[256]; - - for (address_pos = 0; address_pos < target->addresses.count; ++address_pos) { - ast_debug(2, "[%p] Address '%d' is '%s' port '%d' with transport '%s'\n", - resolve, addresses.count, pj_sockaddr_print(&target->addresses.entry[address_pos].addr, addr, sizeof(addr), 0), - pj_sockaddr_get_port(&target->addresses.entry[address_pos].addr), pjsip_transport_get_type_name(target->addresses.entry[address_pos].type)); - addresses.entry[addresses.count++] = target->addresses.entry[address_pos]; - } - - if (addresses.count == PJSIP_MAX_RESOLVED_ADDRESSES) { - break; - } - } - - ast_debug(2, "[%p] Invoking user callback with '%d' addresses\n", resolve, addresses.count); - resolve->callback(PJ_SUCCESS, resolve->token, &addresses); + for (idx = 0; idx < resolve->addresses.count; ++idx) { + char addr[PJ_INET6_ADDRSTRLEN + 10]; + + ast_debug(2, "[%p] Address '%d' is %s with transport '%s'\n", + resolve, idx, pj_sockaddr_print(&resolve->addresses.entry[idx].addr, addr, sizeof(addr), 3), + pjsip_transport_get_type_name(resolve->addresses.entry[idx].type)); + } + + ast_debug(2, "[%p] Invoking user callback with '%d' addresses\n", resolve, resolve->addresses.count); + resolve->callback(PJ_SUCCESS, resolve->token, &resolve->addresses); ao2_ref(resolve, -1); @@ -137,8 +133,8 @@ { struct sip_resolve *resolve = ast_dns_query_set_get_data(query_set); struct ast_dns_query_set *queries = resolve->queries; - struct addresses resolving; - int idx; + struct targets resolving; + int idx, address_count = 0; ast_debug(2, "[%p] All parallel queries completed\n", resolve); @@ -148,13 +144,16 @@ * to the old. */ resolving = resolve->resolving; - AST_VECTOR_INIT(&resolve->resolving, 1); - - /* Add any AAAA/A records to the resolved list */ + AST_VECTOR_INIT(&resolve->resolving, 0); + + /* The order of queries is what defines the preference order for the records within this invocation. + * The preference order overall is defined as a result of drilling down from other records. Each + * invocation starts placing records at the beginning, moving others that may have already been present. + */ for (idx = 0; idx < ast_dns_query_set_num_queries(queries); ++idx) { struct ast_dns_query *query = ast_dns_query_set_get(queries, idx); struct ast_dns_result *result = ast_dns_query_get_result(query); - struct sip_resolved_target *target; + struct sip_target *target; const struct ast_dns_record *record; if (!result) { @@ -165,31 +164,66 @@ target = AST_VECTOR_GET_ADDR(&resolving, idx); for (record = ast_dns_result_get_records(result); record; record = ast_dns_record_get_next(record)) { - if (ast_dns_record_get_rr_type(record) == ns_t_a) { - ast_debug(2, "[%p] A record received on target '%s'\n", resolve, ast_dns_query_get_name(query)); - target->addresses.entry[target->addresses.count].type = target->transport; - target->addresses.entry[target->addresses.count].addr_len = sizeof(pj_sockaddr_in); - pj_sockaddr_init(pj_AF_INET(), &target->addresses.entry[target->addresses.count].addr, NULL, target->port); - target->addresses.entry[target->addresses.count++].addr.ipv4.sin_addr = *(struct pj_in_addr*)ast_dns_record_get_data(record); - } else if (ast_dns_record_get_rr_type(record) == ns_t_aaaa) { - ast_debug(2, "[%p] AAAA record received on target '%s'\n", resolve, ast_dns_query_get_name(query)); - target->addresses.entry[target->addresses.count].type = target->transport; - target->addresses.entry[target->addresses.count].addr_len = sizeof(pj_sockaddr_in6); - pj_sockaddr_init(pj_AF_INET6(), &target->addresses.entry[target->addresses.count].addr, NULL, target->port); - pj_memcpy(&target->addresses.entry[target->addresses.count++].addr.ipv6.sin6_addr, ast_dns_record_get_data(record), - sizeof(pj_sockaddr_in6)); + + if (ast_dns_record_get_rr_type(record) == ns_t_a || + ast_dns_record_get_rr_type(record) == ns_t_aaaa) { + + /* If the maximum number of addresses has already been reached by this query set, skip subsequent + * records as they have lower preference - any existing ones may get replaced/moved if another + * invocation occurs after this one + */ + if (address_count == PJSIP_MAX_RESOLVED_ADDRESSES) { + continue; + } + + /* Move any existing addresses so we can make room for this record, this may hurt your head slightly but + * essentially it figures out the maximum number of previous addresses that can exist and caps the + * the memmove operation to that + */ + memmove(&resolve->addresses.entry[address_count + 1], &resolve->addresses.entry[address_count], + sizeof(resolve->addresses.entry[0]) * + MIN(resolve->addresses.count, PJSIP_MAX_RESOLVED_ADDRESSES - address_count - 1)); + + resolve->addresses.entry[address_count].type = target->transport; + + /* Populate address information for the new address entry */ + if (ast_dns_record_get_rr_type(record) == ns_t_a) { + ast_debug(2, "[%p] A record received on target '%s'\n", resolve, ast_dns_query_get_name(query)); + resolve->addresses.entry[address_count].addr_len = sizeof(pj_sockaddr_in); + pj_sockaddr_init(pj_AF_INET(), &resolve->addresses.entry[address_count].addr, NULL, + target->port); + resolve->addresses.entry[address_count].addr.ipv4.sin_addr = *(struct pj_in_addr*)ast_dns_record_get_data(record); + } else { + ast_debug(2, "[%p] AAAA record received on target '%s'\n", resolve, ast_dns_query_get_name(query)); + resolve->addresses.entry[address_count].addr_len = sizeof(pj_sockaddr_in6); + pj_sockaddr_init(pj_AF_INET6(), &resolve->addresses.entry[address_count].addr, NULL, + target->port); + pj_memcpy(&resolve->addresses.entry[address_count].addr.ipv6.sin6_addr, ast_dns_record_get_data(record), + ast_dns_record_get_data_size(record)); + } + + address_count++; } else if (ast_dns_record_get_rr_type(record) == ns_t_srv) { + /* SRV records just create new queries for AAAA+A, nothing fancy */ ast_debug(2, "[%p] SRV record received on target '%s'\n", resolve, ast_dns_query_get_name(query)); - sip_resolve_add(resolve, ast_dns_srv_get_host(record), ns_t_a, ns_c_in, target->transport, ast_dns_srv_get_port(record)); - sip_resolve_add(resolve, ast_dns_srv_get_host(record), ns_t_aaaa, ns_c_in, target->transport, ast_dns_srv_get_port(record)); + + if (sip_available_transports[target->transport + PJSIP_TRANSPORT_IPV6]) { + sip_resolve_add(resolve, ast_dns_srv_get_host(record), ns_t_aaaa, ns_c_in, target->transport + PJSIP_TRANSPORT_IPV6, + ast_dns_srv_get_port(record)); + } + + if (sip_available_transports[target->transport]) { + sip_resolve_add(resolve, ast_dns_srv_get_host(record), ns_t_a, ns_c_in, target->transport, + ast_dns_srv_get_port(record)); + } } } - - /* Only add this finished result if there's actually addresses on it */ - if (target->addresses.count) { - AST_VECTOR_APPEND(&resolve->resolved, *target); - } - } + } + + /* Update the server addresses to include any new entries, but since it's limited to the maximum resolved + * it must never exceed that + */ + resolve->addresses.count = MIN(resolve->addresses.count + address_count, PJSIP_MAX_RESOLVED_ADDRESSES); /* Free the vector we stole as we are responsible for it */ AST_VECTOR_FREE(&resolving); @@ -202,8 +236,7 @@ return; } - /* Invoke callback with target resolved addresses */ - ast_debug(2, "[%p] Resolution completed - %zd viable targets\n", resolve, AST_VECTOR_SIZE(&resolve->resolved)); + ast_debug(2, "[%p] Resolution completed - %d viable targets\n", resolve, resolve->addresses.count); /* Push a task to invoke the callback, we do this so it is guaranteed to run in a PJSIP thread */ ao2_ref(resolve, +1); @@ -237,7 +270,7 @@ int ip_addr_ver; pjsip_transport_type_e type = target->type; struct sip_resolve *resolve; - char host[NI_MAXHOST], srv[NI_MAXHOST]; + char host[NI_MAXHOST]; int res = 0; ast_copy_pj_str(host, &target->addr.host, sizeof(host)); @@ -303,7 +336,7 @@ resolve->callback = cb; resolve->token = token; - if (AST_VECTOR_INIT(&resolve->resolving, 2) || AST_VECTOR_INIT(&resolve->resolved, 2)) { + if (AST_VECTOR_INIT(&resolve->resolving, 2)) { ao2_ref(resolve, -1); cb(PJ_EINVAL, token, NULL); return; @@ -311,23 +344,33 @@ ast_debug(2, "[%p] Created resolution tracking for target '%s'\n", resolve, host); - res |= sip_resolve_add(resolve, host, ns_t_a, ns_c_in, (type == PJSIP_TRANSPORT_UNSPECIFIED ? PJSIP_TRANSPORT_UDP : type), target->addr.port); - res |= sip_resolve_add(resolve, host, ns_t_aaaa, ns_c_in, (type == PJSIP_TRANSPORT_UNSPECIFIED ? PJSIP_TRANSPORT_UDP : type), target->addr.port); - /* If no port has been specified we can do NAPTR + SRV */ if (!target->addr.port) { - if (type == PJSIP_TRANSPORT_UDP || type == PJSIP_TRANSPORT_UNSPECIFIED) { + char srv[NI_MAXHOST]; + + if ((type == PJSIP_TRANSPORT_TLS || type == PJSIP_TRANSPORT_UNSPECIFIED) && + (sip_available_transports[PJSIP_TRANSPORT_TLS] || sip_available_transports[PJSIP_TRANSPORT_TLS6])) { + snprintf(srv, sizeof(srv), "_sips._tcp.%s", host); + res |= sip_resolve_add(resolve, srv, ns_t_srv, ns_c_in, PJSIP_TRANSPORT_TLS, 0); + } + if ((type == PJSIP_TRANSPORT_TCP || type == PJSIP_TRANSPORT_UNSPECIFIED) && + (sip_available_transports[PJSIP_TRANSPORT_TCP] || sip_available_transports[PJSIP_TRANSPORT_TCP6])) { + snprintf(srv, sizeof(srv), "_sip._tcp.%s", host); + res |= sip_resolve_add(resolve, srv, ns_t_srv, ns_c_in, PJSIP_TRANSPORT_TCP, 0); + } + if ((type == PJSIP_TRANSPORT_UDP || type == PJSIP_TRANSPORT_UNSPECIFIED) && + (sip_available_transports[PJSIP_TRANSPORT_UDP] || sip_available_transports[PJSIP_TRANSPORT_UDP6])) { snprintf(srv, sizeof(srv), "_sip._udp.%s", host); res |= sip_resolve_add(resolve, srv, ns_t_srv, ns_c_in, PJSIP_TRANSPORT_UDP, 0); } - if (type == PJSIP_TRANSPORT_TCP || type == PJSIP_TRANSPORT_UNSPECIFIED) { - snprintf(srv, sizeof(srv), "_sip._tcp.%s", host); - res |= sip_resolve_add(resolve, srv, ns_t_srv, ns_c_in, PJSIP_TRANSPORT_TCP, 0); - } - if (type == PJSIP_TRANSPORT_TLS || type == PJSIP_TRANSPORT_UNSPECIFIED) { - snprintf(srv, sizeof(srv), "_sips._tcp.%s", host); - res |= sip_resolve_add(resolve, srv, ns_t_srv, ns_c_in, PJSIP_TRANSPORT_TLS, 0); - } + } + + if (sip_available_transports[PJSIP_TRANSPORT_UDP6]) { + res |= sip_resolve_add(resolve, host, ns_t_aaaa, ns_c_in, (type == PJSIP_TRANSPORT_UNSPECIFIED ? PJSIP_TRANSPORT_UDP6 : type), target->addr.port); + } + + if (sip_available_transports[PJSIP_TRANSPORT_UDP]) { + res |= sip_resolve_add(resolve, host, ns_t_a, ns_c_in, (type == PJSIP_TRANSPORT_UNSPECIFIED ? PJSIP_TRANSPORT_UDP : type), target->addr.port); } if (res) { @@ -342,8 +385,45 @@ ao2_ref(resolve, -1); } +/*! \brief Internal function used to determine if a transport is available */ +static void sip_check_transport(pj_pool_t *pool, pjsip_transport_type_e type, const char *name) +{ + pjsip_tpmgr_fla2_param prm; + + pjsip_tpmgr_fla2_param_default(&prm); + prm.tp_type = type; + + if (pjsip_tpmgr_find_local_addr2(pjsip_endpt_get_tpmgr(ast_sip_get_pjsip_endpoint()), + pool, &prm) == PJ_SUCCESS) { + ast_verb(2, "'%s' is an available SIP transport\n", name); + sip_available_transports[type] = 1; + } else { + ast_verb(2, "'%s' is not an available SIP transport, disabling resolver support for it\n", + name); + } +} + static int sip_replace_resolver(void *data) { + pj_pool_t *pool; + + + pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(), "Transport Availability", 256, 256); + if (!pool) { + return -1; + } + + /* Determine what transports are available on the system */ + sip_check_transport(pool, PJSIP_TRANSPORT_UDP, "UDP+IPv4"); + sip_check_transport(pool, PJSIP_TRANSPORT_TCP, "TCP+IPv4"); + sip_check_transport(pool, PJSIP_TRANSPORT_TLS, "TLS+IPv4"); + sip_check_transport(pool, PJSIP_TRANSPORT_UDP6, "UDP+IPv6"); + sip_check_transport(pool, PJSIP_TRANSPORT_TCP6, "TCP+IPv6"); + sip_check_transport(pool, PJSIP_TRANSPORT_TLS6, "TLS+IPv6"); + + pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool); + + /* Replace the PJSIP resolver with our own implementation */ pjsip_endpt_set_resolver_implementation(ast_sip_get_pjsip_endpoint(), sip_resolve); return 0; } -- _____________________________________________________________________ -- Bandwidth and Colocation Provided by http://www.api-digital.com -- svn-commits mailing list To UNSUBSCRIBE or update options visit: http://lists.digium.com/mailman/listinfo/svn-commits