diff --git a/bin/tests/test_string.cpp b/bin/tests/test_string.cpp index be37ce118ff..4496b940000 100644 --- a/bin/tests/test_string.cpp +++ b/bin/tests/test_string.cpp @@ -32,6 +32,7 @@ #include #include "os/os.h" #include "drivers/nrex/regex.h" +#include "core/io/ip_address.h" #include "test_string.h" @@ -843,6 +844,62 @@ bool test_28() { return state; } +bool test_29() { + + bool error = false; + bool state = true; + bool success = false; + + IP_Address ip0("2001:0db8:85a3:0000:0000:8a2e:0370:7334"); + OS::get_singleton()->print("ip0 is %ls\n", String(ip0).c_str()); + + IP_Address ip(0x0123, 0x4567, 0x89ab, 0xcdef, true); + OS::get_singleton()->print("ip6 is %ls\n", String(ip).c_str()); + + IP_Address ip2("fe80::52e5:49ff:fe93:1baf"); + OS::get_singleton()->print("ip6 is %ls\n", String(ip2).c_str()); + + IP_Address ip3("::ffff:192.168.0.1"); + OS::get_singleton()->print("ip6 is %ls\n", String(ip3).c_str()); + + String ip4 = "192.168.0.1"; + success = ip4.is_valid_ip_address(); + OS::get_singleton()->print("Is valid ipv4: %ls, %s\n", ip4.c_str(), success ? "OK" : "FAIL"); + if (!success) state = false; + + ip4 = "192.368.0.1"; + success = (!ip4.is_valid_ip_address()); + OS::get_singleton()->print("Is invalid ipv4: %ls, %s\n", ip4.c_str(), success ? "OK" : "FAIL"); + if (!success) state = false; + + String ip6 = "2001:0db8:85a3:0000:0000:8a2e:0370:7334"; + success = ip6.is_valid_ip_address(); + OS::get_singleton()->print("Is valid ipv6: %ls, %s\n", ip6.c_str(), success ? "OK" : "FAIL"); + if (!success) state = false; + + ip6 = "2001:0db8:85j3:0000:0000:8a2e:0370:7334"; + success = (!ip6.is_valid_ip_address()); + OS::get_singleton()->print("Is invalid ipv6: %ls, %s\n", ip6.c_str(), success ? "OK" : "FAIL"); + if (!success) state = false; + + ip6 = "2001:0db8:85f345:0000:0000:8a2e:0370:7334"; + success = (!ip6.is_valid_ip_address()); + OS::get_singleton()->print("Is invalid ipv6: %ls, %s\n", ip6.c_str(), success ? "OK" : "FAIL"); + if (!success) state = false; + + ip6 = "2001:0db8::0:8a2e:370:7334"; + success = (ip6.is_valid_ip_address()); + OS::get_singleton()->print("Is valid ipv6: %ls, %s\n", ip6.c_str(), success ? "OK" : "FAIL"); + if (!success) state = false; + + ip6 = "::ffff:192.168.0.1"; + success = (ip6.is_valid_ip_address()); + OS::get_singleton()->print("Is valid ipv6: %ls, %s\n", ip6.c_str(), success ? "OK" : "FAIL"); + if (!success) state = false; + + return state; +}; + typedef bool (*TestFunc)(void); TestFunc test_funcs[] = { @@ -875,6 +932,7 @@ TestFunc test_funcs[] = { test_26, test_27, test_28, + test_29, 0 }; diff --git a/core/io/http_client.cpp b/core/io/http_client.cpp index 2a831dd9923..5420521f811 100644 --- a/core/io/http_client.cpp +++ b/core/io/http_client.cpp @@ -29,10 +29,14 @@ #include "http_client.h" #include "io/stream_peer_ssl.h" +void HTTPClient::set_ip_type(IP::Type p_type) { + ip_type = p_type; +} Error HTTPClient::connect(const String &p_host, int p_port, bool p_ssl,bool p_verify_host){ close(); + tcp_connection->set_ip_type(ip_type); conn_port=p_port; conn_host=p_host; @@ -62,7 +66,7 @@ Error HTTPClient::connect(const String &p_host, int p_port, bool p_ssl,bool p_ve status=STATUS_CONNECTING; } else { //is hostname - resolving=IP::get_singleton()->resolve_hostname_queue_item(conn_host); + resolving=IP::get_singleton()->resolve_hostname_queue_item(conn_host, ip_type); status=STATUS_RESOLVING; } @@ -635,6 +639,7 @@ Error HTTPClient::_get_http_data(uint8_t* p_buffer, int p_bytes,int &r_received) void HTTPClient::_bind_methods() { + ObjectTypeDB::bind_method(_MD("set_ip_type","ip_type"),&HTTPClient::set_ip_type); ObjectTypeDB::bind_method(_MD("connect:Error","host","port","use_ssl","verify_host"),&HTTPClient::connect,DEFVAL(false),DEFVAL(true)); ObjectTypeDB::bind_method(_MD("set_connection","connection:StreamPeer"),&HTTPClient::set_connection); ObjectTypeDB::bind_method(_MD("get_connection:StreamPeer"),&HTTPClient::get_connection); @@ -761,6 +766,7 @@ String HTTPClient::query_string_from_dict(const Dictionary& p_dict) { HTTPClient::HTTPClient(){ + ip_type = IP::TYPE_ANY; tcp_connection = StreamPeerTCP::create_ref(); resolving = IP::RESOLVER_INVALID_ID; status=STATUS_DISCONNECTED; diff --git a/core/io/http_client.h b/core/io/http_client.h index 32d2e721015..fdbf47b9cc9 100644 --- a/core/io/http_client.h +++ b/core/io/http_client.h @@ -132,6 +132,7 @@ public: private: + IP::Type ip_type; Status status; IP::ResolverID resolving; int conn_port; @@ -164,6 +165,7 @@ private: public: + void set_ip_type(IP::Type p_type); //Error connect_and_get(const String& p_url,bool p_verify_host=true); //connects to a full url and perform request Error connect(const String &p_host,int p_port,bool p_ssl=false,bool p_verify_host=true); diff --git a/core/io/ip.cpp b/core/io/ip.cpp index a77aace07f6..0b607624221 100644 --- a/core/io/ip.cpp +++ b/core/io/ip.cpp @@ -43,10 +43,12 @@ struct _IP_ResolverPrivate { volatile IP::ResolverStatus status; IP_Address response; String hostname; + IP::Type type; void clear() { status = IP::RESOLVER_STATUS_NONE; response = IP_Address(); + type = IP::TYPE_NONE; hostname=""; }; @@ -78,9 +80,9 @@ struct _IP_ResolverPrivate { if (queue[i].status!=IP::RESOLVER_STATUS_WAITING) 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==IP_Address()) queue[i].status=IP::RESOLVER_STATUS_ERROR; else queue[i].status=IP::RESOLVER_STATUS_DONE; @@ -105,25 +107,30 @@ struct _IP_ResolverPrivate { HashMap cache; + static String get_cache_key(String p_hostname, IP::Type p_type) { + return itos(p_type) + p_hostname; + } + }; -IP_Address IP::resolve_hostname(const String& p_hostname) { +IP_Address IP::resolve_hostname(const String& p_hostname, IP::Type p_type) { - GLOBAL_LOCK_FUNCTION + GLOBAL_LOCK_FUNCTION; - if (resolver->cache.has(p_hostname)) - return resolver->cache[p_hostname]; + String key = _IP_ResolverPrivate::get_cache_key(p_hostname, p_type); + if (resolver->cache.has(key)) + return resolver->cache[key]; - IP_Address res = _resolve_hostname(p_hostname); - resolver->cache[p_hostname]=res; + IP_Address res = _resolve_hostname(p_hostname, p_type); + resolver->cache[key]=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::Type p_type) { - GLOBAL_LOCK_FUNCTION + GLOBAL_LOCK_FUNCTION; ResolverID id = resolver->find_empty_id(); @@ -132,9 +139,11 @@ IP::ResolverID IP::resolve_hostname_queue_item(const String& p_hostname) { return id; } + String key = _IP_ResolverPrivate::get_cache_key(p_hostname, p_type); resolver->queue[id].hostname=p_hostname; - if (resolver->cache.has(p_hostname)) { - resolver->queue[id].response=resolver->cache[p_hostname]; + resolver->queue[id].type = p_type; + if (resolver->cache.has(key)) { + resolver->queue[id].response=resolver->cache[key]; resolver->queue[id].status=IP::RESOLVER_STATUS_DONE; } else { resolver->queue[id].response=IP_Address(); @@ -145,10 +154,6 @@ IP::ResolverID IP::resolve_hostname_queue_item(const String& p_hostname) { resolver->resolve_queues(); } - - - - return id; } @@ -187,6 +192,17 @@ 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(_IP_ResolverPrivate::get_cache_key(p_hostname, IP::TYPE_NONE)); + resolver->cache.erase(_IP_ResolverPrivate::get_cache_key(p_hostname, IP::TYPE_IPV4)); + resolver->cache.erase(_IP_ResolverPrivate::get_cache_key(p_hostname, IP::TYPE_IPV6)); + resolver->cache.erase(_IP_ResolverPrivate::get_cache_key(p_hostname, IP::TYPE_ANY)); + } +}; Array IP::_get_local_addresses() const { @@ -202,12 +218,13 @@ Array IP::_get_local_addresses() const { void IP::_bind_methods() { - ObjectTypeDB::bind_method(_MD("resolve_hostname","host"),&IP::resolve_hostname); - ObjectTypeDB::bind_method(_MD("resolve_hostname_queue_item","host"),&IP::resolve_hostname_queue_item); + ObjectTypeDB::bind_method(_MD("resolve_hostname","host","ip_type"),&IP::resolve_hostname,DEFVAL(IP::TYPE_ANY)); + ObjectTypeDB::bind_method(_MD("resolve_hostname_queue_item","host","ip_type"),&IP::resolve_hostname_queue_item,DEFVAL(IP::TYPE_ANY)); ObjectTypeDB::bind_method(_MD("get_resolve_item_status","id"),&IP::get_resolve_item_status); 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 ); @@ -217,6 +234,10 @@ void IP::_bind_methods() { BIND_CONSTANT( RESOLVER_MAX_QUERIES ); BIND_CONSTANT( RESOLVER_INVALID_ID ); + BIND_CONSTANT( TYPE_NONE ); + BIND_CONSTANT( TYPE_IPV4 ); + BIND_CONSTANT( TYPE_IPV6 ); + BIND_CONSTANT( TYPE_ANY ); } diff --git a/core/io/ip.h b/core/io/ip.h index 38c86e7ba3d..64360b9a760 100644 --- a/core/io/ip.h +++ b/core/io/ip.h @@ -48,6 +48,14 @@ public: RESOLVER_STATUS_ERROR, }; + enum Type { + + TYPE_NONE = 0, + TYPE_IPV4 = 1, + TYPE_IPV6 = 2, + TYPE_ANY = 3, + }; + enum { RESOLVER_MAX_QUERIES = 32, RESOLVER_INVALID_ID=-1 @@ -65,7 +73,7 @@ protected: static IP*singleton; static void _bind_methods(); - virtual IP_Address _resolve_hostname(const String& p_hostname)=0; + virtual IP_Address _resolve_hostname(const String& p_hostname, Type p_type = TYPE_ANY)=0; Array _get_local_addresses() const; static IP* (*_create)(); @@ -73,14 +81,16 @@ public: - IP_Address resolve_hostname(const String& p_hostname); + IP_Address resolve_hostname(const String& p_hostname, Type p_type = TYPE_ANY); // async resolver hostname - ResolverID resolve_hostname_queue_item(const String& p_hostname); + ResolverID resolve_hostname_queue_item(const String& p_hostname, Type p_type = TYPE_ANY); ResolverStatus get_resolve_item_status(ResolverID p_id) const; IP_Address get_resolve_item_address(ResolverID p_id) const; virtual void get_local_addresses(List *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(); @@ -91,4 +101,6 @@ public: }; +VARIANT_ENUM_CAST(IP::Type); + #endif // IP_H diff --git a/core/io/ip_address.cpp b/core/io/ip_address.cpp index 7a51bce7c6b..7df5fe79ece 100644 --- a/core/io/ip_address.cpp +++ b/core/io/ip_address.cpp @@ -32,29 +32,209 @@ IP_Address::operator Variant() const { return operator String(); }*/ + +#include +#include + IP_Address::operator String() const { - return itos(field[0])+"."+itos(field[1])+"."+itos(field[2])+"."+itos(field[3]); + if(is_ipv4()) + // IPv4 address mapped to IPv6 + return itos(field8[12])+"."+itos(field8[13])+"."+itos(field8[14])+"."+itos(field8[15]); + String ret; + for (int i=0; i<8; i++) { + if (i > 0) + ret = ret + ":"; + uint16_t num = (field8[i*2] << 8) + field8[i*2+1]; + ret = ret + String::num_int64(num, 16); + }; + + return ret; +} + +static void _parse_hex(const String& p_string, int p_start, uint8_t* p_dst) { + + uint16_t ret = 0; + for (int i=p_start; 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 if (c == ':') { + break; + } else { + ERR_EXPLAIN("Invalid character in ipv6 address: " + p_string); + ERR_FAIL(); + }; + ret = ret << 4; + ret += n; + }; + + p_dst[0] = ret >> 8; + p_dst[1] = ret & 0xff; +}; + +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= '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= 0) { - field[i]=p_string.get_slicec('.',i).to_int(); - } + _parse_ipv6(p_string); + } else { + // Mapped to IPv6 + field16[5] = 0xffff; + _parse_ipv4(p_string, 0, &field8[12]); + }; } -IP_Address::IP_Address(uint8_t p_a,uint8_t p_b,uint8_t p_c,uint8_t p_d) { +_FORCE_INLINE_ static void _32_to_buf(uint8_t* p_dst, uint32_t p_n) { + + p_dst[0] = (p_n >> 24) & 0xff; + p_dst[1] = (p_n >> 16) & 0xff; + p_dst[2] = (p_n >> 8) & 0xff; + p_dst[3] = (p_n >> 0) & 0xff; +}; + +IP_Address::IP_Address(uint32_t p_a,uint32_t p_b,uint32_t p_c,uint32_t p_d, bool is_v6) { + + clear(); + if (!is_v6) { + // Mapped to IPv6 + field16[5]=0xffff; + field8[12]=p_a; + field8[13]=p_b; + field8[14]=p_c; + field8[15]=p_d; + } else { + + _32_to_buf(&field8[0], p_a); + _32_to_buf(&field8[4], p_b); + _32_to_buf(&field8[8], p_c); + _32_to_buf(&field8[12], p_d); + } - field[0]=p_a; - field[1]=p_b; - field[2]=p_c; - field[3]=p_d; } diff --git a/core/io/ip_address.h b/core/io/ip_address.h index 12923117297..b7c1649547d 100644 --- a/core/io/ip_address.h +++ b/core/io/ip_address.h @@ -33,22 +33,45 @@ struct IP_Address { +private: + union { - uint8_t field[4]; - uint32_t host; + 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; 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 { - 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(); + bool is_ipv4() const; + const uint8_t *get_ipv4() const; + void set_ipv4(const uint8_t *p_ip); + + const uint8_t *get_ipv6() const; + void set_ipv6(const uint8_t *buf); + operator String() const; 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() { host=0; } + IP_Address(uint32_t p_a,uint32_t p_b,uint32_t p_c,uint32_t p_d, bool is_v6=false); + IP_Address() { clear(); } }; diff --git a/core/io/packet_peer_udp.cpp b/core/io/packet_peer_udp.cpp index efc619e4147..d04371f4fc1 100644 --- a/core/io/packet_peer_udp.cpp +++ b/core/io/packet_peer_udp.cpp @@ -29,27 +29,20 @@ #include "packet_peer_udp.h" #include "io/ip.h" - PacketPeerUDP* (*PacketPeerUDP::_create)()=NULL; -int PacketPeerUDP::_get_packet_address() const { - - IP_Address ip = get_packet_address(); - return ip.host; -} - String PacketPeerUDP::_get_packet_ip() const { return get_packet_address(); } -Error PacketPeerUDP::_set_send_address(const String& p_address,int p_port) { +Error PacketPeerUDP::_set_send_address(const String& p_address, int p_port) { IP_Address ip; if (p_address.is_valid_ip_address()) { ip=p_address; } else { - ip=IP::get_singleton()->resolve_hostname(p_address); + ip=IP::get_singleton()->resolve_hostname(p_address, ip_type); if (ip==IP_Address()) return ERR_CANT_RESOLVE; } @@ -58,14 +51,20 @@ Error PacketPeerUDP::_set_send_address(const String& p_address,int p_port) { return OK; } +void PacketPeerUDP::set_ip_type(IP::Type p_type) { + close(); + ip_type = p_type; +} + void PacketPeerUDP::_bind_methods() { - ObjectTypeDB::bind_method(_MD("listen:Error","port","recv_buf_size"),&PacketPeerUDP::listen,DEFVAL(65536)); + ObjectTypeDB::bind_method(_MD("set_ip_type","ip_type"),&PacketPeerUDP::set_ip_type); + ObjectTypeDB::bind_method(_MD("listen:Error","port", "recv_buf_size"),&PacketPeerUDP::listen,DEFVAL(65536)); ObjectTypeDB::bind_method(_MD("close"),&PacketPeerUDP::close); ObjectTypeDB::bind_method(_MD("wait:Error"),&PacketPeerUDP::wait); 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_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("set_send_address","host","port"),&PacketPeerUDP::_set_send_address); @@ -88,4 +87,5 @@ PacketPeerUDP* PacketPeerUDP::create() { PacketPeerUDP::PacketPeerUDP() { + ip_type = IP::TYPE_ANY; } diff --git a/core/io/packet_peer_udp.h b/core/io/packet_peer_udp.h index 70d92834fc2..600d4c46822 100644 --- a/core/io/packet_peer_udp.h +++ b/core/io/packet_peer_udp.h @@ -30,6 +30,7 @@ #define PACKET_PEER_UDP_H +#include "io/ip.h" #include "io/packet_peer.h" class PacketPeerUDP : public PacketPeer { @@ -37,17 +38,19 @@ class PacketPeerUDP : public PacketPeer { protected: + IP::Type ip_type; + static PacketPeerUDP* (*_create)(); static void _bind_methods(); - int _get_packet_address() const; String _get_packet_ip() const; virtual Error _set_send_address(const String& p_address,int p_port); public: - virtual Error listen(int p_port,int p_recv_buffer_size=65536)=0; + virtual void set_ip_type(IP::Type p_type); + virtual Error listen(int p_port, int p_recv_buffer_size=65536)=0; virtual void close()=0; virtual Error wait()=0; virtual bool is_listening() const=0; diff --git a/core/io/stream_peer_tcp.cpp b/core/io/stream_peer_tcp.cpp index fbb0c69cb78..6c26dbb89ea 100644 --- a/core/io/stream_peer_tcp.cpp +++ b/core/io/stream_peer_tcp.cpp @@ -30,9 +30,30 @@ StreamPeerTCP* (*StreamPeerTCP::_create)()=NULL; +Error StreamPeerTCP::_connect(const String& p_address,int p_port) { + + IP_Address ip; + if (p_address.is_valid_ip_address()) { + ip=p_address; + } else { + ip=IP::get_singleton()->resolve_hostname(p_address, ip_type); + if (ip==IP_Address()) + return ERR_CANT_RESOLVE; + } + + connect(ip,p_port); + return OK; +} + +void StreamPeerTCP::set_ip_type(IP::Type p_type) { + disconnect(); + ip_type = p_type; +} + void StreamPeerTCP::_bind_methods() { - ObjectTypeDB::bind_method(_MD("connect","host","port"),&StreamPeerTCP::connect); + ObjectTypeDB::bind_method(_MD("set_ip_type","ip_type"),&StreamPeerTCP::set_ip_type); + ObjectTypeDB::bind_method(_MD("connect","host","port"),&StreamPeerTCP::_connect); ObjectTypeDB::bind_method(_MD("is_connected"),&StreamPeerTCP::is_connected); ObjectTypeDB::bind_method(_MD("get_status"),&StreamPeerTCP::get_status); ObjectTypeDB::bind_method(_MD("get_connected_host"),&StreamPeerTCP::get_connected_host); @@ -62,6 +83,7 @@ StreamPeerTCP* StreamPeerTCP::create() { StreamPeerTCP::StreamPeerTCP() { + ip_type = IP::TYPE_ANY; } StreamPeerTCP::~StreamPeerTCP() { diff --git a/core/io/stream_peer_tcp.h b/core/io/stream_peer_tcp.h index 4c58e7e149b..2408f4cdf53 100644 --- a/core/io/stream_peer_tcp.h +++ b/core/io/stream_peer_tcp.h @@ -32,6 +32,7 @@ #include "stream_peer.h" #include "ip_address.h" +#include "io/ip.h" class StreamPeerTCP : public StreamPeer { @@ -50,11 +51,15 @@ public: protected: + IP::Type ip_type; + + virtual Error _connect(const String& p_address, int p_port); static StreamPeerTCP* (*_create)(); static void _bind_methods(); public: + virtual void set_ip_type(IP::Type p_type); virtual Error connect(const IP_Address& p_host, uint16_t p_port)=0; //read/write from streampeer diff --git a/core/io/tcp_server.cpp b/core/io/tcp_server.cpp index 274d20a48ae..5f3f74131d1 100644 --- a/core/io/tcp_server.cpp +++ b/core/io/tcp_server.cpp @@ -44,18 +44,24 @@ TCP_Server* TCP_Server::create() { return _create(); } -Error TCP_Server::_listen(uint16_t p_port,DVector p_accepted_hosts) { +Error TCP_Server::_listen(uint16_t p_port, DVector p_accepted_hosts) { List hosts; for(int i=0;i())); ObjectTypeDB::bind_method(_MD("is_connection_available"),&TCP_Server::is_connection_available); ObjectTypeDB::bind_method(_MD("take_connection"),&TCP_Server::take_connection); @@ -66,4 +72,5 @@ void TCP_Server::_bind_methods() { TCP_Server::TCP_Server() { + ip_type = IP::TYPE_ANY; } diff --git a/core/io/tcp_server.h b/core/io/tcp_server.h index 512a7e640a5..5b8b40b704e 100644 --- a/core/io/tcp_server.h +++ b/core/io/tcp_server.h @@ -38,14 +38,17 @@ class TCP_Server : public Reference { OBJ_TYPE( TCP_Server, Reference ); protected: + IP::Type ip_type; + static TCP_Server* (*_create)(); //bind helper - Error _listen(uint16_t p_port,DVector p_accepted_hosts=DVector()); + Error _listen(uint16_t p_port, DVector p_accepted_hosts=DVector()); static void _bind_methods(); public: - virtual Error listen(uint16_t p_port,const List *p_accepted_hosts=NULL)=0; + virtual void set_ip_type(IP::Type p_type); + virtual Error listen(uint16_t p_port, const List *p_accepted_hosts=NULL)=0; virtual bool is_connection_available() const=0; virtual Ref take_connection()=0; diff --git a/core/ustring.cpp b/core/ustring.cpp index 2e907381f76..f9c10615b31 100644 --- a/core/ustring.cpp +++ b/core/ustring.cpp @@ -1543,11 +1543,11 @@ String::String(const StrRange& p_range) { copy_from(p_range.c_str,p_range.len); } -int String::hex_to_int() const { +int String::hex_to_int(bool p_with_prefix) const { int l = length(); - if (l<3) - return 0; + if (p_with_prefix && l<3) + return 0; const CharType *s=ptr(); @@ -1556,15 +1556,16 @@ int String::hex_to_int() const { if (sign<0) { s++; l--; - if (l<2) + if (p_with_prefix && l<2) return 0; } - if (s[0]!='0' || s[1]!='x') - return 0; - - s+=2; - l-=2; + if (p_with_prefix) { + if (s[0]!='0' || s[1]!='x') + return 0; + s+=2; + l-=2; + }; int hex=0; @@ -3510,6 +3511,36 @@ bool String::is_valid_integer() const { } +bool String::is_valid_hex_number(bool p_with_prefix) const { + + int from = 0; + int len = length(); + + if (len!=1 && (operator[](0)=='+' || operator[](0)=='-')) + from++; + + if (p_with_prefix) { + + if (len < 2) + return false; + if (operator[](from) != '0' || operator[](from+1) != 'x') { + return false; + }; + from += 2; + }; + + for (int i=from; i= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')) + continue; + return false; + }; + + return true; +}; + + bool String::is_valid_float() const { int len = length(); @@ -3646,20 +3677,41 @@ bool String::is_valid_html_color() const { } + bool String::is_valid_ip_address() const { - Vector ip = split("."); - if (ip.size()!=4) - return false; - for(int i=0;i= 0) { - String n = ip[i]; - if (!n.is_valid_integer()) + Vector ip = split(":"); + for (int i=0; i 0xffff) + return false; + continue; + }; + if (!n.is_valid_ip_address()) + return false; + }; + + } else { + Vector ip = split("."); + if (ip.size()!=4) return false; - int val = n.to_int(); - if (val<0 || val>255) - return false; - } + for(int i=0;i255) + return false; + } + }; return true; } diff --git a/core/ustring.h b/core/ustring.h index 09d13a9e641..452f2528570 100644 --- a/core/ustring.h +++ b/core/ustring.h @@ -144,7 +144,7 @@ public: bool is_numeric() const; double to_double() const; float to_float() const; - int hex_to_int() const; + int hex_to_int(bool p_with_prefix = true) const; int to_int() const; int64_t to_int64() const; @@ -226,6 +226,7 @@ public: bool is_valid_identifier() const; bool is_valid_integer() const; bool is_valid_float() const; + bool is_valid_hex_number(bool p_with_prefix) const; bool is_valid_html_color() const; bool is_valid_ip_address() const; diff --git a/core/variant_call.cpp b/core/variant_call.cpp index f2e62b63472..c8a53537e01 100644 --- a/core/variant_call.cpp +++ b/core/variant_call.cpp @@ -1760,6 +1760,7 @@ _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_BILINEAR",Image::INTERPOLATE_BILINEAR); _VariantCall::add_constant(Variant::IMAGE,"INTERPOLATE_CUBIC",Image::INTERPOLATE_CUBIC); + } void unregister_variant_methods() { diff --git a/doc/base/classes.xml b/doc/base/classes.xml index abd7e83818b..3e36ff7f05c 100644 --- a/doc/base/classes.xml +++ b/doc/base/classes.xml @@ -15596,8 +15596,10 @@ + + - Resolve a given hostname, blocking. Resolved hostname is returned as an IP. + Resolve a given hostname, blocking. Resolved hostname is returned as an IPv4 or IPv6 depending on "ip_type". @@ -15605,8 +15607,10 @@ + + - Create a queue item for resolving a given hostname. The queue ID is returned, or RESOLVER_INVALID_ID on error. + Create a queue item for resolving a given hostname to an IPv4 or IPv6 depending on "ip_type". The queue ID is returned, or RESOLVER_INVALID_ID on error. @@ -24543,7 +24547,7 @@ - Make this [PacketPeerUDP] listen on the "port" using a buffer size "recv_buf_size". Listens on all available adresses. + Make this [PacketPeerUDP] listen on the "port" with a buffer size "recv_buf_size". Listens on all available addresses. @@ -24554,7 +24558,7 @@ - Set the destination address and port for sending packets and variables, a hostname will be resolved if valid. + Set the destination address and port for sending packets and variables, a hostname will be resolved using if valid. @@ -38120,7 +38124,7 @@ - Connect to the specified IP:port pair. Returns [OK] on success or [FAILED] on failure. + Connect to the specified host:port pair. A hostname will be resolved if valid. Returns [OK] on success or [FAILED] on failure. @@ -39634,7 +39638,7 @@ - Listen on a port, alternatively give a white-list of accepted hosts. + Listen on a port using protocol, alternatively give a white-list of accepted hosts. diff --git a/drivers/unix/ip_unix.cpp b/drivers/unix/ip_unix.cpp index 535a4253026..c17deafc602 100644 --- a/drivers/unix/ip_unix.cpp +++ b/drivers/unix/ip_unix.cpp @@ -28,10 +28,15 @@ /*************************************************************************/ #include "ip_unix.h" -#if defined(UNIX_ENABLED) || defined(WINDOWS_ENABLED) && !defined(WINRT_ENABLED) +#if defined(UNIX_ENABLED) || defined(WINDOWS_ENABLED) +#include #ifdef WINDOWS_ENABLED + // Workaround mingw missing flags! + #ifndef AI_ADDRCONFIG + #define AI_ADDRCONFIG 0x00000400 + #endif #ifdef WINRT_ENABLED #include #include @@ -62,16 +67,50 @@ #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; + if (p_addr->sa_family == AF_INET) { + struct sockaddr_in* addr = (struct sockaddr_in*)p_addr; + ip.set_ipv4((uint8_t *)&(addr->sin_addr)); + } else { + struct sockaddr_in6* addr6 = (struct sockaddr_in6*)p_addr; + ip.set_ipv6(addr6->sin6_addr.s6_addr); + }; - ip.host= *((unsigned long*)he->h_addr); + return ip; +}; + +IP_Address IP_Unix::_resolve_hostname(const String& p_hostname, Type p_type) { + + struct addrinfo hints; + struct addrinfo* result; + + memset(&hints, 0, sizeof(struct addrinfo)); + if (p_type == TYPE_IPV4) { + hints.ai_family = AF_INET; + } else if (p_type == TYPE_IPV6) { + hints.ai_family = AF_INET6; + hints.ai_flags = 0; + } else { + hints.ai_family = AF_UNSPEC; + hints.ai_flags = AI_ADDRCONFIG; + }; + + 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; @@ -83,6 +122,18 @@ IP_Address IP_Unix::_resolve_hostname(const String& p_hostname) { void IP_Unix::get_local_addresses(List *r_addresses) const { + using namespace Windows::Networking; + using namespace Windows::Networking::Connectivity; + + auto hostnames = NetworkInformation::GetHostNames(); + + for (int i = 0; i < hostnames->Size; i++) { + + 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()))); + } + } }; #else @@ -95,7 +146,7 @@ void IP_Unix::get_local_addresses(List *r_addresses) const { while (true) { 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_DNS_SERVER | GAA_FLAG_SKIP_FRIENDLY_NAME, @@ -121,14 +172,20 @@ void IP_Unix::get_local_addresses(List *r_addresses) const { IP_ADAPTER_UNICAST_ADDRESS* address = adapter->FirstUnicastAddress; while (address != NULL) { - char addr_chr[INET_ADDRSTRLEN]; - SOCKADDR_IN* ipv4 = reinterpret_cast(address->Address.lpSockaddr); - IP_Address ip; - ip.host= *((unsigned long*)&ipv4->sin_addr); + if (address->Address.lpSockaddr->sa_family == AF_INET) { + + SOCKADDR_IN* ipv4 = reinterpret_cast(address->Address.lpSockaddr); + + ip.set_ipv4((uint8_t *)&(ipv4->sin_addr)); + } else { // ipv6 + + SOCKADDR_IN6* ipv6 = reinterpret_cast(address->Address.lpSockaddr); + + ip.set_ipv6(ipv6->sin6_addr.s6_addr); + }; - //inet_ntop(AF_INET, &ipv4->sin_addr, addr_chr, INET_ADDRSTRLEN); r_addresses->push_back(ip); @@ -154,20 +211,9 @@ void IP_Unix::get_local_addresses(List *r_addresses) const { for (ifa = ifAddrStruct; ifa != NULL; ifa = ifa->ifa_next) { if (!ifa->ifa_addr) 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); - - 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); - } */ + IP_Address ip = _sockaddr2ip(ifa->ifa_addr); + r_addresses->push_back(ip); } if (ifAddrStruct!=NULL) freeifaddrs(ifAddrStruct); diff --git a/drivers/unix/ip_unix.h b/drivers/unix/ip_unix.h index c0034c9a3a4..9959d45a1a9 100644 --- a/drivers/unix/ip_unix.h +++ b/drivers/unix/ip_unix.h @@ -36,7 +36,7 @@ class IP_Unix : public 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::Type p_type); static IP* _create_unix(); public: diff --git a/drivers/unix/packet_peer_udp_posix.cpp b/drivers/unix/packet_peer_udp_posix.cpp index 0201a856518..62290c41721 100644 --- a/drivers/unix/packet_peer_udp_posix.cpp +++ b/drivers/unix/packet_peer_udp_posix.cpp @@ -54,6 +54,7 @@ #include #endif +#include "drivers/unix/socket_helpers.h" int PacketPeerUDPPosix::get_available_packet_count() const { @@ -73,7 +74,17 @@ Error PacketPeerUDPPosix::get_packet(const uint8_t **r_buffer,int &r_buffer_size 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::TYPE_IPV4) { + uint8_t ip[4]; + rb.read(ip,4,true); + packet_ip.set_ipv4(ip); + } else { + uint8_t ipv6[16]; + rb.read(ipv6,16,true); + packet_ip.set_ipv6(ipv6); + }; rb.read((uint8_t*)&packet_port,4,true); rb.read((uint8_t*)&size,4,true); rb.read(packet_buffer,size,true); @@ -85,17 +96,17 @@ 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){ + ERR_FAIL_COND_V(peer_addr == IP_Address(), ERR_UNCONFIGURED); + int sock = _get_socket(); 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; + size_t addr_size = _set_sockaddr(&addr, peer_addr, peer_port, ip_type); errno = 0; int err; - while ( (err = sendto(sock, p_buffer, p_buffer_size, 0, (struct sockaddr*)&addr, sizeof(addr))) != p_buffer_size) { + while ( (err = sendto(sock, p_buffer, p_buffer_size, 0, (struct sockaddr*)&addr, addr_size)) != p_buffer_size) { if (errno != EAGAIN) { return FAILED; @@ -110,17 +121,18 @@ int PacketPeerUDPPosix::get_max_packet_size() const{ return 512; // uhm maybe not } -Error PacketPeerUDPPosix::listen(int p_port, int p_recv_buffer_size){ +Error PacketPeerUDPPosix::listen(int p_port, int p_recv_buffer_size) { close(); int sock = _get_socket(); + 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; - if (bind(sock, (struct sockaddr*)&addr, sizeof(sockaddr_in)) == -1 ) { + + sockaddr_storage addr = {0}; + size_t addr_size = _set_listen_sockaddr(&addr, p_port, ip_type, NULL); + + if (bind(sock, (struct sockaddr*)&addr, addr_size) == -1 ) { close(); return ERR_UNAVAILABLE; } @@ -145,16 +157,41 @@ Error PacketPeerUDPPosix::wait() { Error PacketPeerUDPPosix::_poll(bool p_wait) { - struct sockaddr_in from = {0}; - socklen_t len = sizeof(struct sockaddr_in); + struct sockaddr_storage from = {0}; + socklen_t len = sizeof(struct sockaddr_storage); 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) { - 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::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 = ntohs(sin_from->sin_port); + + } else if (from.ss_family == AF_INET6) { + + uint8_t type = (uint8_t)IP::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 = ntohs(s6_from->sin6_port); + + } else { + // WARN_PRINT("Ignoring packet with unknown address family"); + uint8_t type = (uint8_t)IP::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; }; @@ -187,9 +224,7 @@ int PacketPeerUDPPosix::_get_socket() { if (sockfd != -1) return sockfd; - sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); - ERR_FAIL_COND_V( sockfd == -1, -1 ); - //fcntl(sockfd, F_SETFL, O_NONBLOCK); + sockfd = _socket_create(ip_type, SOCK_DGRAM, IPPROTO_UDP); return sockfd; } @@ -218,6 +253,7 @@ PacketPeerUDPPosix::PacketPeerUDPPosix() { packet_port=0; queue_count=0; peer_port=0; + ip_type = IP::TYPE_ANY; } PacketPeerUDPPosix::~PacketPeerUDPPosix() { diff --git a/drivers/unix/packet_peer_udp_posix.h b/drivers/unix/packet_peer_udp_posix.h index a11282e5d66..e679d18df4f 100644 --- a/drivers/unix/packet_peer_udp_posix.h +++ b/drivers/unix/packet_peer_udp_posix.h @@ -44,8 +44,8 @@ class PacketPeerUDPPosix : public PacketPeerUDP { mutable RingBuffer 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; @@ -65,7 +65,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, int p_recv_buffer_size=65536); virtual void close(); virtual Error wait(); virtual bool is_listening() const; diff --git a/drivers/unix/socket_helpers.h b/drivers/unix/socket_helpers.h new file mode 100644 index 00000000000..373feb4b82d --- /dev/null +++ b/drivers/unix/socket_helpers.h @@ -0,0 +1,106 @@ +#ifndef SOCKET_HELPERS_H +#define SOCKET_HELPERS_H + +#include + +#ifdef WINDOWS_ENABLED + // Workaround mingw missing flags! + #ifndef IPV6_V6ONLY + #define IPV6_V6ONLY 27 + #endif +#endif + +// helpers for sockaddr -> IP_Address and back, should work for posix and winsock. All implementations should use this + +static size_t _set_sockaddr(struct sockaddr_storage* p_addr, const IP_Address& p_ip, int p_port, IP::Type p_sock_type = IP::TYPE_ANY) { + + memset(p_addr, 0, sizeof(struct sockaddr_storage)); + + ERR_FAIL_COND_V(p_ip==IP_Address(),0); + + // IPv6 socket + if (p_sock_type == IP::TYPE_IPV6 || p_sock_type == IP::TYPE_ANY) { + + // IPv6 only socket with IPv4 address + ERR_FAIL_COND_V(p_sock_type == IP::TYPE_IPV6 && p_ip.is_ipv4(),0); + + 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.get_ipv6(), 16); + return sizeof(sockaddr_in6); + + } else { // IPv4 socket + + // IPv4 socket with IPv6 address + ERR_FAIL_COND_V(!p_ip.is_ipv4(),0); + + uint32_t ipv4 = *((uint32_t *)p_ip.get_ipv4()); + struct sockaddr_in* addr4 = (struct sockaddr_in*)p_addr; + addr4->sin_family = AF_INET; + addr4->sin_port = htons(p_port); // short, network byte order + copymem(&addr4->sin_addr.s_addr, p_ip.get_ipv4(), 16); + return sizeof(sockaddr_in); + }; +}; + +static size_t _set_listen_sockaddr(struct sockaddr_storage* p_addr, int p_port, IP::Type p_sock_type, const List *p_accepted_hosts) { + + memset(p_addr, 0, sizeof(struct sockaddr_storage)); + if (p_sock_type == IP::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 + return sizeof(sockaddr_in); + } 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 + return sizeof(sockaddr_in6); + }; +}; + +static int _socket_create(IP::Type p_type, int type, int protocol) { + + ERR_FAIL_COND_V(p_type > IP::TYPE_ANY || p_type < IP::TYPE_NONE, ERR_INVALID_PARAMETER); + + int family = p_type == IP::TYPE_IPV4 ? AF_INET : AF_INET6; + int sockfd = socket(family, type, protocol); + + ERR_FAIL_COND_V( sockfd == -1, -1 ); + + if(family == AF_INET6) { + // Select IPv4 over IPv6 mapping + int opt = p_type != IP::TYPE_ANY; + if(setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY, (const char*)&opt, sizeof(opt)) != 0) { + WARN_PRINT("Unable to set/unset IPv4 address mapping over IPv6"); + } + } + + return sockfd; +} + + +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) { + + struct sockaddr_in* addr4 = (struct sockaddr_in*)p_addr; + r_ip.set_ipv4((uint8_t *)&(addr4->sin_addr.s_addr)); + + r_port = ntohs(addr4->sin_port); + + } else if (p_addr->ss_family == AF_INET6) { + + struct sockaddr_in6* addr6 = (struct sockaddr_in6*)p_addr; + r_ip.set_ipv6(addr6->sin6_addr.s6_addr); + + r_port = ntohs(addr6->sin6_port); + }; +}; + + +#endif diff --git a/drivers/unix/stream_peer_tcp_posix.cpp b/drivers/unix/stream_peer_tcp_posix.cpp index 45a4b934c16..8889f997fdc 100644 --- a/drivers/unix/stream_peer_tcp_posix.cpp +++ b/drivers/unix/stream_peer_tcp_posix.cpp @@ -61,13 +61,7 @@ #define MSG_NOSIGNAL SO_NOSIGPIPE #endif -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); -}; +#include "drivers/unix/socket_helpers.h" StreamPeerTCP* StreamPeerTCPPosix::_create() { @@ -103,16 +97,22 @@ Error StreamPeerTCPPosix::_poll_connection(bool p_block) const { _block(sockfd, false, true); }; - struct sockaddr_in their_addr; - set_addr_in(their_addr, peer_host, peer_port); - if (::connect(sockfd, (struct sockaddr *)&their_addr,sizeof(struct sockaddr)) == -1) { + struct sockaddr_storage their_addr; + size_t addr_size = _set_sockaddr(&their_addr, peer_host, peer_port, ip_type); + + if (::connect(sockfd, (struct sockaddr *)&their_addr,addr_size) == -1) { if (errno == EISCONN) { status = STATUS_CONNECTED; return OK; }; - return OK; + if (errno == EINPROGRESS || errno == EALREADY) { + return OK; + } + + status = STATUS_ERROR; + return ERR_CONNECTION_ERROR; } else { status = STATUS_CONNECTED; @@ -122,8 +122,9 @@ Error StreamPeerTCPPosix::_poll_connection(bool p_block) const { return OK; }; -void StreamPeerTCPPosix::set_socket(int p_sockfd, IP_Address p_host, int p_port) { +void StreamPeerTCPPosix::set_socket(int p_sockfd, IP_Address p_host, int p_port, IP::Type p_ip_type) { + ip_type = p_ip_type; sockfd = p_sockfd; #ifndef NO_FCNTL fcntl(sockfd, F_SETFL, O_NONBLOCK); @@ -140,9 +141,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) { - ERR_FAIL_COND_V( p_host.host == 0, ERR_INVALID_PARAMETER); + ERR_FAIL_COND_V( p_host == IP_Address(), ERR_INVALID_PARAMETER); - if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { + sockfd = _socket_create(ip_type, SOCK_STREAM, IPPROTO_TCP); + if (sockfd == -1) { ERR_PRINT("Socket creation failed!"); disconnect(); //perror("socket"); @@ -156,11 +158,11 @@ Error StreamPeerTCPPosix::connect(const IP_Address& p_host, uint16_t p_port) { ioctl(sockfd, FIONBIO, &bval); #endif - struct sockaddr_in their_addr; - set_addr_in(their_addr, p_host, p_port); + struct sockaddr_storage their_addr; + size_t addr_size = _set_sockaddr(&their_addr, p_host, p_port, ip_type); errno = 0; - if (::connect(sockfd, (struct sockaddr *)&their_addr,sizeof(struct sockaddr)) == -1 && errno != EINPROGRESS) { + if (::connect(sockfd, (struct sockaddr *)&their_addr,addr_size) == -1 && errno != EINPROGRESS) { ERR_PRINT("Connection to remote host failed!"); disconnect(); @@ -391,6 +393,7 @@ StreamPeerTCPPosix::StreamPeerTCPPosix() { sockfd = -1; status = STATUS_NONE; peer_port = 0; + ip_type = IP::TYPE_ANY; }; StreamPeerTCPPosix::~StreamPeerTCPPosix() { diff --git a/drivers/unix/stream_peer_tcp_posix.h b/drivers/unix/stream_peer_tcp_posix.h index a379efe3ca9..e4e912117fe 100644 --- a/drivers/unix/stream_peer_tcp_posix.h +++ b/drivers/unix/stream_peer_tcp_posix.h @@ -69,7 +69,7 @@ public: virtual int get_available_bytes() const; - void set_socket(int p_sockfd, IP_Address p_host, int p_port); + void set_socket(int p_sockfd, IP_Address p_host, int p_port, IP::Type p_ip_type); virtual IP_Address get_connected_host() const; virtual uint16_t get_connected_port() const; diff --git a/drivers/unix/tcp_server_posix.cpp b/drivers/unix/tcp_server_posix.cpp index c67bb513346..dd00e0bf7e8 100644 --- a/drivers/unix/tcp_server_posix.cpp +++ b/drivers/unix/tcp_server_posix.cpp @@ -55,6 +55,9 @@ #include #include #include + +#include "drivers/unix/socket_helpers.h" + TCP_Server* TCPServerPosix::_create() { return memnew(TCPServerPosix); @@ -68,8 +71,10 @@ void TCPServerPosix::make_default() { Error TCPServerPosix::listen(uint16_t p_port,const List *p_accepted_hosts) { int sockfd; - sockfd = socket(AF_INET, SOCK_STREAM, 0); + sockfd = _socket_create(ip_type, SOCK_STREAM, IPPROTO_TCP); + ERR_FAIL_COND_V(sockfd == -1, FAILED); + #ifndef NO_FCNTL fcntl(sockfd, F_SETFL, O_NONBLOCK); #else @@ -82,13 +87,12 @@ Error TCPServerPosix::listen(uint16_t p_port,const List *p_accepted_host WARN_PRINT("REUSEADDR 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 addr; + size_t addr_size = _set_listen_sockaddr(&addr, p_port, ip_type, p_accepted_hosts); - if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof my_addr) != -1) { + // automatically fill with my IP TODO: use p_accepted_hosts + + if (bind(sockfd, (struct sockaddr *)&addr, addr_size) != -1) { if (::listen(sockfd, 1) == -1) { @@ -136,9 +140,9 @@ Ref TCPServerPosix::take_connection() { return Ref(); }; - struct sockaddr_in their_addr; - socklen_t sin_size = sizeof(their_addr); - int fd = accept(listen_sockfd, (struct sockaddr *)&their_addr, &sin_size); + struct sockaddr_storage their_addr; + socklen_t size = sizeof(their_addr); + int fd = accept(listen_sockfd, (struct sockaddr *)&their_addr, &size); ERR_FAIL_COND_V(fd == -1, Ref()); #ifndef NO_FCNTL fcntl(fd, F_SETFL, O_NONBLOCK); @@ -149,8 +153,11 @@ Ref TCPServerPosix::take_connection() { Ref conn = memnew(StreamPeerTCPPosix); IP_Address ip; - ip.host = (uint32_t)their_addr.sin_addr.s_addr; - conn->set_socket(fd, ip, ntohs(their_addr.sin_port)); + + int port; + _set_ip_addr_port(ip, port, &their_addr); + + conn->set_socket(fd, ip, port, ip_type); return conn; }; @@ -169,6 +176,7 @@ void TCPServerPosix::stop() { TCPServerPosix::TCPServerPosix() { listen_sockfd = -1; + ip_type = IP::TYPE_ANY; }; TCPServerPosix::~TCPServerPosix() { diff --git a/platform/windows/detect.py b/platform/windows/detect.py index ae620c67870..77653b22ad4 100644 --- a/platform/windows/detect.py +++ b/platform/windows/detect.py @@ -239,7 +239,7 @@ def configure(env): env.Append(CCFLAGS=['/DGLES2_ENABLED']) - LIBS = ['winmm', 'opengl32', 'dsound', 'kernel32', 'ole32', 'oleaut32', 'user32', 'gdi32', 'IPHLPAPI', 'Shlwapi', 'wsock32', 'shell32', 'advapi32', 'dinput8', 'dxguid'] + LIBS = ['winmm', 'opengl32', 'dsound', 'kernel32', 'ole32', 'oleaut32', 'user32', 'gdi32', 'IPHLPAPI', 'Shlwapi', 'wsock32', 'ws2_32', 'shell32', 'advapi32', 'dinput8', 'dxguid'] env.Append(LINKFLAGS=[p + env["LIBSUFFIX"] for p in LIBS]) env.Append(LIBPATH=[os.getenv("WindowsSdkDir") + "/Lib"]) @@ -358,7 +358,7 @@ def configure(env): env.Append(CCFLAGS=['-DWINDOWS_ENABLED', '-mwindows']) env.Append(CPPFLAGS=['-DRTAUDIO_ENABLED']) env.Append(CCFLAGS=['-DGLES2_ENABLED']) - env.Append(LIBS=['mingw32', 'opengl32', 'dsound', 'ole32', 'd3d9', 'winmm', 'gdi32', 'iphlpapi', 'shlwapi', 'wsock32', 'kernel32', 'oleaut32', 'dinput8', 'dxguid']) + env.Append(LIBS=['mingw32', 'opengl32', 'dsound', 'ole32', 'd3d9', 'winmm', 'gdi32', 'iphlpapi', 'shlwapi', 'wsock32', 'ws2_32', 'kernel32', 'oleaut32', 'dinput8', 'dxguid']) # if (env["bits"]=="32"): # env.Append(LIBS=['gcc_s']) diff --git a/platform/windows/packet_peer_udp_winsock.cpp b/platform/windows/packet_peer_udp_winsock.cpp index 2c79365c08d..bad967eedd9 100644 --- a/platform/windows/packet_peer_udp_winsock.cpp +++ b/platform/windows/packet_peer_udp_winsock.cpp @@ -29,6 +29,9 @@ #include "packet_peer_udp_winsock.h" #include +#include + +#include "drivers/unix/socket_helpers.h" int PacketPeerUDPWinsock::get_available_packet_count() const { @@ -48,7 +51,17 @@ 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::TYPE_IPV4) { + uint8_t ip[4]; + rb.read(ip,4,true); + packet_ip.set_ipv4(ip); + } else { + uint8_t ip[16]; + rb.read(ip,16,true); + packet_ip.set_ipv6(ip); + }; rb.read((uint8_t*)&packet_port,4,true); rb.read((uint8_t*)&size,4,true); rb.read(packet_buffer,size,true); @@ -62,17 +75,14 @@ Error PacketPeerUDPWinsock::put_packet(const uint8_t *p_buffer,int p_buffer_size int sock = _get_socket(); 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; + size_t addr_size = _set_sockaddr(&addr, peer_addr, peer_port, ip_type); _set_blocking(true); errno = 0; int err; - while ( (err = sendto(sock, (const char*)p_buffer, p_buffer_size, 0, (struct sockaddr*)&addr, sizeof(addr))) != p_buffer_size) { + while ( (err = sendto(sock, (const char*)p_buffer, p_buffer_size, 0, (struct sockaddr*)&addr, addr_size)) != p_buffer_size) { if (WSAGetLastError() != WSAEWOULDBLOCK) { return FAILED; @@ -104,17 +114,17 @@ void PacketPeerUDPWinsock::_set_blocking(bool p_blocking) { }; } -Error PacketPeerUDPWinsock::listen(int p_port, int p_recv_buffer_size){ +Error PacketPeerUDPWinsock::listen(int p_port, int p_recv_buffer_size) { close(); int sock = _get_socket(); 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; - if (bind(sock, (struct sockaddr*)&addr, sizeof(sockaddr_in)) == -1 ) { + + struct sockaddr_storage addr = {0}; + size_t addr_size = _set_listen_sockaddr(&addr, p_port, ip_type, NULL); + + if (bind(sock, (struct sockaddr*)&addr, addr_size) == -1 ) { close(); return ERR_UNAVAILABLE; } @@ -146,17 +156,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::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 = ntohs(sin_from->sin_port); + + } else if (from.ss_family == AF_INET6) { + + uint8_t type = (uint8_t)IP::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 = ntohs(s6_from->sin6_port); + + } else { + // WARN_PRINT("Ignoring packet with unknown address family"); + uint8_t type = (uint8_t)IP::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; }; @@ -207,9 +241,7 @@ int PacketPeerUDPWinsock::_get_socket() { if (sockfd != -1) return sockfd; - sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); - ERR_FAIL_COND_V( sockfd == -1, -1 ); - //fcntl(sockfd, F_SETFL, O_NONBLOCK); + sockfd = _socket_create(ip_type, SOCK_DGRAM, IPPROTO_UDP); return sockfd; } @@ -239,6 +271,7 @@ PacketPeerUDPWinsock::PacketPeerUDPWinsock() { packet_port=0; queue_count=0; peer_port=0; + ip_type = IP::TYPE_ANY; } PacketPeerUDPWinsock::~PacketPeerUDPWinsock() { diff --git a/platform/windows/packet_peer_udp_winsock.h b/platform/windows/packet_peer_udp_winsock.h index b24dbac592c..1ffdc816858 100644 --- a/platform/windows/packet_peer_udp_winsock.h +++ b/platform/windows/packet_peer_udp_winsock.h @@ -42,8 +42,8 @@ class PacketPeerUDPWinsock : public PacketPeerUDP { mutable RingBuffer 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; @@ -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, int p_recv_buffer_size=65536); virtual void close(); virtual Error wait(); virtual bool is_listening() const; diff --git a/platform/windows/stream_peer_winsock.cpp b/platform/windows/stream_peer_winsock.cpp index fcf0cb16403..e9a017a0fad 100644 --- a/platform/windows/stream_peer_winsock.cpp +++ b/platform/windows/stream_peer_winsock.cpp @@ -31,17 +31,12 @@ #include "stream_peer_winsock.h" #include +#include + +#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,10 +87,10 @@ 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; + size_t addr_size = _set_sockaddr(&their_addr, peer_host, peer_port, ip_type); - if (::connect(sockfd, (struct sockaddr *)&their_addr,sizeof(struct sockaddr)) == SOCKET_ERROR) { + if (::connect(sockfd, (struct sockaddr *)&their_addr,addr_size) == SOCKET_ERROR) { int err = WSAGetLastError(); if (err == WSAEISCONN) { @@ -103,7 +98,12 @@ Error StreamPeerWinsock::_poll_connection(bool p_block) const { return OK; }; - return OK; + if (errno == WSAEINPROGRESS || errno == WSAEALREADY) { + return OK; + } + + status = STATUS_ERROR; + return ERR_CONNECTION_ERROR; } else { status = STATUS_CONNECTED; @@ -289,8 +289,9 @@ void StreamPeerWinsock::disconnect() { peer_port = 0; }; -void StreamPeerWinsock::set_socket(int p_sockfd, IP_Address p_host, int p_port) { +void StreamPeerWinsock::set_socket(int p_sockfd, IP_Address p_host, int p_port, IP::Type p_ip_type) { + ip_type = p_ip_type; sockfd = p_sockfd; status = STATUS_CONNECTING; peer_host = p_host; @@ -299,9 +300,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 == IP_Address(), ERR_INVALID_PARAMETER); - if ((sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET) { + sockfd = _socket_create(ip_type, SOCK_STREAM, IPPROTO_TCP); + if (sockfd == INVALID_SOCKET) { ERR_PRINT("Socket creation failed!"); disconnect(); //perror("socket"); @@ -315,10 +317,10 @@ 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; + size_t addr_size = _set_sockaddr(&their_addr, p_host, p_port, ip_type); - if (::connect(sockfd, (struct sockaddr *)&their_addr,sizeof(struct sockaddr)) == SOCKET_ERROR) { + if (::connect(sockfd, (struct sockaddr *)&their_addr,addr_size) == SOCKET_ERROR) { if (WSAGetLastError() != WSAEWOULDBLOCK) { ERR_PRINT("Connection to remote host failed!"); @@ -366,6 +368,7 @@ StreamPeerWinsock::StreamPeerWinsock() { sockfd = INVALID_SOCKET; status = STATUS_NONE; peer_port = 0; + ip_type = IP::TYPE_ANY; }; StreamPeerWinsock::~StreamPeerWinsock() { diff --git a/platform/windows/stream_peer_winsock.h b/platform/windows/stream_peer_winsock.h index bbff661490e..c2b63e1ffb3 100644 --- a/platform/windows/stream_peer_winsock.h +++ b/platform/windows/stream_peer_winsock.h @@ -68,7 +68,7 @@ public: virtual int get_available_bytes() const; - void set_socket(int p_sockfd, IP_Address p_host, int p_port); + void set_socket(int p_sockfd, IP_Address p_host, int p_port, IP::Type p_ip_type); virtual IP_Address get_connected_host() const; virtual uint16_t get_connected_port() const; diff --git a/platform/windows/tcp_server_winsock.cpp b/platform/windows/tcp_server_winsock.cpp index dd1cf43f3b4..ac37f80e7a2 100644 --- a/platform/windows/tcp_server_winsock.cpp +++ b/platform/windows/tcp_server_winsock.cpp @@ -31,6 +31,9 @@ #include "stream_peer_winsock.h" #include +#include + +#include "drivers/unix/socket_helpers.h" extern int winsock_refcount; @@ -63,7 +66,7 @@ void TCPServerWinsock::cleanup() { Error TCPServerWinsock::listen(uint16_t p_port,const List *p_accepted_hosts) { int sockfd; - sockfd = socket(AF_INET, SOCK_STREAM, 0); + sockfd = _socket_create(ip_type, SOCK_STREAM, IPPROTO_TCP); ERR_FAIL_COND_V(sockfd == INVALID_SOCKET, FAILED); unsigned long par = 1; @@ -73,11 +76,8 @@ Error TCPServerWinsock::listen(uint16_t p_port,const List *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; + size_t addr_size = _set_listen_sockaddr(&my_addr, p_port, ip_type, p_accepted_hosts); int reuse=1; if(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse)) < 0) { @@ -86,7 +86,7 @@ Error TCPServerWinsock::listen(uint16_t p_port,const List *p_accepted_ho } - if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof my_addr) != SOCKET_ERROR) { + if (bind(sockfd, (struct sockaddr *)&my_addr, addr_size) != SOCKET_ERROR) { if (::listen(sockfd, SOMAXCONN) == SOCKET_ERROR) { @@ -140,16 +140,17 @@ Ref 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 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, ip_type); return conn; }; @@ -167,6 +168,7 @@ void TCPServerWinsock::stop() { TCPServerWinsock::TCPServerWinsock() { listen_sockfd = INVALID_SOCKET; + ip_type = IP::TYPE_ANY; }; TCPServerWinsock::~TCPServerWinsock() { diff --git a/scene/main/http_request.cpp b/scene/main/http_request.cpp index 4b6cbde859f..46ab3859546 100644 --- a/scene/main/http_request.cpp +++ b/scene/main/http_request.cpp @@ -28,6 +28,10 @@ /*************************************************************************/ #include "http_request.h" +void HTTPRequest::set_ip_type(IP::Type p_type) { + client->set_ip_type(p_type); +} + void HTTPRequest::_redirect_request(const String& p_new_url) { @@ -535,6 +539,7 @@ int HTTPRequest::get_body_size() const{ void HTTPRequest::_bind_methods() { + ObjectTypeDB::bind_method(_MD("set_ip_type","ip_type"),&HTTPRequest::set_ip_type); ObjectTypeDB::bind_method(_MD("request","url","custom_headers","ssl_validate_domain","method","request_data"),&HTTPRequest::request,DEFVAL(StringArray()),DEFVAL(true),DEFVAL(HTTPClient::METHOD_GET),DEFVAL(String())); ObjectTypeDB::bind_method(_MD("cancel_request"),&HTTPRequest::cancel_request); diff --git a/scene/main/http_request.h b/scene/main/http_request.h index 705799f0447..978ad3428b3 100644 --- a/scene/main/http_request.h +++ b/scene/main/http_request.h @@ -116,6 +116,7 @@ protected: static void _bind_methods(); public: + void set_ip_type(IP::Type p_type); Error request(const String& p_url, const Vector& p_custom_headers=Vector(), bool p_ssl_validate_domain=true, HTTPClient::Method p_method=HTTPClient::METHOD_GET, const String& p_request_data=""); //connects to a full url and perform request void cancel_request(); HTTPClient::Status get_http_client_status() const;