TEST_F(TestNetworkProviderInMemory, PacketLoss50Percent) { OClock testTime{Clock::now()}; std::vector<uint8_t> payload = {1,2,3,4}; NetworkProviderInMemory::RandomSettings settings{ std::bind(myRandom0To1, myRandomEngine), {}, Milliseconds{0}, 0.5f, 0.75f, 0}; NetworkProviderInMemory buffer(settings, [&testTime] () -> OClock { return testTime; }); auto addressServer = udp::endpoint{address_v4(1l), 13444}; auto addressClient = udp::endpoint{address_v4(2l), 4444}; auto packetToClient = NetworkPacket{payload, addressClient}; buffer.RunAs(addressServer); buffer.Send({packetToClient, packetToClient, packetToClient, packetToClient, packetToClient, packetToClient, packetToClient, packetToClient}); buffer.RunAs(addressClient); auto result = buffer.Receive(); EXPECT_NE(result.size(), 8); EXPECT_NE(result.size(), 0); }
libtorrent::address address() const { #if TORRENT_USE_IPV6 if (v4) return address_v4(addr.v4); else return address_v6(addr.v6); #else return address_v4(addr.v4); #endif }
operator udp::endpoint() const { #if TORRENT_USE_IPV6 if (v4) return udp::endpoint(address_v4(addr.v4), port); else return udp::endpoint(address_v6(addr.v6), port); #else return udp::endpoint(address_v4(addr.v4), port); #endif }
TEST_F(TestNetworkProviderInMemory, LatencyInOrder) { OClock testTime{Clock::now()}; std::vector<std::vector<uint8_t>> payloads = {{1,2,3,4}, {4,4}, {3,5,6,7}, {8,8,8,8,8,8,8,8}}; NetworkProviderInMemory::RandomSettings settings{ std::bind(myRandom0To1, myRandomEngine), std::bind(myLatency, myRandomEngine), Milliseconds{100}, 0, 0, 0}; NetworkProviderInMemory buffer(settings, [&testTime] () -> OClock { return testTime; }); auto addressServer = udp::endpoint{address_v4(1l), 13444}; auto addressClient = udp::endpoint{address_v4(2l), 4444}; auto packets = std::vector<NetworkPacket>{}; for (auto payload : payloads) { packets.emplace_back(payload, addressClient); } buffer.RunAs(addressServer); for (int i = 0; i < 8; i++) { buffer.Send(packets); testTime += std::chrono::milliseconds(10); } testTime -= std::chrono::milliseconds(8 * 10); buffer.RunAs(addressClient); auto result = buffer.Receive(); EXPECT_EQ(result.size(), 0); // Minimum latency is 100 ms. testTime -= std::chrono::milliseconds(99); result = buffer.Receive(); EXPECT_EQ(result.size(), 0); // Should get all packets after 1 second. testTime += std::chrono::milliseconds(1001); result = buffer.Receive(); EXPECT_EQ(result.size(), 8 * payloads.size()); int i = 0; for (auto& packet : result) { EXPECT_EQ(payloads[i], packet.data); i = (i + 1) % payloads.size(); } }
bool can_broadcast() const { error_code ec; return broadcast && netmask != address_v4() && socket->local_endpoint(ec).address().is_v4(); }
address external_ip::external_address(address const& ip) const { address ext = m_vote_group[ip.is_v6()].external_address(); #if TORRENT_USE_IPV6 if (ip.is_v6() && ext == address_v4()) return address_v6(); #endif return ext; }
address_v4 broadcast_address() const { error_code ec; #if BOOST_VERSION < 104700 return address_v4(socket->local_endpoint(ec).address().to_v4().to_ulong() | ((~netmask.to_ulong()) & 0xffffffff)); #else return address_v4::broadcast(socket->local_endpoint(ec).address().to_v4(), netmask); #endif }
TEST_F(TestNetworkProviderInMemory, NoLatency) { NetworkProviderInMemory buffer{}; std::vector<uint8_t> payloads[2] = {{1,2,3,4}, {6,7,8,9,10}}; auto addressServer = udp::endpoint{address_v4(1l), 13444}; auto addressClient = udp::endpoint{address_v4(2l), 4444}; auto packetToClient = NetworkPacket{payloads[1], addressClient}; buffer.RunAs(addressServer); buffer.Send({packetToClient}); buffer.RunAs(addressClient); auto result = buffer.Receive(); ASSERT_EQ(1, result.size()); EXPECT_EQ(payloads[1], result[0].data); }
address observer::target_addr() const { #if TORRENT_USE_IPV6 if (flags & flag_ipv6_address) return address_v6(m_addr.v6); else #endif return address_v4(m_addr.v4); }
tcp::endpoint peer() const { #if TORRENT_USE_IPV6 if (is_v6_addr) return tcp::endpoint(address_v6(addr.v6), port); else #endif return tcp::endpoint(address_v4(addr.v4), port); }
TEST_F(TestNetworkProviderInMemory, LatencyOutOfOrder) { OClock testTime{Clock::now()}; std::vector<std::vector<uint8_t>> payloads = {{1,2,3,4}, {4,4}, {3,5,6,7}, {8,8,8,8,8,8,8,8}}; NetworkProviderInMemory::RandomSettings settings{ std::bind(myRandom0To1, myRandomEngine), std::bind(myLatency, myRandomEngine), Milliseconds{100}, 0, 0, 1.0}; NetworkProviderInMemory buffer(settings, [&testTime] () -> OClock { return testTime; }); auto addressServer = udp::endpoint{address_v4(1l), 13444}; auto addressClient = udp::endpoint{address_v4(2l), 4444}; auto packets = std::vector<NetworkPacket>{}; for (auto payload : payloads) { packets.emplace_back(payload, addressClient); } buffer.RunAs(addressServer); buffer.Send(packets); testTime += std::chrono::milliseconds(1000); buffer.RunAs(addressClient); auto result = buffer.Receive(); EXPECT_EQ(result.size(), payloads.size()); bool inOrder = true; for (std::size_t i = 0; i < result.size(); ++i) { if (result[i].data != payloads[i]) { inOrder = false; } } EXPECT_FALSE(inOrder); }
address build_netmask(int bits, int family) { if (family == AF_INET) { typedef asio::ip::address_v4::bytes_type bytes_t; bytes_t b; std::memset(&b[0], 0xff, b.size()); for (int i = sizeof(bytes_t)/8-1; i > 0; --i) { if (bits < 8) { b[i] <<= bits; break; } b[i] = 0; bits -= 8; } return address_v4(b); } #if TORRENT_USE_IPV6 else if (family == AF_INET6) { typedef asio::ip::address_v6::bytes_type bytes_t; bytes_t b; std::memset(&b[0], 0xff, b.size()); for (int i = sizeof(bytes_t)/8-1; i > 0; --i) { if (bits < 8) { b[i] <<= bits; break; } b[i] = 0; bits -= 8; } return address_v6(b); } #endif else { return address(); } }
BOOST_FIXTURE_TEST_CASE(Tcp, ResolverFixture<tcp>) { TcpResolver::asyncResolve("www.named-data.net", "6363", bind(&ResolverFixture<tcp>::onSuccess, this, _1, tcp::endpoint(address_v4(), 6363), true, false), bind(&ResolverFixture<tcp>::onFailure, this, false)); TcpResolver::asyncResolve("www.named-data.net", "notport", bind(&ResolverFixture<tcp>::onSuccess, this, _1, tcp::endpoint(address_v4(), 0), false, false), bind(&ResolverFixture<tcp>::onFailure, this, true)); // should fail TcpResolver::asyncResolve("nothost.nothost.nothost.arpa", "6363", bind(&ResolverFixture<tcp>::onSuccess, this, _1, tcp::endpoint(address_v4(), 6363), false, false), bind(&ResolverFixture<tcp>::onFailure, this, true)); // should fail TcpResolver::asyncResolve("www.google.com", "80", bind(&ResolverFixture<tcp>::onSuccess, this, _1, tcp::endpoint(address_v4(), 80), true, false), bind(&ResolverFixture<tcp>::onFailure, this, false), resolver::Ipv4Address()); // request IPv4 address TcpResolver::asyncResolve("www.google.com", "80", bind(&ResolverFixture<tcp>::onSuccess, this, _1, tcp::endpoint(address_v6(), 80), true, false), bind(&ResolverFixture<tcp>::onFailure, this, false), resolver::Ipv6Address()); // request IPv6 address TcpResolver::asyncResolve("ipv6.google.com", "80", // only IPv6 address should be available bind(&ResolverFixture<tcp>::onSuccess, this, _1, tcp::endpoint(address_v6(), 80), true, false), bind(&ResolverFixture<tcp>::onFailure, this, false)); TcpResolver::asyncResolve("ipv6.google.com", "80", // only IPv6 address should be available bind(&ResolverFixture<tcp>::onSuccess, this, _1, tcp::endpoint(address_v6(), 80), true, false), bind(&ResolverFixture<tcp>::onFailure, this, false), resolver::Ipv6Address()); TcpResolver::asyncResolve("ipv6.google.com", "80", // only IPv6 address should be available bind(&ResolverFixture<tcp>::onSuccess, this, _1, tcp::endpoint(address_v6(), 80), false, false), bind(&ResolverFixture<tcp>::onFailure, this, true), // should fail resolver::Ipv4Address()); TcpResolver::asyncResolve("192.0.2.1", "80", bind(&ResolverFixture<tcp>::onSuccess, this, _1, tcp::endpoint(address_v4::from_string("192.0.2.1"), 80), true, true), bind(&ResolverFixture<tcp>::onFailure, this, false)); TcpResolver::asyncResolve("2001:db8:3f9:0:3025:ccc5:eeeb:86d3", "80", bind(&ResolverFixture<tcp>::onSuccess, this, _1, tcp::endpoint(address_v6:: from_string("2001:db8:3f9:0:3025:ccc5:eeeb:86d3"), 80), true, true), bind(&ResolverFixture<tcp>::onFailure, this, false)); g_io.run(); BOOST_CHECK_EQUAL(m_nFailures, 3); BOOST_CHECK_EQUAL(m_nSuccesses, 7); }
std::vector<ip_route> enum_routes(io_service& ios, error_code& ec) { std::vector<ip_route> ret; TORRENT_UNUSED(ios); #ifdef TORRENT_BUILD_SIMULATOR TORRENT_UNUSED(ec); std::vector<address> ips = ios.get_ips(); for (int i = 0; i < int(ips.size()); ++i) { ip_route r; if (ips[i].is_v4()) { r.destination = address_v4(); r.netmask = address_v4::from_string("255.255.255.0"); address_v4::bytes_type b = ips[i].to_v4().to_bytes(); b[3] = 1; r.gateway = address_v4(b); } else { r.destination = address_v6(); r.netmask = address_v6::from_string("FFFF:FFFF:FFFF:FFFF::0"); address_v6::bytes_type b = ips[i].to_v6().to_bytes(); b[14] = 1; r.gateway = address_v6(b); } strcpy(r.name, "eth0"); r.mtu = ios.sim().config().path_mtu(ips[i], ips[i]); ret.push_back(r); } #elif TORRENT_USE_SYSCTL /* struct rt_msg { rt_msghdr m_rtm; char buf[512]; }; rt_msg m; int len = sizeof(rt_msg); bzero(&m, len); m.m_rtm.rtm_type = RTM_GET; m.m_rtm.rtm_flags = RTF_UP | RTF_GATEWAY; m.m_rtm.rtm_version = RTM_VERSION; m.m_rtm.rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK; m.m_rtm.rtm_seq = 0; m.m_rtm.rtm_msglen = len; int s = socket(PF_ROUTE, SOCK_RAW, AF_UNSPEC); if (s == -1) { ec = error_code(errno, boost::asio::error::system_category); return std::vector<ip_route>(); } int n = write(s, &m, len); if (n == -1) { ec = error_code(errno, boost::asio::error::system_category); close(s); return std::vector<ip_route>(); } else if (n != len) { ec = boost::asio::error::operation_not_supported; close(s); return std::vector<ip_route>(); } bzero(&m, len); n = read(s, &m, len); if (n == -1) { ec = error_code(errno, boost::asio::error::system_category); close(s); return std::vector<ip_route>(); } for (rt_msghdr* ptr = &m.m_rtm; (char*)ptr < ((char*)&m.m_rtm) + n; ptr = (rt_msghdr*)(((char*)ptr) + ptr->rtm_msglen)) { std::cout << " rtm_msglen: " << ptr->rtm_msglen << std::endl; std::cout << " rtm_type: " << ptr->rtm_type << std::endl; if (ptr->rtm_errno) { ec = error_code(ptr->rtm_errno, boost::asio::error::system_category); return std::vector<ip_route>(); } if (m.m_rtm.rtm_flags & RTF_UP == 0 || m.m_rtm.rtm_flags & RTF_GATEWAY == 0) { ec = boost::asio::error::operation_not_supported; return address_v4::any(); } if (ptr->rtm_addrs & RTA_DST == 0 || ptr->rtm_addrs & RTA_GATEWAY == 0 || ptr->rtm_addrs & RTA_NETMASK == 0) { ec = boost::asio::error::operation_not_supported; return std::vector<ip_route>(); } if (ptr->rtm_msglen > len - ((char*)ptr - ((char*)&m.m_rtm))) { ec = boost::asio::error::operation_not_supported; return std::vector<ip_route>(); } int min_len = sizeof(rt_msghdr) + 2 * sizeof(sockaddr_in); if (m.m_rtm.rtm_msglen < min_len) { ec = boost::asio::error::operation_not_supported; return std::vector<ip_route>(); } ip_route r; // destination char* p = m.buf; sockaddr_in* sin = (sockaddr_in*)p; r.destination = sockaddr_to_address((sockaddr*)p); // gateway p += sin->sin_len; sin = (sockaddr_in*)p; r.gateway = sockaddr_to_address((sockaddr*)p); // netmask p += sin->sin_len; sin = (sockaddr_in*)p; r.netmask = sockaddr_to_address((sockaddr*)p); ret.push_back(r); } close(s); */ int mib[6] = { CTL_NET, PF_ROUTE, 0, AF_UNSPEC, NET_RT_DUMP, 0}; size_t needed = 0; #ifdef TORRENT_OS2 if (__libsocket_sysctl(mib, 6, 0, &needed, 0, 0) < 0) #else if (sysctl(mib, 6, 0, &needed, 0, 0) < 0) #endif { ec = error_code(errno, boost::asio::error::system_category); return std::vector<ip_route>(); } if (needed <= 0) { return std::vector<ip_route>(); } boost::scoped_array<char> buf(new (std::nothrow) char[needed]); if (buf.get() == 0) { ec = boost::asio::error::no_memory; return std::vector<ip_route>(); } #ifdef TORRENT_OS2 if (__libsocket_sysctl(mib, 6, buf.get(), &needed, 0, 0) < 0) #else if (sysctl(mib, 6, buf.get(), &needed, 0, 0) < 0) #endif { ec = error_code(errno, boost::asio::error::system_category); return std::vector<ip_route>(); } char* end = buf.get() + needed; int s = socket(AF_INET, SOCK_DGRAM, 0); if (s < 0) { ec = error_code(errno, boost::asio::error::system_category); return std::vector<ip_route>(); } rt_msghdr* rtm; for (char* next = buf.get(); next < end; next += rtm->rtm_msglen) { rtm = reinterpret_cast<rt_msghdr*>(next); if (rtm->rtm_version != RTM_VERSION) continue; ip_route r; if (parse_route(s, rtm, &r)) ret.push_back(r); } close(s); #elif TORRENT_USE_GETIPFORWARDTABLE /* move this to enum_net_interfaces // Load Iphlpapi library HMODULE iphlp = LoadLibraryA("Iphlpapi.dll"); if (!iphlp) { ec = boost::asio::error::operation_not_supported; return std::vector<ip_route>(); } // Get GetAdaptersInfo() pointer typedef DWORD (WINAPI *GetAdaptersInfo_t)(PIP_ADAPTER_INFO, PULONG); GetAdaptersInfo_t GetAdaptersInfo = (GetAdaptersInfo_t)GetProcAddress(iphlp, "GetAdaptersInfo"); if (!GetAdaptersInfo) { FreeLibrary(iphlp); ec = boost::asio::error::operation_not_supported; return std::vector<ip_route>(); } PIP_ADAPTER_INFO adapter_info = 0; ULONG out_buf_size = 0; if (GetAdaptersInfo(adapter_info, &out_buf_size) != ERROR_BUFFER_OVERFLOW) { FreeLibrary(iphlp); ec = boost::asio::error::operation_not_supported; return std::vector<ip_route>(); } adapter_info = (IP_ADAPTER_INFO*)malloc(out_buf_size); if (!adapter_info) { FreeLibrary(iphlp); ec = boost::asio::error::no_memory; return std::vector<ip_route>(); } if (GetAdaptersInfo(adapter_info, &out_buf_size) == NO_ERROR) { for (PIP_ADAPTER_INFO adapter = adapter_info; adapter != 0; adapter = adapter->Next) { ip_route r; r.destination = address::from_string(adapter->IpAddressList.IpAddress.String, ec); r.gateway = address::from_string(adapter->GatewayList.IpAddress.String, ec); r.netmask = address::from_string(adapter->IpAddressList.IpMask.String, ec); strncpy(r.name, adapter->AdapterName, sizeof(r.name)); if (ec) { ec = error_code(); continue; } ret.push_back(r); } } // Free memory free(adapter_info); FreeLibrary(iphlp); */ // Load Iphlpapi library HMODULE iphlp = LoadLibraryA("Iphlpapi.dll"); if (!iphlp) { ec = boost::asio::error::operation_not_supported; return std::vector<ip_route>(); } typedef DWORD (WINAPI *GetIfEntry_t)(PMIB_IFROW pIfRow); GetIfEntry_t GetIfEntry = (GetIfEntry_t)GetProcAddress(iphlp, "GetIfEntry"); if (!GetIfEntry) { ec = boost::asio::error::operation_not_supported; return std::vector<ip_route>(); } #if _WIN32_WINNT >= 0x0600 typedef DWORD (WINAPI *GetIpForwardTable2_t)( ADDRESS_FAMILY, PMIB_IPFORWARD_TABLE2*); typedef void (WINAPI *FreeMibTable_t)(PVOID Memory); GetIpForwardTable2_t GetIpForwardTable2 = (GetIpForwardTable2_t)GetProcAddress( iphlp, "GetIpForwardTable2"); FreeMibTable_t FreeMibTable = (FreeMibTable_t)GetProcAddress( iphlp, "FreeMibTable"); if (GetIpForwardTable2 && FreeMibTable) { MIB_IPFORWARD_TABLE2* routes = NULL; int res = GetIpForwardTable2(AF_UNSPEC, &routes); if (res == NO_ERROR) { for (int i = 0; i < routes->NumEntries; ++i) { ip_route r; r.gateway = sockaddr_to_address((const sockaddr*)&routes->Table[i].NextHop); r.destination = sockaddr_to_address( (const sockaddr*)&routes->Table[i].DestinationPrefix.Prefix); r.netmask = build_netmask(routes->Table[i].SitePrefixLength , routes->Table[i].DestinationPrefix.Prefix.si_family); MIB_IFROW ifentry; ifentry.dwIndex = routes->Table[i].InterfaceIndex; if (GetIfEntry(&ifentry) == NO_ERROR) { wcstombs(r.name, ifentry.wszName, sizeof(r.name)); r.mtu = ifentry.dwMtu; ret.push_back(r); } } } if (routes) FreeMibTable(routes); FreeLibrary(iphlp); return ret; } #endif // Get GetIpForwardTable() pointer typedef DWORD (WINAPI *GetIpForwardTable_t)(PMIB_IPFORWARDTABLE pIpForwardTable,PULONG pdwSize,BOOL bOrder); GetIpForwardTable_t GetIpForwardTable = (GetIpForwardTable_t)GetProcAddress( iphlp, "GetIpForwardTable"); if (!GetIpForwardTable) { FreeLibrary(iphlp); ec = boost::asio::error::operation_not_supported; return std::vector<ip_route>(); } MIB_IPFORWARDTABLE* routes = NULL; ULONG out_buf_size = 0; if (GetIpForwardTable(routes, &out_buf_size, FALSE) != ERROR_INSUFFICIENT_BUFFER) { FreeLibrary(iphlp); ec = boost::asio::error::operation_not_supported; return std::vector<ip_route>(); } routes = (MIB_IPFORWARDTABLE*)malloc(out_buf_size); if (!routes) { FreeLibrary(iphlp); ec = boost::asio::error::no_memory; return std::vector<ip_route>(); } if (GetIpForwardTable(routes, &out_buf_size, FALSE) == NO_ERROR) { for (int i = 0; i < routes->dwNumEntries; ++i) { ip_route r; r.destination = inaddr_to_address((in_addr const*)&routes->table[i].dwForwardDest); r.netmask = inaddr_to_address((in_addr const*)&routes->table[i].dwForwardMask); r.gateway = inaddr_to_address((in_addr const*)&routes->table[i].dwForwardNextHop); MIB_IFROW ifentry; ifentry.dwIndex = routes->table[i].dwForwardIfIndex; if (GetIfEntry(&ifentry) == NO_ERROR) { wcstombs(r.name, ifentry.wszName, sizeof(r.name)); r.name[sizeof(r.name)-1] = 0; r.mtu = ifentry.dwMtu; ret.push_back(r); } } } // Free memory free(routes); FreeLibrary(iphlp); #elif TORRENT_USE_NETLINK enum { BUFSIZE = 8192 }; int sock = socket(PF_ROUTE, SOCK_DGRAM, NETLINK_ROUTE); if (sock < 0) { ec = error_code(errno, boost::asio::error::system_category); return std::vector<ip_route>(); } int seq = 0; char msg[BUFSIZE]; memset(msg, 0, BUFSIZE); nlmsghdr* nl_msg = (nlmsghdr*)msg; nl_msg->nlmsg_len = NLMSG_LENGTH(sizeof(rtmsg)); nl_msg->nlmsg_type = RTM_GETROUTE; nl_msg->nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST; nl_msg->nlmsg_seq = seq++; nl_msg->nlmsg_pid = getpid(); if (send(sock, nl_msg, nl_msg->nlmsg_len, 0) < 0) { ec = error_code(errno, boost::asio::error::system_category); close(sock); return std::vector<ip_route>(); } int len = read_nl_sock(sock, msg, BUFSIZE, seq, getpid()); if (len < 0) { ec = error_code(errno, boost::asio::error::system_category); close(sock); return std::vector<ip_route>(); } int s = socket(AF_INET, SOCK_DGRAM, 0); if (s < 0) { ec = error_code(errno, boost::asio::error::system_category); return std::vector<ip_route>(); } for (; NLMSG_OK(nl_msg, len); nl_msg = NLMSG_NEXT(nl_msg, len)) { ip_route r; if (parse_route(s, nl_msg, &r)) ret.push_back(r); } close(s); close(sock); #endif return ret; }
bool ip_voter::cast_vote(address const& ip , int source_type, address const& source) { if (is_any(ip)) return false; if (is_local(ip)) return false; if (is_loopback(ip)) return false; // don't trust source that aren't connected to us // on a different address family than the external // IP they claim we have if (ip.is_v4() != source.is_v4()) return false; // this is the key to use for the bloom filters // it represents the identity of the voter sha1_hash k; hash_address(source, k); // do we already have an entry for this external IP? std::vector<external_ip_t>::iterator i = std::find_if(m_external_addresses.begin() , m_external_addresses.end(), boost::bind(&external_ip_t::addr, _1) == ip); if (i == m_external_addresses.end()) { // each IP only gets to add a new IP once if (m_external_address_voters.find(k)) return maybe_rotate(); if (m_external_addresses.size() > 40) { if (random() % 100 < 50) return maybe_rotate(); // use stable sort here to maintain the fifo-order // of the entries with the same number of votes // this will sort in ascending order, i.e. the lowest // votes first. Also, the oldest are first, so this // is a sort of weighted LRU. std::stable_sort(m_external_addresses.begin(), m_external_addresses.end()); // erase the last element, since it is one of the // ones with the fewest votes m_external_addresses.erase(m_external_addresses.end() - 1); } m_external_addresses.push_back(external_ip_t()); i = m_external_addresses.end() - 1; i->addr = ip; } // add one more vote to this external IP if (!i->add_vote(k, source_type)) return maybe_rotate(); ++m_total_votes; if (m_valid_external) return maybe_rotate(); i = std::min_element(m_external_addresses.begin(), m_external_addresses.end()); TORRENT_ASSERT(i != m_external_addresses.end()); if (i->addr == m_external_address) return maybe_rotate(); if (m_external_address != address_v4()) { // we have a temporary external address. As soon as we have // more than 25 votes, consider deciding which one to settle for return (m_total_votes >= 25) ? maybe_rotate() : false; } m_external_address = i->addr; return true; }
/*! * \brief Parse from Client * * \author Fimbulwinter Development Team * \author GreenBox * \date 08/12/11 * **/ int CharServer::parse_from_client(tcp_connection::pointer cl) { CharSessionData *csd = ((CharSessionData *)cl->get_data()); if (cl->flags.eof) { if (csd && csd->auth && auth_conn_ok) { WFIFOHEAD(auth_conn,6); WFIFOW(auth_conn,0) = INTER_CA_SET_ACC_OFF; WFIFOL(auth_conn,2) = csd->account_id; auth_conn->send_buffer(6); } set_char_offline(csd->account_id, -1); if (csd) delete csd; ShowInfo("Closed connection from '"CL_WHITE"%s"CL_RESET"'.\n", cl->socket().remote_endpoint().address().to_string().c_str()); cl->do_close(); return 0; } while(RFIFOREST(cl) >= 2) { unsigned short cmd = RFIFOW(cl, 0); #define FIFOSD_CHECK(rest) { if(RFIFOREST(cl) < rest) return 0; if (csd==NULL || !csd->auth) { cl->skip(rest); return 0; } } switch (cmd) { case HEADER_CH_SELECT_CHAR: FIFOSD_CHECK(3); { int slot = RFIFOB(cl,2); int char_id; CharData cd; cl->skip(3); { statement s = (database->prepare << "SELECT `char_id` FROM `char` WHERE `account_id`=:a AND `char_num`=:s", use(csd->account_id), use(slot), into(char_id)); s.execute(true); if (s.get_affected_rows() <= 0) { WFIFOPACKET(cl, spacket, HC_REFUSE_ENTER); spacket->error_code = 0; cl->send_buffer(sizeof(struct PACKET_HC_REFUSE_ENTER)); } } chars->load_char(char_id, cd, true); int server = -1; if (map_to_zone.count(cd.last_point.map)) server = map_to_zone[cd.last_point.map]; if (server < 0) { // TODO: Find for major city WFIFOPACKET(cl, spacket, SC_NOTIFY_BAN); spacket->error_code = 1; cl->send_buffer(sizeof(struct PACKET_SC_NOTIFY_BAN)); break; } auth_nodes[csd->account_id].sex = csd->sex; auth_nodes[csd->account_id].char_id = char_id; auth_nodes[csd->account_id].gmlevel = csd->gmlevel; auth_nodes[csd->account_id].login_id1 = csd->login_id1; auth_nodes[csd->account_id].login_id2 = csd->login_id2; auth_nodes[csd->account_id].expiration_time = csd->expiration_time; WFIFOPACKET(cl, spacket, HC_NOTIFY_ZONESVR); spacket->char_id = char_id; maps.copy_map_name_ext((char*)spacket->map_name, cd.last_point.map); spacket->addr.ip = htonl(servers[server].addr.to_ulong()); spacket->addr.port = servers[server].port; cl->send_buffer(sizeof(struct PACKET_HC_NOTIFY_ZONESVR)); } break; case HEADER_CH_REQUEST_DEL_TIMER: FIFOSD_CHECK(6); delete2_req(cl, csd); cl->skip(6); break; case HEADER_CH_ACCEPT_DEL_REQ: FIFOSD_CHECK(12); delete2_accept(cl, csd); cl->skip(6); break; case HEADER_CH_CANCEL_DEL_REQ: FIFOSD_CHECK(6); delete2_cancel(cl, csd); cl->skip(6); break; case HEADER_CH_DELETE_CHAR: case HEADER_CH_DELETE_CHAR2: if (cmd == HEADER_CH_DELETE_CHAR) FIFOSD_CHECK(sizeof(struct PACKET_CH_DELETE_CHAR)); if (cmd == HEADER_CH_DELETE_CHAR2) FIFOSD_CHECK(sizeof(struct PACKET_CH_DELETE_CHAR2)); { int cid = RFIFOL(cl,2); char email[40]; memcpy(email, RFIFOP(cl,6), 40); cl->skip((cmd == HEADER_CH_DELETE_CHAR) ? sizeof(struct PACKET_CH_DELETE_CHAR) : sizeof(struct PACKET_CH_DELETE_CHAR2)); if (_strcmpi(email, csd->email) != 0 && (strcmp("*****@*****.**", csd->email) || (strcmp("*****@*****.**", email) && strcmp("", email)))) { WFIFOPACKET(cl, spacket, HC_REFUSE_DELETECHAR); spacket->error_code = 0; cl->send_buffer(sizeof(struct PACKET_HC_REFUSE_DELETECHAR)); break; } bool found = false; int i, ch; for (i = 0; i < MAX_CHARS; i++) { if (csd->found_char[i] == cid) { found = true; break; } } if (!found) { WFIFOPACKET(cl, spacket, HC_REFUSE_DELETECHAR); spacket->error_code = 0; cl->send_buffer(sizeof(struct PACKET_HC_REFUSE_DELETECHAR)); break; } else { for(ch = i; ch < MAX_CHARS - 1; ch++) csd->found_char[ch] = csd->found_char[ch+1]; csd->found_char[MAX_CHARS - 1] = -1; if (!chars->delete_char(cid)) { WFIFOPACKET(cl, spacket, HC_REFUSE_DELETECHAR); spacket->error_code = 0; cl->send_buffer(sizeof(struct PACKET_HC_REFUSE_DELETECHAR)); break; } WFIFOPACKET(cl, spacket, HC_ACCEPT_DELETECHAR); cl->send_buffer(sizeof(struct PACKET_HC_ACCEPT_DELETECHAR)); } } break; case HEADER_CH_MAKE_CHAR: FIFOSD_CHECK(sizeof(struct PACKET_CH_MAKE_CHAR)); { TYPECAST_PACKET(RFIFOP(cl,0),rpacket,CH_MAKE_CHAR); // TODO: Check create char disabled int i = create_char(csd, (char*)rpacket->name,rpacket->str,rpacket->agi,rpacket->vit,rpacket->int_,rpacket->dex,rpacket->luk,rpacket->char_slot,rpacket->head_color,rpacket->head_style); //'Charname already exists' (-1), 'Char creation denied' (-2) and 'You are underaged' (-3) if (i < 0) { WFIFOPACKET(cl, spacket, HC_REFUSE_MAKECHAR); switch (i) { case -1: spacket->error_code = 0x00; break; case -2: spacket->error_code = 0xFF; break; case -3: spacket->error_code = 0x01; break; } cl->send_buffer(sizeof(struct PACKET_HC_REFUSE_MAKECHAR)); } else { // retrieve data CharData char_dat; memset(&char_dat, 0, sizeof(CharData)); chars->load_char(i, char_dat, false); //Only the short data is needed. // send to player WFIFOPACKET(cl, spacket, HC_ACCEPT_MAKECHAR); char_to_buf(&spacket->charinfo, &char_dat); cl->send_buffer(sizeof(struct PACKET_HC_ACCEPT_MAKECHAR)); // add new entry to the chars list for (int n = 0; n < MAX_CHARS; n++) { if(csd->found_char[n] == -1) csd->found_char[n] = i; // the char_id of the new char } } cl->skip(sizeof(struct PACKET_CH_MAKE_CHAR)); } break; case HEADER_CH_ENTER_CHECKBOT: FIFOSD_CHECK(sizeof(struct PACKET_CH_ENTER_CHECKBOT)); { WFIFOPACKET(cl, spacket, HC_CHECKBOT_RESULT); spacket->packet_len = sizeof(struct PACKET_HC_CHECKBOT_RESULT); spacket->result = 1; cl->send_buffer(spacket->packet_len); cl->skip(TYPECAST_PACKET_ONCE(RFIFOP(cl,0), CH_ENTER_CHECKBOT)->packet_len); } break; case HEADER_CH_CHECKBOT: FIFOSD_CHECK(sizeof(struct PACKET_CH_CHECKBOT)); { WFIFOPACKET(cl, spacket, HC_CHECKBOT_RESULT); spacket->packet_len = sizeof(struct PACKET_HC_CHECKBOT_RESULT); spacket->result = 1; cl->send_buffer(spacket->packet_len); cl->skip(TYPECAST_PACKET_ONCE(RFIFOP(cl,0), CH_CHECKBOT)->packet_len); } break; case HEADER_CH_ENTER: if(RFIFOREST(cl) < sizeof(struct PACKET_CH_ENTER)) return 0; { int account_id = RFIFOL(cl,2); unsigned int login_id1 = RFIFOL(cl,6); unsigned int login_id2 = RFIFOL(cl,10); char sex = RFIFOB(cl,16); cl->skip(sizeof(struct PACKET_CH_ENTER)); if (csd) { break; } csd = new CharSessionData(); csd->account_id = account_id; csd->login_id1 = login_id1; csd->login_id2 = login_id2; csd->sex = sex; csd->auth = false; csd->cl = cl; cl->set_data((char*)csd); WFIFOHEAD(cl, 4); WFIFOL(cl,0) = account_id; cl->send_buffer(4); if (auth_nodes.count(account_id) && auth_nodes[account_id].login_id1 == login_id1 && auth_nodes[account_id].login_id2 == login_id2) { auth_nodes.erase(account_id); auth_ok(cl, csd); } else { if (auth_conn_ok) { WFIFOHEAD(auth_conn,19); WFIFOW(auth_conn,0) = INTER_CA_AUTH; WFIFOL(auth_conn,2) = csd->account_id; WFIFOL(auth_conn,6) = csd->login_id1; WFIFOL(auth_conn,10) = csd->login_id2; WFIFOB(auth_conn,14) = csd->sex; WFIFOL(auth_conn,15) = cl->tag(); auth_conn->send_buffer(19); } else { WFIFOPACKET(cl, spacket, HC_REFUSE_ENTER); spacket->error_code = 0; cl->send_buffer(sizeof(struct PACKET_HC_REFUSE_ENTER)); } } } break; case HEADER_PING: if (RFIFOREST(cl) < sizeof(PACKET_PING)) return 0; cl->skip(sizeof(PACKET_PING)); break; case INTER_ZC_LOGIN: if (RFIFOREST(cl) < 60) return 0; { char *user = (char*)RFIFOP(cl, 2); char *pass = (char*)RFIFOP(cl, 26); if (strcmp(user, config.inter_login_user.c_str()) || strcmp(pass, config.inter_login_pass.c_str())) { WFIFOHEAD(cl, 3); WFIFOW(cl, 0) = INTER_CZ_LOGIN_REPLY; WFIFOB(cl, 2) = 1; cl->send_buffer(3); } else { int id = cl->tag(); servers[id].cl = cl; servers[id].addr = address_v4(ntohl(RFIFOL(cl, 54))); servers[id].port = ntohs(RFIFOW(cl, 58)); servers[id].users = 0; cl->set_parser(&CharServer::parse_from_zone); cl->flags.server = 1; cl->realloc_fifo(FIFOSIZE_SERVERLINK, FIFOSIZE_SERVERLINK); WFIFOHEAD(cl, 3); WFIFOW(cl, 0) = INTER_CZ_LOGIN_REPLY; WFIFOB(cl, 2) = 0; cl->send_buffer(3); } cl->skip(60); } break; default: ShowWarning("Unknown packet 0x%04x sent from %s, closing connection.\n", cmd, cl->socket().remote_endpoint().address().to_string().c_str()); cl->set_eof(); return 0; } } return 0; }
static address loopback() { return address_v4(0x7F000001); }
address read_v4_address(InIt& in) { unsigned long ip = read_uint32(in); return address_v4(ip); }
operator address() const { if (v4) return address(address_v4(addr.v4)); else return address(address_v6(addr.v6)); }
/// Obtain an address object that represents the loopback address. static address_v4 loopback() { return address_v4(static_cast<unsigned long>(INADDR_LOOPBACK)); }
static address any() { return address_v4(); }
address read_v4_address(InIt&& in) { std::uint32_t const ip = read_uint32(in); return address_v4(ip); }
bool rpc_manager::incoming(msg const& m, node_id* id) { INVARIANT_CHECK; if (m_destructing) return false; // we only deal with replies, not queries TORRENT_ASSERT(m.message.dict_find_string_value("y") == "r"); // if we don't have the transaction id in our // request list, ignore the packet std::string transaction_id = m.message.dict_find_string_value("t"); std::string::const_iterator i = transaction_id.begin(); int tid = transaction_id.size() != 2 ? -1 : io::read_uint16(i); observer_ptr o; for (transactions_t::iterator i = m_transactions.begin() , end(m_transactions.end()); i != end; ++i) { TORRENT_ASSERT(*i); if ((*i)->transaction_id() != tid) continue; if (m.addr.address() != (*i)->target_addr()) continue; o = *i; m_transactions.erase(i); break; } if (!o) { #ifdef TORRENT_DHT_VERBOSE_LOGGING TORRENT_LOG(rpc) << "Reply with invalid transaction id size: " << transaction_id.size() << " from " << m.addr; #endif entry e; incoming_error(e, "invalid transaction id"); m_send(m_userdata, e, m.addr, 0); return false; } #ifdef TORRENT_DHT_VERBOSE_LOGGING std::ofstream reply_stats("round_trip_ms.log", std::ios::app); reply_stats << m.addr << "\t" << total_milliseconds(time_now_hires() - o->sent()) << std::endl; #endif lazy_entry const* ret_ent = m.message.dict_find_dict("r"); if (ret_ent == 0) { entry e; incoming_error(e, "missing 'r' key"); m_send(m_userdata, e, m.addr, 0); return false; } lazy_entry const* node_id_ent = ret_ent->dict_find_string("id"); if (node_id_ent == 0 || node_id_ent->string_length() != 20) { entry e; incoming_error(e, "missing 'id' key"); m_send(m_userdata, e, m.addr, 0); return false; } lazy_entry const* ext_ip = ret_ent->dict_find_string("ip"); if (ext_ip && ext_ip->string_length() == 4) { // this node claims we use the wrong node-ID! address_v4::bytes_type b; memcpy(&b[0], ext_ip->string_ptr(), 4); m_ext_ip(address_v4(b), aux::session_impl::source_dht, m.addr.address()); } #if TORRENT_USE_IPV6 else if (ext_ip && ext_ip->string_length() == 16) { // this node claims we use the wrong node-ID! address_v6::bytes_type b; memcpy(&b[0], ext_ip->string_ptr(), 16); m_ext_ip(address_v6(b), aux::session_impl::source_dht, m.addr.address()); } #endif #ifdef TORRENT_DHT_VERBOSE_LOGGING TORRENT_LOG(rpc) << "[" << o->m_algorithm.get() << "] Reply with transaction id: " << tid << " from " << m.addr; #endif o->reply(m); *id = node_id(node_id_ent->string_ptr()); // we found an observer for this reply, hence the node is not spoofing // add it to the routing table return m_table.node_seen(*id, m.addr); }
static address broadcast() { return address_v4(0xFFFFFFFF); }
/** * @relates address_v4 */ inline address_v4 make_address_v4(const address_v4::bytes_type& bytes) { return address_v4(bytes); }
/// Obtain an address object that represents any address. static address_v4 any() { return address_v4(static_cast<unsigned long>(INADDR_ANY)); }
/** * @relates address_v4 */ inline address_v4 make_address_v4(address_v4::uint_type addr) { return address_v4(addr); }
/// Obtain an address object that represents the broadcast address. static address_v4 broadcast() { return address_v4(static_cast<unsigned long>(INADDR_BROADCAST)); }
std::pair<address,int> ipport_from_string(const std::string&ipPortStr) { std::string ipStr,portStr; const size_t first=ipPortStr.find_first_of(':'); const size_t last=(first==std::string::npos ?std::string::npos : ipPortStr.find_last_of(':',first+1) ); bool v6=false; if (first!=std::string::npos) { const size_t posR=ipPortStr.find_first_of(']'); const size_t posL=ipPortStr.find_first_of('['); if (last!=first ||posR!=std::string::npos ||posL!=std::string::npos )//is ipv6? { if (posR!=std::string::npos&&posL==std::string::npos ||posR==std::string::npos&&posL!=std::string::npos ||posL>posR ) { return std::pair<address,int>(address(),0);//error format } v6=true; if (posR!=std::string::npos)//[ip]:port { BOOST_ASSERT(posL!=std::string::npos&&posR>posL); ipStr=ipPortStr.substr(posL+1,posR-posL-1); if (last>posR&&last!=std::string::npos&&last+1<ipPortStr.size()) portStr=ipPortStr.substr(last+1); } else// only ip { ipStr=ipPortStr; } } else//is ipv4? { ipStr=ipPortStr.substr(0,last); if (last+1<ipPortStr.size()) portStr=ipPortStr.substr(last+1); } } else { const size_t pos=ipPortStr.find_first_of(']'); if (pos!=std::string::npos)//[] { v6=true; if (ipPortStr[0]=='[') ipStr=ipPortStr.substr(1,pos); else return std::pair<address,int>(address(),0);//error format if (pos+1<ipPortStr.size()) portStr=ipPortStr.substr(pos+1); if (boost::iequals(ipStr,"localhost")||boost::iequals(ipStr,"loopback")) { ipStr="::1"; } } else// only ip { ipStr=ipPortStr; } ipStr=ipPortStr; } error_code ec; if (ipStr.empty()) { if (v6) ipStr=address_v6().to_string(ec); else ipStr=address_v4().to_string(ec); } if (boost::iequals(ipStr,"localhost")||boost::iequals(ipStr,"loopback")) { if (v6) ipStr=address_v6::loopback().to_string(ec); else ipStr=address_v4::loopback().to_string(ec); } int port=0; if (!portStr.empty()) port=atoi(portStr.c_str()); if (v6) return std::pair<address,int>(address_v6::from_string(ipStr,ec),port); else return std::pair<address,int>(address_v4::from_string(ipStr,ec),port); }