/* ** Command & Conquer Generals Zero Hour(tm) ** Copyright 2025 Electronic Arts Inc. ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . */ #include #include #ifdef _WINDOWS #include // *MUST* be included before ANY Wnet/Wlib headers if _REENTRANT is defined #endif #include "mangler.h" #include "crc.h" #include #include "threadfac.h" #include "endian.h" #include "xtime.h" #include #include #include #include // ST - 2/1/01 12:46PM bool BigEndian = false; unsigned long ResolveIP(char *Server) { char serverName[100]; struct hostent *serverStruct; struct in_addr *serverNode; if (Server == NULL) { ERRMSG("Can't resolve NULL"); return 0; } if (isdigit(Server[0])) return ( ntohl(inet_addr(Server)) ); strcpy(serverName, Server); serverStruct = gethostbyname(Server); if (serverStruct == NULL) { ERRMSG("Can't resolve " << Server); return 0; } serverNode = (struct in_addr *) serverStruct->h_addr; return ( ntohl(serverNode->s_addr) ); } void DisplayHelp(const char *prog) { cout << "Usage: " << prog << " " << endl; exit(0); } int main(int argc, char **argv) { ConfigFile config; FILE* conf; if( argc <= 1 ) { // No args - use a default config file if ((conf = fopen("manglertest.cfg", "r")) == NULL) { cout << "Cannot open mangler.cfg for reading." << endl; DisplayHelp(argv[0]); } config.readFile(conf); fclose(conf); } else if( argc == 2 && (strcmp(argv[1], "help") == 0 || strcmp(argv[1], "?") == 0 || strcmp(argv[1], "-h") == 0) ) DisplayHelp(argv[0]); else if( argc == 2 ) { // Use a user-supplied config file if ((conf = fopen(argv[1], "r")) == NULL) { cout << "Cannot open " << argv[1] << " for reading." << endl; DisplayHelp(argv[0]); } config.readFile(conf); fclose(conf); } // ----- LOGGING ----- // Setup debugging & logging output Wstring output_file("manglertest.log"); config.getString("LOGFILE", output_file); Wstring backup_file; backup_file = output_file; backup_file += ".bak"; rename(output_file.get(),backup_file.get()); // save the old file FileD output_device(output_file.get()); MsgManager::setAllStreams(&output_device); DBGMSG("DBG working..."); INFMSG("INF working..."); WRNMSG("WRN working..."); // // See if our processor is big or little endian. Network order is big endian. // ST - 2/1/01 12:11PM // if (htonl(0x12345678) == 0x12345678) { BigEndian = true; } // ----- Initialize Winsock ----- #ifdef _WINDOWS WORD verReq = MAKEWORD(2, 2); WSADATA wsadata; int err = WSAStartup(verReq, &wsadata); if (err != 0) { ERRMSG("Winsock Init failed."); return 1; } if ((LOBYTE(wsadata.wVersion) != 2) || (HIBYTE(wsadata.wVersion) !=2)) { ERRMSG("Winsock DLL is not 2.2"); WSACleanup(); ERRMSG("Winsock Init failed."); return 1; } INFMSG("Winsock Init done."); #endif // Set up a UDP listener uint8 *buff=new uint8[1024]; int retval; UDP udp; int port = 4321; config.getInt("MANGLERPORT", port); int localport = 4444; config.getInt("CLIENTPORT", localport); retval = udp.Bind((uint32)0,(uint16)localport); DBGMSG("Bind returned " << retval); //----------------------------------------------------------------------------------------- const int packet_size = sizeof(ManglerData); INFMSG("sizeof(packet) == " << packet_size); unsigned char buf[packet_size]; memset(buf, 0x44, packet_size); // init to something known for memory dumps :) struct sockaddr_in addr; int doBlitz = 0; config.getInt("BLITZ", doBlitz); if (doBlitz) { INFMSG("Requsting port blitz"); } unsigned char *theAddr; fd_set fdset; unsigned long server_addr; Wstring manglername = "localhost"; config.getString("MANGLERIP", manglername); server_addr = ResolveIP(manglername.get()); if (!server_addr) { ERRMSG("Cannot resolve mangler server IP"); return 1; } ManglerData *packet = (ManglerData *)buf; packet->NetCommandType = 12; packet->packetID = 9999; packet->BlitzMe = doBlitz; packet->magic = htons((unsigned short)0xf00d); Build_Packet_CRC(buf, packet_size); DBGMSG("Writing to " << manglername.get() << ":" << port); udp.Write(buf,packet_size,server_addr, 4321); retval = udp.Wait(5, 0, fdset); if (retval) { DBGMSG("Wait returned " << retval); retval = udp.Read(buf, packet_size, &addr); // Wait until there is something on the socket if (retval > 0) { theAddr = (unsigned char *)&(addr.sin_addr.s_addr); if (retval != packet_size) { WRNMSG("Recieved mis-sized packet (" << retval << " bytes) from " << theAddr[0] << "." << theAddr[1] << "." << theAddr[2] << "." << theAddr[3] << ":" << addr.sin_port); } else { int packetCommand; packetCommand = packet->NetCommandType; if (!Passes_CRC_Check(buf, packet_size)) { WRNMSG("CRC error!"); } else if (packetCommand != 13) { WRNMSG("Returned packet had command type " << packetCommand); } else { int addr[4]; unsigned short retPort; retPort = htons(packet->MyMangledPortNumber); addr[0] = packet->MyMangledAddress[0]; addr[1] = packet->MyMangledAddress[1]; addr[2] = packet->MyMangledAddress[2]; addr[3] = packet->MyMangledAddress[3]; DBGMSG("Saw " << addr[0] << "." << addr[1] << "." << addr[2] << "." << addr[3] << ":" << retPort); } } } } else { DBGMSG("Wait timed out"); } return 0; }