Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable IPv6 for reporting / sharing / etc. #11004

Merged
merged 3 commits into from
Jun 6, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 25 additions & 4 deletions UI/RemoteISOScreen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,13 +71,34 @@ static void RegisterServer(int port) {
http::Client http;
Buffer theVoid;

if (http.Resolve(REPORT_HOSTNAME, REPORT_PORT)) {
char resource4[1024] = {};
if (http.Resolve(REPORT_HOSTNAME, REPORT_PORT, net::DNSType::IPV4)) {
if (http.Connect(2, 20.0, &scanCancelled)) {
char resource[1024] = {};
std::string ip = fd_util::GetLocalIP(http.sock());
snprintf(resource, sizeof(resource) - 1, "/match/update?local=%s&port=%d", ip.c_str(), port);
snprintf(resource4, sizeof(resource4) - 1, "/match/update?local=%s&port=%d", ip.c_str(), port);

http.GET(resource4, &theVoid);
theVoid.Skip(theVoid.size());
http.Disconnect();
}
}

if (http.Resolve(REPORT_HOSTNAME, REPORT_PORT, net::DNSType::IPV6)) {
// We register both IPv4 and IPv6 in case the other client is using a different one.
if (resource4[0] != 0 && http.Connect()) {
http.GET(resource4, &theVoid);
theVoid.Skip(theVoid.size());
http.Disconnect();
}

// Currently, we're not using keepalive, so gotta reconnect...
if (http.Connect()) {
char resource6[1024] = {};
std::string ip = fd_util::GetLocalIP(http.sock());
snprintf(resource6, sizeof(resource6) - 1, "/match/update?local=%s&port=%d", ip.c_str(), port);

http.GET(resource, &theVoid);
http.GET(resource6, &theVoid);
theVoid.Skip(theVoid.size());
http.Disconnect();
}
}
Expand Down
15 changes: 13 additions & 2 deletions ext/native/file/fd_util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -133,11 +133,22 @@ void SetNonBlocking(int sock, bool non_blocking) {
}

std::string GetLocalIP(int sock) {
struct sockaddr_in server_addr;
union {
struct sockaddr sa;
struct sockaddr_in ipv4;
struct sockaddr_in6 ipv6;
} server_addr;
memset(&server_addr, 0, sizeof(server_addr));
socklen_t len = sizeof(server_addr);
if (getsockname(sock, (struct sockaddr *)&server_addr, &len) == 0) {
char *result = inet_ntoa(*(in_addr *)&server_addr.sin_addr);
char temp[64];
void *addr;
if (server_addr.sa.sa_family == AF_INET6) {
addr = &server_addr.ipv6.sin6_addr;
} else {
addr = &server_addr.ipv4.sin_addr;
}
const char *result = inet_ntop(server_addr.sa.sa_family, addr, temp, sizeof(temp));
if (result) {
return result;
}
Expand Down
8 changes: 4 additions & 4 deletions ext/native/net/http_client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ inline unsigned short myhtons(unsigned short x) {
return (x >> 8) | (x << 8);
}

bool Connection::Resolve(const char *host, int port) {
bool Connection::Resolve(const char *host, int port, DNSType type) {
if ((intptr_t)sock_ != -1) {
ELOG("Resolve: Already have a socket");
return false;
Expand All @@ -63,7 +63,7 @@ bool Connection::Resolve(const char *host, int port) {
snprintf(port_str, sizeof(port_str), "%d", port);

std::string err;
if (!net::DNSResolve(host, port_str, &resolved_, err)) {
if (!net::DNSResolve(host, port_str, &resolved_, err, type)) {
ELOG("Failed to resolve host %s: %s", host, err.c_str());
// So that future calls fail.
port_ = 0;
Expand All @@ -87,10 +87,10 @@ bool Connection::Connect(int maxTries, double timeout, bool *cancelConnect) {
FD_ZERO(&fds);
for (addrinfo *possible = resolved_; possible != nullptr; possible = possible->ai_next) {
// TODO: Could support ipv6 without huge difficulty...
if (possible->ai_family != AF_INET)
if (possible->ai_family != AF_INET && possible->ai_family != AF_INET6)
continue;

int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
int sock = socket(possible->ai_family, SOCK_STREAM, IPPROTO_TCP);
if ((intptr_t)sock == -1) {
ELOG("Bad socket");
continue;
Expand Down
3 changes: 2 additions & 1 deletion ext/native/net/http_client.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

#include "base/basictypes.h"
#include "base/buffer.h"
#include "net/resolve.h"

#ifdef _WIN32
#ifndef NOMINMAX
Expand All @@ -28,7 +29,7 @@ class Connection {
virtual ~Connection();

// Inits the sockaddr_in.
bool Resolve(const char *host, int port);
bool Resolve(const char *host, int port, DNSType type = DNSType::ANY);

bool Connect(int maxTries = 2, double timeout = 20.0f, bool *cancelConnect = nullptr);
void Disconnect();
Expand Down
74 changes: 69 additions & 5 deletions ext/native/net/http_server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,9 +130,21 @@ void Server::SetFallbackHandler(UrlHandlerFunc handler) {
fallback_ = handler;
}

bool Server::Listen(int port) {
bool Server::Listen(int port, net::DNSType type) {
bool success = false;
if (type == net::DNSType::ANY || type == net::DNSType::IPV6) {
success = Listen6(port, type == net::DNSType::IPV6);
}
if (!success && (type == net::DNSType::ANY || type == net::DNSType::IPV4)) {
success = Listen4(port);
}
return success;
}

bool Server::Listen4(int port) {
listener_ = socket(AF_INET, SOCK_STREAM, 0);
CHECK_GE(listener_, 0);
if (listener_ < 0)
return false;

struct sockaddr_in server_addr;
memset(&server_addr, 0, sizeof(server_addr));
Expand All @@ -145,14 +157,18 @@ bool Server::Listen(int port) {
setsockopt(listener_, SOL_SOCKET, SO_REUSEADDR, (const char *)&opt, sizeof(opt));

if (bind(listener_, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
closesocket(listener_);
ELOG("Failed to bind to port %i. Bailing.", port);
return false;
}

fd_util::SetNonBlocking(listener_, true);

// 1024 is the max number of queued requests.
CHECK_GE(listen(listener_, 1024), 0);
if (listen(listener_, 1024) < 0) {
closesocket(listener_);
return false;
}

socklen_t len = sizeof(server_addr);
if (getsockname(listener_, (struct sockaddr *)&server_addr, &len) == 0) {
Expand All @@ -165,6 +181,50 @@ bool Server::Listen(int port) {
return true;
}

bool Server::Listen6(int port, bool ipv6_only) {
listener_ = socket(AF_INET6, SOCK_STREAM, 0);
if (listener_ < 0)
return false;

struct sockaddr_in6 server_addr;
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin6_family = AF_INET6;
server_addr.sin6_addr = in6addr_any;
server_addr.sin6_port = htons(port);

int opt = 1;
// Enable re-binding to avoid the pain when restarting the server quickly.
setsockopt(listener_, SOL_SOCKET, SO_REUSEADDR, (const char *)&opt, sizeof(opt));

// Enable listening on IPv6 and IPv4?
opt = ipv6_only ? 1 : 0;
setsockopt(listener_, IPPROTO_IPV6, IPV6_V6ONLY, (const char *)&opt, sizeof(opt));

if (bind(listener_, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
closesocket(listener_);
ELOG("Failed to bind to port %i. Bailing.", port);
return false;
}

fd_util::SetNonBlocking(listener_, true);

// 1024 is the max number of queued requests.
if (listen(listener_, 1024) < 0) {
closesocket(listener_);
return false;
}

socklen_t len = sizeof(server_addr);
if (getsockname(listener_, (struct sockaddr *)&server_addr, &len) == 0) {
port = ntohs(server_addr.sin6_port);
}

ILOG("HTTP server started on port %i", port);
port_ = port;

return true;
}

bool Server::RunSlice(double timeout) {
if (listener_ < 0 || port_ == 0) {
return false;
Expand All @@ -177,9 +237,13 @@ bool Server::RunSlice(double timeout) {
return false;
}

sockaddr client_addr;
union {
struct sockaddr sa;
struct sockaddr_in ipv4;
struct sockaddr_in6 ipv6;
} client_addr;
socklen_t client_addr_size = sizeof(client_addr);
int conn_fd = accept(listener_, &client_addr, &client_addr_size);
int conn_fd = accept(listener_, &client_addr.sa, &client_addr_size);
if (conn_fd >= 0) {
executor_->Run(std::bind(&Server::HandleConnection, this, conn_fd));
return true;
Expand Down
8 changes: 6 additions & 2 deletions ext/native/net/http_server.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

#include "base/buffer.h"
#include "net/http_headers.h"
#include "net/resolve.h"
#include "thread/executor.h"

namespace net {
Expand Down Expand Up @@ -73,7 +74,7 @@ class Server {
// May run for (significantly) longer than timeout, but won't wait longer than that
// for a new connection to handle.
bool RunSlice(double timeout);
bool Listen(int port);
bool Listen(int port, net::DNSType type = net::DNSType::ANY);
void Stop();

void RegisterHandler(const char *url_path, UrlHandlerFunc handler);
Expand All @@ -85,10 +86,13 @@ class Server {
virtual void HandleRequest(const Request &request);

int Port() {
return port_;
return port_;
}

private:
bool Listen6(int port, bool ipv6_only);
bool Listen4(int port);

void HandleConnection(int conn_fd);

// Things like default 404, etc.
Expand Down
8 changes: 6 additions & 2 deletions ext/native/net/resolve.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ char *DNSResolve(const char *host)
return ip;
}

bool DNSResolve(const std::string &host, const std::string &service, addrinfo **res, std::string &error)
bool DNSResolve(const std::string &host, const std::string &service, addrinfo **res, std::string &error, DNSType type)
{
addrinfo hints = {0};
// TODO: Might be uses to lookup other values.
Expand All @@ -89,7 +89,11 @@ bool DNSResolve(const std::string &host, const std::string &service, addrinfo **
// http://stackoverflow.com/questions/1408030/what-is-the-purpose-of-the-ai-v4mapped-flag-in-getaddrinfo
hints.ai_flags = /*AI_V4MAPPED |*/ AI_ADDRCONFIG;
#endif
hints.ai_protocol = IPPROTO_TCP;
hints.ai_protocol = 0;
if (type == DNSType::IPV4)
hints.ai_family = AF_INET;
else if (type == DNSType::IPV6)
hints.ai_family = AF_INET6;

const char *servicep = service.length() == 0 ? NULL : service.c_str();

Expand Down
8 changes: 7 additions & 1 deletion ext/native/net/resolve.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,13 @@ void Shutdown();
char *DNSResolveTry(const char *host, const char **err);
char *DNSResolve(const char *host);

bool DNSResolve(const std::string &host, const std::string &service, addrinfo **res, std::string &error);
enum class DNSType {
ANY = 0,
IPV4 = 1,
IPV6 = 2,
};

bool DNSResolve(const std::string &host, const std::string &service, addrinfo **res, std::string &error, DNSType type = DNSType::ANY);
void DNSResolveFree(addrinfo *res);

int inet_pton(int af, const char* src, void* dst);
Expand Down