diff options
Diffstat (limited to 'src/OSSupport/UDPEndpointImpl.cpp')
-rw-r--r-- | src/OSSupport/UDPEndpointImpl.cpp | 233 |
1 files changed, 177 insertions, 56 deletions
diff --git a/src/OSSupport/UDPEndpointImpl.cpp b/src/OSSupport/UDPEndpointImpl.cpp index 2550c5378..3ae5db485 100644 --- a/src/OSSupport/UDPEndpointImpl.cpp +++ b/src/OSSupport/UDPEndpointImpl.cpp @@ -16,15 +16,15 @@ namespace UDPEndpointImplHelper { - static bool IsValidSocket(evutil_socket_t a_Socket) - { +static bool IsValidSocket(evutil_socket_t a_Socket) +{ #ifdef _WIN32 - return (a_Socket != INVALID_SOCKET); + return (a_Socket != INVALID_SOCKET); #else // _WIN32 - return (a_Socket >= 0); + return (a_Socket >= 0); #endif // else _WIN32 - } } +} // namespace UDPEndpointImplHelper @@ -37,8 +37,8 @@ static void ConvertIPv4ToMappedIPv6(sockaddr_in & a_SrcAddr, sockaddr_in6 & a_Ds a_DstAddr.sin6_family = AF_INET6; a_DstAddr.sin6_addr.s6_addr[10] = 0xff; a_DstAddr.sin6_addr.s6_addr[11] = 0xff; - a_DstAddr.sin6_addr.s6_addr[12] = static_cast<Byte>((a_SrcAddr.sin_addr.s_addr >> 0) & 0xff); - a_DstAddr.sin6_addr.s6_addr[13] = static_cast<Byte>((a_SrcAddr.sin_addr.s_addr >> 8) & 0xff); + a_DstAddr.sin6_addr.s6_addr[12] = static_cast<Byte>((a_SrcAddr.sin_addr.s_addr >> 0) & 0xff); + a_DstAddr.sin6_addr.s6_addr[13] = static_cast<Byte>((a_SrcAddr.sin_addr.s_addr >> 8) & 0xff); a_DstAddr.sin6_addr.s6_addr[14] = static_cast<Byte>((a_SrcAddr.sin_addr.s_addr >> 16) & 0xff); a_DstAddr.sin6_addr.s6_addr[15] = static_cast<Byte>((a_SrcAddr.sin_addr.s_addr >> 24) & 0xff); a_DstAddr.sin6_port = a_SrcAddr.sin_port; @@ -54,11 +54,16 @@ static void ConvertIPv4ToMappedIPv6(sockaddr_in & a_SrcAddr, sockaddr_in6 & a_Ds /** A hostname-to-IP resolver callback that sends the data stored within to the resolved IP address. This is used for sending UDP datagrams to hostnames, so that the cUDPEndpoint::Send() doesn't block. Instead an instance of this callback is queued for resolving and the data is sent once the IP is resolved. */ -class cUDPSendAfterLookup: - public cNetwork::cResolveNameCallbacks +class cUDPSendAfterLookup : public cNetwork::cResolveNameCallbacks { -public: - cUDPSendAfterLookup(const AString & a_Data, UInt16 a_Port, evutil_socket_t a_MainSock, evutil_socket_t a_SecondSock, bool a_IsMainSockIPv6): + public: + cUDPSendAfterLookup( + const AString & a_Data, + UInt16 a_Port, + evutil_socket_t a_MainSock, + evutil_socket_t a_SecondSock, + bool a_IsMainSockIPv6 + ) : m_Data(a_Data), m_Port(a_Port), m_MainSock(a_MainSock), @@ -69,7 +74,7 @@ public: { } -protected: + protected: /** The data to send after the hostname is resolved. */ AString m_Data; @@ -137,20 +142,41 @@ protected: { if (m_HasIPv6) { - sendto(m_MainSock, m_Data.data(), m_Data.size(), 0, reinterpret_cast<const sockaddr *>(&m_AddrIPv6), static_cast<socklen_t>(sizeof(m_AddrIPv6))); + sendto( + m_MainSock, + m_Data.data(), + m_Data.size(), + 0, + reinterpret_cast<const sockaddr *>(&m_AddrIPv6), + static_cast<socklen_t>(sizeof(m_AddrIPv6)) + ); } else if (m_HasIPv4) { // If the secondary socket is valid, it is an IPv4 socket, so use that: if (m_SecondSock != -1) { - sendto(m_SecondSock, m_Data.data(), m_Data.size(), 0, reinterpret_cast<const sockaddr *>(&m_AddrIPv4), static_cast<socklen_t>(sizeof(m_AddrIPv4))); + sendto( + m_SecondSock, + m_Data.data(), + m_Data.size(), + 0, + reinterpret_cast<const sockaddr *>(&m_AddrIPv4), + static_cast<socklen_t>(sizeof(m_AddrIPv4)) + ); } else { // Need an address conversion from IPv4 to IPv6-mapped-IPv4: ConvertIPv4ToMappedIPv6(m_AddrIPv4, m_AddrIPv6); - sendto(m_MainSock, m_Data.data(), m_Data.size(), 0, reinterpret_cast<const sockaddr *>(&m_AddrIPv6), static_cast<socklen_t>(sizeof(m_AddrIPv6))); + sendto( + m_MainSock, + m_Data.data(), + m_Data.size(), + 0, + reinterpret_cast<const sockaddr *>(&m_AddrIPv6), + static_cast<socklen_t>(sizeof(m_AddrIPv6)) + ); } } else @@ -167,7 +193,14 @@ protected: LOGD("UDP endpoint queued sendto: Name not resolved to IPv4 for an IPv4-only socket"); return; } - sendto(m_MainSock, m_Data.data(), m_Data.size(), 0, reinterpret_cast<const sockaddr *>(&m_AddrIPv4), static_cast<socklen_t>(sizeof(m_AddrIPv4))); + sendto( + m_MainSock, + m_Data.data(), + m_Data.size(), + 0, + reinterpret_cast<const sockaddr *>(&m_AddrIPv4), + static_cast<socklen_t>(sizeof(m_AddrIPv4)) + ); } } @@ -184,7 +217,7 @@ protected: //////////////////////////////////////////////////////////////////////////////// // cUDPEndpointImpl: -cUDPEndpointImpl::cUDPEndpointImpl(UInt16 a_Port, cUDPEndpoint::cCallbacks & a_Callbacks): +cUDPEndpointImpl::cUDPEndpointImpl(UInt16 a_Port, cUDPEndpoint::cCallbacks & a_Callbacks) : Super(a_Callbacks), m_Port(0), m_MainSock(-1), @@ -270,7 +303,8 @@ bool cUDPEndpointImpl::Send(const AString & a_Payload, const AString & a_Host, U if (evutil_parse_sockaddr_port(a_Host.c_str(), reinterpret_cast<sockaddr *>(&sa), &salen) != 0) { // a_Host is a hostname, we need to do a lookup first: - auto queue = std::make_shared<cUDPSendAfterLookup>(a_Payload, a_Port, m_MainSock, m_SecondarySock, m_IsMainSockIPv6); + auto queue = + std::make_shared<cUDPSendAfterLookup>(a_Payload, a_Port, m_MainSock, m_SecondarySock, m_IsMainSockIPv6); return cNetwork::HostnameToIP(a_Host, queue); } @@ -287,19 +321,40 @@ bool cUDPEndpointImpl::Send(const AString & a_Payload, const AString & a_Host, U if (UDPEndpointImplHelper::IsValidSocket(m_SecondarySock)) { // The secondary socket, which is always IPv4, is present: - NumSent = static_cast<int>(sendto(m_SecondarySock, a_Payload.data(), a_Payload.size(), 0, reinterpret_cast<const sockaddr *>(&sa), static_cast<socklen_t>(salen))); + NumSent = static_cast<int>(sendto( + m_SecondarySock, + a_Payload.data(), + a_Payload.size(), + 0, + reinterpret_cast<const sockaddr *>(&sa), + static_cast<socklen_t>(salen) + )); } else { // Need to convert IPv4 to IPv6 address before sending: sockaddr_in6 IPv6; ConvertIPv4ToMappedIPv6(*reinterpret_cast<sockaddr_in *>(&sa), IPv6); - NumSent = static_cast<int>(sendto(m_MainSock, a_Payload.data(), a_Payload.size(), 0, reinterpret_cast<const sockaddr *>(&IPv6), static_cast<socklen_t>(sizeof(IPv6)))); + NumSent = static_cast<int>(sendto( + m_MainSock, + a_Payload.data(), + a_Payload.size(), + 0, + reinterpret_cast<const sockaddr *>(&IPv6), + static_cast<socklen_t>(sizeof(IPv6)) + )); } } else { - NumSent = static_cast<int>(sendto(m_MainSock, a_Payload.data(), a_Payload.size(), 0, reinterpret_cast<const sockaddr *>(&sa), static_cast<socklen_t>(salen))); + NumSent = static_cast<int>(sendto( + m_MainSock, + a_Payload.data(), + a_Payload.size(), + 0, + reinterpret_cast<const sockaddr *>(&sa), + static_cast<socklen_t>(salen) + )); } break; } @@ -307,7 +362,14 @@ bool cUDPEndpointImpl::Send(const AString & a_Payload, const AString & a_Host, U case AF_INET6: { reinterpret_cast<sockaddr_in6 *>(&sa)->sin6_port = htons(a_Port); - NumSent = static_cast<int>(sendto(m_MainSock, a_Payload.data(), a_Payload.size(), 0, reinterpret_cast<const sockaddr *>(&sa), static_cast<socklen_t>(salen))); + NumSent = static_cast<int>(sendto( + m_MainSock, + a_Payload.data(), + a_Payload.size(), + 0, + reinterpret_cast<const sockaddr *>(&sa), + static_cast<socklen_t>(salen) + )); break; } default: @@ -332,7 +394,13 @@ void cUDPEndpointImpl::EnableBroadcasts(void) int broadcastInt = 1; char broadcastChar = 1; // (Note that Windows uses const char * for option values, while Linux uses const void *) - if (setsockopt(m_MainSock, SOL_SOCKET, SO_BROADCAST, reinterpret_cast<const char *>(&broadcastInt), sizeof(broadcastInt)) == -1) + if (setsockopt( + m_MainSock, + SOL_SOCKET, + SO_BROADCAST, + reinterpret_cast<const char *>(&broadcastInt), + sizeof(broadcastInt) + ) == -1) { if (setsockopt(m_MainSock, SOL_SOCKET, SO_BROADCAST, &broadcastChar, sizeof(broadcastChar)) == -1) { @@ -347,7 +415,12 @@ void cUDPEndpointImpl::EnableBroadcasts(void) if (setsockopt(m_SecondarySock, SOL_SOCKET, SO_BROADCAST, &broadcastChar, sizeof(broadcastChar)) == -1) { int err = EVUTIL_SOCKET_ERROR(); - LOGWARNING("Cannot enable broadcasts on port %d (secondary): %d (%s)", m_Port, err, evutil_socket_error_to_string(err)); + LOGWARNING( + "Cannot enable broadcasts on port %d (secondary): %d (%s)", + m_Port, + err, + evutil_socket_error_to_string(err) + ); } } return; @@ -356,10 +429,21 @@ void cUDPEndpointImpl::EnableBroadcasts(void) // Enable broadcasts on the secondary socket, if opened (use int, it worked for primary): if (UDPEndpointImplHelper::IsValidSocket(m_SecondarySock)) { - if (setsockopt(m_SecondarySock, SOL_SOCKET, SO_BROADCAST, reinterpret_cast<const char *>(&broadcastInt), sizeof(broadcastInt)) == -1) + if (setsockopt( + m_SecondarySock, + SOL_SOCKET, + SO_BROADCAST, + reinterpret_cast<const char *>(&broadcastInt), + sizeof(broadcastInt) + ) == -1) { int err = EVUTIL_SOCKET_ERROR(); - LOGWARNING("Cannot enable broadcasts on port %d (secondary): %d (%s)", m_Port, err, evutil_socket_error_to_string(err)); + LOGWARNING( + "Cannot enable broadcasts on port %d (secondary): %d (%s)", + m_Port, + err, + evutil_socket_error_to_string(err) + ); } } } @@ -392,8 +476,14 @@ void cUDPEndpointImpl::Open(UInt16 a_Port) if (!UDPEndpointImplHelper::IsValidSocket(m_MainSock)) { err = EVUTIL_SOCKET_ERROR(); - m_Callbacks.OnError(err, fmt::format(FMT_STRING("Cannot create UDP socket for port {}: {} ({})"), - a_Port, err, evutil_socket_error_to_string(err)) + m_Callbacks.OnError( + err, + fmt::format( + FMT_STRING("Cannot create UDP socket for port {}: {} ({})"), + a_Port, + err, + evutil_socket_error_to_string(err) + ) ); return; } @@ -403,8 +493,9 @@ void cUDPEndpointImpl::Open(UInt16 a_Port) { err = EVUTIL_SOCKET_ERROR(); LOG("UDP Port %d cannot be made reusable: %d (%s). Restarting the server might not work.", - a_Port, err, evutil_socket_error_to_string(err) - ); + a_Port, + err, + evutil_socket_error_to_string(err)); } // Bind to all interfaces: @@ -415,8 +506,14 @@ void cUDPEndpointImpl::Open(UInt16 a_Port) if (bind(m_MainSock, reinterpret_cast<const sockaddr *>(&name), sizeof(name)) != 0) { err = EVUTIL_SOCKET_ERROR(); - m_Callbacks.OnError(err, fmt::format(FMT_STRING("Cannot bind UDP port {}: {} ({})"), - a_Port, err, evutil_socket_error_to_string(err)) + m_Callbacks.OnError( + err, + fmt::format( + FMT_STRING("Cannot bind UDP port {}: {} ({})"), + a_Port, + err, + evutil_socket_error_to_string(err) + ) ); evutil_closesocket(m_MainSock); return; @@ -426,22 +523,24 @@ void cUDPEndpointImpl::Open(UInt16 a_Port) { // IPv6 socket created, switch it into "dualstack" mode: UInt32 Zero = 0; - #ifdef _WIN32 - // WinXP doesn't support this feature, so if the setting fails, create another socket later on: - int res = setsockopt(m_MainSock, IPPROTO_IPV6, IPV6_V6ONLY, reinterpret_cast<const char *>(&Zero), sizeof(Zero)); - err = EVUTIL_SOCKET_ERROR(); - NeedsTwoSockets = ((res == SOCKET_ERROR) && (err == WSAENOPROTOOPT)); - #else +#ifdef _WIN32 + // WinXP doesn't support this feature, so if the setting fails, create another socket later on: + int res = setsockopt(m_MainSock, IPPROTO_IPV6, IPV6_V6ONLY, reinterpret_cast<const char *>(&Zero), sizeof(Zero)); - #endif + err = EVUTIL_SOCKET_ERROR(); + NeedsTwoSockets = ((res == SOCKET_ERROR) && (err == WSAENOPROTOOPT)); +#else + setsockopt(m_MainSock, IPPROTO_IPV6, IPV6_V6ONLY, reinterpret_cast<const char *>(&Zero), sizeof(Zero)); +#endif // Allow the port to be reused right after the socket closes: if (evutil_make_listen_socket_reuseable(m_MainSock) != 0) { - err = EVUTIL_SOCKET_ERROR(); + err = EVUTIL_SOCKET_ERROR(); LOG("UDP Port %d cannot be made reusable: %d (%s). Restarting the server might not work.", - a_Port, err, evutil_socket_error_to_string(err) - ); + a_Port, + err, + evutil_socket_error_to_string(err)); } // Bind to all interfaces: @@ -452,8 +551,14 @@ void cUDPEndpointImpl::Open(UInt16 a_Port) if (bind(m_MainSock, reinterpret_cast<const sockaddr *>(&name), sizeof(name)) != 0) { err = EVUTIL_SOCKET_ERROR(); - m_Callbacks.OnError(err, fmt::format(FMT_STRING("Cannot bind to UDP port {}: {} ({})"), - a_Port, err, evutil_socket_error_to_string(err)) + m_Callbacks.OnError( + err, + fmt::format( + FMT_STRING("Cannot bind to UDP port {}: {} ({})"), + a_Port, + err, + evutil_socket_error_to_string(err) + ) ); evutil_closesocket(m_MainSock); return; @@ -462,13 +567,20 @@ void cUDPEndpointImpl::Open(UInt16 a_Port) if (evutil_make_socket_nonblocking(m_MainSock) != 0) { err = EVUTIL_SOCKET_ERROR(); - m_Callbacks.OnError(err, fmt::format(FMT_STRING("Cannot make socket on UDP port {} nonblocking: {} ({})"), - a_Port, err, evutil_socket_error_to_string(err)) + m_Callbacks.OnError( + err, + fmt::format( + FMT_STRING("Cannot make socket on UDP port {} nonblocking: {} ({})"), + a_Port, + err, + evutil_socket_error_to_string(err) + ) ); evutil_closesocket(m_MainSock); return; } - m_MainEvent = event_new(cNetworkSingleton::Get().GetEventBase(), m_MainSock, EV_READ | EV_PERSIST, RawCallback, this); + m_MainEvent = + event_new(cNetworkSingleton::Get().GetEventBase(), m_MainSock, EV_READ | EV_PERSIST, RawCallback, this); event_add(m_MainEvent, nullptr); // Read the actual port number on which the socket is listening: @@ -507,7 +619,12 @@ void cUDPEndpointImpl::Open(UInt16 a_Port) { // Don't report as an error, the primary socket is working err = EVUTIL_SOCKET_ERROR(); - LOGD("Socket creation failed for secondary UDP socket for port %d: %d, %s", m_Port, err, evutil_socket_error_to_string(err)); + LOGD( + "Socket creation failed for secondary UDP socket for port %d: %d, %s", + m_Port, + err, + evutil_socket_error_to_string(err) + ); return; } @@ -516,8 +633,11 @@ void cUDPEndpointImpl::Open(UInt16 a_Port) { // Don't report as an error, the primary socket is working err = EVUTIL_SOCKET_ERROR(); - LOGD("UDP Port %d cannot be made reusable (second socket): %d (%s). Restarting the server might not work.", - a_Port, err, evutil_socket_error_to_string(err) + LOGD( + "UDP Port %d cannot be made reusable (second socket): %d (%s). Restarting the server might not work.", + a_Port, + err, + evutil_socket_error_to_string(err) ); evutil_closesocket(m_SecondarySock); m_SecondarySock = -1; @@ -529,7 +649,11 @@ void cUDPEndpointImpl::Open(UInt16 a_Port) { // Don't report as an error, the primary socket is working err = EVUTIL_SOCKET_ERROR(); - LOGD("evutil_make_socket_nonblocking() failed for secondary UDP socket: %d, %s", err, evutil_socket_error_to_string(err)); + LOGD( + "evutil_make_socket_nonblocking() failed for secondary UDP socket: %d, %s", + err, + evutil_socket_error_to_string(err) + ); evutil_closesocket(m_SecondarySock); m_SecondarySock = -1; return; @@ -550,7 +674,8 @@ void cUDPEndpointImpl::Open(UInt16 a_Port) return; } - m_SecondaryEvent = event_new(cNetworkSingleton::Get().GetEventBase(), m_SecondarySock, EV_READ | EV_PERSIST, RawCallback, this); + m_SecondaryEvent = + event_new(cNetworkSingleton::Get().GetEventBase(), m_SecondarySock, EV_READ | EV_PERSIST, RawCallback, this); event_add(m_SecondaryEvent, nullptr); } @@ -621,7 +746,3 @@ cUDPEndpointPtr cNetwork::CreateUDPEndpoint(UInt16 a_Port, cUDPEndpoint::cCallba { return std::make_shared<cUDPEndpointImpl>(a_Port, a_Callbacks); } - - - - |