michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* vim: set ts=2 et sw=2 tw=80: */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this file, michael@0: * You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: extern "C" { michael@0: #include michael@0: #include "r_types.h" michael@0: #include "stun.h" michael@0: #include "addrs.h" michael@0: } michael@0: michael@0: #include michael@0: #include michael@0: #include "nsINetworkManager.h" michael@0: #include "nsINetworkInterfaceListService.h" michael@0: #include "runnable_utils.h" michael@0: #include "nsCOMPtr.h" michael@0: #include "nsMemory.h" michael@0: #include "nsThreadUtils.h" michael@0: #include "nsServiceManagerUtils.h" michael@0: #include "mozilla/SyncRunnable.h" michael@0: michael@0: namespace { michael@0: struct NetworkInterface { michael@0: struct sockaddr_in addr; michael@0: std::string name; michael@0: // See NR_INTERFACE_TYPE_* in nICEr/src/net/local_addrs.h michael@0: int type; michael@0: }; michael@0: michael@0: nsresult michael@0: GetInterfaces(std::vector* aInterfaces) michael@0: { michael@0: MOZ_ASSERT(aInterfaces); michael@0: michael@0: // Obtain network interfaces from network manager. michael@0: nsresult rv; michael@0: nsCOMPtr listService = michael@0: do_GetService("@mozilla.org/network/interface-list-service;1", &rv); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: int32_t flags = michael@0: nsINetworkInterfaceListService::LIST_NOT_INCLUDE_SUPL_INTERFACES | michael@0: nsINetworkInterfaceListService::LIST_NOT_INCLUDE_MMS_INTERFACES | michael@0: nsINetworkInterfaceListService::LIST_NOT_INCLUDE_IMS_INTERFACES | michael@0: nsINetworkInterfaceListService::LIST_NOT_INCLUDE_DUN_INTERFACES; michael@0: nsCOMPtr networkList; michael@0: NS_ENSURE_SUCCESS(listService->GetDataInterfaceList(flags, michael@0: getter_AddRefs(networkList)), michael@0: NS_ERROR_FAILURE); michael@0: michael@0: // Translate nsINetworkInterfaceList to NetworkInterface. michael@0: int32_t listLength; michael@0: NS_ENSURE_SUCCESS(networkList->GetNumberOfInterface(&listLength), michael@0: NS_ERROR_FAILURE); michael@0: aInterfaces->clear(); michael@0: michael@0: for (int32_t i = 0; i < listLength; i++) { michael@0: nsCOMPtr iface; michael@0: if (NS_FAILED(networkList->GetInterface(i, getter_AddRefs(iface)))) { michael@0: continue; michael@0: } michael@0: michael@0: char16_t **ips = nullptr; michael@0: uint32_t *prefixs = nullptr; michael@0: uint32_t count = 0; michael@0: bool isAddressGot = false; michael@0: NetworkInterface interface; michael@0: memset(&(interface.addr), 0, sizeof(interface.addr)); michael@0: interface.addr.sin_family = AF_INET; michael@0: michael@0: if (NS_FAILED(iface->GetAddresses(&ips, &prefixs, &count))) { michael@0: continue; michael@0: } michael@0: michael@0: for (uint32_t j = 0; j < count; j++) { michael@0: nsAutoString ip; michael@0: michael@0: ip.Assign(ips[j]); michael@0: if (inet_pton(AF_INET, NS_ConvertUTF16toUTF8(ip).get(), michael@0: &(interface.addr.sin_addr.s_addr)) == 1) { michael@0: isAddressGot = true; michael@0: break; michael@0: } michael@0: } michael@0: michael@0: nsMemory::Free(prefixs); michael@0: NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(count, ips); michael@0: michael@0: if (!isAddressGot) { michael@0: continue; michael@0: } michael@0: michael@0: nsAutoString ifaceName; michael@0: if (NS_FAILED(iface->GetName(ifaceName))) { michael@0: continue; michael@0: } michael@0: interface.name = NS_ConvertUTF16toUTF8(ifaceName).get(); michael@0: michael@0: int32_t type; michael@0: if (NS_FAILED(iface->GetType(&type))) { michael@0: continue; michael@0: } michael@0: switch (type) { michael@0: case nsINetworkInterface::NETWORK_TYPE_WIFI: michael@0: interface.type = NR_INTERFACE_TYPE_WIFI; michael@0: break; michael@0: case nsINetworkInterface::NETWORK_TYPE_MOBILE: michael@0: interface.type = NR_INTERFACE_TYPE_MOBILE; michael@0: break; michael@0: } michael@0: michael@0: aInterfaces->push_back(interface); michael@0: } michael@0: return NS_OK; michael@0: } michael@0: } // anonymous namespace michael@0: michael@0: int michael@0: nr_stun_get_addrs(nr_local_addr aAddrs[], int aMaxAddrs, michael@0: int aDropLoopback, int* aCount) michael@0: { michael@0: nsresult rv; michael@0: int r; michael@0: michael@0: // Get network interface list. michael@0: std::vector interfaces; michael@0: nsCOMPtr mainThread = do_GetMainThread(); michael@0: mozilla::SyncRunnable::DispatchToThread( michael@0: mainThread.get(), michael@0: mozilla::WrapRunnableNMRet(&GetInterfaces, &interfaces, &rv), michael@0: false); michael@0: if (NS_FAILED(rv)) { michael@0: return R_FAILED; michael@0: } michael@0: michael@0: // Translate to nr_transport_addr. michael@0: int32_t n = 0; michael@0: size_t num_interface = std::min(interfaces.size(), (size_t)aMaxAddrs); michael@0: for (size_t i = 0; i < num_interface; ++i) { michael@0: NetworkInterface &interface = interfaces[i]; michael@0: if (nr_sockaddr_to_transport_addr((sockaddr*)&(interface.addr), michael@0: sizeof(struct sockaddr_in), michael@0: IPPROTO_UDP, 0, &(aAddrs[n].addr))) { michael@0: r_log(NR_LOG_STUN, LOG_WARNING, "Problem transforming address"); michael@0: return R_FAILED; michael@0: } michael@0: strlcpy(aAddrs[n].addr.ifname, interface.name.c_str(), michael@0: sizeof(aAddrs[n].addr.ifname)); michael@0: aAddrs[n].interface.type = interface.type; michael@0: aAddrs[n].interface.estimated_speed = 0; michael@0: n++; michael@0: } michael@0: michael@0: *aCount = n; michael@0: r = nr_stun_remove_duplicate_addrs(aAddrs, aDropLoopback, aCount); michael@0: if (r != 0) { michael@0: return r; michael@0: } michael@0: michael@0: for (int i = 0; i < *aCount; ++i) { michael@0: char typestr[100]; michael@0: nr_local_addr_fmt_info_string(aAddrs + i, typestr, sizeof(typestr)); michael@0: r_log(NR_LOG_STUN, LOG_DEBUG, "Address %d: %s on %s, type: %s\n", michael@0: i, aAddrs[i].addr.as_string, aAddrs[i].addr.ifname, typestr); michael@0: } michael@0: michael@0: return 0; michael@0: }