]> git.netwichtig.de Git - user/henk/code/inspircd.git/blobdiff - win/inspircd_win32wrapper.cpp
Check in tag names too
[user/henk/code/inspircd.git] / win / inspircd_win32wrapper.cpp
index ad45bb0aec8a2b3a51a210697223bc584e296710..c32d31d5a2b81045387d0e8e6dbea6735bc976ca 100644 (file)
@@ -2,7 +2,7 @@
  *       | Inspire Internet Relay Chat Daemon |
  *       +------------------------------------+
  *
- *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ *  InspIRCd: (C) 2002-2008 InspIRCd Development Team
  * See: http://www.inspircd.org/wiki/index.php/Credits
  *
  * This program is free but copyrighted software; see
 
 #include "inspircd_win32wrapper.h"
 #include "inspircd.h"
+#include "configreader.h"
 #include <string>
 #include <errno.h>
 #include <assert.h>
+#pragma comment(lib, "winmm.lib")
 using namespace std;
 
 #ifndef INADDR_NONE
 #define INADDR_NONE 0xffffffff
 #endif
 
-HANDLE hIPCPipe;
+#include <mmsystem.h>
+
+/* This MUST remain static and delcared outside the class, so that WriteProcessMemory can reference it properly */
+static DWORD owner_processid = 0;
+
 
 int inet_aton(const char *cp, struct in_addr *addr)
 {
@@ -296,7 +302,6 @@ int getopt_long_only(int ___argc, char *const *___argv, const char *__shortopts,
                return -1;
 
        const char * opt = ___argv[arg_counter];
-       int return_val = 0;
 
        // if we're not an option, return an error.
        if (strnicmp(opt, "--", 2) != 0)
@@ -363,7 +368,7 @@ int getopt_long_only(int ___argc, char *const *___argv, const char *__shortopts,
 #define IPC_MESSAGE_DIE                2
 #define IPC_MESSAGE_RESTART    3
 
-void InitIPC()
+IPC::IPC(InspIRCd* Srv) : Instance(Srv)
 {
        static DWORD buflen = 1024;
        static const char * pipename = "\\\\.\\mailslot\\Inspircd";
@@ -372,7 +377,7 @@ void InitIPC()
                printf("IPC Pipe could not be created. Are you sure you didn't start InspIRCd twice?\n");
 }
 
-void CheckIPC(InspIRCd * Instance)
+void IPC::Check()
 {
        if (hIPCPipe == INVALID_HANDLE_VALUE)
                return;
@@ -384,14 +389,14 @@ void CheckIPC(InspIRCd * Instance)
        if (!res)
        {
                if (GetLastError() != ERROR_SEM_TIMEOUT)
-                       Instance->Log(DEFAULT, "IPC Pipe Error %u: %s", GetLastError(), dlerror());
+                       Instance->Logs->Log("win32",DEFAULT, "IPC Pipe Error %u: %s", GetLastError(), dlerror());
                return;
        }
 
        switch (action)
        {
                case IPC_MESSAGE_REHASH:
-                       Instance->Rehash(0);
+                       Instance->Rehash("due to IPC message");
                break;
                
                case IPC_MESSAGE_DIE:
@@ -404,7 +409,7 @@ void CheckIPC(InspIRCd * Instance)
        }
 }
 
-void CloseIPC()
+IPC::~IPC()
 {
        CloseHandle(hIPCPipe);
 }
@@ -511,3 +516,145 @@ void ClearConsole()
        }
        return;
 }
+
+/* Many inspircd classes contain function pointers/functors which can be changed to point at platform specific implementations
+ * of code. This function repoints these pointers and functors so that calls are windows specific.
+ */
+void ChangeWindowsSpecificPointers(InspIRCd* Instance)
+{
+       Instance->Logs->Log("win32",DEBUG,"Changing to windows specific pointer and functor set");
+       Instance->Config->DNSServerValidator = &ValidateWindowsDnsServer;
+}
+
+DWORD WindowsForkStart(InspIRCd* Instance)
+{
+        /* Windows implementation of fork() :P */
+       if (owner_processid)
+               return 0;
+
+        char module[MAX_PATH];
+        if(!GetModuleFileName(NULL, module, MAX_PATH))
+        {
+                printf("GetModuleFileName() failed.\n");
+                return false;
+        }
+
+        STARTUPINFO startupinfo;
+        PROCESS_INFORMATION procinfo;
+        ZeroMemory(&startupinfo, sizeof(STARTUPINFO));
+        ZeroMemory(&procinfo, sizeof(PROCESS_INFORMATION));
+
+        // Fill in the startup info struct
+        GetStartupInfo(&startupinfo);
+
+        /* Default creation flags create the processes suspended */
+        DWORD startupflags = CREATE_SUSPENDED;
+
+        /* On windows 2003/XP and above, we can use the value
+         * CREATE_PRESERVE_CODE_AUTHZ_LEVEL which gives more access
+         * to the process which we may require on these operating systems.
+         */
+        OSVERSIONINFO vi;
+        vi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+        GetVersionEx(&vi);
+        if ((vi.dwMajorVersion >= 5) && (vi.dwMinorVersion > 0))
+                startupflags |= CREATE_PRESERVE_CODE_AUTHZ_LEVEL;
+
+        // Launch our "forked" process.
+        BOOL bSuccess = CreateProcess ( module, // Module (exe) filename
+                strdup(GetCommandLine()),       // Command line (exe plus parameters from the OS)
+                                                // NOTE: We cannot return the direct value of the
+                                                // GetCommandLine function here, as the pointer is
+                                                // passed straight to the child process, and will be
+                                                // invalid once we exit as it goes out of context.
+                                                // strdup() seems ok, though.
+                0,                              // PROCESS_SECURITY_ATTRIBUTES
+                0,                              // THREAD_SECURITY_ATTRIBUTES
+                TRUE,                           // We went to inherit handles.
+                startupflags,                   // Allow us full access to the process and suspend it.
+                0,                              // ENVIRONMENT
+                0,                              // CURRENT_DIRECTORY
+                &startupinfo,                   // startup info
+                &procinfo);                     // process info
+
+        if(!bSuccess)
+        {
+                printf("CreateProcess() error: %s\n", dlerror());
+                return false;
+        }
+
+        // Set the owner process id in the target process.
+        SIZE_T written = 0;
+        DWORD pid = GetCurrentProcessId();
+        if(!WriteProcessMemory(procinfo.hProcess, &owner_processid, &pid, sizeof(DWORD), &written) || written != sizeof(DWORD))
+        {
+                printf("WriteProcessMemory() failed: %s\n", dlerror());
+                return false;
+        }
+
+        // Resume the other thread (let it start)
+        ResumeThread(procinfo.hThread);
+
+        // Wait for the new process to kill us. If there is some error, the new process will end and we will end up at the next line.
+        WaitForSingleObject(procinfo.hProcess, INFINITE);
+
+        // If we hit this it means startup failed, default to 14 if this fails.
+        DWORD ExitCode = 14;
+        GetExitCodeProcess(procinfo.hProcess, &ExitCode);
+        CloseHandle(procinfo.hThread);
+        CloseHandle(procinfo.hProcess);
+        return ExitCode;
+}
+
+void WindowsForkKillOwner(InspIRCd * Instance)
+{
+        HANDLE hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, owner_processid);
+        if(!hProcess || !owner_processid)
+        {
+                printf("Could not open process id %u: %s.\n", owner_processid, dlerror());
+                Instance->Exit(14);
+        }
+
+        // die die die
+        if(!TerminateProcess(hProcess, 0))
+        {
+                printf("Could not TerminateProcess(): %s\n", dlerror());
+                Instance->Exit(14);
+        }
+
+        CloseHandle(hProcess);
+}
+
+bool ValidateWindowsDnsServer(ServerConfig* conf, const char* tag, const char* value, ValueItem &data)
+{
+       if (!*(data.GetString()))
+       {
+               std::string nameserver;
+               conf->GetInstance()->Logs->Log("win32",DEFAULT,"WARNING: <dns:server> not defined, attempting to find working server in the registry...");
+               nameserver = FindNameServerWin();
+               /* Windows stacks multiple nameservers in one registry key, seperated by commas.
+                * Spotted by Cataclysm.
+                */
+               if (nameserver.find(',') != std::string::npos)
+                       nameserver = nameserver.substr(0, nameserver.find(','));
+               /* Just to be FUCKING AKWARD, windows fister... err i mean vista...
+                * seperates the nameservers with spaces instead.
+                */
+               if (nameserver.find(' ') != std::string::npos)
+                       nameserver = nameserver.substr(0, nameserver.find(' '));
+               data.Set(nameserver.c_str());
+               conf->GetInstance()->Logs->Log("win32",DEFAULT,"<dns:server> set to '%s' as first active resolver in registry.", nameserver.c_str());
+       }
+       return true;
+}
+
+int gettimeofday(struct timeval * tv, void * tz)
+{
+       if(tv == NULL)
+               return -1;
+
+       DWORD mstime = timeGetTime();
+       tv->tv_sec   = time(NULL);
+       tv->tv_usec  = (mstime - (tv->tv_sec * 1000)) * 1000;
+    return 0;  
+}