diff --git a/core/io/ip.cpp b/core/io/ip.cpp index a77aace07f65..aba55687a5b2 100644 --- a/core/io/ip.cpp +++ b/core/io/ip.cpp @@ -32,6 +32,7 @@ #include "hash_map.h" VARIANT_ENUM_CAST(IP::ResolverStatus); +VARIANT_ENUM_CAST(IP_Address::AddrType); /************* RESOLVER ******************/ @@ -43,10 +44,12 @@ struct _IP_ResolverPrivate { volatile IP::ResolverStatus status; IP_Address response; String hostname; + IP_Address::AddrType type; void clear() { status = IP::RESOLVER_STATUS_NONE; response = IP_Address(); + type = IP_Address::TYPE_NONE; hostname=""; }; @@ -78,9 +81,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.type==IP_Address::TYPE_NONE) queue[i].status=IP::RESOLVER_STATUS_ERROR; else 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)) 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; 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(); @@ -133,6 +136,7 @@ IP::ResolverID IP::resolve_hostname_queue_item(const String& p_hostname) { } resolver->queue[id].hostname=p_hostname; + resolver->queue[id].type = p_type; if (resolver->cache.has(p_hostname)) { resolver->queue[id].response=resolver->cache[p_hostname]; 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(); } - - - - return id; } diff --git a/core/io/ip.h b/core/io/ip.h index 38c86e7ba3df..9ffe01b1af97 100644 --- a/core/io/ip.h +++ b/core/io/ip.h @@ -48,6 +48,14 @@ public: RESOLVER_STATUS_ERROR, }; + enum AddressType { + + ADDRESS_IPV4 = 1, + ADDRESS_IPV6 = 2, + + ADDRESS_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, IP_Address::AddrType p_type = IP_Address::TYPE_ANY)=0; Array _get_local_addresses() const; 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 - 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; IP_Address get_resolve_item_address(ResolverID p_id) const; virtual void get_local_addresses(List *r_addresses) const=0; diff --git a/core/io/ip_address.cpp b/core/io/ip_address.cpp index 7a51bce7c6b7..2a8ab0ae00df 100644 --- a/core/io/ip_address.cpp +++ b/core/io/ip_address.cpp @@ -32,29 +32,179 @@ IP_Address::operator Variant() const { return operator String(); }*/ + +#include + 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; - int slices = p_string.get_slice_count("."); + uint16_t ret = 0; + 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= '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) { + + _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; } diff --git a/core/io/ip_address.h b/core/io/ip_address.h index 12923117297f..fe13d70611e5 100644 --- a/core/io/ip_address.h +++ b/core/io/ip_address.h @@ -33,22 +33,48 @@ struct IP_Address { - union { - uint8_t field[4]; - uint32_t host; +public: + enum AddrType { + 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; 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(); + 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, AddrType p_type=TYPE_IPV4); + IP_Address() { clear(); type=TYPE_NONE; } }; diff --git a/core/io/packet_peer_udp.cpp b/core/io/packet_peer_udp.cpp index efc619e41475..018dc77d9166 100644 --- a/core/io/packet_peer_udp.cpp +++ b/core/io/packet_peer_udp.cpp @@ -29,14 +29,9 @@ #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; -} +VARIANT_ENUM_CAST(IP_Address::AddrType); 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("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); diff --git a/core/io/packet_peer_udp.h b/core/io/packet_peer_udp.h index 70d92834fc2e..c0806a9e6a72 100644 --- a/core/io/packet_peer_udp.h +++ b/core/io/packet_peer_udp.h @@ -40,14 +40,13 @@ protected: 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 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 Error wait()=0; virtual bool is_listening() const=0; diff --git a/core/io/tcp_server.cpp b/core/io/tcp_server.cpp index 274d20a48aef..53d6e900f384 100644 --- a/core/io/tcp_server.cpp +++ b/core/io/tcp_server.cpp @@ -30,6 +30,8 @@ TCP_Server* (*TCP_Server::_create)()=NULL; +VARIANT_ENUM_CAST(IP_Address::AddrType); + Ref TCP_Server::create_ref() { if (!_create) @@ -44,19 +46,19 @@ 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, IP_Address::AddrType p_type, DVector p_accepted_hosts) { List hosts; for(int i=0;i())); + ObjectTypeDB::bind_method(_MD("listen","port","accepted_hosts"),&TCP_Server::_listen,DEFVAL(IP_Address::TYPE_IPV4), DEFVAL(DVector())); 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("stop"),&TCP_Server::stop); diff --git a/core/io/tcp_server.h b/core/io/tcp_server.h index 512a7e640a58..883a3ef2f63b 100644 --- a/core/io/tcp_server.h +++ b/core/io/tcp_server.h @@ -41,11 +41,11 @@ protected: static TCP_Server* (*_create)(); //bind helper - Error _listen(uint16_t p_port,DVector p_accepted_hosts=DVector()); + Error _listen(uint16_t p_port, IP_Address::AddrType p_type = IP_Address::TYPE_IPV4 ,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 Error listen(uint16_t p_port, IP_Address::AddrType p_type = IP_Address::TYPE_IPV4, const List *p_accepted_hosts=NULL)=0; virtual bool is_connection_available() const=0; virtual Ref take_connection()=0; diff --git a/core/variant_call.cpp b/core/variant_call.cpp index 51cd4c23995f..9b6fa27cf47b 100644 --- a/core/variant_call.cpp +++ b/core/variant_call.cpp @@ -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_BILINEAR",Image::INTERPOLATE_BILINEAR); _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() { diff --git a/drivers/unix/ip_unix.cpp b/drivers/unix/ip_unix.cpp index 08a8c195836d..6294f57b03e0 100644 --- a/drivers/unix/ip_unix.cpp +++ b/drivers/unix/ip_unix.cpp @@ -30,6 +30,7 @@ #if defined(UNIX_ENABLED) || defined(WINDOWS_ENABLED) +#include #ifdef WINDOWS_ENABLED #ifdef WINRT_ENABLED @@ -62,16 +63,51 @@ #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.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; @@ -90,10 +126,9 @@ void IP_Unix::get_local_addresses(List *r_addresses) const { 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()))); - } } @@ -108,7 +143,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, @@ -134,14 +169,23 @@ 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.field32[0] = *((unsigned long*)&ipv4->sin_addr); + ip.type = IP_Address::TYPE_IPV4; + } else { // ipv6 + + SOCKADDR_IN6* ipv6 = reinterpret_cast(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); @@ -167,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 c0034c9a3a4e..d198a330e726 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_Address::AddrType 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 0201a856518e..cab2b2bbb9ad 100644 --- a/drivers/unix/packet_peer_udp_posix.cpp +++ b/drivers/unix/packet_peer_udp_posix.cpp @@ -73,7 +73,15 @@ 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_Address::TYPE_IPV4) { + rb.read((uint8_t*)&packet_ip.field8,4,true); + packet_ip.type = IP_Address::TYPE_IPV4; + } else { + rb.read((uint8_t*)&packet_ip.field8,16,true); + packet_ip.type = IP_Address::TYPE_IPV6; + }; rb.read((uint8_t*)&packet_port,4,true); rb.read((uint8_t*)&size,4,true); rb.read(packet_buffer,size,true); @@ -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){ - 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 ); - 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; + if (peer_addr.type == IP_Address::TYPE_IPV4) { + struct sockaddr_in* addr_in = (struct sockaddr_in*)&addr; + addr_in->sin_family = AF_INET; + addr_in->sin_port = htons(peer_port); + addr_in->sin_addr = *((struct in_addr*)&peer_addr.field32[0]); + } else { + struct sockaddr_in6* addr_in6 = (struct sockaddr_in6*)&addr; + addr_in6->sin6_family = AF_INET; + addr_in6->sin6_port = htons(peer_port); + copymem(&addr_in6->sin6_addr.s6_addr, peer_addr.field8, 16); + }; errno = 0; int err; @@ -110,17 +128,32 @@ 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, 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(); - int sock = _get_socket(); + int sock = _get_socket(p_address_type); if (sock == -1 ) return ERR_CANT_CREATE; - sockaddr_in addr = {0}; - addr.sin_family = AF_INET; - addr.sin_port = htons(p_port); - addr.sin_addr.s_addr = INADDR_ANY; - if (bind(sock, (struct sockaddr*)&addr, sizeof(sockaddr_in)) == -1 ) { + + sockaddr_storage addr = {0}; + + if (p_address_type == IP_Address::TYPE_IPV4) { + struct sockaddr_in* addr4 = (struct sockaddr_in*)&addr; + addr4->sin_family = AF_INET; + addr4->sin_port = htons(p_port); + addr4->sin_addr.s_addr = INADDR_ANY; + } else { + + struct sockaddr_in6* addr6 = (struct sockaddr_in6*)&addr; + + addr6->sin6_family = AF_INET6; + addr6->sin6_port = htons(p_port); + addr6->sin6_addr = in6addr_any; + }; + + if (bind(sock, (struct sockaddr*)&addr, sizeof(sockaddr_storage)) == -1 ) { close(); return ERR_UNAVAILABLE; } @@ -145,16 +178,40 @@ 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_Address::TYPE_IPV4; + rb.write(&type, 1); + struct sockaddr_in* sin_from = (struct sockaddr_in*)&from; + rb.write((uint8_t*)&sin_from->sin_addr, 4); + port = sin_from->sin_port; + + } else if (from.ss_family == AF_INET6) { + + uint8_t type = (uint8_t)IP_Address::TYPE_IPV6; + rb.write(&type, 1); + + struct sockaddr_in6* s6_from = (struct sockaddr_in6*)&from; + rb.write((uint8_t*)&s6_from->sin6_addr, 16); + + port = s6_from->sin6_port; + + } else { + // WARN_PRINT("Ignoring packet with unknown address family"); + uint8_t type = (uint8_t)IP_Address::TYPE_NONE; + rb.write(&type, 1); + }; + rb.write((uint8_t*)&port, 4); rb.write((uint8_t*)&ret, 4); rb.write(recv_buffer, ret); - len = sizeof(struct sockaddr_in); + ++queue_count; }; @@ -182,12 +239,14 @@ int PacketPeerUDPPosix::get_packet_port() const{ return packet_port; } -int PacketPeerUDPPosix::_get_socket() { +int PacketPeerUDPPosix::_get_socket(IP_Address::AddrType p_type) { if (sockfd != -1) return sockfd; - sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + int family = p_type == IP_Address::TYPE_IPV6 ? AF_INET6 : AF_INET; + + sockfd = socket(family, SOCK_DGRAM, IPPROTO_UDP); ERR_FAIL_COND_V( sockfd == -1, -1 ); //fcntl(sockfd, F_SETFL, O_NONBLOCK); diff --git a/drivers/unix/packet_peer_udp_posix.h b/drivers/unix/packet_peer_udp_posix.h index a11282e5d668..13b6969e5389 100644 --- a/drivers/unix/packet_peer_udp_posix.h +++ b/drivers/unix/packet_peer_udp_posix.h @@ -44,15 +44,15 @@ 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; IP_Address peer_addr; int peer_port; - _FORCE_INLINE_ int _get_socket(); + _FORCE_INLINE_ int _get_socket(IP_Address::AddrType p_type); static PacketPeerUDP* _create(); virtual Error _poll(bool p_block); @@ -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, IP_Address::AddrType p_address_type, int p_recv_buffer_size=65536); virtual void close(); virtual Error wait(); virtual bool is_listening() const; diff --git a/drivers/unix/stream_peer_tcp_posix.cpp b/drivers/unix/stream_peer_tcp_posix.cpp index 45a4b934c160..bb672cef3168 100644 --- a/drivers/unix/stream_peer_tcp_posix.cpp +++ b/drivers/unix/stream_peer_tcp_posix.cpp @@ -61,12 +61,23 @@ #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) { +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 - 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); + memset(&their_addr, 0, sizeof(struct sockaddr_storage)); + if (p_host.type == IP_Address::TYPE_IPV6) { + + struct sockaddr_in6* addr6 = (struct sockaddr_in6*)&their_addr; + addr6->sin6_family = AF_INET6; + addr6->sin6_port = htons(p_port); + copymem(&addr6->sin6_addr.s6_addr, p_host.field8, 16); + + } else { + + struct sockaddr_in* addr4 = (struct sockaddr_in*)&their_addr; + addr4->sin_family = AF_INET; // host byte order + addr4->sin_port = htons(p_port); // short, network byte order + addr4->sin_addr = *((struct in_addr*)&p_host.field32[0]); + }; }; StreamPeerTCP* StreamPeerTCPPosix::_create() { @@ -103,9 +114,9 @@ Error StreamPeerTCPPosix::_poll_connection(bool p_block) const { _block(sockfd, false, true); }; - struct sockaddr_in their_addr; + struct sockaddr_storage their_addr; 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) { 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) { - 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!"); disconnect(); //perror("socket"); @@ -156,11 +168,11 @@ Error StreamPeerTCPPosix::connect(const IP_Address& p_host, uint16_t p_port) { ioctl(sockfd, FIONBIO, &bval); #endif - struct sockaddr_in their_addr; + struct sockaddr_storage their_addr; set_addr_in(their_addr, p_host, p_port); 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!"); disconnect(); diff --git a/drivers/unix/tcp_server_posix.cpp b/drivers/unix/tcp_server_posix.cpp index c67bb5133467..03312a7538a0 100644 --- a/drivers/unix/tcp_server_posix.cpp +++ b/drivers/unix/tcp_server_posix.cpp @@ -55,6 +55,7 @@ #include #include #include + TCP_Server* TCPServerPosix::_create() { return memnew(TCPServerPosix); @@ -65,10 +66,11 @@ void TCPServerPosix::make_default() { TCP_Server::_create = TCPServerPosix::_create; }; -Error TCPServerPosix::listen(uint16_t p_port,const List *p_accepted_hosts) { +Error TCPServerPosix::listen(uint16_t p_port, IP_Address::AddrType p_type, const List *p_accepted_hosts) { 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); #ifndef NO_FCNTL fcntl(sockfd, F_SETFL, O_NONBLOCK); @@ -82,13 +84,22 @@ 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); + sockaddr_storage addr = {0}; + if (p_type == IP_Address::TYPE_IPV4) { + struct sockaddr_in* addr4 = (struct sockaddr_in*)&addr; + addr4->sin_family = AF_INET; + addr4->sin_port = htons(p_port); + addr4->sin_addr.s_addr = INADDR_ANY; + } else { - 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) { @@ -136,9 +147,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 +160,23 @@ 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)); + + 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; }; diff --git a/drivers/unix/tcp_server_posix.h b/drivers/unix/tcp_server_posix.h index 570bcaab129b..134ec494cb21 100644 --- a/drivers/unix/tcp_server_posix.h +++ b/drivers/unix/tcp_server_posix.h @@ -40,7 +40,7 @@ class TCPServerPosix : public TCP_Server { public: - virtual Error listen(uint16_t p_port,const List *p_accepted_hosts=NULL); + virtual Error listen(uint16_t p_port, IP_Address::AddrType p_type = IP_Address::TYPE_IPV4, const List *p_accepted_hosts=NULL); virtual bool is_connection_available() const; virtual Ref take_connection(); diff --git a/modules/enet/networked_multiplayer_enet.cpp b/modules/enet/networked_multiplayer_enet.cpp index b4dfa9c62ec0..a82283591d96 100644 --- a/modules/enet/networked_multiplayer_enet.cpp +++ b/modules/enet/networked_multiplayer_enet.cpp @@ -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){ 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 */, 1 /* only allow 1 outgoing connection */, @@ -90,7 +91,7 @@ Error NetworkedMultiplayerENet::create_client(const IP_Address& p_ip, int p_port _setup_compressor(); ENetAddress address; - address.host=p_ip.host; + address.host=p_ip.field32[0]; address.port=p_port; //enet_address_set_host (& address, "localhost"); @@ -149,7 +150,8 @@ void NetworkedMultiplayerENet::poll(){ } 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 ); *new_id = event.data; @@ -683,5 +685,6 @@ NetworkedMultiplayerENet::~NetworkedMultiplayerENet(){ // sets IP for ENet to bind when using create_server // if no IP is set, then ENet bind to ENET_HOST_ANY 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]; }