//***************************************************************************** // void SERVER_MASTER_Tick( void ) { UCVarValue Val; while (( g_lStoredQueryIPHead != g_lStoredQueryIPTail ) && ( gametic >= g_StoredQueryIPs[g_lStoredQueryIPHead].lNextAllowedGametic )) { g_lStoredQueryIPHead++; g_lStoredQueryIPHead = g_lStoredQueryIPHead % MAX_STORED_QUERY_IPS; } // Send an update to the master server every 30 seconds. if ( gametic % ( TICRATE * 30 )) return; // User doesn't wish to update the master server. if ( sv_updatemaster == false ) return; NETWORK_ClearBuffer( &g_MasterServerBuffer ); Val = sv_masterip.GetGenericRep( CVAR_String ); NETWORK_StringToAddress( Val.String, &g_AddressMasterServer ); I_SetPort( g_AddressMasterServer, g_lMasterPort ); // Write to our packet a challenge to the master server. Val = sv_masteroverrideip.GetGenericRep( CVAR_String ); if ( Val.String[0] == '\0' ) NETWORK_WriteLong( &g_MasterServerBuffer, SERVER_MASTER_CHALLENGE ); else { netadr_t OverrideIP; NETWORK_WriteLong( &g_MasterServerBuffer, SERVER_MASTER_CHALLENGE_OVERRIDE ); NETWORK_StringToAddress( Val.String, &OverrideIP ); NETWORK_WriteByte( &g_MasterServerBuffer, OverrideIP.ip[0] ); NETWORK_WriteByte( &g_MasterServerBuffer, OverrideIP.ip[1] ); NETWORK_WriteByte( &g_MasterServerBuffer, OverrideIP.ip[2] ); NETWORK_WriteByte( &g_MasterServerBuffer, OverrideIP.ip[3] ); NETWORK_WriteShort( &g_MasterServerBuffer, NETWORK_GetLocalPort( )); } // Send the master server our packet. // NETWORK_LaunchPacket( &g_MasterServerBuffer, g_AddressMasterServer, true ); NETWORK_LaunchPacket( &g_MasterServerBuffer, g_AddressMasterServer ); }
void NETWORK_Construct( USHORT usPort, bool bAllocateLANSocket ) { char szString[128]; ULONG ulArg; USHORT usNewPort; bool bSuccess; // Initialize the Huffman buffer. HUFFMAN_Construct( ); #ifdef __WIN32__ // [BB] Linux doesn't know WSADATA, so this may not be moved outside the ifdef. WSADATA WSAData; if ( WSAStartup( 0x0101, &WSAData )) network_Error( "Winsock initialization failed!\n" ); Printf( "Winsock initialization succeeded!\n" ); #endif ULONG ulInAddr = INADDR_ANY; const char* pszIPAddress = Args->CheckValue( "-useip" ); // [BB] An IP was specfied. Check if it's valid and if it is, try to bind our socket to it. if ( pszIPAddress ) { ULONG requestedIP = inet_addr( pszIPAddress ); if ( requestedIP == INADDR_NONE ) { sprintf( szString, "NETWORK_Construct: %s is not a valid IP address\n", pszIPAddress ); network_Error( szString ); } else ulInAddr = requestedIP; } g_usLocalPort = usPort; // Allocate a socket, and attempt to bind it to the given port. g_NetworkSocket = network_AllocateSocket( ); // [BB] If we can't allocate a socket, sending / receiving net packets won't work. if ( g_NetworkSocket == INVALID_SOCKET ) network_Error( "NETWORK_Construct: Couldn't allocate socket. You will not be able to host or join servers.\n" ); else if ( network_BindSocketToPort( g_NetworkSocket, ulInAddr, g_usLocalPort, false ) == false ) { bSuccess = true; bool bSuccessIP = true; usNewPort = g_usLocalPort; while ( network_BindSocketToPort( g_NetworkSocket, ulInAddr, ++usNewPort, false ) == false ) { // Didn't find an available port. Oh well... if ( usNewPort == g_usLocalPort ) { // [BB] We couldn't use the specified IP, so just try any. if ( ulInAddr != INADDR_ANY ) { ulInAddr = INADDR_ANY; bSuccessIP = false; continue; } bSuccess = false; break; } } if ( bSuccess == false ) { sprintf( szString, "NETWORK_Construct: Couldn't bind socket to port: %d\n", g_usLocalPort ); network_Error( szString ); } else if ( bSuccessIP == false ) { sprintf( szString, "NETWORK_Construct: Couldn't bind socket to IP %s, using the default IP instead:\n", pszIPAddress ); network_Error( szString ); } else { Printf( "NETWORK_Construct: Couldn't bind to %d. Binding to %d instead...\n", g_usLocalPort, usNewPort ); g_usLocalPort = usNewPort; } } ulArg = true; if ( ioctlsocket( g_NetworkSocket, FIONBIO, &ulArg ) == -1 ) printf( "network_AllocateSocket: ioctl FIONBIO: %s", strerror( errno )); // If we're not starting a server, setup a socket to listen for LAN servers. if ( bAllocateLANSocket ) { g_LANSocket = network_AllocateSocket( ); if ( network_BindSocketToPort( g_LANSocket, ulInAddr, DEFAULT_BROADCAST_PORT, true ) == false ) { sprintf( szString, "network_BindSocketToPort: Couldn't bind LAN socket to port: %d. You will not be able to see LAN servers in the browser.", DEFAULT_BROADCAST_PORT ); network_Error( szString ); // [BB] The socket won't work in this case, make sure not to use it. g_bLANSocketInvalid = true; } if ( ioctlsocket( g_LANSocket, FIONBIO, &ulArg ) == -1 ) printf( "network_AllocateSocket: ioctl FIONBIO: %s", strerror( errno )); } // Init our read buffer. // [BB] Vortex Cortex pointed us to the fact that the smallest huffman code is only 3 bits // and it turns into 8 bits when it's decompressed. Thus we need to allocate a buffer that // can hold the biggest possible size we may get after decompressing (aka Huffman decoding) // the incoming UDP packet. NETWORK_InitBuffer( &g_NetworkMessage, ((MAX_UDP_PACKET * 8) / 3 + 1), BUFFERTYPE_READ ); NETWORK_ClearBuffer( &g_NetworkMessage ); // [BB] Get and save our local IP. if ( ( ulInAddr == INADDR_ANY ) || ( pszIPAddress == NULL ) ) g_LocalAddress = NETWORK_GetLocalAddress( ); // [BB] We are using a specified IP, so we don't need to figure out what IP we have, but just use the specified one. else { NETWORK_StringToAddress ( pszIPAddress, &g_LocalAddress ); g_LocalAddress.usPort = htons ( NETWORK_GetLocalPort() ); } // Print out our local IP address. Printf( "IP address %s\n", NETWORK_AddressToString( g_LocalAddress )); // If hosting, update the server GUI. if( NETWORK_GetState() == NETSTATE_SERVER ) SERVERCONSOLE_UpdateIP( g_LocalAddress ); // [BB] Initialize the checksum of the non-map lumps that need to be authenticated when connecting a new player. std::vector<std::string> lumpsToAuthenticate; std::vector<LumpAuthenticationMode> lumpsToAuthenticateMode; lumpsToAuthenticate.push_back( "COLORMAP" ); lumpsToAuthenticateMode.push_back( LAST_LUMP ); lumpsToAuthenticate.push_back( "PLAYPAL" ); lumpsToAuthenticateMode.push_back( LAST_LUMP ); lumpsToAuthenticate.push_back( "HTICDEFS" ); lumpsToAuthenticateMode.push_back( ALL_LUMPS ); lumpsToAuthenticate.push_back( "HEXNDEFS" ); lumpsToAuthenticateMode.push_back( ALL_LUMPS ); lumpsToAuthenticate.push_back( "STRFDEFS" ); lumpsToAuthenticateMode.push_back( ALL_LUMPS ); lumpsToAuthenticate.push_back( "DOOMDEFS" ); lumpsToAuthenticateMode.push_back( ALL_LUMPS ); lumpsToAuthenticate.push_back( "GLDEFS" ); lumpsToAuthenticateMode.push_back( ALL_LUMPS ); lumpsToAuthenticate.push_back( "DECORATE" ); lumpsToAuthenticateMode.push_back( ALL_LUMPS ); lumpsToAuthenticate.push_back( "LOADACS" ); lumpsToAuthenticateMode.push_back( ALL_LUMPS ); lumpsToAuthenticate.push_back( "DEHACKED" ); lumpsToAuthenticateMode.push_back( ALL_LUMPS ); lumpsToAuthenticate.push_back( "GAMEMODE" ); lumpsToAuthenticateMode.push_back( ALL_LUMPS ); FString checksum, longChecksum; bool noProtectedLumpsAutoloaded = true; // [BB] All precompiled ACS libraries need to be authenticated. The only way to find all of them // at this point is to parse all LOADACS lumps. { int lump, lastlump = 0; while ((lump = Wads.FindLump ("LOADACS", &lastlump)) != -1) { FScanner sc(lump); while (sc.GetString()) { NETWORK_AddLumpForAuthentication ( Wads.CheckNumForName (sc.String, ns_acslibrary) ); } } } // [BB] First check the lumps that were marked for authentication while initializing. This // includes for example those lumps included by DECORATE lumps. It's much easier to mark those // lumps while the engine parses the DECORATE code than trying to find all included lumps from // the DECORATE lumps directly. for ( unsigned int i = 0; i < g_LumpNumsToAuthenticate.Size(); ++i ) { if ( !network_GenerateLumpMD5HashAndWarnIfNeeded( g_LumpNumsToAuthenticate[i], Wads.GetLumpFullName (g_LumpNumsToAuthenticate[i]), checksum ) ) noProtectedLumpsAutoloaded = false; longChecksum += checksum; } for ( unsigned int i = 0; i < lumpsToAuthenticate.size(); i++ ) { switch ( lumpsToAuthenticateMode[i] ){ case LAST_LUMP: int lump; lump = Wads.CheckNumForName(lumpsToAuthenticate[i].c_str()); // [BB] Possibly we find the COLORMAP lump only in the colormaps name space. if ( ( lump == -1 ) && ( lumpsToAuthenticate[i].compare ( "COLORMAP" ) == 0 ) ) lump = Wads.CheckNumForName("COLORMAP", ns_colormaps); if ( lump == -1 ) { Printf ( PRINT_BOLD, "Warning: Can't find lump %s for authentication!\n", lumpsToAuthenticate[i].c_str() ); continue; } if ( !network_GenerateLumpMD5HashAndWarnIfNeeded( lump, lumpsToAuthenticate[i].c_str(), checksum ) ) noProtectedLumpsAutoloaded = false; // [BB] To make Doom and Freedoom network compatible, substitue the Freedoom PLAYPAL/COLORMAP hash // by the corresponding Doom hash. // 4804c7f34b5285c334a7913dd98fae16 Doom PLAYPAL hash // 061a4c0f80aa8029f2c1bc12dc2e261e Doom COLORMAP hash // 2e01ae6258f2a0fdad32125537efe1af Freedoom PLAYPAL hash // bb535e66cae508e3833a5d2de974267b Freedoom COLORMAP hash if ( ( stricmp ( lumpsToAuthenticate[i].c_str(), "PLAYPAL" ) == 0 ) && ( stricmp ( checksum.GetChars(), "2e01ae6258f2a0fdad32125537efe1af" ) == 0 ) ) checksum = "4804c7f34b5285c334a7913dd98fae16"; else if ( ( stricmp ( lumpsToAuthenticate[i].c_str(), "COLORMAP" ) == 0 ) && ( stricmp ( checksum.GetChars(), "bb535e66cae508e3833a5d2de974267b" ) == 0 ) ) checksum = "061a4c0f80aa8029f2c1bc12dc2e261e"; longChecksum += checksum; break; case ALL_LUMPS: int workingLump, lastLump; lastLump = 0; while ((workingLump = Wads.FindLump(lumpsToAuthenticate[i].c_str(), &lastLump)) != -1) { if ( !network_GenerateLumpMD5HashAndWarnIfNeeded( workingLump, lumpsToAuthenticate[i].c_str(), checksum ) ) noProtectedLumpsAutoloaded = false; longChecksum += checksum; } break; } } CMD5Checksum::GetMD5( reinterpret_cast<const BYTE *>(longChecksum.GetChars()), longChecksum.Len(), g_lumpsAuthenticationChecksum ); // [BB] Warn the user about problematic auto-loaded files. if ( noProtectedLumpsAutoloaded == false ) { Printf ( PRINT_BOLD, "Warning: Above auto-loaded files contain protected lumps.\n" ); if ( Args->CheckParm( "-host" ) ) Printf ( PRINT_BOLD, "Clients without these files can't connect to this server.\n" ); else Printf ( PRINT_BOLD, "You can't connect to servers without these files.\n" ); } // [BB] Initialize the actor network class indices. for ( unsigned int i = 0; i < PClass::m_Types.Size(); i++ ) { PClass* cls = PClass::m_Types[i]; if ( (cls->IsDescendantOf(RUNTIME_CLASS(AActor))) // [BB] The server only binaries don't know DynamicLight and derived classes. && !(cls->IsDescendantOf(PClass::FindClass("DynamicLight"))) ) cls->ActorNetworkIndex = 1 + g_ActorNetworkIndexClassPointerMap.Push ( cls ); else cls->ActorNetworkIndex = 0; } // [RC/BB] Init the list of PWADs. network_InitPWADList( ); // Call NETWORK_Destruct() when Skulltag closes. atterm( NETWORK_Destruct ); Printf( "UDP Initialized.\n" ); }