added implementation for get_default_router for linux

This commit is contained in:
Arvid Norberg 2008-04-25 05:51:21 +00:00
parent 0d818da41a
commit 6a7790cd28
2 changed files with 165 additions and 24 deletions

View File

@ -11,22 +11,23 @@ int main()
asio::error_code ec; asio::error_code ec;
std::vector<ip_interface> const& net = enum_net_interfaces(ios, ec); std::vector<ip_interface> const& net = enum_net_interfaces(ios, ec);
address local = guess_local_address(ios);
std::cout << "Local address: " << local << std::endl;
address gateway = get_default_gateway(ios, local, ec);
std::cout << "Default gateway: " << gateway << std::endl;
std::cout << "================\n";
std::cout << "interface\tnetmask \tflags\n";
for (std::vector<ip_interface>::const_iterator i = net.begin() for (std::vector<ip_interface>::const_iterator i = net.begin()
, end(net.end()); i != end; ++i) , end(net.end()); i != end; ++i)
{ {
std::cout << "address: " << i->interface_address << std::endl std::cout << i->interface_address << "\t" << i->netmask << "\t";
<< " mask: " << i->netmask << std::endl
<< " flags: ";
if (is_multicast(i->interface_address)) std::cout << "multicast "; if (is_multicast(i->interface_address)) std::cout << "multicast ";
if (is_local(i->interface_address)) std::cout << "local "; if (is_local(i->interface_address)) std::cout << "local ";
if (is_loopback(i->interface_address)) std::cout << "loopback "; if (is_loopback(i->interface_address)) std::cout << "loopback ";
std::cout << std::endl; std::cout << std::endl;
} }
address local = guess_local_address(ios);
std::cout << "Local address: " << local << std::endl;
address gateway = get_default_gateway(ios, local, ec);
std::cout << "Default gateway: " << gateway << std::endl;
} }

View File

