aboutsummaryrefslogtreecommitdiff
path: root/src/shm.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/shm.cc')
-rw-r--r--src/shm.cc385
1 files changed, 385 insertions, 0 deletions
diff --git a/src/shm.cc b/src/shm.cc
new file mode 100644
index 0000000..5cd4a52
--- /dev/null
+++ b/src/shm.cc
@@ -0,0 +1,385 @@
+#include "main.hh"
+
+// NOTE(fusion): This looks like an interface to external tools. Looking at the
+// `bin` directory this program was in, there are other programs that probably
+// use this interface to control certain aspects of the server. My previous
+// assumption that each connection was dispatched into its own process may not
+// be correct after all.
+
+struct TSharedMemory {
+ int Command;
+ char CommandBuffer[256];
+ uint32 RoundNr;
+ uint32 ObjectCounter;
+ uint32 Errors;
+ int PlayersOnline;
+ int NewbiesOnline;
+ int PrintBufferPosition;
+ char PrintBuffer[200][128];
+ GAMESTATE GameState;
+ pid_t GameThreadPID;
+};
+
+static TSharedMemory *SHM = NULL;
+static bool IsGameServer = false;
+static bool VerboseOutput = false;
+
+void StartGame(void){
+ if(SHM != NULL){
+ if(SHM->GameState == GAME_STARTING){
+ SHM->GameState = GAME_RUNNING;
+ }
+ }else{
+ error("StartGame: SharedMemory existiert nicht.\n");
+ }
+}
+
+void CloseGame(void){
+ if(SHM != NULL){
+ if(SHM->GameState == GAME_RUNNING){
+ SHM->GameState = GAME_CLOSING;
+ }
+ }else{
+ error("CloseGame: SharedMemory existiert nicht.\n");
+ }
+}
+
+void EndGame(void){
+ if(SHM != NULL){
+ SHM->GameState = GAME_ENDING;
+ }else{
+ error("EndGame: SharedMemory existiert nicht.\n");
+ }
+}
+
+bool LoginAllowed(void){
+ bool Result = false;
+ if(SHM != NULL){
+ Result = SHM->GameState == GAME_RUNNING;
+ }else{
+ error("IsLoginAllowed: SharedMemory existiert nicht.\n");
+ }
+ return Result;
+}
+
+bool GameRunning(void){
+ bool Result = false;
+ if(SHM != NULL){
+ Result = SHM->GameState == GAME_STARTING
+ || SHM->GameState == GAME_RUNNING
+ || SHM->GameState == GAME_CLOSING;
+ }else{
+ error("GameRunning: SharedMemory existiert nicht.\n");
+ }
+ return Result;
+}
+
+bool GameStarting(void){
+ bool Result = false;
+ if(SHM != NULL){
+ Result = SHM->GameState == GAME_STARTING;
+ }else{
+ error("GameStarting: SharedMemory existiert nicht.\n");
+ }
+ return Result;
+}
+
+bool GameEnding(void){
+ bool Result = false;
+ if(SHM != NULL){
+ Result = SHM->GameState == GAME_CLOSING
+ || SHM->GameState == GAME_ENDING;
+ }else{
+ error("GameEnding: SharedMemory existiert nicht.\n");
+ }
+ return Result;
+}
+
+pid_t GetGameThreadPID(void){
+ pid_t Pid = 0;
+ if(SHM != NULL){
+ Pid = SHM->GameThreadPID;
+ }
+ return Pid;
+}
+
+static void ErrorHandler(char *Text){
+ if(VerboseOutput){
+ printf("%s", Text);
+ }
+
+ if(SHM != NULL){
+ SHM->Errors += 1;
+ if(SHM->Errors <= 0x8000){
+ Log("error", Text);
+ if(SHM->Errors == 0x8000){
+ Log("error", "Zu viele Fehler. Keine weitere Protokollierung.\n");
+ }
+ }
+ }
+}
+
+static void PrintHandler(int Level, char *Text){
+ static Semaphore LogfileMutex(1);
+
+ if(Level > DebugLevel){
+ return;
+ }
+
+ if(VerboseOutput){
+ printf("%s", Text);
+ }
+
+ if(SHM != NULL){
+ // TODO(fusion): Does it even make sense to have this Semaphore here?
+ // It controls writes to the print buffer but reads outside this scope
+ // may be partial. But then, it doesn't seem like it is read anywhere
+ // else. Perhaps some external monitor tool, in which case do we even
+ // print from multiple threads?
+ LogfileMutex.down();
+ int Line = SHM->PrintBufferPosition;
+ char *Buffer = SHM->PrintBuffer[Line];
+ // TODO(fusion): Ughh...
+ strncpy(Buffer, Text, sizeof(SHM->PrintBuffer[0]) - 1);
+ Buffer[sizeof(SHM->PrintBuffer[0]) - 2] = 0;
+ if(Buffer[0] != 0){
+ usize TextLen = strlen(Buffer);
+ if(Buffer[TextLen - 1] != '\n'){
+ strcat(Buffer, "\n");
+ }
+ }
+ SHM->PrintBufferPosition = (Line + 1) % NARRAY(SHM->PrintBuffer);
+ LogfileMutex.up();
+ }
+}
+
+int GetPrintlogPosition(void){
+ int Result = 0;
+ if(SHM != NULL){
+ Result = SHM->PrintBufferPosition;
+ }
+ return Result;
+}
+
+char *GetPrintlogLine(int Line){
+ char *Result = NULL;
+ if(SHM != NULL && Line >= 0 && Line < NARRAY(SHM->PrintBuffer)){
+ Result = SHM->PrintBuffer[Line];
+ }
+ return Result;
+}
+
+void IncrementObjectCounter(void){
+ if(SHM != NULL){
+ SHM->ObjectCounter += 1;
+ }
+}
+
+void DecrementObjectCounter(void){
+ if(SHM != NULL){
+ SHM->ObjectCounter -= 1;
+ }
+}
+
+uint32 GetObjectCounter(void){
+ uint32 ObjectCounter = 0;
+ if(SHM != NULL){
+ ObjectCounter = SHM->ObjectCounter;
+ }
+ return ObjectCounter;
+}
+
+void IncrementPlayersOnline(void){
+ if(SHM != NULL){
+ SHM->PlayersOnline += 1;
+ }
+}
+
+void DecrementPlayersOnline(void){
+ if(SHM != NULL){
+ SHM->PlayersOnline -= 1;
+ }
+}
+
+int GetPlayersOnline(void){
+ int PlayersOnline = 0;
+ if(SHM != NULL){
+ PlayersOnline = SHM->PlayersOnline;
+ }
+ return PlayersOnline;
+}
+
+void IncrementNewbiesOnline(void){
+ if(SHM != NULL){
+ SHM->NewbiesOnline += 1;
+ }
+}
+
+void DecrementNewbiesOnline(void){
+ if(SHM != NULL){
+ SHM->NewbiesOnline -= 1;
+ }
+}
+
+int GetNewbiesOnline(void){
+ int NewbiesOnline = 0;
+ if(SHM != NULL){
+ NewbiesOnline = SHM->NewbiesOnline;
+ }
+ return NewbiesOnline;
+}
+
+void SetRoundNr(uint32 RoundNr){
+ if(SHM != NULL){
+ SHM->RoundNr = RoundNr;
+ }
+}
+
+uint32 GetRoundNr(void){
+ uint32 RoundNr = 0;
+ if(SHM != NULL){
+ RoundNr = SHM->RoundNr;
+ }
+ return RoundNr;
+}
+
+void SetCommand(int Command, char *Text){
+ if(SHM != NULL){
+ SHM->Command = Command;
+ if(Text == NULL){
+ SHM->CommandBuffer[0] = 0;
+ }else{
+ strncpy(SHM->CommandBuffer, sizeof(SHM->CommandBuffer), Text);
+ SHM->CommandBuffer[sizeof(SHM->CommandBuffer) - 1] = 0;
+ }
+ }
+}
+
+int GetCommand(void){
+ int Command = 0;
+ if(SHM != NULL){
+ Command = SHM->Command;
+ }
+ return Command;
+}
+
+char *GetCommandBuffer(void){
+ char *Buffer = NULL;
+ if(SHM != NULL && SHM->Command != 0){
+ Buffer = SHM->CommandBuffer;
+ }
+ return Buffer;
+}
+
+static bool DeleteSHM(void){
+ int SHMID = shmget(SHMKey, 0, 0);
+ if(SHMID == -1){
+ if(VerboseOutput){
+ puts("DeleteSHM: SharedMemory existiert nicht.");
+ }
+ return true;
+ }
+
+ if(shmctl(SHMID, IPC_RMID, NULL) == -1){
+ if(VerboseOutput){
+ // TODO(fusion): Include `errno` in the error message?
+ puts("DeleteSHM: Kann SharedMemory nicht löschen.");
+ }
+ return false;
+ }
+
+ return true;
+}
+
+static void CreateSHM(void){
+ bool Deleted = false;
+ while(true){
+ int SHMID = shmget(SHMKey, sizeof(TSharedMemory), IPC_CREAT | IPC_EXCL | 0777);
+ if(SHMID != -1){
+ return;
+ }
+
+ if(errno != EEXIST || Deleted){
+ if(VerboseOutput){
+ printf("CreateSHM: Kann SharedMemory nicht anlegen (Fehler %d).\n", errno);
+ }
+ throw "Cannot create SharedMemory";
+ }
+
+ if(!DeleteSHM()){
+ throw "Cannot delete SharedMemory";
+ }
+
+ Deleted = true;
+ }
+}
+
+static void AttachSHM(void){
+ int SHMID = shmget(SHMKey, sizeof(TSharedMemory), 0);
+ if(SHMID == -1){
+ if(VerboseOutput){
+ // TODO(fusion): Include `errno` in the error message?
+ puts("AttachSHM: Kann SharedMemory nicht fassen.");
+ }
+ SHM = NULL;
+ throw "Cannot get SharedMemory";
+ }
+
+ SHM = (TSharedMemory*)shmat(SHMID, NULL, 0);
+ if(SHM == (void*)-1){
+ if(VerboseOutput){
+ puts("AttachSHM: Kann SharedMemory nicht anbinden.");
+ }
+
+ SHM = NULL;
+ throw "Cannot attach SharedMemory";
+ }
+}
+
+static void DetachSHM(void){
+ if(SHM != NULL){
+ if(shmdt(SHM) == -1 && VerboseOutput){
+ puts("DetachSHM: Kann SharedMemory nicht löschen.");
+ }
+ SHM = NULL;
+ }
+}
+
+void InitSHM(bool Verbose){
+ IsGameServer = true;
+ VerboseOutput = Verbose;
+
+ CreateSHM();
+ AttachSHM();
+ SetErrorFunction(ErrorHandler);
+ SetPrintFunction(PrintHandler);
+
+ // NOTE(fusion): `CreateSHM` ensures a new shared memory segment is created
+ // and it should be always zero initialized as per the manual. Nevertheless
+ // the decompiled version was also clearing SHM, probably just in case.
+ memset(SHM, 0, sizeof(TSharedMemory));
+
+ strncpy(SHM->PrintBuffer[0], sizeof(SHM->PrintBuffer[0]),
+ "SHM initialized. System printing is working!\n");
+ SHM->PrintBuffer[0][sizeof(SHM->PrintBuffer[0]) - 1] = 0;
+
+ SHM->PrintBufferPosition = 1;
+ SHM->GameState = GAME_STARTING;
+ SHM->GameThreadPID = getpid();
+}
+
+void ExitSHM(void){
+ SetErrorFunction(NULL);
+ SetPrintFunction(NULL);
+ DetachSHM();
+ DeleteSHM();
+}
+
+void InitSHMExtern(bool Verbose){
+ VerboseOutput = Verbose;
+ AttachSHM();
+}
+
+void ExitSHMExtern(void){
+ DetachSHM();
+}