added windows support for ipv6, cleaned up unix code

(cherry picked from commit 672225b710)
This commit is contained in:
Ariel Manzur 2016-10-20 07:04:10 -03:00 committed by Fabio Alessandrelli
parent 904285f4b4
commit d8b0070b8c
11 changed files with 175 additions and 122 deletions

View file

@ -117,7 +117,9 @@ IP_Address IP::resolve_hostname(const String& p_hostname, IP_Address::AddrType p
GLOBAL_LOCK_FUNCTION;
if (resolver->cache.has(p_hostname))
return resolver->cache[p_hostname];
if (resolver->cache[p_hostname].type & p_type != 0)
return resolver->cache[p_hostname];
// requested type is different from type in cache. continue resolution, if successful it'll overwrite cache
IP_Address res = _resolve_hostname(p_hostname, p_type);
resolver->cache[p_hostname]=res;
@ -137,7 +139,7 @@ IP::ResolverID IP::resolve_hostname_queue_item(const String& p_hostname, IP_Addr
resolver->queue[id].hostname=p_hostname;
resolver->queue[id].type = p_type;
if (resolver->cache.has(p_hostname)) {
if (resolver->cache.has(p_hostname) && (resolver->cache[p_hostname].type & p_type) != 0) {
resolver->queue[id].response=resolver->cache[p_hostname];
resolver->queue[id].status=IP::RESOLVER_STATUS_DONE;
} else {
@ -187,6 +189,14 @@ void IP::erase_resolve_item(ResolverID p_id) {
}
void IP::clear_cache(const String &p_hostname) {
if (p_hostname.empty()) {
resolver->cache.clear();
} else {
resolver->cache.erase(p_hostname);
}
};
Array IP::_get_local_addresses() const {
@ -208,6 +218,7 @@ void IP::_bind_methods() {
ObjectTypeDB::bind_method(_MD("get_resolve_item_address","id"),&IP::get_resolve_item_address);
ObjectTypeDB::bind_method(_MD("erase_resolve_item","id"),&IP::erase_resolve_item);
ObjectTypeDB::bind_method(_MD("get_local_addresses"),&IP::_get_local_addresses);
ObjectTypeDB::bind_method(_MD("clear_cache"),&IP::clear_cache, DEFVAL(""));
BIND_CONSTANT( RESOLVER_STATUS_NONE );
BIND_CONSTANT( RESOLVER_STATUS_WAITING );

View file

@ -89,6 +89,8 @@ public:
virtual void get_local_addresses(List<IP_Address> *r_addresses) const=0;
void erase_resolve_item(ResolverID p_id);
void clear_cache(const String& p_hostname = "");
static IP* get_singleton();
static IP* create();

View file

@ -54,6 +54,7 @@
#include <arpa/inet.h>
#endif
#include "drivers/unix/socket_helpers.h"
int PacketPeerUDPPosix::get_available_packet_count() const {
@ -98,17 +99,7 @@ Error PacketPeerUDPPosix::put_packet(const uint8_t *p_buffer,int p_buffer_size){
int sock = _get_socket(peer_addr.type);
ERR_FAIL_COND_V( sock == -1, FAILED );
struct sockaddr_storage addr;
if (peer_addr.type == IP_Address::TYPE_IPV4) {
struct sockaddr_in* addr_in = (struct sockaddr_in*)&addr;
addr_in->sin_family = AF_INET;
addr_in->sin_port = htons(peer_port);
addr_in->sin_addr = *((struct in_addr*)&peer_addr.field32[0]);
} else {
struct sockaddr_in6* addr_in6 = (struct sockaddr_in6*)&addr;
addr_in6->sin6_family = AF_INET;
addr_in6->sin6_port = htons(peer_port);
copymem(&addr_in6->sin6_addr.s6_addr, peer_addr.field8, 16);
};
_set_sockaddr(&addr, peer_addr, peer_port);
errno = 0;
int err;
@ -138,20 +129,7 @@ Error PacketPeerUDPPosix::listen(int p_port, IP_Address::AddrType p_address_type
return ERR_CANT_CREATE;
sockaddr_storage addr = {0};
if (p_address_type == IP_Address::TYPE_IPV4) {
struct sockaddr_in* addr4 = (struct sockaddr_in*)&addr;
addr4->sin_family = AF_INET;
addr4->sin_port = htons(p_port);
addr4->sin_addr.s_addr = INADDR_ANY;
} else {
struct sockaddr_in6* addr6 = (struct sockaddr_in6*)&addr;
addr6->sin6_family = AF_INET6;
addr6->sin6_port = htons(p_port);
addr6->sin6_addr = in6addr_any;
};
_set_listen_sockaddr(&addr, p_port, p_address_type, NULL);
if (bind(sock, (struct sockaddr*)&addr, sizeof(sockaddr_storage)) == -1 ) {
close();
@ -212,6 +190,7 @@ Error PacketPeerUDPPosix::_poll(bool p_wait) {
rb.write((uint8_t*)&ret, 4);
rb.write(recv_buffer, ret);
len = sizeof(struct sockaddr_storage);
++queue_count;
};

View file

@ -0,0 +1,66 @@
#ifndef SOCKET_HELPERS_H
#define SOCKET_HELPERS_H
#include <string.h>
// helpers for sockaddr -> IP_Address and back, should work for posix and winsock. All implementations should use this
static void _set_sockaddr(struct sockaddr_storage* p_addr, const IP_Address& p_ip, int p_port) {
memset(p_addr, 0, sizeof(struct sockaddr_storage));
if (p_ip.type == IP_Address::TYPE_IPV6) {
struct sockaddr_in6* addr6 = (struct sockaddr_in6*)p_addr;
addr6->sin6_family = AF_INET6;
addr6->sin6_port = htons(p_port);
copymem(&addr6->sin6_addr.s6_addr, p_ip.field8, 16);
} else {
struct sockaddr_in* addr4 = (struct sockaddr_in*)p_addr;
addr4->sin_family = AF_INET; // host byte order
addr4->sin_port = htons(p_port); // short, network byte order
addr4->sin_addr = *((struct in_addr*)&p_ip.field32[0]);
};
};
static void _set_listen_sockaddr(struct sockaddr_storage* p_addr, int p_port, IP_Address::AddrType p_address_type, const List<String> *p_accepted_hosts) {
memset(p_addr, 0, sizeof(struct sockaddr_storage));
if (p_address_type == IP_Address::TYPE_IPV4) {
struct sockaddr_in* addr4 = (struct sockaddr_in*)p_addr;
addr4->sin_family = AF_INET;
addr4->sin_port = htons(p_port);
addr4->sin_addr.s_addr = INADDR_ANY; // TODO: use accepted hosts list
} else {
struct sockaddr_in6* addr6 = (struct sockaddr_in6*)p_addr;
addr6->sin6_family = AF_INET6;
addr6->sin6_port = htons(p_port);
addr6->sin6_addr = in6addr_any; // TODO: use accepted hosts list
};
};
static void _set_ip_addr_port(IP_Address& r_ip, int& r_port, struct sockaddr_storage* p_addr) {
if (p_addr->ss_family == AF_INET) {
r_ip.type = IP_Address::TYPE_IPV4;
struct sockaddr_in* addr4 = (struct sockaddr_in*)p_addr;
r_ip.field32[0] = (uint32_t)addr4->sin_addr.s_addr;
r_port = ntohs(addr4->sin_port);
} else if (p_addr->ss_family == AF_INET6) {
r_ip.type = IP_Address::TYPE_IPV6;
struct sockaddr_in6* addr6 = (struct sockaddr_in6*)p_addr;
copymem(&addr6->sin6_addr.s6_addr, r_ip.field8, 16);
r_port = ntohs(addr6->sin6_port);
};
};
#endif

View file

@ -61,24 +61,7 @@
#define MSG_NOSIGNAL SO_NOSIGPIPE
#endif
static void set_addr_in(struct sockaddr_storage& their_addr, const IP_Address& p_host, uint16_t p_port) {
memset(&their_addr, 0, sizeof(struct sockaddr_storage));
if (p_host.type == IP_Address::TYPE_IPV6) {
struct sockaddr_in6* addr6 = (struct sockaddr_in6*)&their_addr;
addr6->sin6_family = AF_INET6;
addr6->sin6_port = htons(p_port);
copymem(&addr6->sin6_addr.s6_addr, p_host.field8, 16);
} else {
struct sockaddr_in* addr4 = (struct sockaddr_in*)&their_addr;
addr4->sin_family = AF_INET; // host byte order
addr4->sin_port = htons(p_port); // short, network byte order
addr4->sin_addr = *((struct in_addr*)&p_host.field32[0]);
};
};
#include "drivers/unix/socket_helpers.h"
StreamPeerTCP* StreamPeerTCPPosix::_create() {
@ -115,7 +98,8 @@ Error StreamPeerTCPPosix::_poll_connection(bool p_block) const {
};
struct sockaddr_storage their_addr;
set_addr_in(their_addr, peer_host, peer_port);
_set_sockaddr(&their_addr, peer_host, peer_port);
if (::connect(sockfd, (struct sockaddr *)&their_addr,sizeof(their_addr)) == -1) {
if (errno == EISCONN) {
@ -169,7 +153,7 @@ Error StreamPeerTCPPosix::connect(const IP_Address& p_host, uint16_t p_port) {
#endif
struct sockaddr_storage their_addr;
set_addr_in(their_addr, p_host, p_port);
_set_sockaddr(&their_addr, p_host, p_port);
errno = 0;
if (::connect(sockfd, (struct sockaddr *)&their_addr,sizeof(their_addr)) == -1 && errno != EINPROGRESS) {

View file

@ -56,6 +56,8 @@
#include <sys/socket.h>
#include <assert.h>
#include "drivers/unix/socket_helpers.h"
TCP_Server* TCPServerPosix::_create() {
return memnew(TCPServerPosix);
@ -84,19 +86,9 @@ Error TCPServerPosix::listen(uint16_t p_port, IP_Address::AddrType p_type, const
WARN_PRINT("REUSEADDR failed!")
}
sockaddr_storage addr = {0};
if (p_type == IP_Address::TYPE_IPV4) {
struct sockaddr_in* addr4 = (struct sockaddr_in*)&addr;
addr4->sin_family = AF_INET;
addr4->sin_port = htons(p_port);
addr4->sin_addr.s_addr = INADDR_ANY;
} else {
struct sockaddr_storage addr;
_set_listen_sockaddr(&addr, p_port, p_type, p_accepted_hosts);
struct sockaddr_in6* addr6 = (struct sockaddr_in6*)&addr;
addr6->sin6_family = AF_INET6;
addr6->sin6_port = htons(p_port);
addr6->sin6_addr = in6addr_any;
};
// automatically fill with my IP TODO: use p_accepted_hosts
if (bind(sockfd, (struct sockaddr *)&addr, sizeof addr) != -1) {
@ -161,22 +153,10 @@ Ref<StreamPeerTCP> TCPServerPosix::take_connection() {
Ref<StreamPeerTCPPosix> conn = memnew(StreamPeerTCPPosix);
IP_Address ip;
if (their_addr.ss_family == AF_INET) {
ip.type = IP_Address::TYPE_IPV4;
int port;
_set_ip_addr_port(ip, port, &their_addr);
struct sockaddr_in* addr4 = (struct sockaddr_in*)&their_addr;
ip.field32[0] = (uint32_t)addr4->sin_addr.s_addr;
conn->set_socket(fd, ip, ntohs(addr4->sin_port));
} else if (their_addr.ss_family == AF_INET6) {
ip.type = IP_Address::TYPE_IPV6;
struct sockaddr_in6* addr6 = (struct sockaddr_in6*)&their_addr;
copymem(&addr6->sin6_addr.s6_addr, ip.field8, 16);
conn->set_socket(fd, ip, ntohs(addr6->sin6_port));
};
conn->set_socket(fd, ip, port);
return conn;
};

View file

@ -29,6 +29,9 @@
#include "packet_peer_udp_winsock.h"
#include <winsock2.h>
#include <ws2tcpip.h>
#include "drivers/unix/socket_helpers.h"
int PacketPeerUDPWinsock::get_available_packet_count() const {
@ -48,7 +51,15 @@ Error PacketPeerUDPWinsock::get_packet(const uint8_t **r_buffer,int &r_buffer_si
return ERR_UNAVAILABLE;
uint32_t size;
rb.read((uint8_t*)&packet_ip.host,4,true);
uint8_t type;
rb.read(&type, 1, true);
if (type == IP_Address::TYPE_IPV4) {
rb.read((uint8_t*)&packet_ip.field8,4,true);
packet_ip.type = IP_Address::TYPE_IPV4;
} else {
rb.read((uint8_t*)&packet_ip.field8,16,true);
packet_ip.type = IP_Address::TYPE_IPV6;
};
rb.read((uint8_t*)&packet_port,4,true);
rb.read((uint8_t*)&size,4,true);
rb.read(packet_buffer,size,true);
@ -60,13 +71,10 @@ Error PacketPeerUDPWinsock::get_packet(const uint8_t **r_buffer,int &r_buffer_si
}
Error PacketPeerUDPWinsock::put_packet(const uint8_t *p_buffer,int p_buffer_size){
int sock = _get_socket();
int sock = _get_socket(peer_addr.type);
ERR_FAIL_COND_V( sock == -1, FAILED );
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(peer_port);
addr.sin_addr = *((struct in_addr*)&peer_addr.host);
struct sockaddr_storage addr;
_set_sockaddr(&addr, peer_addr, peer_port);
_set_blocking(true);
@ -104,16 +112,16 @@ void PacketPeerUDPWinsock::_set_blocking(bool p_blocking) {
};
}
Error PacketPeerUDPWinsock::listen(int p_port, int p_recv_buffer_size){
Error PacketPeerUDPWinsock::listen(int p_port, IP_Address::AddrType p_address_type, int p_recv_buffer_size) {
close();
int sock = _get_socket();
int sock = _get_socket(p_address_type);
if (sock == -1 )
return ERR_CANT_CREATE;
sockaddr_in addr = {0};
addr.sin_family = AF_INET;
addr.sin_port = htons(p_port);
addr.sin_addr.s_addr = INADDR_ANY;
struct sockaddr_storage addr = {0};
_set_listen_sockaddr(&addr, p_port, p_address_type, NULL);
if (bind(sock, (struct sockaddr*)&addr, sizeof(sockaddr_in)) == -1 ) {
close();
return ERR_UNAVAILABLE;
@ -146,17 +154,41 @@ Error PacketPeerUDPWinsock::_poll(bool p_wait) {
_set_blocking(p_wait);
struct sockaddr_in from = {0};
int len = sizeof(struct sockaddr_in);
struct sockaddr_storage from = {0};
int len = sizeof(struct sockaddr_storage);
int ret;
while ( (ret = recvfrom(sockfd, (char*)recv_buffer, MIN((int)sizeof(recv_buffer),MAX(rb.space_left()-12, 0)), 0, (struct sockaddr*)&from, &len)) > 0) {
rb.write((uint8_t*)&from.sin_addr, 4);
uint32_t port = ntohs(from.sin_port);
uint32_t port = 0;
if (from.ss_family == AF_INET) {
uint8_t type = (uint8_t)IP_Address::TYPE_IPV4;
rb.write(&type, 1);
struct sockaddr_in* sin_from = (struct sockaddr_in*)&from;
rb.write((uint8_t*)&sin_from->sin_addr, 4);
port = sin_from->sin_port;
} else if (from.ss_family == AF_INET6) {
uint8_t type = (uint8_t)IP_Address::TYPE_IPV6;
rb.write(&type, 1);
struct sockaddr_in6* s6_from = (struct sockaddr_in6*)&from;
rb.write((uint8_t*)&s6_from->sin6_addr, 16);
port = s6_from->sin6_port;
} else {
// WARN_PRINT("Ignoring packet with unknown address family");
uint8_t type = (uint8_t)IP_Address::TYPE_NONE;
rb.write(&type, 1);
};
rb.write((uint8_t*)&port, 4);
rb.write((uint8_t*)&ret, 4);
rb.write(recv_buffer, ret);
len = sizeof(struct sockaddr_in);
len = sizeof(struct sockaddr_storage);
++queue_count;
};
@ -202,12 +234,14 @@ int PacketPeerUDPWinsock::get_packet_port() const{
return packet_port;
}
int PacketPeerUDPWinsock::_get_socket() {
int PacketPeerUDPWinsock::_get_socket(IP_Address::AddrType p_type) {
if (sockfd != -1)
return sockfd;
sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
int family = p_type == IP_Address::TYPE_IPV6 ? AF_INET6 : AF_INET;
sockfd = socket(family, SOCK_DGRAM, IPPROTO_UDP);
ERR_FAIL_COND_V( sockfd == -1, -1 );
//fcntl(sockfd, F_SETFL, O_NONBLOCK);

View file

@ -42,15 +42,15 @@ class PacketPeerUDPWinsock : public PacketPeerUDP {
mutable RingBuffer<uint8_t> rb;
uint8_t recv_buffer[PACKET_BUFFER_SIZE];
mutable uint8_t packet_buffer[PACKET_BUFFER_SIZE];
IP_Address packet_ip;
int packet_port;
mutable IP_Address packet_ip;
mutable int packet_port;
mutable int queue_count;
int sockfd;
IP_Address peer_addr;
int peer_port;
_FORCE_INLINE_ int _get_socket();
_FORCE_INLINE_ int _get_socket(IP_Address::AddrType p_type);
static PacketPeerUDP* _create();
@ -67,7 +67,7 @@ public:
virtual int get_max_packet_size() const;
virtual Error listen(int p_port,int p_recv_buffer_size=65536);
virtual Error listen(int p_port, IP_Address::AddrType p_address_type, int p_recv_buffer_size=65536);
virtual void close();
virtual Error wait();
virtual bool is_listening() const;

View file

@ -31,17 +31,12 @@
#include "stream_peer_winsock.h"
#include <winsock2.h>
#include <ws2tcpip.h>
#include "drivers/unix/socket_helpers.h"
int winsock_refcount = 0;
static void set_addr_in(struct sockaddr_in& their_addr, const IP_Address& p_host, uint16_t p_port) {
their_addr.sin_family = AF_INET; // host byte order
their_addr.sin_port = htons(p_port); // short, network byte order
their_addr.sin_addr = *((struct in_addr*)&p_host.host);
memset(&(their_addr.sin_zero), '\0', 8);
};
StreamPeerTCP* StreamPeerWinsock::_create() {
return memnew(StreamPeerWinsock);
@ -92,8 +87,8 @@ Error StreamPeerWinsock::_poll_connection(bool p_block) const {
_block(sockfd, false, true);
};
struct sockaddr_in their_addr;
set_addr_in(their_addr, peer_host, peer_port);
struct sockaddr_storage their_addr;
_set_sockaddr(&their_addr, peer_host, peer_port);
if (::connect(sockfd, (struct sockaddr *)&their_addr,sizeof(struct sockaddr)) == SOCKET_ERROR) {
@ -299,9 +294,10 @@ void StreamPeerWinsock::set_socket(int p_sockfd, IP_Address p_host, int p_port)
Error StreamPeerWinsock::connect(const IP_Address& p_host, uint16_t p_port) {
ERR_FAIL_COND_V( p_host.host == 0, ERR_INVALID_PARAMETER);
ERR_FAIL_COND_V( p_host.type == IP_Address::TYPE_NONE, ERR_INVALID_PARAMETER);
if ((sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET) {
int family = p_host.type == IP_Address::TYPE_IPV6 ? AF_INET6 : AF_INET;
if ((sockfd = socket(family, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET) {
ERR_PRINT("Socket creation failed!");
disconnect();
//perror("socket");
@ -315,8 +311,8 @@ Error StreamPeerWinsock::connect(const IP_Address& p_host, uint16_t p_port) {
return FAILED;
};
struct sockaddr_in their_addr;
set_addr_in(their_addr, p_host, p_port);
struct sockaddr_storage their_addr;
_set_sockaddr(&their_addr, p_host, p_port);
if (::connect(sockfd, (struct sockaddr *)&their_addr,sizeof(struct sockaddr)) == SOCKET_ERROR) {

View file

@ -31,6 +31,9 @@
#include "stream_peer_winsock.h"
#include <winsock2.h>
#include <ws2tcpip.h>
#include "drivers/unix/socket_helpers.h"
extern int winsock_refcount;
@ -60,7 +63,7 @@ void TCPServerWinsock::cleanup() {
};
Error TCPServerWinsock::listen(uint16_t p_port,const List<String> *p_accepted_hosts) {
Error TCPServerWinsock::listen(uint16_t p_port, IP_Address::AddrType p_type,const List<String> *p_accepted_hosts) {
int sockfd;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
@ -73,11 +76,8 @@ Error TCPServerWinsock::listen(uint16_t p_port,const List<String> *p_accepted_ho
return FAILED;
};
struct sockaddr_in my_addr;
my_addr.sin_family = AF_INET; // host byte order
my_addr.sin_port = htons(p_port); // short, network byte order
my_addr.sin_addr.s_addr = INADDR_ANY; // automatically fill with my IP TODO: use p_accepted_hosts
memset(my_addr.sin_zero, '\0', sizeof my_addr.sin_zero);
struct sockaddr_storage my_addr;
_set_listen_sockaddr(&my_addr, p_port, p_type, p_accepted_hosts);
int reuse=1;
if(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse)) < 0) {
@ -140,16 +140,17 @@ Ref<StreamPeerTCP> TCPServerWinsock::take_connection() {
return NULL;
};
struct sockaddr_in their_addr;
struct sockaddr_storage their_addr;
int sin_size = sizeof(their_addr);
int fd = accept(listen_sockfd, (struct sockaddr *)&their_addr, &sin_size);
ERR_FAIL_COND_V(fd == INVALID_SOCKET, NULL);
Ref<StreamPeerWinsock> conn = memnew(StreamPeerWinsock);
IP_Address ip;
ip.host = (uint32_t)their_addr.sin_addr.s_addr;
int port;
_set_ip_addr_port(ip, port, &their_addr);
conn->set_socket(fd, ip, ntohs(their_addr.sin_port));
conn->set_socket(fd, ip, port);
return conn;
};

View file

@ -39,7 +39,7 @@ class TCPServerWinsock : public TCP_Server {
public:
virtual Error listen(uint16_t p_port,const List<String> *p_accepted_hosts=NULL);
virtual Error listen(uint16_t p_port, IP_Address::AddrType p_type = IP_Address::TYPE_IPV4,const List<String> *p_accepted_hosts=NULL);
virtual bool is_connection_available() const;
virtual Ref<StreamPeerTCP> take_connection();