/* * Convert address string with numbers and dots to binary IP address. */ PJ_DEF(pj_in_addr) pj_inet_addr(const pj_str_t *cp) { pj_in_addr addr; pj_inet_aton(cp, &addr); return addr; }
static int format_test(void) { pj_str_t s = pj_str(ADDRESS); unsigned char *p; pj_in_addr addr; char zero[64]; pj_sockaddr_in addr2; const pj_str_t *hostname; PJ_LOG(3,("test", "...format_test()")); /* pj_inet_aton() */ if (pj_inet_aton(&s, &addr) != 1) return -10; /* Check the result. */ p = (unsigned char*)&addr; if (p[0]!=A0 || p[1]!=A1 || p[2]!=A2 || p[3]!=A3) { PJ_LOG(3,("test", " error: mismatched address. p0=%d, p1=%d, " "p2=%d, p3=%d", p[0] & 0xFF, p[1] & 0xFF, p[2] & 0xFF, p[3] & 0xFF)); return -15; } /* pj_inet_ntoa() */ p = (unsigned char*) pj_inet_ntoa(addr); if (!p) return -20; if (pj_strcmp2(&s, (char*)p) != 0) return -30; /* Test that pj_sockaddr_in_init() initialize the whole structure, * including sin_zero. */ pj_sockaddr_in_init(&addr2, 0, 1000); pj_bzero(zero, sizeof(zero)); if (pj_memcmp(addr2.sin_zero, zero, sizeof(addr2.sin_zero)) != 0) return -35; /* pj_gethostname() */ hostname = pj_gethostname(); if (!hostname || !hostname->ptr || !hostname->slen) return -40; PJ_LOG(3,("test", "....hostname is %.*s", (int)hostname->slen, hostname->ptr)); /* pj_gethostaddr() */ return 0; }
/* * Internal: * determine if an address is a valid IP address, and if it is, * return the IP version (4 or 6). */ static int get_ip_addr_ver(const pj_str_t *host) { pj_in_addr dummy; pj_in6_addr dummy6; /* First check with inet_aton() */ if (pj_inet_aton(host, &dummy) > 0) return 4; /* Then check if this is an IPv6 address */ if (pj_inet_pton(pj_AF_INET6(), host, &dummy6) == PJ_SUCCESS) return 6; /* Not an IP address */ return 0; }
/* * Generic testing for transport, to make sure that basic * attributes have been initialized properly. */ int generic_transport_test(pjsip_transport *tp) { PJ_LOG(3,(THIS_FILE, " structure test...")); /* Check that local address name is valid. */ { struct pj_in_addr addr; /* Note: inet_aton() returns non-zero if addr is valid! */ if (pj_inet_aton(&tp->local_name.host, &addr) != 0) { if (addr.s_addr==PJ_INADDR_ANY || addr.s_addr==PJ_INADDR_NONE) { PJ_LOG(3,(THIS_FILE, " Error: invalid address name")); return -420; } } else { /* It's okay. local_name.host may be a hostname instead of * IP address. */ } } /* Check that port is valid. */ if (tp->local_name.port <= 0) { return -430; } /* Check length of address (for now we only check against sockaddr_in). */ if (tp->addr_len != sizeof(pj_sockaddr_in)) return -440; /* Check type. */ if (tp->key.type == PJSIP_TRANSPORT_UNSPECIFIED) return -450; /* That's it. */ return PJ_SUCCESS; }
/* * This is the main function for performing server resolution. */ PJ_DEF(void) pjsip_resolve( pjsip_resolver_t *resolver, pj_pool_t *pool, const pjsip_host_info *target, void *token, pjsip_resolver_callback *cb) { pjsip_server_addresses svr_addr; pj_status_t status = PJ_SUCCESS; int ip_addr_ver; struct query *query; pjsip_transport_type_e type = target->type; /* Is it IP address or hostname? And if it's an IP, which version? */ ip_addr_ver = get_ip_addr_ver(&target->addr.host); /* Set the transport type if not explicitly specified. * RFC 3263 section 4.1 specify rules to set up this. */ if (type == PJSIP_TRANSPORT_UNSPECIFIED) { if (ip_addr_ver || (target->addr.port != 0)) { #if PJ_HAS_TCP if (target->flag & PJSIP_TRANSPORT_SECURE) { type = PJSIP_TRANSPORT_TLS; } else if (target->flag & PJSIP_TRANSPORT_RELIABLE) { type = PJSIP_TRANSPORT_TCP; } else #endif { type = PJSIP_TRANSPORT_UDP; } } else { /* No type or explicit port is specified, and the address is * not IP address. * In this case, full NAPTR resolution must be performed. * But we don't support it (yet). */ #if PJ_HAS_TCP if (target->flag & PJSIP_TRANSPORT_SECURE) { type = PJSIP_TRANSPORT_TLS; } else if (target->flag & PJSIP_TRANSPORT_RELIABLE) { type = PJSIP_TRANSPORT_TCP; } else #endif { type = PJSIP_TRANSPORT_UDP; } } /* Add IPv6 flag for IPv6 address */ if (ip_addr_ver == 6) type = (pjsip_transport_type_e)((int)type + PJSIP_TRANSPORT_IPV6); } /* If target is an IP address, or if resolver is not configured, * we can just finish the resolution now using pj_gethostbyname() */ if (ip_addr_ver || resolver->res == NULL) { char addr_str[PJ_INET6_ADDRSTRLEN+10]; pj_uint16_t srv_port; if (ip_addr_ver != 0) { /* Target is an IP address, no need to resolve */ if (ip_addr_ver == 4) { pj_sockaddr_init(pj_AF_INET(), &svr_addr.entry[0].addr, NULL, 0); pj_inet_aton(&target->addr.host, &svr_addr.entry[0].addr.ipv4.sin_addr); } else { pj_sockaddr_init(pj_AF_INET6(), &svr_addr.entry[0].addr, NULL, 0); pj_inet_pton(pj_AF_INET6(), &target->addr.host, &svr_addr.entry[0].addr.ipv6.sin6_addr); } } else { pj_addrinfo ai; unsigned count; int af; PJ_LOG(5,(THIS_FILE, "DNS resolver not available, target '%.*s:%d' type=%s " "will be resolved with getaddrinfo()", target->addr.host.slen, target->addr.host.ptr, target->addr.port, pjsip_transport_get_type_name(target->type))); if (type & PJSIP_TRANSPORT_IPV6) { af = pj_AF_INET6(); } else { af = pj_AF_INET(); } /* Resolve */ count = 1; status = pj_getaddrinfo(af, &target->addr.host, &count, &ai); if (status != PJ_SUCCESS) goto on_error; svr_addr.entry[0].addr.addr.sa_family = (pj_uint16_t)af; pj_memcpy(&svr_addr.entry[0].addr, &ai.ai_addr, sizeof(pj_sockaddr)); } /* Set the port number */ if (target->addr.port == 0) { srv_port = (pj_uint16_t) pjsip_transport_get_default_port_for_type(type); } else { srv_port = (pj_uint16_t)target->addr.port; } pj_sockaddr_set_port(&svr_addr.entry[0].addr, srv_port); /* Call the callback. */ PJ_LOG(5,(THIS_FILE, "Target '%.*s:%d' type=%s resolved to " "'%s' type=%s (%s)", (int)target->addr.host.slen, target->addr.host.ptr, target->addr.port, pjsip_transport_get_type_name(target->type), pj_sockaddr_print(&svr_addr.entry[0].addr, addr_str, sizeof(addr_str), 3), pjsip_transport_get_type_name(type), pjsip_transport_get_type_desc(type))); svr_addr.count = 1; svr_addr.entry[0].priority = 0; svr_addr.entry[0].weight = 0; svr_addr.entry[0].type = type; svr_addr.entry[0].addr_len = pj_sockaddr_get_len(&svr_addr.entry[0].addr); (*cb)(status, token, &svr_addr); /* Done. */ return; } /* Target is not an IP address so we need to resolve it. */ #if PJSIP_HAS_RESOLVER /* Build the query state */ query = PJ_POOL_ZALLOC_T(pool, struct query); query->objname = THIS_FILE; query->token = token; query->cb = cb; query->req.target = *target; pj_strdup(pool, &query->req.target.addr.host, &target->addr.host); /* If port is not specified, start with SRV resolution * (should be with NAPTR, but we'll do that later) */ PJ_TODO(SUPPORT_DNS_NAPTR); /* Build dummy NAPTR entry */ query->naptr_cnt = 1; pj_bzero(&query->naptr[0], sizeof(query->naptr[0])); query->naptr[0].order = 0; query->naptr[0].pref = 0; query->naptr[0].type = type; pj_strdup(pool, &query->naptr[0].name, &target->addr.host); /* Start DNS SRV or A resolution, depending on whether port is specified */ if (target->addr.port == 0) { query->query_type = PJ_DNS_TYPE_SRV; query->req.def_port = 5060; if (type == PJSIP_TRANSPORT_TLS) { query->naptr[0].res_type = pj_str("_sips._tcp."); query->req.def_port = 5061; } else if (type == PJSIP_TRANSPORT_TCP) query->naptr[0].res_type = pj_str("_sip._tcp."); else if (type == PJSIP_TRANSPORT_UDP) query->naptr[0].res_type = pj_str("_sip._udp."); else { pj_assert(!"Unknown transport type"); query->naptr[0].res_type = pj_str("_sip._udp."); } } else { /* Otherwise if port is specified, start with A (or AAAA) host * resolution */ query->query_type = PJ_DNS_TYPE_A; query->naptr[0].res_type.slen = 0; query->req.def_port = target->addr.port; } /* Start the asynchronous query */ PJ_LOG(5, (query->objname, "Starting async DNS %s query: target=%.*s%.*s, transport=%s, " "port=%d", pj_dns_get_type_name(query->query_type), (int)query->naptr[0].res_type.slen, query->naptr[0].res_type.ptr, (int)query->naptr[0].name.slen, query->naptr[0].name.ptr, pjsip_transport_get_type_name(target->type), target->addr.port)); if (query->query_type == PJ_DNS_TYPE_SRV) { unsigned option = PJ_TRUE; if (type & PJSIP_TRANSPORT_IPV6) { option |= PJ_DNS_SRV_FALLBACK_GETADDRINFO_IPV6; } else { option |= PJ_DNS_SRV_FALLBACK_GETADDRINFO_IPV4; } status = pj_dns_srv_resolve(&query->naptr[0].name, &query->naptr[0].res_type, query->req.def_port, pool, resolver->res, option, query, &srv_resolver_cb, NULL); } else if (query->query_type == PJ_DNS_TYPE_A) { status = pj_dns_resolver_start_query(resolver->res, &query->naptr[0].name, PJ_DNS_TYPE_A, 0, &dns_a_callback, query, &query->object); } else { pj_assert(!"Unexpected"); status = PJ_EBUG; } if (status != PJ_SUCCESS) goto on_error; return; #else /* PJSIP_HAS_RESOLVER */ PJ_UNUSED_ARG(pool); PJ_UNUSED_ARG(query); PJ_UNUSED_ARG(srv_name); #endif /* PJSIP_HAS_RESOLVER */ on_error: if (status != PJ_SUCCESS) { char errmsg[PJ_ERR_MSG_SIZE]; PJ_LOG(4,(THIS_FILE, "Failed to resolve '%.*s'. Err=%d (%s)", (int)target->addr.host.slen, target->addr.host.ptr, status, pj_strerror(status,errmsg,sizeof(errmsg)).ptr)); (*cb)(status, token, NULL); return; } }
static int format_test(void) { pj_str_t s = pj_str(ADDRESS); unsigned char *p; pj_in_addr addr; char zero[64]; pj_sockaddr_in addr2; const pj_str_t *hostname; const unsigned char A[] = {127, 0, 0, 1}; PJ_LOG(3,("test", "...format_test()")); /* pj_inet_aton() */ if (pj_inet_aton(&s, &addr) != 1) return -10; /* Check the result. */ p = (unsigned char*)&addr; if (p[0]!=A[0] || p[1]!=A[1] || p[2]!=A[2] || p[3]!=A[3]) { PJ_LOG(3,("test", " error: mismatched address. p0=%d, p1=%d, " "p2=%d, p3=%d", p[0] & 0xFF, p[1] & 0xFF, p[2] & 0xFF, p[3] & 0xFF)); return -15; } /* pj_inet_ntoa() */ p = (unsigned char*) pj_inet_ntoa(addr); if (!p) return -20; if (pj_strcmp2(&s, (char*)p) != 0) return -22; #if defined(PJ_HAS_IPV6) && PJ_HAS_IPV6!=0 /* pj_inet_pton() */ /* pj_inet_ntop() */ { const pj_str_t s_ipv4 = pj_str("127.0.0.1"); const pj_str_t s_ipv6 = pj_str("fe80::2ff:83ff:fe7c:8b42"); char buf_ipv4[PJ_INET_ADDRSTRLEN]; char buf_ipv6[PJ_INET6_ADDRSTRLEN]; pj_in_addr ipv4; pj_in6_addr ipv6; if (pj_inet_pton(pj_AF_INET(), &s_ipv4, &ipv4) != PJ_SUCCESS) return -24; p = (unsigned char*)&ipv4; if (p[0]!=A[0] || p[1]!=A[1] || p[2]!=A[2] || p[3]!=A[3]) { return -25; } if (pj_inet_pton(pj_AF_INET6(), &s_ipv6, &ipv6) != PJ_SUCCESS) return -26; p = (unsigned char*)&ipv6; if (p[0] != 0xfe || p[1] != 0x80 || p[2] != 0 || p[3] != 0 || p[4] != 0 || p[5] != 0 || p[6] != 0 || p[7] != 0 || p[8] != 0x02 || p[9] != 0xff || p[10] != 0x83 || p[11] != 0xff || p[12]!=0xfe || p[13]!=0x7c || p[14] != 0x8b || p[15]!=0x42) { return -27; } if (pj_inet_ntop(pj_AF_INET(), &ipv4, buf_ipv4, sizeof(buf_ipv4)) != PJ_SUCCESS) return -28; if (pj_stricmp2(&s_ipv4, buf_ipv4) != 0) return -29; if (pj_inet_ntop(pj_AF_INET6(), &ipv6, buf_ipv6, sizeof(buf_ipv6)) != PJ_SUCCESS) return -30; if (pj_stricmp2(&s_ipv6, buf_ipv6) != 0) return -31; } #endif /* PJ_HAS_IPV6 */ /* Test that pj_sockaddr_in_init() initialize the whole structure, * including sin_zero. */ pj_sockaddr_in_init(&addr2, 0, 1000); pj_bzero(zero, sizeof(zero)); if (pj_memcmp(addr2.sin_zero, zero, sizeof(addr2.sin_zero)) != 0) return -35; /* pj_gethostname() */ hostname = pj_gethostname(); if (!hostname || !hostname->ptr || !hostname->slen) return -40; PJ_LOG(3,("test", "....hostname is %.*s", (int)hostname->slen, hostname->ptr)); /* pj_gethostaddr() */ /* Various constants */ #if !defined(PJ_SYMBIAN) || PJ_SYMBIAN==0 if (PJ_AF_INET==0xFFFF) return -5500; if (PJ_AF_INET6==0xFFFF) return -5501; /* 0xFFFF could be a valid SOL_SOCKET (e.g: on some Win or Mac) */ //if (PJ_SOL_SOCKET==0xFFFF) return -5503; if (PJ_SOL_IP==0xFFFF) return -5502; if (PJ_SOL_TCP==0xFFFF) return -5510; if (PJ_SOL_UDP==0xFFFF) return -5520; if (PJ_SOL_IPV6==0xFFFF) return -5530; if (PJ_SO_TYPE==0xFFFF) return -5540; if (PJ_SO_RCVBUF==0xFFFF) return -5550; if (PJ_SO_SNDBUF==0xFFFF) return -5560; if (PJ_TCP_NODELAY==0xFFFF) return -5570; if (PJ_SO_REUSEADDR==0xFFFF) return -5580; if (PJ_MSG_OOB==0xFFFF) return -5590; if (PJ_MSG_PEEK==0xFFFF) return -5600; #endif return 0; }
static int format_test(void) { pj_str_t s = pj_str(ADDRESS); unsigned char *p; pj_in_addr addr; char zero[64]; pj_sockaddr_in addr2; const pj_str_t *hostname; const unsigned char A[] = {127, 0, 0, 1}; PJ_LOG(3,("test", "...format_test()")); /* pj_inet_aton() */ if (pj_inet_aton(&s, &addr) != 1) return -10; /* Check the result. */ p = (unsigned char*)&addr; if (p[0]!=A[0] || p[1]!=A[1] || p[2]!=A[2] || p[3]!=A[3]) { PJ_LOG(3,("test", " error: mismatched address. p0=%d, p1=%d, " "p2=%d, p3=%d", p[0] & 0xFF, p[1] & 0xFF, p[2] & 0xFF, p[3] & 0xFF)); return -15; } /* pj_inet_ntoa() */ p = (unsigned char*) pj_inet_ntoa(addr); if (!p) return -20; if (pj_strcmp2(&s, (char*)p) != 0) return -22; #if defined(PJ_HAS_IPV6) && PJ_HAS_IPV6!=0 /* pj_inet_pton() */ /* pj_inet_ntop() */ { const pj_str_t s_ipv4 = pj_str("127.0.0.1"); const pj_str_t s_ipv6 = pj_str("fe80::2ff:83ff:fe7c:8b42"); char buf_ipv4[PJ_INET_ADDRSTRLEN]; char buf_ipv6[PJ_INET6_ADDRSTRLEN]; pj_in_addr ipv4; pj_in6_addr ipv6; if (pj_inet_pton(pj_AF_INET(), &s_ipv4, &ipv4) != PJ_SUCCESS) return -24; p = (unsigned char*)&ipv4; if (p[0]!=A[0] || p[1]!=A[1] || p[2]!=A[2] || p[3]!=A[3]) { return -25; } if (pj_inet_pton(pj_AF_INET6(), &s_ipv6, &ipv6) != PJ_SUCCESS) return -26; p = (unsigned char*)&ipv6; if (p[0] != 0xfe || p[1] != 0x80 || p[2] != 0 || p[3] != 0 || p[4] != 0 || p[5] != 0 || p[6] != 0 || p[7] != 0 || p[8] != 0x02 || p[9] != 0xff || p[10] != 0x83 || p[11] != 0xff || p[12]!=0xfe || p[13]!=0x7c || p[14] != 0x8b || p[15]!=0x42) { return -27; } if (pj_inet_ntop(pj_AF_INET(), &ipv4, buf_ipv4, sizeof(buf_ipv4)) != PJ_SUCCESS) return -28; if (pj_stricmp2(&s_ipv4, buf_ipv4) != 0) return -29; if (pj_inet_ntop(pj_AF_INET6(), &ipv6, buf_ipv6, sizeof(buf_ipv6)) != PJ_SUCCESS) return -30; if (pj_stricmp2(&s_ipv6, buf_ipv6) != 0) return -31; } #endif /* PJ_HAS_IPV6 */ /* Test that pj_sockaddr_in_init() initialize the whole structure, * including sin_zero. */ pj_sockaddr_in_init(&addr2, 0, 1000); pj_bzero(zero, sizeof(zero)); if (pj_memcmp(addr2.sin_zero, zero, sizeof(addr2.sin_zero)) != 0) return -35; /* pj_gethostname() */ hostname = pj_gethostname(); if (!hostname || !hostname->ptr || !hostname->slen) return -40; PJ_LOG(3,("test", "....hostname is %.*s", (int)hostname->slen, hostname->ptr)); /* pj_gethostaddr() */ return 0; }