adding ipv6
This commit is contained in:
parent
048bffd13a
commit
887a897c02
17 changed files with 445 additions and 127 deletions
|
@ -32,6 +32,7 @@
|
||||||
#include "hash_map.h"
|
#include "hash_map.h"
|
||||||
|
|
||||||
VARIANT_ENUM_CAST(IP::ResolverStatus);
|
VARIANT_ENUM_CAST(IP::ResolverStatus);
|
||||||
|
VARIANT_ENUM_CAST(IP_Address::AddrType);
|
||||||
|
|
||||||
/************* RESOLVER ******************/
|
/************* RESOLVER ******************/
|
||||||
|
|
||||||
|
@ -43,10 +44,12 @@ struct _IP_ResolverPrivate {
|
||||||
volatile IP::ResolverStatus status;
|
volatile IP::ResolverStatus status;
|
||||||
IP_Address response;
|
IP_Address response;
|
||||||
String hostname;
|
String hostname;
|
||||||
|
IP_Address::AddrType type;
|
||||||
|
|
||||||
void clear() {
|
void clear() {
|
||||||
status = IP::RESOLVER_STATUS_NONE;
|
status = IP::RESOLVER_STATUS_NONE;
|
||||||
response = IP_Address();
|
response = IP_Address();
|
||||||
|
type = IP_Address::TYPE_NONE;
|
||||||
hostname="";
|
hostname="";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -78,9 +81,9 @@ struct _IP_ResolverPrivate {
|
||||||
|
|
||||||
if (queue[i].status!=IP::RESOLVER_STATUS_WAITING)
|
if (queue[i].status!=IP::RESOLVER_STATUS_WAITING)
|
||||||
continue;
|
continue;
|
||||||
queue[i].response=IP::get_singleton()->resolve_hostname(queue[i].hostname);
|
queue[i].response=IP::get_singleton()->resolve_hostname(queue[i].hostname, queue[i].type);
|
||||||
|
|
||||||
if (queue[i].response.host==0)
|
if (queue[i].response.type==IP_Address::TYPE_NONE)
|
||||||
queue[i].status=IP::RESOLVER_STATUS_ERROR;
|
queue[i].status=IP::RESOLVER_STATUS_ERROR;
|
||||||
else
|
else
|
||||||
queue[i].status=IP::RESOLVER_STATUS_DONE;
|
queue[i].status=IP::RESOLVER_STATUS_DONE;
|
||||||
|
@ -109,21 +112,21 @@ struct _IP_ResolverPrivate {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
IP_Address IP::resolve_hostname(const String& p_hostname) {
|
IP_Address IP::resolve_hostname(const String& p_hostname, IP_Address::AddrType p_type) {
|
||||||
|
|
||||||
GLOBAL_LOCK_FUNCTION
|
GLOBAL_LOCK_FUNCTION;
|
||||||
|
|
||||||
if (resolver->cache.has(p_hostname))
|
if (resolver->cache.has(p_hostname))
|
||||||
return resolver->cache[p_hostname];
|
return resolver->cache[p_hostname];
|
||||||
|
|
||||||
IP_Address res = _resolve_hostname(p_hostname);
|
IP_Address res = _resolve_hostname(p_hostname, p_type);
|
||||||
resolver->cache[p_hostname]=res;
|
resolver->cache[p_hostname]=res;
|
||||||
return res;
|
return res;
|
||||||
|
|
||||||
}
|
}
|
||||||
IP::ResolverID IP::resolve_hostname_queue_item(const String& p_hostname) {
|
IP::ResolverID IP::resolve_hostname_queue_item(const String& p_hostname, IP_Address::AddrType p_type) {
|
||||||
|
|
||||||
GLOBAL_LOCK_FUNCTION
|
GLOBAL_LOCK_FUNCTION;
|
||||||
|
|
||||||
ResolverID id = resolver->find_empty_id();
|
ResolverID id = resolver->find_empty_id();
|
||||||
|
|
||||||
|
@ -133,6 +136,7 @@ IP::ResolverID IP::resolve_hostname_queue_item(const String& p_hostname) {
|
||||||
}
|
}
|
||||||
|
|
||||||
resolver->queue[id].hostname=p_hostname;
|
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->queue[id].response=resolver->cache[p_hostname];
|
resolver->queue[id].response=resolver->cache[p_hostname];
|
||||||
resolver->queue[id].status=IP::RESOLVER_STATUS_DONE;
|
resolver->queue[id].status=IP::RESOLVER_STATUS_DONE;
|
||||||
|
@ -145,10 +149,6 @@ IP::ResolverID IP::resolve_hostname_queue_item(const String& p_hostname) {
|
||||||
resolver->resolve_queues();
|
resolver->resolve_queues();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
14
core/io/ip.h
14
core/io/ip.h
|
@ -48,6 +48,14 @@ public:
|
||||||
RESOLVER_STATUS_ERROR,
|
RESOLVER_STATUS_ERROR,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum AddressType {
|
||||||
|
|
||||||
|
ADDRESS_IPV4 = 1,
|
||||||
|
ADDRESS_IPV6 = 2,
|
||||||
|
|
||||||
|
ADDRESS_ANY = 3,
|
||||||
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
RESOLVER_MAX_QUERIES = 32,
|
RESOLVER_MAX_QUERIES = 32,
|
||||||
RESOLVER_INVALID_ID=-1
|
RESOLVER_INVALID_ID=-1
|
||||||
|
@ -65,7 +73,7 @@ protected:
|
||||||
static IP*singleton;
|
static IP*singleton;
|
||||||
static void _bind_methods();
|
static void _bind_methods();
|
||||||
|
|
||||||
virtual IP_Address _resolve_hostname(const String& p_hostname)=0;
|
virtual IP_Address _resolve_hostname(const String& p_hostname, IP_Address::AddrType p_type = IP_Address::TYPE_ANY)=0;
|
||||||
Array _get_local_addresses() const;
|
Array _get_local_addresses() const;
|
||||||
|
|
||||||
static IP* (*_create)();
|
static IP* (*_create)();
|
||||||
|
@ -73,9 +81,9 @@ public:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
IP_Address resolve_hostname(const String& p_hostname);
|
IP_Address resolve_hostname(const String& p_hostname, IP_Address::AddrType p_type = IP_Address::TYPE_ANY);
|
||||||
// async resolver hostname
|
// async resolver hostname
|
||||||
ResolverID resolve_hostname_queue_item(const String& p_hostname);
|
ResolverID resolve_hostname_queue_item(const String& p_hostname, IP_Address::AddrType p_type = IP_Address::TYPE_ANY);
|
||||||
ResolverStatus get_resolve_item_status(ResolverID p_id) const;
|
ResolverStatus get_resolve_item_status(ResolverID p_id) const;
|
||||||
IP_Address get_resolve_item_address(ResolverID p_id) const;
|
IP_Address get_resolve_item_address(ResolverID p_id) const;
|
||||||
virtual void get_local_addresses(List<IP_Address> *r_addresses) const=0;
|
virtual void get_local_addresses(List<IP_Address> *r_addresses) const=0;
|
||||||
|
|
|
@ -32,29 +32,179 @@ IP_Address::operator Variant() const {
|
||||||
|
|
||||||
return operator String();
|
return operator String();
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
IP_Address::operator String() const {
|
IP_Address::operator String() const {
|
||||||
|
|
||||||
return itos(field[0])+"."+itos(field[1])+"."+itos(field[2])+"."+itos(field[3]);
|
if (type == TYPE_NONE)
|
||||||
|
return "0.0.0.0";
|
||||||
|
if (type == TYPE_IPV4)
|
||||||
|
return itos(field8[0])+"."+itos(field8[1])+"."+itos(field8[2])+"."+itos(field8[3]);
|
||||||
|
else
|
||||||
|
return String::num_int64(field16[0], 16) +
|
||||||
|
":" + String::num_int64(field16[1], 16) +
|
||||||
|
":" + String::num_int64(field16[2], 16) +
|
||||||
|
":" + String::num_int64(field16[3], 16) +
|
||||||
|
":" + String::num_int64(field16[4], 16) +
|
||||||
|
":" + String::num_int64(field16[5], 16) +
|
||||||
|
":" + String::num_int64(field16[6], 16) +
|
||||||
|
":" + String::num_int64(field16[7], 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
IP_Address::IP_Address(const String& p_string) {
|
static uint16_t _parse_hex(const String& p_string, int p_start) {
|
||||||
|
|
||||||
host=0;
|
uint16_t ret = 0;
|
||||||
int slices = p_string.get_slice_count(".");
|
for (int i=p_start; i<4; i++) {
|
||||||
|
|
||||||
|
if (i >= p_string.length()) {
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
|
||||||
|
int n = 0;
|
||||||
|
CharType c = p_string[i];
|
||||||
|
if (c >= '0' && c <= '9') {
|
||||||
|
|
||||||
|
n = c - '0';
|
||||||
|
} else if (c >= 'a' && c <= 'f') {
|
||||||
|
n = 10 + (c - 'a');
|
||||||
|
} else if (c >= 'A' && c <= 'F') {
|
||||||
|
n = 10 + (c - 'A');
|
||||||
|
} else {
|
||||||
|
ERR_EXPLAIN("Invalid character in ipv6 address: " + p_string);
|
||||||
|
ERR_FAIL_V(0);
|
||||||
|
};
|
||||||
|
ret = ret << 4;
|
||||||
|
ret += n;
|
||||||
|
};
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
};
|
||||||
|
|
||||||
|
void IP_Address::_parse_ipv6(const String& p_string) {
|
||||||
|
|
||||||
|
static const int parts_total = 8;
|
||||||
|
int parts[parts_total] = {0};
|
||||||
|
int parts_count = 0;
|
||||||
|
bool part_found = false;
|
||||||
|
bool part_skip = false;
|
||||||
|
bool part_ipv4 = false;
|
||||||
|
int parts_idx = 0;
|
||||||
|
|
||||||
|
for (int i=0; i<p_string.length(); i++) {
|
||||||
|
|
||||||
|
CharType c = p_string[i];
|
||||||
|
if (c == ':') {
|
||||||
|
|
||||||
|
if (i == 0) {
|
||||||
|
continue; // next must be a ":"
|
||||||
|
};
|
||||||
|
if (!part_found) {
|
||||||
|
part_skip = true;
|
||||||
|
parts[parts_idx++] = -1;
|
||||||
|
};
|
||||||
|
part_found = false;
|
||||||
|
} else if (c == '.') {
|
||||||
|
|
||||||
|
part_ipv4 = true;
|
||||||
|
|
||||||
|
} else if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')) {
|
||||||
|
if (!part_found) {
|
||||||
|
parts[parts_idx++] = i;
|
||||||
|
part_found = true;
|
||||||
|
++parts_count;
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
|
||||||
|
ERR_EXPLAIN("Invalid character in IPv6 address: " + p_string);
|
||||||
|
ERR_FAIL();
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
int parts_extra = 0;
|
||||||
|
if (part_skip) {
|
||||||
|
parts_extra = parts_total - parts_count;
|
||||||
|
};
|
||||||
|
|
||||||
|
int idx = 0;
|
||||||
|
for (int i=0; i<parts_idx; i++) {
|
||||||
|
|
||||||
|
if (parts[i] == -1) {
|
||||||
|
|
||||||
|
for (int j=0; j<parts_extra; j++) {
|
||||||
|
field16[idx++] = 0;
|
||||||
|
};
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (part_ipv4 && i == parts_idx - 1) {
|
||||||
|
_parse_ipv4(p_string, parts[i], (uint8_t*)&field16[idx]); // should be the last one
|
||||||
|
} else {
|
||||||
|
|
||||||
|
field16[idx++] = _parse_hex(p_string, parts[i]);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
void IP_Address::_parse_ipv4(const String& p_string, int p_start, uint8_t* p_ret) {
|
||||||
|
|
||||||
|
String ip;
|
||||||
|
if (p_start != 0) {
|
||||||
|
ip = p_string.substr(p_start, p_string.length() - p_start);
|
||||||
|
} else {
|
||||||
|
ip = p_string;
|
||||||
|
};
|
||||||
|
|
||||||
|
int slices = ip.get_slice_count(".");
|
||||||
if (slices!=4) {
|
if (slices!=4) {
|
||||||
ERR_EXPLAIN("Invalid IP Address String: "+p_string);
|
ERR_EXPLAIN("Invalid IP Address String: "+ip);
|
||||||
ERR_FAIL();
|
ERR_FAIL();
|
||||||
}
|
}
|
||||||
for(int i=0;i<4;i++) {
|
for(int i=0;i<4;i++) {
|
||||||
|
|
||||||
field[i]=p_string.get_slicec('.',i).to_int();
|
p_ret[i]=ip.get_slicec('.',i).to_int();
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void IP_Address::clear() {
|
||||||
|
|
||||||
|
memset(&field8[0], 0, sizeof(field8));
|
||||||
|
};
|
||||||
|
|
||||||
|
IP_Address::IP_Address(const String& p_string) {
|
||||||
|
|
||||||
|
clear();
|
||||||
|
if (p_string.find(":") >= 0) {
|
||||||
|
|
||||||
|
_parse_ipv6(p_string);
|
||||||
|
type = TYPE_IPV6;
|
||||||
|
} else {
|
||||||
|
|
||||||
|
_parse_ipv4(p_string, 0, &field8[0]);
|
||||||
|
type = TYPE_IPV4;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
IP_Address::IP_Address(uint8_t p_a,uint8_t p_b,uint8_t p_c,uint8_t p_d) {
|
IP_Address::IP_Address(uint32_t p_a,uint32_t p_b,uint32_t p_c,uint32_t p_d, IP_Address::AddrType p_type) {
|
||||||
|
|
||||||
|
type = p_type;
|
||||||
|
memset(&field8[0], 0, sizeof(field8));
|
||||||
|
if (p_type == TYPE_IPV4) {
|
||||||
|
field8[0]=p_a;
|
||||||
|
field8[1]=p_b;
|
||||||
|
field8[2]=p_c;
|
||||||
|
field8[3]=p_d;
|
||||||
|
} else if (type == TYPE_IPV6) {
|
||||||
|
|
||||||
|
field32[0]=p_a;
|
||||||
|
field32[1]=p_b;
|
||||||
|
field32[2]=p_c;
|
||||||
|
field32[3]=p_d;
|
||||||
|
} else {
|
||||||
|
type = TYPE_NONE;
|
||||||
|
ERR_EXPLAIN("Invalid type specified for IP_Address (use TYPE_IPV4 or TYPE_IPV6");
|
||||||
|
ERR_FAIL();
|
||||||
|
};
|
||||||
|
|
||||||
field[0]=p_a;
|
|
||||||
field[1]=p_b;
|
|
||||||
field[2]=p_c;
|
|
||||||
field[3]=p_d;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,22 +33,48 @@
|
||||||
|
|
||||||
struct IP_Address {
|
struct IP_Address {
|
||||||
|
|
||||||
union {
|
public:
|
||||||
uint8_t field[4];
|
enum AddrType {
|
||||||
uint32_t host;
|
TYPE_NONE = 0,
|
||||||
|
TYPE_IPV4 = 1,
|
||||||
|
TYPE_IPV6 = 2,
|
||||||
|
|
||||||
|
TYPE_ANY = 3,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
AddrType type;
|
||||||
|
|
||||||
|
union {
|
||||||
|
uint8_t field8[16];
|
||||||
|
uint16_t field16[8];
|
||||||
|
uint32_t field32[4];
|
||||||
|
};
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void _parse_ipv6(const String& p_string);
|
||||||
|
void _parse_ipv4(const String& p_string, int p_start, uint8_t* p_ret);
|
||||||
|
|
||||||
|
public:
|
||||||
//operator Variant() const;
|
//operator Variant() const;
|
||||||
bool operator==(const IP_Address& p_ip) const {
|
bool operator==(const IP_Address& p_ip) const {
|
||||||
return host==p_ip.host;
|
for (int i=0; i<4; i++)
|
||||||
|
if (field32[i] != p_ip.field32[i])
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
bool operator!=(const IP_Address& p_ip) const {
|
bool operator!=(const IP_Address& p_ip) const {
|
||||||
return host!=p_ip.host;
|
for (int i=0; i<4; i++)
|
||||||
|
if (field32[i] != p_ip.field32[i])
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void clear();
|
||||||
|
|
||||||
operator String() const;
|
operator String() const;
|
||||||
IP_Address(const String& p_string);
|
IP_Address(const String& p_string);
|
||||||
IP_Address(uint8_t p_a,uint8_t p_b,uint8_t p_c,uint8_t p_d);
|
IP_Address(uint32_t p_a,uint32_t p_b,uint32_t p_c,uint32_t p_d, AddrType p_type=TYPE_IPV4);
|
||||||
IP_Address() { host=0; }
|
IP_Address() { clear(); type=TYPE_NONE; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -29,14 +29,9 @@
|
||||||
#include "packet_peer_udp.h"
|
#include "packet_peer_udp.h"
|
||||||
#include "io/ip.h"
|
#include "io/ip.h"
|
||||||
|
|
||||||
|
|
||||||
PacketPeerUDP* (*PacketPeerUDP::_create)()=NULL;
|
PacketPeerUDP* (*PacketPeerUDP::_create)()=NULL;
|
||||||
|
|
||||||
int PacketPeerUDP::_get_packet_address() const {
|
VARIANT_ENUM_CAST(IP_Address::AddrType);
|
||||||
|
|
||||||
IP_Address ip = get_packet_address();
|
|
||||||
return ip.host;
|
|
||||||
}
|
|
||||||
|
|
||||||
String PacketPeerUDP::_get_packet_ip() const {
|
String PacketPeerUDP::_get_packet_ip() const {
|
||||||
|
|
||||||
|
@ -65,7 +60,7 @@ void PacketPeerUDP::_bind_methods() {
|
||||||
ObjectTypeDB::bind_method(_MD("wait:Error"),&PacketPeerUDP::wait);
|
ObjectTypeDB::bind_method(_MD("wait:Error"),&PacketPeerUDP::wait);
|
||||||
ObjectTypeDB::bind_method(_MD("is_listening"),&PacketPeerUDP::is_listening);
|
ObjectTypeDB::bind_method(_MD("is_listening"),&PacketPeerUDP::is_listening);
|
||||||
ObjectTypeDB::bind_method(_MD("get_packet_ip"),&PacketPeerUDP::_get_packet_ip);
|
ObjectTypeDB::bind_method(_MD("get_packet_ip"),&PacketPeerUDP::_get_packet_ip);
|
||||||
ObjectTypeDB::bind_method(_MD("get_packet_address"),&PacketPeerUDP::_get_packet_address);
|
//ObjectTypeDB::bind_method(_MD("get_packet_address"),&PacketPeerUDP::_get_packet_address);
|
||||||
ObjectTypeDB::bind_method(_MD("get_packet_port"),&PacketPeerUDP::get_packet_port);
|
ObjectTypeDB::bind_method(_MD("get_packet_port"),&PacketPeerUDP::get_packet_port);
|
||||||
ObjectTypeDB::bind_method(_MD("set_send_address","host","port"),&PacketPeerUDP::_set_send_address);
|
ObjectTypeDB::bind_method(_MD("set_send_address","host","port"),&PacketPeerUDP::_set_send_address);
|
||||||
|
|
||||||
|
|
|
@ -40,14 +40,13 @@ protected:
|
||||||
static PacketPeerUDP* (*_create)();
|
static PacketPeerUDP* (*_create)();
|
||||||
static void _bind_methods();
|
static void _bind_methods();
|
||||||
|
|
||||||
int _get_packet_address() const;
|
|
||||||
String _get_packet_ip() const;
|
String _get_packet_ip() const;
|
||||||
|
|
||||||
virtual Error _set_send_address(const String& p_address,int p_port);
|
virtual Error _set_send_address(const String& p_address,int p_port);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
virtual Error listen(int p_port,int p_recv_buffer_size=65536)=0;
|
virtual Error listen(int p_port, IP_Address::AddrType p_address_type = IP_Address::TYPE_IPV4, int p_recv_buffer_size=65536)=0;
|
||||||
virtual void close()=0;
|
virtual void close()=0;
|
||||||
virtual Error wait()=0;
|
virtual Error wait()=0;
|
||||||
virtual bool is_listening() const=0;
|
virtual bool is_listening() const=0;
|
||||||
|
|
|
@ -30,6 +30,8 @@
|
||||||
|
|
||||||
TCP_Server* (*TCP_Server::_create)()=NULL;
|
TCP_Server* (*TCP_Server::_create)()=NULL;
|
||||||
|
|
||||||
|
VARIANT_ENUM_CAST(IP_Address::AddrType);
|
||||||
|
|
||||||
Ref<TCP_Server> TCP_Server::create_ref() {
|
Ref<TCP_Server> TCP_Server::create_ref() {
|
||||||
|
|
||||||
if (!_create)
|
if (!_create)
|
||||||
|
@ -44,19 +46,19 @@ TCP_Server* TCP_Server::create() {
|
||||||
return _create();
|
return _create();
|
||||||
}
|
}
|
||||||
|
|
||||||
Error TCP_Server::_listen(uint16_t p_port,DVector<String> p_accepted_hosts) {
|
Error TCP_Server::_listen(uint16_t p_port, IP_Address::AddrType p_type, DVector<String> p_accepted_hosts) {
|
||||||
|
|
||||||
List<String> hosts;
|
List<String> hosts;
|
||||||
for(int i=0;i<p_accepted_hosts.size();i++)
|
for(int i=0;i<p_accepted_hosts.size();i++)
|
||||||
hosts.push_back(p_accepted_hosts.get(i));
|
hosts.push_back(p_accepted_hosts.get(i));
|
||||||
|
|
||||||
return listen(p_port,hosts.size()?&hosts:NULL);
|
return listen(p_port,p_type, hosts.size()?&hosts:NULL);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TCP_Server::_bind_methods() {
|
void TCP_Server::_bind_methods() {
|
||||||
|
|
||||||
ObjectTypeDB::bind_method(_MD("listen","port","accepted_hosts"),&TCP_Server::_listen,DEFVAL(DVector<String>()));
|
ObjectTypeDB::bind_method(_MD("listen","port","accepted_hosts"),&TCP_Server::_listen,DEFVAL(IP_Address::TYPE_IPV4), DEFVAL(DVector<String>()));
|
||||||
ObjectTypeDB::bind_method(_MD("is_connection_available"),&TCP_Server::is_connection_available);
|
ObjectTypeDB::bind_method(_MD("is_connection_available"),&TCP_Server::is_connection_available);
|
||||||
ObjectTypeDB::bind_method(_MD("take_connection"),&TCP_Server::take_connection);
|
ObjectTypeDB::bind_method(_MD("take_connection"),&TCP_Server::take_connection);
|
||||||
ObjectTypeDB::bind_method(_MD("stop"),&TCP_Server::stop);
|
ObjectTypeDB::bind_method(_MD("stop"),&TCP_Server::stop);
|
||||||
|
|
|
@ -41,11 +41,11 @@ protected:
|
||||||
static TCP_Server* (*_create)();
|
static TCP_Server* (*_create)();
|
||||||
|
|
||||||
//bind helper
|
//bind helper
|
||||||
Error _listen(uint16_t p_port,DVector<String> p_accepted_hosts=DVector<String>());
|
Error _listen(uint16_t p_port, IP_Address::AddrType p_type = IP_Address::TYPE_IPV4 ,DVector<String> p_accepted_hosts=DVector<String>());
|
||||||
static void _bind_methods();
|
static void _bind_methods();
|
||||||
public:
|
public:
|
||||||
|
|
||||||
virtual Error listen(uint16_t p_port,const List<String> *p_accepted_hosts=NULL)=0;
|
virtual Error listen(uint16_t p_port, IP_Address::AddrType p_type = IP_Address::TYPE_IPV4, const List<String> *p_accepted_hosts=NULL)=0;
|
||||||
virtual bool is_connection_available() const=0;
|
virtual bool is_connection_available() const=0;
|
||||||
virtual Ref<StreamPeerTCP> take_connection()=0;
|
virtual Ref<StreamPeerTCP> take_connection()=0;
|
||||||
|
|
||||||
|
|
|
@ -1820,6 +1820,11 @@ _VariantCall::addfunc(Variant::m_vtype,Variant::m_ret,_SCS(#m_method),VCALL(m_cl
|
||||||
_VariantCall::add_constant(Variant::IMAGE,"INTERPOLATE_NEAREST",Image::INTERPOLATE_NEAREST);
|
_VariantCall::add_constant(Variant::IMAGE,"INTERPOLATE_NEAREST",Image::INTERPOLATE_NEAREST);
|
||||||
_VariantCall::add_constant(Variant::IMAGE,"INTERPOLATE_BILINEAR",Image::INTERPOLATE_BILINEAR);
|
_VariantCall::add_constant(Variant::IMAGE,"INTERPOLATE_BILINEAR",Image::INTERPOLATE_BILINEAR);
|
||||||
_VariantCall::add_constant(Variant::IMAGE,"INTERPOLATE_CUBIC",Image::INTERPOLATE_CUBIC);
|
_VariantCall::add_constant(Variant::IMAGE,"INTERPOLATE_CUBIC",Image::INTERPOLATE_CUBIC);
|
||||||
|
|
||||||
|
_VariantCall::add_constant(Variant::INT, "IP_TYPE_NONE", IP_Address::TYPE_NONE);
|
||||||
|
_VariantCall::add_constant(Variant::INT, "IP_TYPE_IPV4", IP_Address::TYPE_IPV4);
|
||||||
|
_VariantCall::add_constant(Variant::INT, "IP_TYPE_IPV6", IP_Address::TYPE_IPV6);
|
||||||
|
_VariantCall::add_constant(Variant::INT, "IP_TYPE_ANY", IP_Address::TYPE_ANY);
|
||||||
}
|
}
|
||||||
|
|
||||||
void unregister_variant_methods() {
|
void unregister_variant_methods() {
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
|
|
||||||
#if defined(UNIX_ENABLED) || defined(WINDOWS_ENABLED)
|
#if defined(UNIX_ENABLED) || defined(WINDOWS_ENABLED)
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
#ifdef WINDOWS_ENABLED
|
#ifdef WINDOWS_ENABLED
|
||||||
#ifdef WINRT_ENABLED
|
#ifdef WINRT_ENABLED
|
||||||
|
@ -62,16 +63,51 @@
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
IP_Address IP_Unix::_resolve_hostname(const String& p_hostname) {
|
static IP_Address _sockaddr2ip(struct sockaddr* p_addr) {
|
||||||
|
|
||||||
struct hostent *he;
|
|
||||||
if ((he=gethostbyname(p_hostname.utf8().get_data())) == NULL) { // get the host info
|
|
||||||
ERR_PRINT("gethostbyname failed!");
|
|
||||||
return IP_Address();
|
|
||||||
}
|
|
||||||
IP_Address ip;
|
IP_Address ip;
|
||||||
|
if (p_addr->sa_family == AF_INET) {
|
||||||
|
struct sockaddr_in* addr = (struct sockaddr_in*)p_addr;
|
||||||
|
ip.field32[0] = ntohl(addr->sin_addr.s_addr);
|
||||||
|
ip.type = IP_Address::TYPE_IPV4;
|
||||||
|
} else {
|
||||||
|
struct sockaddr_in6* addr6 = (struct sockaddr_in6*)p_addr;
|
||||||
|
for (int i=0; i<16; i++)
|
||||||
|
ip.field8[i] = addr6->sin6_addr.s6_addr[i];
|
||||||
|
ip.type = IP_Address::TYPE_IPV6;
|
||||||
|
};
|
||||||
|
|
||||||
ip.host= *((unsigned long*)he->h_addr);
|
return ip;
|
||||||
|
};
|
||||||
|
|
||||||
|
IP_Address IP_Unix::_resolve_hostname(const String& p_hostname, IP_Address::AddrType p_type) {
|
||||||
|
|
||||||
|
struct addrinfo hints;
|
||||||
|
struct addrinfo* result;
|
||||||
|
|
||||||
|
memset(&hints, 0, sizeof(struct addrinfo));
|
||||||
|
if (p_type == IP_Address::TYPE_IPV4) {
|
||||||
|
hints.ai_family = AF_INET;
|
||||||
|
} else if (p_type == IP_Address::TYPE_IPV6) {
|
||||||
|
hints.ai_family = AF_INET6;
|
||||||
|
} else {
|
||||||
|
hints.ai_family = AF_UNSPEC;
|
||||||
|
};
|
||||||
|
|
||||||
|
int s = getaddrinfo(p_hostname.utf8().get_data(), NULL, &hints, &result);
|
||||||
|
if (s != 0) {
|
||||||
|
ERR_PRINT("getaddrinfo failed!");
|
||||||
|
return IP_Address();
|
||||||
|
};
|
||||||
|
|
||||||
|
if (result == NULL || result->ai_addr == NULL) {
|
||||||
|
ERR_PRINT("Invalid response from getaddrinfo");
|
||||||
|
return IP_Address();
|
||||||
|
};
|
||||||
|
|
||||||
|
IP_Address ip = _sockaddr2ip(result->ai_addr);
|
||||||
|
|
||||||
|
freeaddrinfo(result);
|
||||||
|
|
||||||
return ip;
|
return ip;
|
||||||
|
|
||||||
|
@ -90,10 +126,9 @@ void IP_Unix::get_local_addresses(List<IP_Address> *r_addresses) const {
|
||||||
|
|
||||||
for (int i = 0; i < hostnames->Size; i++) {
|
for (int i = 0; i < hostnames->Size; i++) {
|
||||||
|
|
||||||
if (hostnames->GetAt(i)->Type == HostNameType::Ipv4 && hostnames->GetAt(i)->IPInformation != nullptr) {
|
if (hostnames->GetAt(i)->Type == HostNameType::Ipv4 || hostnames->GetAt(i)->Type == HostNameType::Ipv6 && hostnames->GetAt(i)->IPInformation != nullptr) {
|
||||||
|
|
||||||
r_addresses->push_back(IP_Address(String(hostnames->GetAt(i)->CanonicalName->Data())));
|
r_addresses->push_back(IP_Address(String(hostnames->GetAt(i)->CanonicalName->Data())));
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,7 +143,7 @@ void IP_Unix::get_local_addresses(List<IP_Address> *r_addresses) const {
|
||||||
while (true) {
|
while (true) {
|
||||||
|
|
||||||
addrs = (IP_ADAPTER_ADDRESSES*)memalloc(buf_size);
|
addrs = (IP_ADAPTER_ADDRESSES*)memalloc(buf_size);
|
||||||
int err = GetAdaptersAddresses(AF_INET, GAA_FLAG_SKIP_ANYCAST |
|
int err = GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_SKIP_ANYCAST |
|
||||||
GAA_FLAG_SKIP_MULTICAST |
|
GAA_FLAG_SKIP_MULTICAST |
|
||||||
GAA_FLAG_SKIP_DNS_SERVER |
|
GAA_FLAG_SKIP_DNS_SERVER |
|
||||||
GAA_FLAG_SKIP_FRIENDLY_NAME,
|
GAA_FLAG_SKIP_FRIENDLY_NAME,
|
||||||
|
@ -134,14 +169,23 @@ void IP_Unix::get_local_addresses(List<IP_Address> *r_addresses) const {
|
||||||
IP_ADAPTER_UNICAST_ADDRESS* address = adapter->FirstUnicastAddress;
|
IP_ADAPTER_UNICAST_ADDRESS* address = adapter->FirstUnicastAddress;
|
||||||
while (address != NULL) {
|
while (address != NULL) {
|
||||||
|
|
||||||
char addr_chr[INET_ADDRSTRLEN];
|
IP_Address ip;
|
||||||
|
|
||||||
|
if (address->Address.lpSockaddr->sa_family == AF_INET) {
|
||||||
|
|
||||||
SOCKADDR_IN* ipv4 = reinterpret_cast<SOCKADDR_IN*>(address->Address.lpSockaddr);
|
SOCKADDR_IN* ipv4 = reinterpret_cast<SOCKADDR_IN*>(address->Address.lpSockaddr);
|
||||||
|
|
||||||
IP_Address ip;
|
ip.field32[0] = *((unsigned long*)&ipv4->sin_addr);
|
||||||
ip.host= *((unsigned long*)&ipv4->sin_addr);
|
ip.type = IP_Address::TYPE_IPV4;
|
||||||
|
} else { // ipv6
|
||||||
|
|
||||||
|
SOCKADDR_IN6* ipv6 = reinterpret_cast<SOCKADDR_IN6*>(address->Address.lpSockaddr);
|
||||||
|
for (int i=0; i<16; i++) {
|
||||||
|
ip.field8[i] = ipv6->sin6_addr.s6_addr[i];
|
||||||
|
};
|
||||||
|
ip.type = IP_Address::TYPE_IPV6;
|
||||||
|
};
|
||||||
|
|
||||||
//inet_ntop(AF_INET, &ipv4->sin_addr, addr_chr, INET_ADDRSTRLEN);
|
|
||||||
|
|
||||||
r_addresses->push_back(ip);
|
r_addresses->push_back(ip);
|
||||||
|
|
||||||
|
@ -167,20 +211,9 @@ void IP_Unix::get_local_addresses(List<IP_Address> *r_addresses) const {
|
||||||
for (ifa = ifAddrStruct; ifa != NULL; ifa = ifa->ifa_next) {
|
for (ifa = ifAddrStruct; ifa != NULL; ifa = ifa->ifa_next) {
|
||||||
if (!ifa->ifa_addr)
|
if (!ifa->ifa_addr)
|
||||||
continue;
|
continue;
|
||||||
if (ifa ->ifa_addr->sa_family==AF_INET) { // check it is IP4
|
|
||||||
// is a valid IP4 Address
|
|
||||||
|
|
||||||
IP_Address ip;
|
|
||||||
ip.host= *((unsigned long*)&((struct sockaddr_in *)ifa->ifa_addr)->sin_addr);
|
|
||||||
|
|
||||||
|
IP_Address ip = _sockaddr2ip(ifa->ifa_addr);
|
||||||
r_addresses->push_back(ip);
|
r_addresses->push_back(ip);
|
||||||
}/* else if (ifa->ifa_addr->sa_family==AF_INET6) { // check it is IP6
|
|
||||||
// is a valid IP6 Address
|
|
||||||
tmpAddrPtr=&((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr;
|
|
||||||
char addressBuffer[INET6_ADDRSTRLEN];
|
|
||||||
inet_ntop(AF_INET6, tmpAddrPtr, addressBuffer, INET6_ADDRSTRLEN);
|
|
||||||
printf("%s IP Address %s\n", ifa->ifa_name, addressBuffer);
|
|
||||||
} */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ifAddrStruct!=NULL) freeifaddrs(ifAddrStruct);
|
if (ifAddrStruct!=NULL) freeifaddrs(ifAddrStruct);
|
||||||
|
|
|
@ -36,7 +36,7 @@
|
||||||
class IP_Unix : public IP {
|
class IP_Unix : public IP {
|
||||||
OBJ_TYPE(IP_Unix, IP);
|
OBJ_TYPE(IP_Unix, IP);
|
||||||
|
|
||||||
virtual IP_Address _resolve_hostname(const String& p_hostname);
|
virtual IP_Address _resolve_hostname(const String& p_hostname, IP_Address::AddrType p_type);
|
||||||
|
|
||||||
static IP* _create_unix();
|
static IP* _create_unix();
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -73,7 +73,15 @@ Error PacketPeerUDPPosix::get_packet(const uint8_t **r_buffer,int &r_buffer_size
|
||||||
return ERR_UNAVAILABLE;
|
return ERR_UNAVAILABLE;
|
||||||
|
|
||||||
uint32_t size;
|
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*)&packet_port,4,true);
|
||||||
rb.read((uint8_t*)&size,4,true);
|
rb.read((uint8_t*)&size,4,true);
|
||||||
rb.read(packet_buffer,size,true);
|
rb.read(packet_buffer,size,true);
|
||||||
|
@ -85,12 +93,22 @@ Error PacketPeerUDPPosix::get_packet(const uint8_t **r_buffer,int &r_buffer_size
|
||||||
}
|
}
|
||||||
Error PacketPeerUDPPosix::put_packet(const uint8_t *p_buffer,int p_buffer_size){
|
Error PacketPeerUDPPosix::put_packet(const uint8_t *p_buffer,int p_buffer_size){
|
||||||
|
|
||||||
int sock = _get_socket();
|
ERR_FAIL_COND_V(peer_addr.type == IP_Address::TYPE_NONE, ERR_UNCONFIGURED);
|
||||||
|
|
||||||
|
int sock = _get_socket(peer_addr.type);
|
||||||
ERR_FAIL_COND_V( sock == -1, FAILED );
|
ERR_FAIL_COND_V( sock == -1, FAILED );
|
||||||
struct sockaddr_in addr;
|
struct sockaddr_storage addr;
|
||||||
addr.sin_family = AF_INET;
|
if (peer_addr.type == IP_Address::TYPE_IPV4) {
|
||||||
addr.sin_port = htons(peer_port);
|
struct sockaddr_in* addr_in = (struct sockaddr_in*)&addr;
|
||||||
addr.sin_addr = *((struct in_addr*)&peer_addr.host);
|
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);
|
||||||
|
};
|
||||||
|
|
||||||
errno = 0;
|
errno = 0;
|
||||||
int err;
|
int err;
|
||||||
|
@ -110,17 +128,32 @@ int PacketPeerUDPPosix::get_max_packet_size() const{
|
||||||
return 512; // uhm maybe not
|
return 512; // uhm maybe not
|
||||||
}
|
}
|
||||||
|
|
||||||
Error PacketPeerUDPPosix::listen(int p_port, int p_recv_buffer_size){
|
Error PacketPeerUDPPosix::listen(int p_port, IP_Address::AddrType p_address_type, int p_recv_buffer_size) {
|
||||||
|
|
||||||
|
ERR_FAIL_COND_V(p_address_type != IP_Address::TYPE_IPV4 && p_address_type != IP_Address::TYPE_IPV6, ERR_INVALID_PARAMETER);
|
||||||
|
|
||||||
close();
|
close();
|
||||||
int sock = _get_socket();
|
int sock = _get_socket(p_address_type);
|
||||||
if (sock == -1 )
|
if (sock == -1 )
|
||||||
return ERR_CANT_CREATE;
|
return ERR_CANT_CREATE;
|
||||||
sockaddr_in addr = {0};
|
|
||||||
addr.sin_family = AF_INET;
|
sockaddr_storage addr = {0};
|
||||||
addr.sin_port = htons(p_port);
|
|
||||||
addr.sin_addr.s_addr = INADDR_ANY;
|
if (p_address_type == IP_Address::TYPE_IPV4) {
|
||||||
if (bind(sock, (struct sockaddr*)&addr, sizeof(sockaddr_in)) == -1 ) {
|
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;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (bind(sock, (struct sockaddr*)&addr, sizeof(sockaddr_storage)) == -1 ) {
|
||||||
close();
|
close();
|
||||||
return ERR_UNAVAILABLE;
|
return ERR_UNAVAILABLE;
|
||||||
}
|
}
|
||||||
|
@ -145,16 +178,40 @@ Error PacketPeerUDPPosix::wait() {
|
||||||
|
|
||||||
Error PacketPeerUDPPosix::_poll(bool p_wait) {
|
Error PacketPeerUDPPosix::_poll(bool p_wait) {
|
||||||
|
|
||||||
struct sockaddr_in from = {0};
|
struct sockaddr_storage from = {0};
|
||||||
socklen_t len = sizeof(struct sockaddr_in);
|
socklen_t len = sizeof(struct sockaddr_storage);
|
||||||
int ret;
|
int ret;
|
||||||
while ( (ret = recvfrom(sockfd, recv_buffer, MIN((int)sizeof(recv_buffer),MAX(rb.space_left()-12, 0)), p_wait?0:MSG_DONTWAIT, (struct sockaddr*)&from, &len)) > 0) {
|
while ( (ret = recvfrom(sockfd, recv_buffer, MIN((int)sizeof(recv_buffer),MAX(rb.space_left()-12, 0)), p_wait?0:MSG_DONTWAIT, (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*)&port, 4);
|
||||||
rb.write((uint8_t*)&ret, 4);
|
rb.write((uint8_t*)&ret, 4);
|
||||||
rb.write(recv_buffer, ret);
|
rb.write(recv_buffer, ret);
|
||||||
len = sizeof(struct sockaddr_in);
|
|
||||||
++queue_count;
|
++queue_count;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -182,12 +239,14 @@ int PacketPeerUDPPosix::get_packet_port() const{
|
||||||
return packet_port;
|
return packet_port;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PacketPeerUDPPosix::_get_socket() {
|
int PacketPeerUDPPosix::_get_socket(IP_Address::AddrType p_type) {
|
||||||
|
|
||||||
if (sockfd != -1)
|
if (sockfd != -1)
|
||||||
return sockfd;
|
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 );
|
ERR_FAIL_COND_V( sockfd == -1, -1 );
|
||||||
//fcntl(sockfd, F_SETFL, O_NONBLOCK);
|
//fcntl(sockfd, F_SETFL, O_NONBLOCK);
|
||||||
|
|
||||||
|
|
|
@ -44,15 +44,15 @@ class PacketPeerUDPPosix : public PacketPeerUDP {
|
||||||
mutable RingBuffer<uint8_t> rb;
|
mutable RingBuffer<uint8_t> rb;
|
||||||
uint8_t recv_buffer[PACKET_BUFFER_SIZE];
|
uint8_t recv_buffer[PACKET_BUFFER_SIZE];
|
||||||
mutable uint8_t packet_buffer[PACKET_BUFFER_SIZE];
|
mutable uint8_t packet_buffer[PACKET_BUFFER_SIZE];
|
||||||
IP_Address packet_ip;
|
mutable IP_Address packet_ip;
|
||||||
int packet_port;
|
mutable int packet_port;
|
||||||
mutable int queue_count;
|
mutable int queue_count;
|
||||||
int sockfd;
|
int sockfd;
|
||||||
|
|
||||||
IP_Address peer_addr;
|
IP_Address peer_addr;
|
||||||
int peer_port;
|
int peer_port;
|
||||||
|
|
||||||
_FORCE_INLINE_ int _get_socket();
|
_FORCE_INLINE_ int _get_socket(IP_Address::AddrType p_type);
|
||||||
|
|
||||||
static PacketPeerUDP* _create();
|
static PacketPeerUDP* _create();
|
||||||
virtual Error _poll(bool p_block);
|
virtual Error _poll(bool p_block);
|
||||||
|
@ -65,7 +65,7 @@ public:
|
||||||
|
|
||||||
virtual int get_max_packet_size() const;
|
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 void close();
|
||||||
virtual Error wait();
|
virtual Error wait();
|
||||||
virtual bool is_listening() const;
|
virtual bool is_listening() const;
|
||||||
|
|
|
@ -61,12 +61,23 @@
|
||||||
#define MSG_NOSIGNAL SO_NOSIGPIPE
|
#define MSG_NOSIGNAL SO_NOSIGPIPE
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static void set_addr_in(struct sockaddr_in& their_addr, const IP_Address& p_host, uint16_t p_port) {
|
static void set_addr_in(struct sockaddr_storage& their_addr, const IP_Address& p_host, uint16_t p_port) {
|
||||||
|
|
||||||
their_addr.sin_family = AF_INET; // host byte order
|
memset(&their_addr, 0, sizeof(struct sockaddr_storage));
|
||||||
their_addr.sin_port = htons(p_port); // short, network byte order
|
if (p_host.type == IP_Address::TYPE_IPV6) {
|
||||||
their_addr.sin_addr = *((struct in_addr*)&p_host.host);
|
|
||||||
memset(&(their_addr.sin_zero), '\0', 8);
|
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]);
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
StreamPeerTCP* StreamPeerTCPPosix::_create() {
|
StreamPeerTCP* StreamPeerTCPPosix::_create() {
|
||||||
|
@ -103,9 +114,9 @@ Error StreamPeerTCPPosix::_poll_connection(bool p_block) const {
|
||||||
_block(sockfd, false, true);
|
_block(sockfd, false, true);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct sockaddr_in their_addr;
|
struct sockaddr_storage their_addr;
|
||||||
set_addr_in(their_addr, peer_host, peer_port);
|
set_addr_in(their_addr, peer_host, peer_port);
|
||||||
if (::connect(sockfd, (struct sockaddr *)&their_addr,sizeof(struct sockaddr)) == -1) {
|
if (::connect(sockfd, (struct sockaddr *)&their_addr,sizeof(their_addr)) == -1) {
|
||||||
|
|
||||||
if (errno == EISCONN) {
|
if (errno == EISCONN) {
|
||||||
status = STATUS_CONNECTED;
|
status = STATUS_CONNECTED;
|
||||||
|
@ -140,9 +151,10 @@ void StreamPeerTCPPosix::set_socket(int p_sockfd, IP_Address p_host, int p_port)
|
||||||
|
|
||||||
Error StreamPeerTCPPosix::connect(const IP_Address& p_host, uint16_t p_port) {
|
Error StreamPeerTCPPosix::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, 0)) == -1) {
|
int family = p_host.type == IP_Address::TYPE_IPV6 ? AF_INET6 : AF_INET;
|
||||||
|
if ((sockfd = socket(family, SOCK_STREAM, 0)) == -1) {
|
||||||
ERR_PRINT("Socket creation failed!");
|
ERR_PRINT("Socket creation failed!");
|
||||||
disconnect();
|
disconnect();
|
||||||
//perror("socket");
|
//perror("socket");
|
||||||
|
@ -156,11 +168,11 @@ Error StreamPeerTCPPosix::connect(const IP_Address& p_host, uint16_t p_port) {
|
||||||
ioctl(sockfd, FIONBIO, &bval);
|
ioctl(sockfd, FIONBIO, &bval);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct sockaddr_in their_addr;
|
struct sockaddr_storage their_addr;
|
||||||
set_addr_in(their_addr, p_host, p_port);
|
set_addr_in(their_addr, p_host, p_port);
|
||||||
|
|
||||||
errno = 0;
|
errno = 0;
|
||||||
if (::connect(sockfd, (struct sockaddr *)&their_addr,sizeof(struct sockaddr)) == -1 && errno != EINPROGRESS) {
|
if (::connect(sockfd, (struct sockaddr *)&their_addr,sizeof(their_addr)) == -1 && errno != EINPROGRESS) {
|
||||||
|
|
||||||
ERR_PRINT("Connection to remote host failed!");
|
ERR_PRINT("Connection to remote host failed!");
|
||||||
disconnect();
|
disconnect();
|
||||||
|
|
|
@ -55,6 +55,7 @@
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
TCP_Server* TCPServerPosix::_create() {
|
TCP_Server* TCPServerPosix::_create() {
|
||||||
|
|
||||||
return memnew(TCPServerPosix);
|
return memnew(TCPServerPosix);
|
||||||
|
@ -65,10 +66,11 @@ void TCPServerPosix::make_default() {
|
||||||
TCP_Server::_create = TCPServerPosix::_create;
|
TCP_Server::_create = TCPServerPosix::_create;
|
||||||
};
|
};
|
||||||
|
|
||||||
Error TCPServerPosix::listen(uint16_t p_port,const List<String> *p_accepted_hosts) {
|
Error TCPServerPosix::listen(uint16_t p_port, IP_Address::AddrType p_type, const List<String> *p_accepted_hosts) {
|
||||||
|
|
||||||
int sockfd;
|
int sockfd;
|
||||||
sockfd = socket(AF_INET, SOCK_STREAM, 0);
|
int family = p_type == IP_Address::TYPE_IPV6 ? AF_INET6 : AF_INET;
|
||||||
|
sockfd = socket(family, SOCK_STREAM, 0);
|
||||||
ERR_FAIL_COND_V(sockfd == -1, FAILED);
|
ERR_FAIL_COND_V(sockfd == -1, FAILED);
|
||||||
#ifndef NO_FCNTL
|
#ifndef NO_FCNTL
|
||||||
fcntl(sockfd, F_SETFL, O_NONBLOCK);
|
fcntl(sockfd, F_SETFL, O_NONBLOCK);
|
||||||
|
@ -82,13 +84,22 @@ Error TCPServerPosix::listen(uint16_t p_port,const List<String> *p_accepted_host
|
||||||
WARN_PRINT("REUSEADDR failed!")
|
WARN_PRINT("REUSEADDR failed!")
|
||||||
}
|
}
|
||||||
|
|
||||||
struct sockaddr_in my_addr;
|
sockaddr_storage addr = {0};
|
||||||
my_addr.sin_family = AF_INET; // host byte order
|
if (p_type == IP_Address::TYPE_IPV4) {
|
||||||
my_addr.sin_port = htons(p_port); // short, network byte order
|
struct sockaddr_in* addr4 = (struct sockaddr_in*)&addr;
|
||||||
my_addr.sin_addr.s_addr = INADDR_ANY; // automatically fill with my IP TODO: use p_accepted_hosts
|
addr4->sin_family = AF_INET;
|
||||||
memset(my_addr.sin_zero, '\0', sizeof my_addr.sin_zero);
|
addr4->sin_port = htons(p_port);
|
||||||
|
addr4->sin_addr.s_addr = INADDR_ANY;
|
||||||
|
} else {
|
||||||
|
|
||||||
if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof my_addr) != -1) {
|
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) {
|
||||||
|
|
||||||
if (::listen(sockfd, 1) == -1) {
|
if (::listen(sockfd, 1) == -1) {
|
||||||
|
|
||||||
|
@ -136,9 +147,9 @@ Ref<StreamPeerTCP> TCPServerPosix::take_connection() {
|
||||||
return Ref<StreamPeerTCP>();
|
return Ref<StreamPeerTCP>();
|
||||||
};
|
};
|
||||||
|
|
||||||
struct sockaddr_in their_addr;
|
struct sockaddr_storage their_addr;
|
||||||
socklen_t sin_size = sizeof(their_addr);
|
socklen_t size = sizeof(their_addr);
|
||||||
int fd = accept(listen_sockfd, (struct sockaddr *)&their_addr, &sin_size);
|
int fd = accept(listen_sockfd, (struct sockaddr *)&their_addr, &size);
|
||||||
ERR_FAIL_COND_V(fd == -1, Ref<StreamPeerTCP>());
|
ERR_FAIL_COND_V(fd == -1, Ref<StreamPeerTCP>());
|
||||||
#ifndef NO_FCNTL
|
#ifndef NO_FCNTL
|
||||||
fcntl(fd, F_SETFL, O_NONBLOCK);
|
fcntl(fd, F_SETFL, O_NONBLOCK);
|
||||||
|
@ -149,8 +160,23 @@ Ref<StreamPeerTCP> TCPServerPosix::take_connection() {
|
||||||
|
|
||||||
Ref<StreamPeerTCPPosix> conn = memnew(StreamPeerTCPPosix);
|
Ref<StreamPeerTCPPosix> conn = memnew(StreamPeerTCPPosix);
|
||||||
IP_Address ip;
|
IP_Address ip;
|
||||||
ip.host = (uint32_t)their_addr.sin_addr.s_addr;
|
|
||||||
conn->set_socket(fd, ip, ntohs(their_addr.sin_port));
|
if (their_addr.ss_family == AF_INET) {
|
||||||
|
ip.type = IP_Address::TYPE_IPV4;
|
||||||
|
|
||||||
|
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));
|
||||||
|
};
|
||||||
|
|
||||||
return conn;
|
return conn;
|
||||||
};
|
};
|
||||||
|
|
|
@ -40,7 +40,7 @@ class TCPServerPosix : public TCP_Server {
|
||||||
|
|
||||||
public:
|
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 bool is_connection_available() const;
|
||||||
virtual Ref<StreamPeerTCP> take_connection();
|
virtual Ref<StreamPeerTCP> take_connection();
|
||||||
|
|
||||||
|
|
|
@ -77,6 +77,7 @@ Error NetworkedMultiplayerENet::create_server(int p_port, int p_max_clients, int
|
||||||
Error NetworkedMultiplayerENet::create_client(const IP_Address& p_ip, int p_port, int p_in_bandwidth, int p_out_bandwidth){
|
Error NetworkedMultiplayerENet::create_client(const IP_Address& p_ip, int p_port, int p_in_bandwidth, int p_out_bandwidth){
|
||||||
|
|
||||||
ERR_FAIL_COND_V(active,ERR_ALREADY_IN_USE);
|
ERR_FAIL_COND_V(active,ERR_ALREADY_IN_USE);
|
||||||
|
ERR_FAIL_COND_V(p_ip.type != IP_Address::TYPE_IPV4, ERR_INVALID_PARAMETER);
|
||||||
|
|
||||||
host = enet_host_create (NULL /* create a client host */,
|
host = enet_host_create (NULL /* create a client host */,
|
||||||
1 /* only allow 1 outgoing connection */,
|
1 /* only allow 1 outgoing connection */,
|
||||||
|
@ -90,7 +91,7 @@ Error NetworkedMultiplayerENet::create_client(const IP_Address& p_ip, int p_port
|
||||||
_setup_compressor();
|
_setup_compressor();
|
||||||
|
|
||||||
ENetAddress address;
|
ENetAddress address;
|
||||||
address.host=p_ip.host;
|
address.host=p_ip.field32[0];
|
||||||
address.port=p_port;
|
address.port=p_port;
|
||||||
|
|
||||||
//enet_address_set_host (& address, "localhost");
|
//enet_address_set_host (& address, "localhost");
|
||||||
|
@ -149,7 +150,8 @@ void NetworkedMultiplayerENet::poll(){
|
||||||
}
|
}
|
||||||
|
|
||||||
IP_Address ip;
|
IP_Address ip;
|
||||||
ip.host=event.peer -> address.host;
|
ip.type = IP_Address::TYPE_IPV4;
|
||||||
|
ip.field32[0]=event.peer -> address.host;
|
||||||
|
|
||||||
int *new_id = memnew( int );
|
int *new_id = memnew( int );
|
||||||
*new_id = event.data;
|
*new_id = event.data;
|
||||||
|
@ -683,5 +685,6 @@ NetworkedMultiplayerENet::~NetworkedMultiplayerENet(){
|
||||||
// sets IP for ENet to bind when using create_server
|
// sets IP for ENet to bind when using create_server
|
||||||
// if no IP is set, then ENet bind to ENET_HOST_ANY
|
// if no IP is set, then ENet bind to ENET_HOST_ANY
|
||||||
void NetworkedMultiplayerENet::set_bind_ip(const IP_Address& p_ip){
|
void NetworkedMultiplayerENet::set_bind_ip(const IP_Address& p_ip){
|
||||||
bind_ip=p_ip.host;
|
ERR_FAIL_COND(p_ip.type != IP_Address::TYPE_IPV4);
|
||||||
|
bind_ip=p_ip.field32[0];
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue