diff --git a/core/io/net_socket.h b/core/io/net_socket.h index bc094776933f..df7bc4f4f5c4 100644 --- a/core/io/net_socket.h +++ b/core/io/net_socket.h @@ -63,6 +63,7 @@ class NetSocket : public Reference { virtual Error recvfrom(uint8_t *p_buffer, int p_len, int &r_read, IP_Address &r_ip, uint16_t &r_port, bool p_peek = false) = 0; virtual Error send(const uint8_t *p_buffer, int p_len, int &r_sent) = 0; virtual Error sendto(const uint8_t *p_buffer, int p_len, int &r_sent, IP_Address p_ip, uint16_t p_port) = 0; + virtual Error getsockname(IP_Address &r_ip, uint16_t &r_port) = 0; virtual Ref accept(IP_Address &r_ip, uint16_t &r_port) = 0; virtual bool is_open() const = 0; diff --git a/drivers/unix/net_socket_posix.cpp b/drivers/unix/net_socket_posix.cpp index 3baabdd2c7d7..2584bfd628c7 100644 --- a/drivers/unix/net_socket_posix.cpp +++ b/drivers/unix/net_socket_posix.cpp @@ -616,6 +616,37 @@ Error NetSocketPosix::sendto(const uint8_t *p_buffer, int p_len, int &r_sent, IP return OK; } +Error NetSocketPosix::getsockname(IP_Address &r_ip, uint16_t &r_port) { + ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED); + + struct sockaddr_storage local; + socklen_t len = sizeof(struct sockaddr_storage); + int ret = ::getsockname(_sock, (struct sockaddr *)&local, &len); + + if (ret != 0) { + NetError err = _get_socket_error(); + if (err == ERR_NET_IN_PROGRESS) { + return ERR_BUSY; + } + return FAILED; + } + + if (local.ss_family == AF_INET) { + struct sockaddr_in *sin_local = (struct sockaddr_in *)&local; + r_ip.set_ipv4((uint8_t *)&sin_local->sin_addr); + r_port = ntohs(sin_local->sin_port); + } else if (local.ss_family == AF_INET6) { + struct sockaddr_in6 *s6_local = (struct sockaddr_in6 *)&local; + r_ip.set_ipv6((uint8_t *)&s6_local->sin6_addr); + r_port = ntohs(s6_local->sin6_port); + } else { + // Unsupported socket family, should never happen. + ERR_FAIL_V(FAILED); + } + + return OK; +} + Error NetSocketPosix::set_broadcasting_enabled(bool p_enabled) { ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED); // IPv6 has no broadcast support. diff --git a/drivers/unix/net_socket_posix.h b/drivers/unix/net_socket_posix.h index cc6af661c8a3..4b6141e4859e 100644 --- a/drivers/unix/net_socket_posix.h +++ b/drivers/unix/net_socket_posix.h @@ -83,6 +83,7 @@ class NetSocketPosix : public NetSocket { virtual Error recvfrom(uint8_t *p_buffer, int p_len, int &r_read, IP_Address &r_ip, uint16_t &r_port, bool p_peek = false); virtual Error send(const uint8_t *p_buffer, int p_len, int &r_sent); virtual Error sendto(const uint8_t *p_buffer, int p_len, int &r_sent, IP_Address p_ip, uint16_t p_port); + virtual Error getsockname(IP_Address &r_ip, uint16_t &r_port); virtual Ref accept(IP_Address &r_ip, uint16_t &r_port); virtual bool is_open() const; diff --git a/thirdparty/enet/godot.cpp b/thirdparty/enet/godot.cpp index 73fa3c62a231..2c74dfff0215 100644 --- a/thirdparty/enet/godot.cpp +++ b/thirdparty/enet/godot.cpp @@ -49,6 +49,8 @@ class ENetGodotSocket { virtual Error sendto(const uint8_t *p_buffer, int p_len, int &r_sent, IP_Address p_ip, uint16_t p_port) = 0; virtual Error recvfrom(uint8_t *p_buffer, int p_len, int &r_read, IP_Address &r_ip, uint16_t &r_port) = 0; virtual int set_option(ENetSocketOption p_option, int p_value) = 0; + virtual Error getsockname(IP_Address &r_ip, uint16_t &r_port) = 0; + virtual Error poll(NetSocket::PollType p_type, int p_timeout) = 0; virtual void close() = 0; virtual void set_refuse_new_connections(bool p_enable) {} /* Only used by dtls server */ virtual ~ENetGodotSocket() {} @@ -140,6 +142,14 @@ class ENetUDP : public ENetGodotSocket { return -1; } + Error getsockname(IP_Address &r_ip, uint16_t &r_port) { + return sock->getsockname(r_ip, r_port); + } + + Error poll(NetSocket::PollType p_type, int p_timeout) { + return sock->poll(p_type, p_timeout); + } + void close() { sock->close(); } @@ -221,6 +231,14 @@ class ENetDTLSClient : public ENetGodotSocket { return -1; } + Error getsockname(IP_Address &r_ip, uint16_t &r_port) { + return FAILED; + } + + Error poll(NetSocket::PollType p_type, int p_timeout) { + return FAILED; + } + void close() { dtls->disconnect_from_peer(); udp->close(); @@ -334,6 +352,14 @@ class ENetDTLSServer : public ENetGodotSocket { return -1; } + Error getsockname(IP_Address &r_ip, uint16_t &r_port) { + return FAILED; + } + + Error poll(NetSocket::PollType p_type, int p_timeout) { + return FAILED; + } + void close() { for (Map>::Element *E = peers.front(); E; E = E->next()) { E->get()->disconnect_from_peer(); @@ -493,13 +519,44 @@ int enet_socket_receive(ENetSocket socket, ENetAddress *address, ENetBuffer *buf return read; } -// Not implemented int enet_socket_wait(ENetSocket socket, enet_uint32 *condition, enet_uint32 timeout) { - return 0; // do we need this function? + ENetGodotSocket *sock = (ENetGodotSocket *)socket; + + NetSocket::PollType pollType; + + if (*condition & ENET_SOCKET_WAIT_SEND && *condition & ENET_SOCKET_WAIT_RECEIVE) { + pollType = NetSocket::PollType::POLL_TYPE_IN_OUT; + } else if (*condition & ENET_SOCKET_WAIT_SEND) { + pollType = NetSocket::PollType::POLL_TYPE_OUT; + } else { + pollType = NetSocket::PollType::POLL_TYPE_IN; + } + Error err = sock->poll(pollType, timeout); + + if (err != OK) { + return -1; + } + + return OK; } int enet_socket_get_address(ENetSocket socket, ENetAddress *address) { - return -1; // do we need this function? + ERR_FAIL_COND_V(address == NULL, -1); + + ENetGodotSocket *sock = (ENetGodotSocket *)socket; + + IP_Address ip; + uint16_t port; + + if (sock->getsockname(ip, port) != OK) { + return -1; + } + + enet_address_set_ip(address, ip.get_ipv6(), 16); + + address->port = port; + + return 0; } int enet_socketset_select(ENetSocket maxSocket, ENetSocketSet *readSet, ENetSocketSet *writeSet, enet_uint32 timeout) {