@ -31,8 +31,8 @@ POSSIBILITY OF SUCH DAMAGE.
*/ */
#include "libtorrent/config.hpp" #include "libtorrent/config.hpp"
#if defined TORRENT_BSD || defined TORRENT_LINUX #if defined TORRENT_BSD
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <netinet/in.h> #include <netinet/in.h>
@ -44,6 +44,87 @@ POSSIBILITY OF SUCH DAMAGE.
#endif #endif
#include <windows.h> #include <windows.h>
#include <iphlpapi.h> #include <iphlpapi.h>
#elif defined TORRENT_LINUX
#include <asm/types.h>
#include <netinet/ether.h>
#include <netinet/in.h>
#include <net/if.h>
#include <stdio.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
struct route_info
{
u_int dst_addr;
u_int src_addr;
u_int gateway;
char if_name[IF_NAMESIZE];
};
int read_nl_sock(int sock, char *buf, int bufsize, int seq, int pid)
{
nlmsghdr* nl_hdr;
int msg_len = 0;
do
{
int read_len = recv(sock, buf, bufsize - msg_len, 0);
if (read_len < 0) return -1;
nl_hdr = (nlmsghdr*)buf;
if ((NLMSG_OK(nl_hdr, read_len) == 0) || (nl_hdr->nlmsg_type == NLMSG_ERROR))
return -1;
if (nl_hdr->nlmsg_type == NLMSG_DONE) break;
buf += read_len;
msg_len += read_len;
if ((nl_hdr->nlmsg_flags & NLM_F_MULTI) == 0) break;
} while((nl_hdr->nlmsg_seq != seq) || (nl_hdr->nlmsg_pid != pid));
return msg_len;
}
// For parsing the route info returned
void parse_route(nlmsghdr *nl_hdr, route_info *rt_info)
{
rtmsg* rt_msg = (rtmsg*)NLMSG_DATA(nl_hdr);
if((rt_msg->rtm_family != AF_INET) || (rt_msg->rtm_table != RT_TABLE_MAIN))
return;
int rt_len = RTM_PAYLOAD(nl_hdr);
for (rtattr* rt_attr = (rtattr*)RTM_RTA(rt_msg);
RTA_OK(rt_attr,rt_len); rt_attr = RTA_NEXT(rt_attr,rt_len))
{
switch(rt_attr->rta_type)
{
case RTA_OIF:
if_indextoname(*(int*)RTA_DATA(rt_attr), rt_info->if_name);
break;
case RTA_GATEWAY:
rt_info->gateway = *(u_int*)RTA_DATA(rt_attr);
break;
case RTA_PREFSRC:
rt_info->src_addr = *(u_int*)RTA_DATA(rt_attr);
break;
case RTA_DST:
rt_info->dst_addr = *(u_int*)RTA_DATA(rt_attr);
break;
}
}
return;
}
#endif #endif
#include "libtorrent/enum_net.hpp" #include "libtorrent/enum_net.hpp"
@ -54,22 +135,28 @@ namespace libtorrent
{ {
namespace namespace
{ {
address inaddr_to_address(in_addr const* ina)
{
typedef asio::ip::address_v4::bytes_type bytes_t;
bytes_t b;
memcpy(&b[0], ina, b.size());
return address_v4(b);
}
address inaddr6_to_address(in6_addr const* ina6)
{
typedef asio::ip::address_v6::bytes_type bytes_t;
bytes_t b;
memcpy(&b[0], ina6, b.size());
return address_v6(b);
}
address sockaddr_to_address(sockaddr const* sin) address sockaddr_to_address(sockaddr const* sin)
{ {
if (sin->sa_family == AF_INET) if (sin->sa_family == AF_INET)
{ return inaddr_to_address(&((sockaddr_in const*)sin)->sin_addr);
typedef asio::ip::address_v4::bytes_type bytes_t;
bytes_t b;
memcpy(&b[0], &((sockaddr_in const*)sin)->sin_addr, b.size());
return address_v4(b);
}
else if (sin->sa_family == AF_INET6) else if (sin->sa_family == AF_INET6)
{ return inaddr6_to_address(&((sockaddr_in6 const*)sin)->sin6_addr);
typedef asio::ip::address_v6::bytes_type bytes_t;
bytes_t b;
memcpy(&b[0], &((sockaddr_in6 const*)sin)->sin6_addr, b.size());
return address_v6(b);
}
return address(); return address();
} }
@ -394,8 +481,61 @@ namespace libtorrent
return ret; return ret;
//#elif defined TORRENT_LINUX #elif defined TORRENT_LINUX
// No linux implementation yet
enum { BUFSIZE = 8192 };
int sock = socket(PF_ROUTE, SOCK_DGRAM, NETLINK_ROUTE);
if (sock < 0)
{
ec = asio::error_code(errno, asio::error::system_category);
return address_v4::any();
}
int seq = 0;
char msg[BUFSIZE];
memset(msg, 0, BUFSIZE);
nlmsghdr* nl_msg = (nlmsghdr*)msg;
nl_msg->nlmsg_len = NLMSG_LENGTH(sizeof(struct 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 = asio::error_code(errno, asio::error::system_category);
close(sock);
return address_v4::any();
}
int len = read_nl_sock(sock, msg, BUFSIZE, seq, getpid());
if (len < 0)
{
ec = asio::error_code(errno, asio::error::system_category);
close(sock);
return address_v4::any();
}
route_info rt_info;
for (; NLMSG_OK(nl_msg, len); nl_msg = NLMSG_NEXT(nl_msg, len))
{
memset(&rt_info, 0, sizeof(route_info));
parse_route(nl_msg, &rt_info);
if (rt_info.dst_addr == 0)
{
in_addr addr;
addr.s_addr = rt_info.gateway;
close(sock);
return inaddr_to_address(&addr);
}
}
close(sock);
return address_v4::any();
#else #else
if (!interface.is_v4()) if (!interface.is_v4())
{ {