diff --git a/Minecraft.Client/Common/Network/NetworkSocketLayer.cpp b/Minecraft.Client/Common/Network/NetworkSocketLayer.cpp index 8136a657..9b29f088 100644 --- a/Minecraft.Client/Common/Network/NetworkSocketLayer.cpp +++ b/Minecraft.Client/Common/Network/NetworkSocketLayer.cpp @@ -3,6 +3,11 @@ #include "NetworkSocketLayer.h" #include "..\..\Common\Network\PlatformNetworkManager.h" #include "..\..\..\Minecraft.World\Socket.h" +#ifdef __ORBIS__ +#include +#endif + +static const DWORD NETWORK_LAN_DISCOVERY_QUERY_MAGIC = 0x4D435152; #if defined _WINDOWS64 || defined _XBOX SOCKET NetworkSocketLayer::s_listenSocket = INVALID_SOCKET; @@ -1290,7 +1295,6 @@ int NetworkSocketLayer::AdvertiseThreadProc(LPVOID param) app.DebugPrintf("PS3 LAN: Broadcast sendto failed: %d\n", sent); } #endif - C4JThread::Sleep(1000); } @@ -1299,8 +1303,14 @@ int NetworkSocketLayer::AdvertiseThreadProc(LPVOID param) bool NetworkSocketLayer::StartDiscovery() { - if (s_discovering) return true; - if (!s_initialized) return false; + if (s_discovering) + { + return true; + } + if (!s_initialized) + { + return false; + } s_discoverySock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); #if defined _WINDOWS64 || defined _XBOX @@ -1321,6 +1331,8 @@ bool NetworkSocketLayer::StartDiscovery() BOOL reuseAddr = TRUE; setsockopt(s_discoverySock, SOL_SOCKET, SO_REUSEADDR, (const char *)&reuseAddr, sizeof(reuseAddr)); + BOOL broadcast = TRUE; + setsockopt(s_discoverySock, SOL_SOCKET, SO_BROADCAST, (const char *)&broadcast, sizeof(broadcast)); struct sockaddr_in bindAddr; memset(&bindAddr, 0, sizeof(bindAddr)); @@ -1337,7 +1349,8 @@ bool NetworkSocketLayer::StartDiscovery() return false; } #elif defined __PS3__ || defined __ORBIS__ - if (::bind(s_discoverySock, (struct sockaddr *)&bindAddr, sizeof(bindAddr)) < 0) + int bindResult = ::bind(s_discoverySock, (struct sockaddr *)&bindAddr, sizeof(bindAddr)); + if (bindResult < 0) { #if defined(__PS3__) app.DebugPrintf("PS3 LAN: Discovery bind failed: %d\n", sys_net_errno); @@ -1349,8 +1362,15 @@ bool NetworkSocketLayer::StartDiscovery() return false; } #endif +#if defined _WINDOWS64 || defined _XBOX DWORD timeout = 500; setsockopt(s_discoverySock, SOL_SOCKET, SO_RCVTIMEO, (const char *)&timeout, sizeof(timeout)); +#elif defined __PS3__ || defined __ORBIS__ + struct timeval timeout; + timeout.tv_sec = 0; + timeout.tv_usec = 500000; + setsockopt(s_discoverySock, SOL_SOCKET, SO_RCVTIMEO, (const char *)&timeout, sizeof(timeout)); +#endif s_discovering = true; s_discoveryThread = new C4JThread(DiscoveryThreadProc, NULL, "DiscoveryThreadProc"); @@ -1393,6 +1413,54 @@ void NetworkSocketLayer::StopDiscovery() std::vector NetworkSocketLayer::GetDiscoveredSessions() { std::vector result; + if (!s_discovering && !StartDiscovery()) + { + return result; + } + + DWORD query = htonl(NETWORK_LAN_DISCOVERY_QUERY_MAGIC); + struct sockaddr_in destination; + memset(&destination, 0, sizeof(destination)); + destination.sin_family = AF_INET; + destination.sin_port = htons(NETWORK_LAN_DISCOVERY_PORT); + destination.sin_addr.s_addr = INADDR_BROADCAST; + sendto(s_discoverySock, (const char *)&query, sizeof(query), 0, + (struct sockaddr *)&destination, sizeof(destination)); + +#ifdef __ORBIS__ + SceNetCtlInfo ipInfo; + SceNetCtlInfo maskInfo; + int ipResult = sceNetCtlGetInfo(SCE_NET_CTL_INFO_IP_ADDRESS, &ipInfo); + int maskResult = sceNetCtlGetInfo(SCE_NET_CTL_INFO_NETMASK, &maskInfo); + if (ipResult == SCE_OK && maskResult == SCE_OK) + { + struct in_addr localAddress; + struct in_addr netmask; + if (inet_pton(AF_INET, ipInfo.ip_address, &localAddress) == 1 && + inet_pton(AF_INET, maskInfo.netmask, &netmask) == 1) + { + DWORD local = ntohl(localAddress.s_addr); + DWORD mask = ntohl(netmask.s_addr); + DWORD first = (local & mask) + 1; + DWORD last = (local | ~mask) - 1; + if (last - first > 1023) + { + first = local & 0xFFFFFF00; + last = first + 254; + ++first; + } + for (DWORD address = first; address <= last; ++address) + { + if (address == local) + continue; + destination.sin_addr.s_addr = htonl(address); + sendto(s_discoverySock, (const char *)&query, sizeof(query), 0, + (struct sockaddr *)&destination, sizeof(destination)); + } + } + } +#endif + if (TryEnterCriticalSection(&s_discoveryLock)) { result = s_discoveredSessions; @@ -1430,8 +1498,30 @@ int NetworkSocketLayer::DiscoveryThreadProc(LPVOID param) } #endif - if (recvLen < (int)sizeof(LANBroadcast)) + if (recvLen == (int)sizeof(DWORD)) + { + DWORD query; + memcpy(&query, recvBuf, sizeof(query)); + if (ntohl(query) == NETWORK_LAN_DISCOVERY_QUERY_MAGIC && s_advertising) + { + EnterCriticalSection(&s_advertiseLock); + LANBroadcast response = s_advertiseData; + LeaveCriticalSection(&s_advertiseLock); + response.magic = htonl(response.magic); + response.netVersion = htons(response.netVersion); + response.gamePort = htons(response.gamePort); + response.gameHostSettings = htonl(response.gameHostSettings); + response.texturePackParentId = htonl(response.texturePackParentId); + sendto(s_discoverySock, (const char *)&response, sizeof(response), 0, + (struct sockaddr *)&senderAddr, senderLen); + } continue; + } + + if (recvLen < (int)sizeof(LANBroadcast)) + { + continue; + } LANBroadcast *broadcast = (LANBroadcast *)recvBuf; @@ -1442,7 +1532,9 @@ int NetworkSocketLayer::DiscoveryThreadProc(LPVOID param) broadcast->texturePackParentId = ntohl(broadcast->texturePackParentId); if (broadcast->magic != NETWORK_LAN_BROADCAST_MAGIC) + { continue; + } char senderIP[64]; #if defined _XBOX @@ -1453,7 +1545,6 @@ int NetworkSocketLayer::DiscoveryThreadProc(LPVOID param) #else inet_ntop(AF_INET, &senderAddr.sin_addr, senderIP, sizeof(senderIP)); #endif - DWORD now = GetTickCount(); EnterCriticalSection(&s_discoveryLock); diff --git a/Minecraft.Client/Common/Network/PlatformNetworkManager.cpp b/Minecraft.Client/Common/Network/PlatformNetworkManager.cpp index 59ce1a0b..ce44a839 100644 --- a/Minecraft.Client/Common/Network/PlatformNetworkManager.cpp +++ b/Minecraft.Client/Common/Network/PlatformNetworkManager.cpp @@ -477,6 +477,8 @@ bool CPlatformNetworkManagerStub::_RunNetworkGame() { extern QNET_STATE _iQNetStubState; _iQNetStubState = QNET_STATE_GAME_PLAY; + if (m_pIQNet->IsHost()) + NetworkSocketLayer::UpdateAdvertiseJoinable(true); for (DWORD i = 0; i < IQNet::s_playerCount; i++) { @@ -698,7 +700,7 @@ void CPlatformNetworkManagerStub::SearchForGames() { std::vector lanSessions = NetworkSocketLayer::GetDiscoveredSessions(); - if (g_MultiplayerJoin) + if (g_MultiplayerJoin && g_MultiplayerIP[0] != '\0') { bool alreadyPresent = false; for (size_t i = 0; i < lanSessions.size(); i++) diff --git a/Minecraft.Client/Orbis/Orbis_Minecraft.cpp b/Minecraft.Client/Orbis/Orbis_Minecraft.cpp index d2366fbd..a658da4f 100644 --- a/Minecraft.Client/Orbis/Orbis_Minecraft.cpp +++ b/Minecraft.Client/Orbis/Orbis_Minecraft.cpp @@ -1059,9 +1059,10 @@ int main(int argc, const char *argv[] ) // XN_SYS_SIGNINCHANGED notifications. This does mean that we need to have a callback in the // ProfileManager for XN_LIVE_INVITE_ACCEPTED for QNet. - g_NetworkManager.Initialise(); - - // debug switch to trial version + g_NetworkManager.Initialise(); + NetworkSocketLayer::Initialize(); + + // debug switch to trial version ProfileManager.SetDebugFullOverride(true); #if 0