mirror of
https://github.com/RetroShare/RetroShare.git
synced 2025-02-27 10:21:40 -05:00

With this commit IPv6-v3 surpass v0.6-IPv6-2 in term of features obsoleting it. p3BitDht handle gracefully unwanted non IPv4 addresses rsUdpStack handle gracefully unwanted non IPv4 addresses pqissludp handle gracefully unwanted non IPv4 addresses Move single address limitation workaround from p3discovery2::sendOwnContactInfo to better place p3PeerMgrIMPL::UpdateOwnAddress this way local address list is queried less often and only id there is some suggestion that it may have changed (probably ir will not be called all the times there is a changes in local network interfaces but is good enough) Implement crossplatform rs_setsockopt to avoid too much ifdef around Implement sockaddr_storage_copy to safely copy sockaddr_storage objects
533 lines
12 KiB
C++
533 lines
12 KiB
C++
/*
|
|
* "$Id: pqinetwork.cc,v 1.18 2007-04-15 18:45:18 rmf24 Exp $"
|
|
*
|
|
* 3P/PQI network interface for RetroShare.
|
|
*
|
|
* Copyright (C) 2004-2006 Robert Fernie.
|
|
* Copyright (C) 2015-2018 Gioacchino Mazzurco <gio@eigenlab.org>
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Library General Public
|
|
* License Version 2 as published by the Free Software Foundation.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Library General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Library General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
|
* USA.
|
|
*
|
|
* Please report all bugs and problems to "retroshare@lunamutt.com".
|
|
*
|
|
*/
|
|
|
|
#ifdef WINDOWS_SYS
|
|
# include "util/rswin.h"
|
|
# include "util/rsmemory.h"
|
|
# include <ws2tcpip.h>
|
|
#endif // WINDOWS_SYS
|
|
|
|
#include "pqi/pqinetwork.h"
|
|
#include "util/rsnet.h"
|
|
|
|
#include <errno.h>
|
|
#include <iostream>
|
|
#include <stdio.h>
|
|
#include <unistd.h>
|
|
|
|
#include "util/rsdebug.h"
|
|
#include "util/rsstring.h"
|
|
#include "util/rsnet.h"
|
|
#include "util/stacktrace.h"
|
|
|
|
static struct RsLog::logInfo pqinetzoneInfo = {RsLog::Default, "pqinet"};
|
|
#define pqinetzone &pqinetzoneInfo
|
|
|
|
/*****
|
|
* #define NET_DEBUG 1
|
|
****/
|
|
|
|
#ifdef WINDOWS_SYS /* Windows - define errno */
|
|
|
|
int errno;
|
|
|
|
#else /* Windows - define errno */
|
|
|
|
#include <netdb.h>
|
|
|
|
#endif
|
|
|
|
#ifdef __HAIKU__
|
|
#include <sys/sockio.h>
|
|
#define IFF_RUNNING 0x0001
|
|
#endif
|
|
|
|
/********************************** WINDOWS/UNIX SPECIFIC PART ******************/
|
|
#ifndef WINDOWS_SYS
|
|
|
|
void showSocketError(std::string &out)
|
|
{
|
|
int err = errno;
|
|
rs_sprintf_append(out, "\tSocket Error(%d) : %s\n", err, socket_errorType(err).c_str());
|
|
}
|
|
|
|
std::string socket_errorType(int err)
|
|
{
|
|
if (err == EBADF)
|
|
{
|
|
return std::string("EBADF");
|
|
}
|
|
else if (err == EINVAL)
|
|
{
|
|
return std::string("EINVAL");
|
|
}
|
|
else if (err == EFAULT)
|
|
{
|
|
return std::string("EFAULT");
|
|
}
|
|
else if (err == ENOTSOCK)
|
|
{
|
|
return std::string("ENOTSOCK");
|
|
}
|
|
else if (err == EISCONN)
|
|
{
|
|
return std::string("EISCONN");
|
|
}
|
|
else if (err == ECONNREFUSED)
|
|
{
|
|
return std::string("ECONNREFUSED");
|
|
}
|
|
else if (err == ETIMEDOUT)
|
|
{
|
|
return std::string("ETIMEDOUT");
|
|
}
|
|
else if (err == ENETUNREACH)
|
|
{
|
|
return std::string("ENETUNREACH");
|
|
}
|
|
else if (err == EADDRINUSE)
|
|
{
|
|
return std::string("EADDRINUSE");
|
|
}
|
|
else if (err == EINPROGRESS)
|
|
{
|
|
return std::string("EINPROGRESS");
|
|
}
|
|
else if (err == EALREADY)
|
|
{
|
|
return std::string("EALREADY");
|
|
}
|
|
else if (err == EAGAIN)
|
|
{
|
|
return std::string("EAGAIN");
|
|
}
|
|
else if (err == EISCONN)
|
|
{
|
|
return std::string("EISCONN");
|
|
}
|
|
else if (err == ENOTCONN)
|
|
{
|
|
return std::string("ENOTCONN");
|
|
}
|
|
// These ones have been turning up in SSL CONNECTION FAILURES.
|
|
else if (err == EPIPE)
|
|
{
|
|
return std::string("EPIPE");
|
|
}
|
|
else if (err == ECONNRESET)
|
|
{
|
|
return std::string("ECONNRESET");
|
|
}
|
|
else if (err == EHOSTUNREACH)
|
|
{
|
|
return std::string("EHOSTUNREACH");
|
|
}
|
|
else if (err == EADDRNOTAVAIL)
|
|
{
|
|
return std::string("EADDRNOTAVAIL");
|
|
}
|
|
//
|
|
|
|
return std::string("UNKNOWN ERROR CODE - ASK RS-DEVS TO ADD IT!");
|
|
}
|
|
|
|
/********************************** WINDOWS/UNIX SPECIFIC PART ******************/
|
|
#else
|
|
|
|
void showSocketError(std::string &out)
|
|
{
|
|
int err = WSAGetLastError();
|
|
rs_sprintf_append(out, "\tSocket Error(%d) : %s\n", err, socket_errorType(err).c_str());
|
|
}
|
|
|
|
|
|
std::string socket_errorType(int err)
|
|
{
|
|
if (err == WSAEBADF)
|
|
{
|
|
return std::string("WSABADF");
|
|
}
|
|
|
|
|
|
else if (err == WSAEINTR)
|
|
{
|
|
return std::string("WSAEINTR");
|
|
}
|
|
else if (err == WSAEACCES)
|
|
{
|
|
return std::string("WSAEACCES");
|
|
}
|
|
else if (err == WSAEFAULT)
|
|
{
|
|
return std::string("WSAEFAULT");
|
|
}
|
|
else if (err == WSAEINVAL)
|
|
{
|
|
return std::string("WSAEINVAL");
|
|
}
|
|
else if (err == WSAEMFILE)
|
|
{
|
|
return std::string("WSAEMFILE");
|
|
}
|
|
else if (err == WSAEWOULDBLOCK)
|
|
{
|
|
return std::string("WSAEWOULDBLOCK");
|
|
}
|
|
else if (err == WSAEINPROGRESS)
|
|
{
|
|
return std::string("WSAEINPROGRESS");
|
|
}
|
|
else if (err == WSAEALREADY)
|
|
{
|
|
return std::string("WSAEALREADY");
|
|
}
|
|
else if (err == WSAENOTSOCK)
|
|
{
|
|
return std::string("WSAENOTSOCK");
|
|
}
|
|
else if (err == WSAEDESTADDRREQ)
|
|
{
|
|
return std::string("WSAEDESTADDRREQ");
|
|
}
|
|
else if (err == WSAEMSGSIZE)
|
|
{
|
|
return std::string("WSAEMSGSIZE");
|
|
}
|
|
else if (err == WSAEPROTOTYPE)
|
|
{
|
|
return std::string("WSAEPROTOTYPE");
|
|
}
|
|
else if (err == WSAENOPROTOOPT)
|
|
{
|
|
return std::string("WSAENOPROTOOPT");
|
|
}
|
|
else if (err == WSAENOTSOCK)
|
|
{
|
|
return std::string("WSAENOTSOCK");
|
|
}
|
|
else if (err == WSAEISCONN)
|
|
{
|
|
return std::string("WSAISCONN");
|
|
}
|
|
else if (err == WSAECONNREFUSED)
|
|
{
|
|
return std::string("WSACONNREFUSED");
|
|
}
|
|
else if (err == WSAECONNRESET)
|
|
{
|
|
return std::string("WSACONNRESET");
|
|
}
|
|
else if (err == WSAETIMEDOUT)
|
|
{
|
|
return std::string("WSATIMEDOUT");
|
|
}
|
|
else if (err == WSAENETUNREACH)
|
|
{
|
|
return std::string("WSANETUNREACH");
|
|
}
|
|
else if (err == WSAEADDRINUSE)
|
|
{
|
|
return std::string("WSAADDRINUSE");
|
|
}
|
|
else if (err == WSAEAFNOSUPPORT)
|
|
{
|
|
return std::string("WSAEAFNOSUPPORT (normally UDP related!)");
|
|
}
|
|
|
|
return std::string("----WINDOWS OPERATING SYSTEM FAILURE----");
|
|
}
|
|
|
|
// implement the improved unix inet address fn.
|
|
// using old one.
|
|
int inet_aton(const char *name, struct in_addr *addr)
|
|
{
|
|
return (((*addr).s_addr = inet_addr(name)) != INADDR_NONE);
|
|
}
|
|
|
|
#endif
|
|
/********************************** WINDOWS/UNIX SPECIFIC PART ******************/
|
|
|
|
|
|
#include <sys/types.h>
|
|
#ifdef WINDOWS_SYS
|
|
# include <winsock2.h>
|
|
# include <iphlpapi.h>
|
|
# pragma comment(lib, "IPHLPAPI.lib")
|
|
#elif defined(__ANDROID__)
|
|
# include <string>
|
|
# include <QString>
|
|
# include <QHostAddress>
|
|
# include <QNetworkInterface>
|
|
#else // not __ANDROID__ nor WINDOWS => Linux and other unixes
|
|
# include <ifaddrs.h>
|
|
# include <net/if.h>
|
|
#endif // WINDOWS_SYS
|
|
|
|
bool getLocalAddresses(std::vector<sockaddr_storage>& addrs)
|
|
{
|
|
addrs.clear();
|
|
|
|
#ifdef WINDOWS_SYS
|
|
// Seems strange to me but M$ documentation suggests to allocate this way...
|
|
DWORD bf_size = 16000;
|
|
IP_ADAPTER_ADDRESSES* adapter_addresses = (IP_ADAPTER_ADDRESSES*) rs_malloc(bf_size);
|
|
|
|
if(adapter_addresses == NULL)
|
|
return false ;
|
|
|
|
DWORD error = GetAdaptersAddresses(AF_UNSPEC,
|
|
GAA_FLAG_SKIP_MULTICAST |
|
|
GAA_FLAG_SKIP_DNS_SERVER |
|
|
GAA_FLAG_SKIP_FRIENDLY_NAME,
|
|
NULL,
|
|
adapter_addresses,
|
|
&bf_size);
|
|
if (error != ERROR_SUCCESS)
|
|
{
|
|
std::cerr << "FATAL ERROR: getLocalAddresses failed!" << std::endl;
|
|
return false ;
|
|
}
|
|
|
|
IP_ADAPTER_ADDRESSES* adapter(NULL);
|
|
for(adapter = adapter_addresses; NULL != adapter; adapter = adapter->Next)
|
|
{
|
|
IP_ADAPTER_UNICAST_ADDRESS* address;
|
|
for ( address = adapter->FirstUnicastAddress; address; address = address->Next)
|
|
{
|
|
sockaddr_storage tmp;
|
|
sockaddr_storage_clear(tmp);
|
|
if (sockaddr_storage_copyip(tmp, * reinterpret_cast<sockaddr_storage*>(address->Address.lpSockaddr)))
|
|
addrs.push_back(tmp);
|
|
}
|
|
}
|
|
free(adapter_addresses);
|
|
#elif defined(__ANDROID__)
|
|
foreach(QHostAddress qAddr, QNetworkInterface::allAddresses())
|
|
{
|
|
sockaddr_storage tmpAddr;
|
|
sockaddr_storage_clear(tmpAddr);
|
|
if(sockaddr_storage_ipv4_aton(tmpAddr, qAddr.toString().toStdString().c_str()))
|
|
addrs.push_back(tmpAddr);
|
|
}
|
|
#else // not WINDOWS_SYS not ANDROID => Linux and other unixes
|
|
struct ifaddrs *ifsaddrs, *ifa;
|
|
if(getifaddrs(&ifsaddrs) != 0)
|
|
{
|
|
std::cerr << __PRETTY_FUNCTION__ << " FATAL ERROR: " << errno << " "
|
|
<< strerror(errno) << std::endl;
|
|
print_stacktrace();
|
|
return false;
|
|
}
|
|
for ( ifa = ifsaddrs; ifa; ifa = ifa->ifa_next )
|
|
if ( ifa->ifa_addr && (ifa->ifa_flags & IFF_UP) )
|
|
{
|
|
sockaddr_storage tmp;
|
|
sockaddr_storage_clear(tmp);
|
|
if (sockaddr_storage_copyip(tmp, *reinterpret_cast<sockaddr_storage*>(ifa->ifa_addr)))
|
|
addrs.push_back(tmp);
|
|
}
|
|
freeifaddrs(ifsaddrs);
|
|
#endif // WINDOWS_SYS
|
|
|
|
#ifdef NET_DEBUG
|
|
std::list<sockaddr_storage>::iterator it;
|
|
std::cout << "getLocalAddresses(...) returning: <" ;
|
|
for(it = addrs.begin(); it != addrs.end(); ++it)
|
|
std::cout << sockaddr_storage_iptostring(*it) << ", ";
|
|
std::cout << ">" << std::endl;
|
|
#endif
|
|
|
|
return !addrs.empty();
|
|
}
|
|
|
|
|
|
/*************************************************************
|
|
* Socket Library Wrapper Functions
|
|
* to get over the crapness of the windows.
|
|
*
|
|
*/
|
|
|
|
int unix_close(int fd)
|
|
{
|
|
int ret;
|
|
/******************* WINDOWS SPECIFIC PART ******************/
|
|
#ifndef WINDOWS_SYS // ie UNIX
|
|
ret = close(fd);
|
|
#else
|
|
|
|
#ifdef NET_DEBUG
|
|
std::cerr << "unix_close()" << std::endl;
|
|
#endif
|
|
ret = closesocket(fd);
|
|
/* translate error */
|
|
#endif
|
|
/******************* WINDOWS SPECIFIC PART ******************/
|
|
return ret;
|
|
}
|
|
|
|
int unix_socket(int domain, int type, int protocol)
|
|
{
|
|
int osock = socket(domain, type, protocol);
|
|
|
|
#ifdef WINDOWS_SYS
|
|
#ifdef NET_DEBUG
|
|
std::cerr << "unix_socket()" << std::endl;
|
|
#endif // NET_DEBUG
|
|
|
|
if ((unsigned) osock == INVALID_SOCKET)
|
|
{
|
|
// Invalidate socket Unix style.
|
|
osock = -1;
|
|
errno = WinToUnixError(WSAGetLastError());
|
|
}
|
|
#endif // WINDOWS_SYS
|
|
|
|
return osock;
|
|
}
|
|
|
|
|
|
int unix_fcntl_nonblock(int fd)
|
|
{
|
|
int ret;
|
|
|
|
/******************* WINDOWS SPECIFIC PART ******************/
|
|
#ifndef WINDOWS_SYS // ie UNIX
|
|
ret = fcntl(fd, F_SETFL, O_NONBLOCK);
|
|
|
|
#ifdef NET_DEBUG
|
|
std::cerr << "unix_fcntl_nonblock():" << ret << " errno:" << errno << std::endl;
|
|
#endif
|
|
|
|
#else
|
|
unsigned long int on = 1;
|
|
ret = ioctlsocket(fd, FIONBIO, &on);
|
|
|
|
#ifdef NET_DEBUG
|
|
std::cerr << "unix_fcntl_nonblock()" << std::endl;
|
|
#endif
|
|
if (ret != 0)
|
|
{
|
|
/* store unix-style error
|
|
*/
|
|
ret = -1;
|
|
errno = WinToUnixError(WSAGetLastError());
|
|
}
|
|
#endif
|
|
/******************* WINDOWS SPECIFIC PART ******************/
|
|
return ret;
|
|
}
|
|
|
|
|
|
int unix_connect(int fd, const sockaddr_storage &serv_addr)
|
|
{
|
|
#ifdef NET_DEBUG
|
|
std::cerr << __PRETTY_FUNCTION__ << std::endl;
|
|
#endif
|
|
|
|
int ret = connect( fd, (const struct sockaddr *) &serv_addr,
|
|
sizeof(struct sockaddr_in6) );
|
|
|
|
/******************* WINDOWS SPECIFIC PART ******************/
|
|
#ifdef WINDOWS_SYS // WINDOWS
|
|
if (ret != 0)
|
|
{
|
|
errno = WinToUnixError(WSAGetLastError());
|
|
ret = -1;
|
|
}
|
|
#endif
|
|
/******************* WINDOWS SPECIFIC PART ******************/
|
|
return ret;
|
|
}
|
|
|
|
|
|
int unix_getsockopt_error(int sockfd, int *err)
|
|
{
|
|
int ret;
|
|
*err = 1;
|
|
/******************* WINDOWS SPECIFIC PART ******************/
|
|
#ifndef WINDOWS_SYS // ie UNIX
|
|
socklen_t optlen = 4;
|
|
ret=getsockopt(sockfd, SOL_SOCKET, SO_ERROR, err, &optlen);
|
|
#else // WINDOWS_SYS
|
|
int optlen = 4;
|
|
ret=getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (char *) err, &optlen);
|
|
/* translate */
|
|
#ifdef NET_DEBUG
|
|
std::cerr << "unix_getsockopt_error() returned: " << (int) err << std::endl;
|
|
#endif
|
|
if (*err != 0)
|
|
{
|
|
*err = WinToUnixError(*err);
|
|
}
|
|
#endif
|
|
/******************* WINDOWS SPECIFIC PART ******************/
|
|
return ret;
|
|
}
|
|
|
|
/******************* WINDOWS SPECIFIC PART ******************/
|
|
#ifdef WINDOWS_SYS // ie WINDOWS.
|
|
|
|
int WinToUnixError(int error)
|
|
{
|
|
#ifdef NET_DEBUG
|
|
std::cerr << "WinToUnixError(" << error << ")" << std::endl;
|
|
#endif
|
|
switch(error)
|
|
{
|
|
case WSAEINPROGRESS:
|
|
return EINPROGRESS;
|
|
break;
|
|
case WSAEWOULDBLOCK:
|
|
return EINPROGRESS;
|
|
break;
|
|
case WSAENETUNREACH:
|
|
return ENETUNREACH;
|
|
break;
|
|
case WSAETIMEDOUT:
|
|
return ETIMEDOUT;
|
|
break;
|
|
case WSAEHOSTDOWN:
|
|
return EHOSTDOWN;
|
|
break;
|
|
case WSAECONNREFUSED:
|
|
return ECONNREFUSED;
|
|
break;
|
|
case WSAECONNRESET:
|
|
return ECONNRESET;
|
|
break;
|
|
default:
|
|
#ifdef NET_DEBUG
|
|
std::cerr << "WinToUnixError(" << error << ") Code Unknown!";
|
|
std::cerr << std::endl;
|
|
#endif
|
|
break;
|
|
}
|
|
return ECONNREFUSED; /* sensible default? */
|
|
}
|
|
|
|
#endif
|
|
/******************* WINDOWS SPECIFIC PART ******************/
|