#include #include "bool.h" #include "Flatline_Net.h" #include "Flatline_Win32.h" #include "Flatline_Client.h" #include "Mariusnet_Defs.h" #include "Daodan_Console.h" #include "Oni_Symbols.h" #include #include #pragma comment(lib, "wininet.lib") char MariusLogin[32]={0}; unsigned char MariusPassword[16]={0}; m_room RoomList[64] = {0}; bool RoomListGotten = 0; bool MariusNet_LoggedIn = 0; bool MsNet_Running = 0; int Marius_Socket = -1; int Room_Socket = -1; sockaddr_in RoomAddr = {0}; int PlayerID = 0; m_gameinfo StaticGameList[64] = {0}; enum { glAddGame, glRemoveGame, glUpdateGame, }; /* RGBA green = {0, 0xFF, 0, 0}; RGBA red = {0, 0, 0xFF, 0}; RGBA grey = {0x80,0x80,0x80,0x80}; */ extern RGBA red; //extern RGBA blue; RGBA blue = {0xFF, 0, 0, 0}; RGBA cyan = {0xFF, 0xFF, 0, 0}; RGBA white = {0xFF, 0xFF, 0xFF, 0}; extern RGBA green; extern RGBA grey; typedef struct { uint16_t x; uint16_t y; } IMtPoint2D; void* DrawInstance = 0; void MSNet_DrawGames() { if(!DrawInstance){ void* TSFFTahoma; TMrInstance_GetDataPtr( 'TSFF', "Tahoma", &TSFFTahoma); TSrContext_New( TSFFTahoma, 7, 1, 1, 0, &DrawInstance); } if(DrawInstance){ const int white = 0x00FFFFFF; const int green = 0x0000FF00; const int red = 0x00FF0000; const int blue = 0x000000FF; int i; char DrawString[255]; const int LineHeight = 15; IMtPoint2D StartLocation = {500, 20}; IMtPoint2D DrawLocation = StartLocation; TSrContext_SetShade(DrawInstance, white); TSrContext_DrawText(DrawInstance, "Mariusnet Games:", 255, 0, &DrawLocation); TSrContext_SetShade(DrawInstance, white); DrawLocation.y += LineHeight; for(i = 0; i < 64; i++) { if(StaticGameList[i].gameID) { DrawLocation.x = StartLocation.x - 10; sprintf(DrawString, "%i.", i ); TSrContext_DrawText(DrawInstance, DrawString, 255, 0, &DrawLocation); DrawLocation.x += 20; TSrContext_DrawText(DrawInstance, StaticGameList[i].g.Buffer, 255, 0, &DrawLocation); DrawLocation.y += LineHeight; } } } } int MariusNet_OutgoingPacketWrapper(int socket, const sockaddr* address, marius_packet* data, short datalen) { data->header.PacketSize = htonl(datalen); //NetUDPSocket_Send( socket, address, (char*)data, sizeof(marius_header) ); //datalen -= sizeof(marius_header); //(char*)data += sizeof(marius_header); return NetUDPSocket_Send( socket, address, (char*)data, datalen); } int PacketCached = 0; int MariusNet_IncomingPacketWrapper(int socket, char buffer[], int bufferlength, int flags) { int inSize = 0; unsigned fullSize = -1; static char cacheBuffer[1440] = {0}; bool NeedMoreData = 0; if(PacketCached) { unsigned int PacketSize = ntohl(((marius_packet*)cacheBuffer)->header.PacketSize); /* if(ntohs(((marius_packet*)cacheBuffer)->header.PacketSignature) != 0xDEAD) { PacketCached = PacketSize = 0; NeedMoreData = 1; } */ if(PacketCached >= PacketSize) { memcpy( buffer, cacheBuffer, PacketSize ); PacketCached -= PacketSize; } else { memcpy( buffer, cacheBuffer, PacketCached ); inSize += PacketCached; NeedMoreData = 1; PacketCached = 0; } if(PacketCached < 0) { DDrConsole_PrintF("Warning, took too much from cache"); PacketCached = 0; } else if (PacketCached > 0)// && ntohs((short*)(cacheBuffer + PacketSize)) == 0xDEAD) { memcpy( cacheBuffer, cacheBuffer + PacketSize, PacketCached ); } else { memset(cacheBuffer, 0, 1440); } if(!NeedMoreData) return PacketSize; } do { int tempSize = recv(socket, buffer + inSize, bufferlength, flags); if(tempSize == SOCKET_ERROR) { NetCatchError(); return SOCKET_ERROR; } if(fullSize == -1) { if(ntohs(((marius_packet*)buffer)->header.PacketSignature) != 0xDEAD) { DDrConsole_PrintF("Bad header signature...closing Mariusnet connection"); return SOCKET_ERROR; } fullSize = ntohl(((marius_packet*)buffer)->header.PacketSize); } inSize += tempSize; } while(inSize < fullSize); //double packet madness if(inSize > fullSize && ntohs(*(short*)(buffer + fullSize)) == 0xDEAD && ntohl(((marius_packet*)(buffer + fullSize))->header.PacketSize) > 0 && inSize - fullSize > sizeof(marius_header) ) { memcpy(cacheBuffer, buffer + fullSize, inSize - fullSize); PacketCached = inSize - fullSize; } else PacketCached = 0; return inSize; } sockaddr_in Marius_Server; bool MariusNet_Initialize() { hostent* host_info = 0; //host_info = gethostbyname("myth.mariusnet.com"); host_info = gethostbyname("metaserver.lhowon.org"); if(!host_info) { DDrConsole_PrintF("Error, could not resolve myth.mariusnet.com"); return 1; } Marius_Server.sin_port = htons(6321); Marius_Server.sin_family = AF_INET; Marius_Server.sin_addr.S_un.S_addr = *(ULONG*)host_info->h_addr_list[0]; return 0; } void Initialize_MPacket( marius_packet* packet, short ID ) { memset( packet, 0, sizeof(marius_packet) ); packet->header.PacketSignature = htons(0xDEAD); packet->header.PacketId = htons(ID); } void Initialize_LoginPacket( marius_packet* packet) { int NameSize = 0; int TeamSize = 0; char (*test)[] = packet; Initialize_MPacket(packet, pt_PlayerLogin); packet->login.UpdateAppearance = 1; packet->login.Platform = htons(1); strncpy(packet->login.LoginId, MariusLogin, 32); packet->login.EncryptionType = htons(1); strcpy(packet->login.AppName, "MARATHON" ); //ONI ;) strncpy(packet->login.BuildDate, __DATE__, 32 ); strncpy(packet->login.BuildTime, __TIME__, 32 ); packet->login.PlayerInfo.clientVersion = htons(5000); NameSize = sprintf(packet->login.PlayerInfo.Name, MariusLogin); //TeamSize = sprintf(packet->login.PlayerInfo.Name + NameSize, "TCTF") + 1; packet->login.PlayerInfoSize = htons(40 + NameSize + TeamSize); } char EncryptionTypes[][32] = { "Plaintext", "Braindead Simple", }; enum { SyntaxError, GamesNotAllowed, InvalidVersion, BadUserOrPassword, UserNotLoggedIn, BadMetaserverVersion, UserAlreadyLoggedIn, UnknownGameType, LoginSuccessful, LogoutSuccessful, PlayerNotInRoom, GameAlreadyExists, AccountAlreadyLoggedIn, RoomFull, AccountLocked, NotSupported }; static const char* sRoomNames[] = { "Crows Bridge", "Otter Ferry", "White Falls", "Silvermines", "Shoal", "Madrigal", "Tyr", "Ash", "Scales", "Covenant", "Muirthemne", "Seven Gates", "Bagrada", "The Barrier", "Forest Heart", "The Ermine", "The Dire Marsh", "The Highlands", "The Drowned Kingdom", "The Great Devoid", "Shiver", "The Caterthuns", "Soulblighter", "Balor", "Sons of Myrgard", "Heart of the Stone", "Arrival", "Ingue Ferroque", "Vimy Ridge", "Stilwell Road" }; void MSNet_LoginError_Output( int code ) { switch(code) { case(BadUserOrPassword): DDrConsole_PrintF( "Login denied: bad username or password." ); break; case(UserAlreadyLoggedIn): DDrConsole_PrintF( "Login denied: that user is already logged in."); break; case(AccountAlreadyLoggedIn): DDrConsole_PrintF( "Login denied: that account is already logged in."); break; case(RoomFull): DDrConsole_PrintF( "Login denied: room is full!?"); break; case(AccountLocked): DDrConsole_PrintF( "Login denied: your account is locked."); break; default: DDrConsole_PrintF("There was a problem connecting to the server" "that tracks Internet games. Please try again later."); break; } } void MSNet_HandleChat( m_message* msg ) { //BGRA *cough* /*RGBA chatcolor; chatcolor.R = (msg->PrimaryColor.Red); chatcolor.G = (msg->PrimaryColor.Green); chatcolor.B = (msg->PrimaryColor.Blue); chatcolor.A = 0;*/ char Message[1024]; int NameLen = sprintf_s( Message, 1024, "%s", msg->Message ) + 1; sprintf_s( Message, 1024 - NameLen, "%s: %s", Message, msg->Message + NameLen ); //DDrConsole_PrintColored( msg->Message, 0, chatcolor,white ); DDrConsole_Print(Message); } void MSNet_SendChat( char* msg ) { marius_packet mPacket = {0}; int len; if(!MsNet_Running || !MariusNet_LoggedIn) return; Initialize_MPacket(&mPacket, pt_ChatMessage); mPacket.message.SecondaryColor.Red = mPacket.message.SecondaryColor.Flags = -1; //mPacket.message.Message = 'Gumby'; len = sprintf(mPacket.message.Message, "O %s", msg ); mPacket.message.Message[1] = 0; mPacket.message.SenderId = htonl(PlayerID); //mPacket.message.TargetId = -1; MariusNet_OutgoingPacketWrapper(Room_Socket, (sockaddr*)&RoomAddr, (char*)&mPacket, sizeof(marius_header) + sizeof(m_message) - (255 - len) ); } void MSNet_RoomExit() { if(MariusNet_LoggedIn) { if( Room_Socket != -1) closesocket(Room_Socket); memset(StaticGameList, 0, sizeof(m_gameinfo) * 64); MsNet_Running = 0; MariusNet_LoggedIn = 0; } return; } int MSNet_Cleanup() { if( Marius_Socket != -1) closesocket(Marius_Socket); Marius_Socket = -1; if( Room_Socket != -1) closesocket(Room_Socket); Room_Socket = -1; memset(RoomList, 0, sizeof(m_room) * 64 ); memset(StaticGameList, 0, sizeof(m_gameinfo) * 64); DDrConsole_PrintF("The metaserver connection will now close." ); MsNet_Running = 0; MariusNet_LoggedIn = 0; return 1; } void MSNet_HandleGameList( m_gameinfo* PacketGames, int PacketSize ) { m_gameinfo TempGameList[64] = {0}; int i, k; for( i = 0; PacketSize > 0; i++ ) { int ThisSize = sizeof(m_gameinfo) + ntohs(PacketGames->len) - sizeof(m_gamedescription); memcpy(TempGameList + i,PacketGames, sizeof(m_gameinfo) - 128); sprintf_s( TempGameList[i].g.Buffer, 128, "%s", PacketGames->g.Buffer); PacketSize -= ThisSize; PacketGames = (m_gameinfo*)((char*)PacketGames + ThisSize); } for( i = 0; TempGameList[i].gameID; i++) { int DesiredID = 0; switch(TempGameList[i].verb) { case(glRemoveGame): //Remove game from list DDrConsole_PrintF("%s has ended", TempGameList[i].g.Buffer); for(k = 0; k < 64; k++) { if(TempGameList[i].gameID == StaticGameList[k].gameID) { memset(StaticGameList + k, 0, sizeof(m_gameinfo) ); break; } } break; case(glAddGame): //Add game to list DDrConsole_PrintF("%s has started", TempGameList[i].g.Buffer); case(glUpdateGame): //Update list //If updating, look for the game to update, otherwise look for empty if(TempGameList[i].verb) DesiredID = TempGameList[i].gameID; for(k = 0; k < 64; k++) { if(DesiredID == StaticGameList[k].gameID) { memcpy(StaticGameList + k, TempGameList + i, sizeof(m_gameinfo) ); break; } } break; break; } //TempGame } //Do stuff with the games. } int MSNet_CreateGame( m_announcegame* Game ) { marius_packet mPacket; Initialize_MPacket(&mPacket, 104); mPacket.newgame = *Game; MariusNet_OutgoingPacketWrapper(Room_Socket, (sockaddr*)&RoomAddr, (char*)&mPacket, sizeof(marius_header) + sizeof(m_announcegame)); } /* Initialize_MPacket(&mPacket, 104); mPacket.newgame.g.maxplayers = -1; mPacket.newgame.g.clientversion = htonl(0xc136e436); mPacket.newgame.g.maxteams = -1; //sprintf(mPacket.newgame.g.Buffer, "Oni!"); memcpy(mPacket.newgame.g.Buffer, "Blam!\0This is Oni, bitch.\0", 50); sent_bytes = MariusNet_OutgoingPacketWrapper(Room_Socket, (sockaddr*)&RoomAddr, (char*)&mPacket, sizeof(marius_header) + sizeof(m_announcegame) + 50); */ int MSNet_Room_Join( short Room, char* Key) { marius_packet mPacket = {0}; char incomingData[1400] = {0}; marius_packet* incomingPacket = (marius_packet*)incomingData; int sent_bytes = 0; sockaddr_in SockAddr; RoomAddr.sin_port = RoomList[Room].Port; RoomAddr.sin_family = AF_INET; RoomAddr.sin_addr.S_un.S_addr = RoomList[Room].IPAddress; Room_Socket = NetTCPSocket_Create(RoomList[Room].Port, &SockAddr); DDrConsole_PrintF("Joining room %hi", Room); if(Room_Socket == -1) { DDrConsole_PrintF("Failed to initialize room socket!"); return MSNet_Cleanup(); } if(connect( Room_Socket, (sockaddr *)&RoomAddr, sizeof(sockaddr_in))) { NetCatchError(); MariusNet_LoggedIn = 0; return MSNet_Cleanup(); } Initialize_MPacket(&mPacket, pt_ChatRoomLogin); memcpy(mPacket.chatroom_join.RoomKey, Key, 32); strcpy(mPacket.chatroom_join.Name, MariusLogin); sent_bytes = MariusNet_OutgoingPacketWrapper(Room_Socket, (sockaddr*)&RoomAddr, (char*)&mPacket, sizeof(marius_header) + 33 + strlen(MariusLogin)); Initialize_MPacket(&mPacket, pt_RoomPlayerInfo); mPacket.player_info.clientVersion = htons(5000); sprintf(mPacket.player_info.Name, MariusLogin); sent_bytes = MariusNet_OutgoingPacketWrapper(Room_Socket, (sockaddr*)&RoomAddr, (char*)&mPacket, sizeof(marius_header) + 40 + strlen(MariusLogin)); if(MariusNet_IncomingPacketWrapper(Room_Socket, incomingData, 1400, 0) == SOCKET_ERROR) { return MSNet_Cleanup(); } if(ntohs(incomingPacket->header.PacketId)== pt_LoginInfo) { //DDrConsole_PrintF("Login failed: %s", incomingPacket->login_denied.DenialMessage ); MSNet_LoginError_Output(ntohl(incomingPacket->login_denied.code)); return MSNet_Cleanup(); } MariusNet_LoggedIn = 1; while(1) { if(MariusNet_IncomingPacketWrapper(Room_Socket, incomingData, 1400, 0) == SOCKET_ERROR) { return 0; } switch(ntohs(incomingPacket->header.PacketId)) { case pt_RoomList: case pt_PlayerInfo: case pt_PlayerList: //Do nothing for now break; case pt_GameList: MSNet_HandleGameList( incomingPacket->gamelist.Games, ntohl(incomingPacket->header.PacketSize) - sizeof(marius_header)); break; case pt_BlueBarMsg: DDrConsole_PrintColored(incomingPacket->motd.Message, 0, cyan, grey ); break; case pt_ChatMessage: MSNet_HandleChat(&incomingPacket->message); break; case pt_KeepAlive: MariusNet_OutgoingPacketWrapper(Room_Socket, (sockaddr*)&RoomAddr, incomingData, sizeof(marius_header)); break; default: DDrConsole_PrintF("Got packet of type %hi", ntohs(incomingPacket->header.PacketId)); break; } } return 0; } DWORD WINAPI MSNet_Handler(void* unused) { int Port = 4156; char RoomToken[33] = {0}; int i = 0; sockaddr_in Marius_Addr = {0}; if(MsNet_Running) { DDrConsole_PrintF("The metaserver handler is already running!"); } MsNet_Running = 1; if(MariusNet_LoggedIn) { DDrConsole_PrintF("You're already logged in!"); return MSNet_Cleanup(); } NetPlatform_Initalize(); if(MariusNet_Initialize()) { return MSNet_Cleanup(); } //Horribly set up. while( (Marius_Socket == -1 || Marius_Socket == 0 )&& Port < 6641) { //Marius_Socket = NetTCPSocket_Create(Port, &Marius_Addr); //NetUDPSocket_Close( Marius_Socket ); Marius_Socket = NetTCPSocket_Create(Port, &Marius_Addr); //Port++; } if(Marius_Socket != -1) { unsigned char incomingData[1400] = {0}; short incomingLength = 0; marius_packet* incomingPacket = &incomingData; //Initialize marius_packet mPacket; int sent_bytes; Initialize_LoginPacket(&mPacket); DDrConsole_PrintF("Logging into Mariusnet <%s>...", inet_ntoa(Marius_Server.sin_addr)); if(connect( Marius_Socket, &Marius_Server, sizeof(sockaddr_in))) { NetCatchError(); return MSNet_Cleanup(); } DDrConsole_PrintF("Sending Player Info..."); sent_bytes = MariusNet_OutgoingPacketWrapper(Marius_Socket, (sockaddr*)&Marius_Server, (char*)&mPacket, sizeof(marius_header) + sizeof(m_player_login) - (sizeof(m_player_info) - ntohs(mPacket.login.PlayerInfoSize) ) ); /* if(!NetUDPSocket_Recieve(Marius_Socket, (sockaddr*)&Marius_Addr,incomingData, &incomingLength)) { DDrConsole_PrintF("Data: %s Length %i", incomingData, incomingLength); return 0; } */ if(MariusNet_IncomingPacketWrapper(Marius_Socket, incomingData, 1400, 0) == SOCKET_ERROR) { return MSNet_Cleanup(); } if(ntohs(incomingPacket->header.PacketId)== pt_EncryptionKey) { //recv( Marius_Socket, incomingData, 1440, 0); DDrConsole_PrintF("Encryption Type %s", EncryptionTypes[ntohs(incomingPacket->salt.EncryptionType)] ); Initialize_MPacket(&mPacket, pt_Password); if(incomingPacket->salt.EncryptionType) { unsigned char* Hash = mPacket.password.passHash; unsigned char* Salt = incomingPacket->salt.salt; unsigned char Pass[16] = {0}; memset(Pass, 0x23, 16); strcpy(Pass, MariusPassword ); for( i = 0; i < 16; i++ ) Hash[i] = Pass[i]^Salt[i]; for( i = 1; i < 16; i++ ) Hash[i] = Hash[i]^Hash[i-1]; for( i = 1; i < 16; i++ ) { short value = ~( Hash[i]*Hash[i-1] ); Hash[i] = (unsigned char) value; } } else { strncpy(mPacket.password.passHash, MariusPassword, 16); } DDrConsole_PrintF("Sending Password..."); sent_bytes = MariusNet_OutgoingPacketWrapper(Marius_Socket, (sockaddr*)&Marius_Server, (char*)&mPacket, sizeof(marius_header) + sizeof(m_password) ); if(!NetUDPSocket_Recieve(Marius_Socket, (sockaddr*)&Marius_Addr,incomingData, &incomingLength)) { return MSNet_Cleanup(); } DDrConsole_PrintF("Password ACK!"); if(ntohs(incomingPacket->header.PacketId)== pt_PasswordAck) { Initialize_MPacket(&mPacket, pt_Localization); mPacket.localization.one = htonl(1); mPacket.localization.two = htonl(2); mPacket.localization.three = htonl(3); mPacket.localization.zero = 0; sent_bytes = MariusNet_OutgoingPacketWrapper(Marius_Socket, (sockaddr*)&Marius_Server, (char*)&mPacket, sizeof(marius_header) + sizeof(m_localization) ); if(MariusNet_IncomingPacketWrapper(Marius_Socket, incomingData, 1400, 0) == SOCKET_ERROR) { return MSNet_Cleanup(); } } } if(ntohs(incomingPacket->header.PacketId)== pt_UserLoggedIn) { PlayerID = ntohl(incomingPacket->login_success.userID); //Not sure if this is a string or byte array, so I allocated 33 bytes, //so it always zero terminates. memcpy(RoomToken, incomingPacket->login_success.Token, 32); DDrConsole_PrintF("Logged into Mariusnet!"); strcpy_s( player_name, 32, MariusLogin ); } else if(ntohs(incomingPacket->header.PacketId)== pt_LoginInfo) { //DDrConsole_PrintF("Login failed: %s", incomingPacket->login_denied.DenialMessage ); MSNet_LoginError_Output(ntohl(incomingPacket->login_denied.code)); return MSNet_Cleanup(); } else { return MSNet_Cleanup(); } do { if(MariusNet_IncomingPacketWrapper(Marius_Socket, incomingData, 1400, 0) == SOCKET_ERROR) { return MSNet_Cleanup(); } if(ntohs(incomingPacket->header.PacketId)== pt_RoomList) { DDrConsole_PrintF("Got room list!"); RoomListGotten = 1; memcpy(RoomList, incomingPacket->roomlist.Rooms, ntohl(incomingPacket->header.PacketSize) - sizeof(marius_header)); } else if(ntohs(incomingPacket->header.PacketId)== pt_PlayerInfo) { //What do we do with this?! DDrConsole_PrintF("Got player info!"); } else { DDrConsole_PrintF("Invalid packet type %hi", ntohs(incomingPacket->header.PacketId)); return MSNet_Cleanup(); } } while(PacketCached || !RoomListGotten); for(i = 0; i < 64, RoomList[i].IPAddress != 0 ; i++) { int IP = ntohl(RoomList[i].IPAddress); DDrConsole_PrintF("Room %i %s IP %s Port %hi Players %hi", i, sRoomNames[ntohs(RoomList[i].RoomIndex)], inet_ntoa(*(in_addr*)&IP), ntohs(RoomList[i].Port), ntohs(RoomList[i].PlayerCount) ); } closesocket(Marius_Socket); MSNet_Room_Join( 0, RoomToken ); } return 0; } uint16_t ONICALL mnet_joingame(sl_callinfo* callinfo, uint32_t numargs, sl_arg args[], int* dontuse1, int* dontuse2, sl_arg* ret) { int index = args[0].value_int32; if(index >= 0) { FLcConnect(StaticGameList[index].ipAddress, StaticGameList[index].port); } return 0; } bool MSNet_Login(char* username, char* password) { sprintf_s(MariusLogin, 32, "%s", username); sprintf_s(MariusPassword, 16, "%s", password); CreateThread(NULL, 0, MSNet_Handler, NULL, 0, 0); return 0; }