network 支持功能
1、本地网络
2、适配器
3、dns
4、网络的开销
获取本机的网络
1、调用 GetAdaptersAddresses函数检索与本地计算机上的适配器关联的地址。
2、遍历适配器信息
- 2.1 判断操作状态,如果是启动才进行处理
-
bool BasicNetworkManager::CreateNetworks(bool include_ignored,
NetworkList* networks) const {
NetworkMap current_networks;
// MSDN recommends a 15KB buffer for the first try at GetAdaptersAddresses.
size_t buffer_size = 16384;
std::unique_ptr<char[]> adapter_info(new char[buffer_size]);
PIP_ADAPTER_ADDRESSES adapter_addrs =
reinterpret_cast<PIP_ADAPTER_ADDRESSES>(adapter_info.get());
// 1. 获取适配器的信息,存放到adapter_info中,如果存储不下,重新分配内存适应
int adapter_flags = (GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_ANYCAST |
GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_INCLUDE_PREFIX);
int ret = 0;
do {
adapter_info.reset(new char[buffer_size]);
//adapter_addrs 指向缓冲区的指针,该缓冲区包含成功返回时IP_ADAPTER_ADDRESSES结构的链表。
adapter_addrs = reinterpret_cast<PIP_ADAPTER_ADDRESSES>(adapter_info.get());
ret = GetAdaptersAddresses(AF_UNSPEC, adapter_flags, 0, adapter_addrs,
reinterpret_cast<PULONG>(&buffer_size));
} while (ret == ERROR_BUFFER_OVERFLOW);
if (ret != ERROR_SUCCESS) {
return false;
}
// 2. 遍历适配器信息,
int count = 0;
while (adapter_addrs) {
// 2.1 判断操作状态,如果是启动才进行处理
if (adapter_addrs->OperStatus == IfOperStatusUp) {
// 2.1.1 第一个单播地址指针
PIP_ADAPTER_UNICAST_ADDRESS address = adapter_addrs->FirstUnicastAddress;
PIP_ADAPTER_PREFIX prefixlist = adapter_addrs->FirstPrefix;
// 2.1.2 获取适配器名称和描述
std::string name;
std::string description;
#if !defined(NDEBUG)
name = ToUtf8(adapter_addrs->FriendlyName,
wcslen(adapter_addrs->FriendlyName));
#endif
description = ToUtf8(adapter_addrs->Description,
wcslen(adapter_addrs->Description));
// 2.1.3 遍历所有的地址
for (; address; address = address->Next) {
#if defined(NDEBUG)
name = rtc::ToString(count);
#endif
// 2.1.3.1 判断IPv4 和 v6
IPAddress ip;
int scope_id = 0;
std::unique_ptr<Network> network;
switch (address->Address.lpSockaddr->sa_family) {
case AF_INET: {
sockaddr_in* v4_addr =
reinterpret_cast<sockaddr_in*>(address->Address.lpSockaddr);
ip = IPAddress(v4_addr->sin_addr);
break;
}
case AF_INET6: {
sockaddr_in6* v6_addr =
reinterpret_cast<sockaddr_in6*>(address->Address.lpSockaddr);
scope_id = v6_addr->sin6_scope_id;
ip = IPAddress(v6_addr->sin6_addr);
if (IsIgnoredIPv6(InterfaceAddress(ip))) {
continue;
}
break;
}
default: {
continue;
}
}
// 2.1.3.2 判断网络是否存在,设置接口类型
IPAddress prefix;
int prefix_length = GetPrefix(prefixlist, ip, &prefix);
std::string key = MakeNetworkKey(name, prefix, prefix_length);
auto existing_network = current_networks.find(key);
if (existing_network == current_networks.end()) {
AdapterType adapter_type = ADAPTER_TYPE_UNKNOWN;
switch (adapter_addrs->IfType) {
case IF_TYPE_SOFTWARE_LOOPBACK:
adapter_type = ADAPTER_TYPE_LOOPBACK;
break;
case IF_TYPE_ETHERNET_CSMACD:
case IF_TYPE_ETHERNET_3MBIT:
case IF_TYPE_IEEE80212:
case IF_TYPE_FASTETHER:
case IF_TYPE_FASTETHER_FX:
case IF_TYPE_GIGABITETHERNET:
adapter_type = ADAPTER_TYPE_ETHERNET;
break;
case IF_TYPE_IEEE80211:
adapter_type = ADAPTER_TYPE_WIFI;
break;
case IF_TYPE_WWANPP:
case IF_TYPE_WWANPP2:
adapter_type = ADAPTER_TYPE_CELLULAR;
break;
default:
// TODO(phoglund): Need to recognize other types as well.
adapter_type = ADAPTER_TYPE_UNKNOWN;
break;
}
// 2.1.3.3 保存网络信息
std::unique_ptr<Network> network(new Network(
name, description, prefix, prefix_length, adapter_type));
network->set_default_local_address_provider(this);
network->set_mdns_responder_provider(this);
network->set_scope_id(scope_id);
network->AddIP(ip);
bool ignored = IsIgnoredNetwork(*network);
network->set_ignored(ignored);
if (include_ignored || !network->ignored()) {
current_networks[key] = network.get();
networks->push_back(network.release());
}
} else {
(*existing_network).second->AddIP(ip);
}
}
// Count is per-adapter - all 'Networks' created from the same
// adapter need to have the same name.
++count;
}
adapter_addrs = adapter_addrs->Next;
}
return true;
}
获取本机地址和端口
1、由于有多个接口,所以先建立链接,然后在获取本机的地址,是通过getsockname获取的。
SocketAddress Win32Socket::GetLocalAddress() const {
sockaddr_storage addr = {0};
socklen_t addrlen = sizeof(addr);
int result =
::getsockname(socket_, reinterpret_cast<sockaddr*>(&addr), &addrlen);
SocketAddress address;
if (result >= 0) {
SocketAddressFromSockAddrStorage(addr, &address);
} else {
RTC_LOG(LS_WARNING) << "GetLocalAddress: unable to get local addr, socket="
<< socket_;
}
return address;
}
dns 获取
DnsLookup* dns = new DnsLookup;
if (!sink_) {
// Explicitly create the sink ourselves here; we can't rely on SetAsync
// because we don't have a socket_ yet.
CreateSink();
}
// TODO: Replace with IPv6 compatible lookup.
// 异步调用, 通过msg 的方式返回,sink_->handle() 是窗口的句柄,专门用来接收socket 的异步消息
dns->handle = WSAAsyncGetHostByName(sink_->handle(), WM_DNSNOTIFY,
addr.hostname().c_str(), dns->buffer,
sizeof(dns->buffer));
if (!dns->handle) {
RTC_LOG_F(LS_ERROR) << "WSAAsyncGetHostByName error: " << WSAGetLastError();
delete dns;
UpdateLastError();
Close();
return SOCKET_ERROR;
}
socket 的信号是通过,消息循环机制接收,接收WM_DNSNOTIFY消息,说明已经返回了dns 结果
bool Win32Socket::EventSink::OnMessage(UINT uMsg,
WPARAM wParam,
LPARAM lParam,
LRESULT& result) {
switch (uMsg) {
case WM_SOCKETNOTIFY:
case WM_TIMER:
return OnSocketNotify(uMsg, wParam, lParam, result);
case WM_DNSNOTIFY:
return OnDnsNotify(wParam, lParam, result);
}
return false;
处理dns 返回的结果,调用DoConnect 进行链接
void Win32Socket::OnDnsNotify(HANDLE task, int error) {
if (!dns_ || dns_->handle != task)
return;
uint32_t ip = 0;
if (error == 0) {
hostent* pHost = reinterpret_cast<hostent*>(dns_->buffer);
uint32_t net_ip = *reinterpret_cast<uint32_t*>(pHost->h_addr_list[0]);
ip = NetworkToHost32(net_ip);
}
RTC_LOG_F(LS_INFO) << "(" << IPAddress(ip).ToSensitiveString() << ", "
<< error << ")";
if (error == 0) {
SocketAddress address(ip, dns_->port);
error = DoConnect(address);
} else {
Close();
}
if (error) {
error_ = error;
SignalCloseEvent(this, error_);
} else {
delete dns_;
dns_ = nullptr;
}
}
网络的开销
根据类型设置的开销,如下
static const uint16_t kNetworkCostMax = 999;
static const uint16_t kNetworkCostHigh = 900;
static const uint16_t kNetworkCostUnknown = 50;
static const uint16_t kNetworkCostLow = 10;
static const uint16_t kNetworkCostMin = 0;
uint16_t ComputeNetworkCostByType(int type) {
switch (type) {
case rtc::ADAPTER_TYPE_ETHERNET:
case rtc::ADAPTER_TYPE_LOOPBACK:
return kNetworkCostMin;
case rtc::ADAPTER_TYPE_WIFI:
return kNetworkCostLow;
case rtc::ADAPTER_TYPE_CELLULAR:
return kNetworkCostHigh;
case rtc::ADAPTER_TYPE_ANY:
// Candidates gathered from the any-address/wildcard ports, as backups,
// are given the maximum cost so that if there are other candidates with
// known interface types, we would not select candidate pairs using these
// backup candidates if other selection criteria with higher precedence
// (network conditions over the route) are the same. Note that setting the
// cost to kNetworkCostUnknown would be problematic since
// ADAPTER_TYPE_CELLULAR would then have a higher cost. See
// P2PTransportChannel::SortConnectionsAndUpdateState for how we rank and
// select candidate pairs, where the network cost is among the criteria.
return kNetworkCostMax;
case rtc::ADAPTER_TYPE_VPN:
// The cost of a VPN should be computed using its underlying network type.
RTC_NOTREACHED();
return kNetworkCostUnknown;
default:
return kNetworkCostUnknown;
}
}