mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-02-21 14:41:39 +00:00
Merge pull request #11004 from unknownbrackets/ipv6
Enable IPv6 for reporting / sharing / etc.
This commit is contained in:
commit
a08fb8bd22
@ -71,13 +71,34 @@ static void RegisterServer(int port) {
|
|||||||
http::Client http;
|
http::Client http;
|
||||||
Buffer theVoid;
|
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)) {
|
if (http.Connect(2, 20.0, &scanCancelled)) {
|
||||||
char resource[1024] = {};
|
|
||||||
std::string ip = fd_util::GetLocalIP(http.sock());
|
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(resource, &theVoid);
|
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(resource6, &theVoid);
|
||||||
|
theVoid.Skip(theVoid.size());
|
||||||
http.Disconnect();
|
http.Disconnect();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -133,11 +133,22 @@ void SetNonBlocking(int sock, bool non_blocking) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::string GetLocalIP(int sock) {
|
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));
|
memset(&server_addr, 0, sizeof(server_addr));
|
||||||
socklen_t len = sizeof(server_addr);
|
socklen_t len = sizeof(server_addr);
|
||||||
if (getsockname(sock, (struct sockaddr *)&server_addr, &len) == 0) {
|
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) {
|
if (result) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -46,7 +46,7 @@ inline unsigned short myhtons(unsigned short x) {
|
|||||||
return (x >> 8) | (x << 8);
|
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) {
|
if ((intptr_t)sock_ != -1) {
|
||||||
ELOG("Resolve: Already have a socket");
|
ELOG("Resolve: Already have a socket");
|
||||||
return false;
|
return false;
|
||||||
@ -63,7 +63,7 @@ bool Connection::Resolve(const char *host, int port) {
|
|||||||
snprintf(port_str, sizeof(port_str), "%d", port);
|
snprintf(port_str, sizeof(port_str), "%d", port);
|
||||||
|
|
||||||
std::string err;
|
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());
|
ELOG("Failed to resolve host %s: %s", host, err.c_str());
|
||||||
// So that future calls fail.
|
// So that future calls fail.
|
||||||
port_ = 0;
|
port_ = 0;
|
||||||
@ -87,10 +87,10 @@ bool Connection::Connect(int maxTries, double timeout, bool *cancelConnect) {
|
|||||||
FD_ZERO(&fds);
|
FD_ZERO(&fds);
|
||||||
for (addrinfo *possible = resolved_; possible != nullptr; possible = possible->ai_next) {
|
for (addrinfo *possible = resolved_; possible != nullptr; possible = possible->ai_next) {
|
||||||
// TODO: Could support ipv6 without huge difficulty...
|
// 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;
|
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) {
|
if ((intptr_t)sock == -1) {
|
||||||
ELOG("Bad socket");
|
ELOG("Bad socket");
|
||||||
continue;
|
continue;
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
#include "base/basictypes.h"
|
#include "base/basictypes.h"
|
||||||
#include "base/buffer.h"
|
#include "base/buffer.h"
|
||||||
|
#include "net/resolve.h"
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#ifndef NOMINMAX
|
#ifndef NOMINMAX
|
||||||
@ -28,7 +29,7 @@ public:
|
|||||||
virtual ~Connection();
|
virtual ~Connection();
|
||||||
|
|
||||||
// Inits the sockaddr_in.
|
// 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);
|
bool Connect(int maxTries = 2, double timeout = 20.0f, bool *cancelConnect = nullptr);
|
||||||
void Disconnect();
|
void Disconnect();
|
||||||
|
@ -130,9 +130,21 @@ void Server::SetFallbackHandler(UrlHandlerFunc handler) {
|
|||||||
fallback_ = 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);
|
listener_ = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
CHECK_GE(listener_, 0);
|
if (listener_ < 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
struct sockaddr_in server_addr;
|
struct sockaddr_in server_addr;
|
||||||
memset(&server_addr, 0, sizeof(server_addr));
|
memset(&server_addr, 0, sizeof(server_addr));
|
||||||
@ -145,6 +157,7 @@ bool Server::Listen(int port) {
|
|||||||
setsockopt(listener_, SOL_SOCKET, SO_REUSEADDR, (const char *)&opt, sizeof(opt));
|
setsockopt(listener_, SOL_SOCKET, SO_REUSEADDR, (const char *)&opt, sizeof(opt));
|
||||||
|
|
||||||
if (bind(listener_, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
|
if (bind(listener_, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
|
||||||
|
closesocket(listener_);
|
||||||
ELOG("Failed to bind to port %i. Bailing.", port);
|
ELOG("Failed to bind to port %i. Bailing.", port);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -152,7 +165,10 @@ bool Server::Listen(int port) {
|
|||||||
fd_util::SetNonBlocking(listener_, true);
|
fd_util::SetNonBlocking(listener_, true);
|
||||||
|
|
||||||
// 1024 is the max number of queued requests.
|
// 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);
|
socklen_t len = sizeof(server_addr);
|
||||||
if (getsockname(listener_, (struct sockaddr *)&server_addr, &len) == 0) {
|
if (getsockname(listener_, (struct sockaddr *)&server_addr, &len) == 0) {
|
||||||
@ -165,6 +181,50 @@ bool Server::Listen(int port) {
|
|||||||
return true;
|
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) {
|
bool Server::RunSlice(double timeout) {
|
||||||
if (listener_ < 0 || port_ == 0) {
|
if (listener_ < 0 || port_ == 0) {
|
||||||
return false;
|
return false;
|
||||||
@ -177,9 +237,13 @@ bool Server::RunSlice(double timeout) {
|
|||||||
return false;
|
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);
|
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) {
|
if (conn_fd >= 0) {
|
||||||
executor_->Run(std::bind(&Server::HandleConnection, this, conn_fd));
|
executor_->Run(std::bind(&Server::HandleConnection, this, conn_fd));
|
||||||
return true;
|
return true;
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
#include "base/buffer.h"
|
#include "base/buffer.h"
|
||||||
#include "net/http_headers.h"
|
#include "net/http_headers.h"
|
||||||
|
#include "net/resolve.h"
|
||||||
#include "thread/executor.h"
|
#include "thread/executor.h"
|
||||||
|
|
||||||
namespace net {
|
namespace net {
|
||||||
@ -73,7 +74,7 @@ public:
|
|||||||
// May run for (significantly) longer than timeout, but won't wait longer than that
|
// May run for (significantly) longer than timeout, but won't wait longer than that
|
||||||
// for a new connection to handle.
|
// for a new connection to handle.
|
||||||
bool RunSlice(double timeout);
|
bool RunSlice(double timeout);
|
||||||
bool Listen(int port);
|
bool Listen(int port, net::DNSType type = net::DNSType::ANY);
|
||||||
void Stop();
|
void Stop();
|
||||||
|
|
||||||
void RegisterHandler(const char *url_path, UrlHandlerFunc handler);
|
void RegisterHandler(const char *url_path, UrlHandlerFunc handler);
|
||||||
@ -85,10 +86,13 @@ public:
|
|||||||
virtual void HandleRequest(const Request &request);
|
virtual void HandleRequest(const Request &request);
|
||||||
|
|
||||||
int Port() {
|
int Port() {
|
||||||
return port_;
|
return port_;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
bool Listen6(int port, bool ipv6_only);
|
||||||
|
bool Listen4(int port);
|
||||||
|
|
||||||
void HandleConnection(int conn_fd);
|
void HandleConnection(int conn_fd);
|
||||||
|
|
||||||
// Things like default 404, etc.
|
// Things like default 404, etc.
|
||||||
|
@ -77,7 +77,7 @@ char *DNSResolve(const char *host)
|
|||||||
return ip;
|
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};
|
addrinfo hints = {0};
|
||||||
// TODO: Might be uses to lookup other values.
|
// TODO: Might be uses to lookup other values.
|
||||||
@ -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
|
// http://stackoverflow.com/questions/1408030/what-is-the-purpose-of-the-ai-v4mapped-flag-in-getaddrinfo
|
||||||
hints.ai_flags = /*AI_V4MAPPED |*/ AI_ADDRCONFIG;
|
hints.ai_flags = /*AI_V4MAPPED |*/ AI_ADDRCONFIG;
|
||||||
#endif
|
#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();
|
const char *servicep = service.length() == 0 ? NULL : service.c_str();
|
||||||
|
|
||||||
|
@ -14,7 +14,13 @@ void Shutdown();
|
|||||||
char *DNSResolveTry(const char *host, const char **err);
|
char *DNSResolveTry(const char *host, const char **err);
|
||||||
char *DNSResolve(const char *host);
|
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);
|
void DNSResolveFree(addrinfo *res);
|
||||||
|
|
||||||
int inet_pton(int af, const char* src, void* dst);
|
int inet_pton(int af, const char* src, void* dst);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user