mirror of
https://github.com/uroni/urbackup_backend.git
synced 2025-10-26 11:36:50 +00:00
298 lines
6.9 KiB
C++
298 lines
6.9 KiB
C++
/*************************************************************************
|
|
* UrBackup - Client/Server backup system
|
|
* Copyright (C) 2011-2016 Martin Raiber
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU Affero General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program 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 Affero General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Affero General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
**************************************************************************/
|
|
|
|
#include "socket_header.h"
|
|
#include <string>
|
|
#ifndef _WIN32
|
|
#include <memory.h>
|
|
#include "LookupService.h"
|
|
#endif
|
|
#include "LookupService.h"
|
|
#include <iostream>
|
|
#include <algorithm>
|
|
#ifdef ENABLE_C_ARES
|
|
#include <ares.h>
|
|
#include "Server.h"
|
|
#endif
|
|
|
|
std::vector<SLookupBlockingResult> LookupBlocking(std::string pServer)
|
|
{
|
|
const char* host = pServer.c_str();
|
|
unsigned int addr = inet_addr(host);
|
|
if (addr != INADDR_NONE)
|
|
{
|
|
SLookupBlockingResult res;
|
|
res.zone = 0;
|
|
res.is_ipv6 = false;
|
|
res.addr_v4 = addr;
|
|
std::vector<SLookupBlockingResult> ret;
|
|
ret.push_back(res);
|
|
return ret;
|
|
}
|
|
|
|
addrinfo hints;
|
|
memset(&hints, 0, sizeof(hints));
|
|
hints.ai_family = AF_UNSPEC;
|
|
hints.ai_socktype = SOCK_STREAM;
|
|
hints.ai_protocol = IPPROTO_TCP;
|
|
|
|
std::vector<SLookupBlockingResult> ret;
|
|
addrinfo* h;
|
|
if (getaddrinfo(pServer.c_str(), NULL, &hints, &h) == 0)
|
|
{
|
|
addrinfo* orig_h = h;
|
|
while (h != NULL)
|
|
{
|
|
if (h->ai_family != AF_INET6
|
|
&& h->ai_family != AF_INET)
|
|
{
|
|
h = h->ai_next;
|
|
continue;
|
|
}
|
|
|
|
if (h->ai_family == AF_INET6)
|
|
{
|
|
if (h->ai_addrlen >= sizeof(sockaddr_in6))
|
|
{
|
|
SLookupBlockingResult dest;
|
|
dest.is_ipv6 = true;
|
|
memcpy(dest.addr_v6, &reinterpret_cast<sockaddr_in6*>(h->ai_addr)->sin6_addr, 16);
|
|
dest.zone = reinterpret_cast<sockaddr_in6*>(h->ai_addr)->sin6_scope_id;
|
|
ret.push_back(dest);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (h->ai_addrlen >= sizeof(sockaddr_in))
|
|
{
|
|
SLookupBlockingResult dest;
|
|
dest.zone = 0;
|
|
dest.is_ipv6 = false;
|
|
dest.addr_v4 = reinterpret_cast<sockaddr_in*>(h->ai_addr)->sin_addr.s_addr;
|
|
ret.push_back(dest);
|
|
}
|
|
}
|
|
|
|
h = h->ai_next;
|
|
}
|
|
freeaddrinfo(orig_h);
|
|
return ret;
|
|
}
|
|
else
|
|
{
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
#ifdef ENABLE_C_ARES
|
|
|
|
void addrinfo_callback(void *arg,
|
|
int status,
|
|
int timeouts,
|
|
struct ares_addrinfo *res)
|
|
{
|
|
std::vector<SLookupBlockingResult>* ret
|
|
= reinterpret_cast<std::vector<SLookupBlockingResult>*>(arg);
|
|
|
|
if (status == ARES_SUCCESS
|
|
&& res!=NULL)
|
|
{
|
|
ares_addrinfo_node* h = res->nodes;
|
|
while (h != NULL)
|
|
{
|
|
if (h->ai_family != AF_INET6
|
|
&& h->ai_family != AF_INET)
|
|
{
|
|
h = h->ai_next;
|
|
continue;
|
|
}
|
|
|
|
if (h->ai_family == AF_INET6)
|
|
{
|
|
if (h->ai_addrlen >= sizeof(sockaddr_in6))
|
|
{
|
|
SLookupBlockingResult dest;
|
|
dest.is_ipv6 = true;
|
|
memcpy(dest.addr_v6, &reinterpret_cast<sockaddr_in6*>(h->ai_addr)->sin6_addr, 16);
|
|
dest.zone = reinterpret_cast<sockaddr_in6*>(h->ai_addr)->sin6_scope_id;
|
|
ret->push_back(dest);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (h->ai_addrlen >= sizeof(sockaddr_in))
|
|
{
|
|
SLookupBlockingResult dest;
|
|
dest.zone = 0;
|
|
dest.is_ipv6 = false;
|
|
dest.addr_v4 = reinterpret_cast<sockaddr_in*>(h->ai_addr)->sin_addr.s_addr;
|
|
ret->push_back(dest);
|
|
}
|
|
}
|
|
|
|
h = h->ai_next;
|
|
}
|
|
}
|
|
}
|
|
|
|
bool LookupInit()
|
|
{
|
|
int rc = ares_library_init(ARES_LIB_INIT_ALL);
|
|
if (rc != ARES_SUCCESS)
|
|
{
|
|
std::cerr << "C-ares initialization failed with code " << ares_strerror(rc) << std::endl;
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
std::vector<SLookupBlockingResult> LookupWithTimeout(std::string pServer, int timeoutms, int stop_timeoutms)
|
|
{
|
|
if (pServer == "localhost")
|
|
{
|
|
pServer = "127.0.0.1";
|
|
}
|
|
|
|
unsigned int addr = inet_addr(pServer.c_str());
|
|
if (addr != INADDR_NONE)
|
|
{
|
|
SLookupBlockingResult res;
|
|
res.zone = 0;
|
|
res.is_ipv6 = false;
|
|
res.addr_v4 = addr;
|
|
std::vector<SLookupBlockingResult> ret;
|
|
ret.push_back(res);
|
|
return ret;
|
|
}
|
|
|
|
ares_channel channel;
|
|
struct ares_options options = {};
|
|
|
|
int rc = ares_init_options(&channel, &options, 0);
|
|
if (rc != ARES_SUCCESS)
|
|
{
|
|
return std::vector<SLookupBlockingResult>();
|
|
}
|
|
|
|
ares_addrinfo_hints hints;
|
|
memset(&hints, 0, sizeof(hints));
|
|
hints.ai_family = AF_UNSPEC;
|
|
hints.ai_socktype = SOCK_STREAM;
|
|
hints.ai_protocol = IPPROTO_TCP;
|
|
|
|
std::vector<SLookupBlockingResult> ret;
|
|
ares_getaddrinfo(channel, pServer.c_str(), NULL, &hints, addrinfo_callback, &ret);
|
|
|
|
int nfds, count;
|
|
fd_set readers, writers;
|
|
timeval maxtv;
|
|
maxtv.tv_sec = (std::min)(stop_timeoutms, timeoutms) / 1000;
|
|
maxtv.tv_usec = ((std::min)(stop_timeoutms, timeoutms) % 1000) * 1000;
|
|
|
|
int64 starttime = Server->getTimeMS();
|
|
do
|
|
{
|
|
ares_socket_t socks[ARES_GETSOCK_MAXNUM];
|
|
|
|
rc = ares_getsock(channel, socks, ARES_GETSOCK_MAXNUM);
|
|
|
|
pollfd conn[ARES_GETSOCK_MAXNUM];
|
|
bool has_fd = false;
|
|
for (int i = 0; i < ARES_GETSOCK_MAXNUM; ++i)
|
|
{
|
|
conn[i].fd = -1;
|
|
conn[i].events = 0;
|
|
conn[i].revents = 0;
|
|
if (ARES_GETSOCK_READABLE(rc, i))
|
|
{
|
|
has_fd = true;
|
|
conn[i].fd = socks[i];
|
|
conn[i].events = POLLIN;
|
|
}
|
|
if (ARES_GETSOCK_WRITABLE(rc, i))
|
|
{
|
|
has_fd = true;
|
|
conn[i].fd = socks[i];
|
|
conn[i].events |= POLLOUT;
|
|
}
|
|
}
|
|
|
|
if (!has_fd)
|
|
break;
|
|
|
|
struct timeval tv;
|
|
ares_timeout(channel, &maxtv, &tv);
|
|
|
|
rc = poll(conn, ARES_GETSOCK_MAXNUM, tv.tv_sec*1000+tv.tv_usec/1000);
|
|
if (rc == -1)
|
|
break;
|
|
|
|
for (int i = 0; i < ARES_GETSOCK_MAXNUM; ++i)
|
|
{
|
|
if (conn[i].revents > 0)
|
|
{
|
|
ares_process_fd(channel, (conn[i].events & POLLIN) ? conn[i].fd : ARES_SOCKET_BAD,
|
|
(conn[i].events & POLLOUT) ? conn[i].fd : ARES_SOCKET_BAD);
|
|
}
|
|
}
|
|
|
|
if (!ret.empty()
|
|
&& Server->getTimeMS() - starttime >= stop_timeoutms)
|
|
{
|
|
break;
|
|
}
|
|
|
|
} while (Server->getTimeMS() - starttime < timeoutms);
|
|
|
|
ares_destroy(channel);
|
|
|
|
return ret;
|
|
}
|
|
|
|
#endif
|
|
|
|
bool LookupHostname(const std::string & pIp, std::string& hostname)
|
|
{
|
|
sockaddr_in addr;
|
|
memset(&addr, 0, sizeof(addr));
|
|
addr.sin_addr.s_addr = inet_addr(pIp.c_str());
|
|
if (addr.sin_addr.s_addr == INADDR_NONE)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
addr.sin_family = AF_INET;
|
|
addr.sin_port = htons(80);
|
|
|
|
char buf[NI_MAXHOST];
|
|
|
|
int rc = getnameinfo(reinterpret_cast<sockaddr*>(&addr), sizeof(addr), buf, sizeof(buf), NULL, 0, NI_NAMEREQD);
|
|
|
|
if (rc == 0)
|
|
{
|
|
hostname = buf;
|
|
}
|
|
|
|
return rc == 0;
|
|
}
|
|
|
|
|
|
|
|
|