]> git.netwichtig.de Git - user/henk/code/inspircd.git/blobdiff - win/inspircd_win32wrapper.cpp
m_callerid Remove redundant includes
[user/henk/code/inspircd.git] / win / inspircd_win32wrapper.cpp
index 0af54a39c14744ff18d2334b69bd549985ef0bfb..43ca87240bff0f477cc4863fb1e73e4f12779a7b 100644 (file)
@@ -1,28 +1,55 @@
-/*       +------------------------------------+
- *       | Inspire Internet Relay Chat Daemon |
- *       +------------------------------------+
+/*
+ * InspIRCd -- Internet Relay Chat Daemon
  *
- *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
- * See: http://www.inspircd.org/wiki/index.php/Credits
+ *   Copyright (C) 2011 Adam <Adam@anope.org>
+ *   Copyright (C) 2007, 2009 Dennis Friis <peavey@inspircd.org>
+ *   Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org>
+ *   Copyright (C) 2007-2009 Craig Edwards <craigedwards@brainbox.cc>
+ *   Copyright (C) 2008 John Brooks <john.brooks@dereferenced.net>
+ *   Copyright (C) 2007 Burlex <???@???>
+ *   Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net>
  *
- * This program is free but copyrighted software; see
- *            the file COPYING for details.
+ * This file is part of InspIRCd.  InspIRCd 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, version 2.
  *
- * ---------------------------------------------------
+ * 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 <http://www.gnu.org/licenses/>.
  */
 
+
 #include "inspircd_win32wrapper.h"
 #include "inspircd.h"
+#include "configreader.h"
 #include <string>
 #include <errno.h>
 #include <assert.h>
+#define _WIN32_DCOM
+#include <comdef.h>
+#include <Wbemidl.h>
+
+#pragma comment(lib, "wbemuuid.lib")
+#pragma comment(lib, "comsuppwd.lib")
+#pragma comment(lib, "winmm.lib")
 using namespace std;
 
 #ifndef INADDR_NONE
 #define INADDR_NONE 0xffffffff
 #endif
 
-HANDLE hIPCPipe;
+#include <mmsystem.h>
+
+IWbemLocator *pLoc = NULL;
+IWbemServices *pSvc = NULL;
+
+/* 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)
 {
@@ -31,7 +58,7 @@ int inet_aton(const char *cp, struct in_addr *addr)
        return (addr->s_addr == INADDR_NONE) ? 0 : 1;
 }
 
-const char *inet_ntop(int af, const void *src, char *dst, socklen_t cnt)
+const char *insp_inet_ntop(int af, const void *src, char *dst, socklen_t cnt)
 {
 
        if (af == AF_INET)
@@ -60,7 +87,7 @@ int geteuid()
        return 1;
 }
 
-int inet_pton(int af, const char *src, void *dst)
+int insp_inet_pton(int af, const char *src, void *dst)
 {
        sockaddr_in sa;
        int len = sizeof(SOCKADDR);
@@ -76,71 +103,6 @@ int inet_pton(int af, const char *src, void *dst)
        return rv;
 }
 
-char * strtok_r(char *_String, const char *_Control, char **_Context)
-{
-       unsigned char *str;
-       const unsigned char *ctl = (const unsigned char*)_Control;
-       unsigned char map[32];
-
-       if (_Context == 0 || !_Control)
-               return 0;
-
-       if (!(_String != NULL || *_Context != NULL))
-               return 0;
-
-       memset(map, 0, 32);
-
-       do {
-               map[*ctl >> 3] |= (1 << (*ctl & 7));
-       } while (*ctl++);
-
-       /* If string is NULL, set str to the saved
-       * pointer (i.e., continue breaking tokens out of the string
-       * from the last strtok call) */
-       if (_String != NULL)
-       {
-               str = (unsigned char*)_String;
-       }
-       else
-       {
-               str = (unsigned char*)*_Context;
-       }
-
-       /* Find beginning of token (skip over leading delimiters). Note that
-       * there is no token iff this loop sets str to point to the terminal
-       * null (*str == 0) */
-       while ((map[*str >> 3] & (1 << (*str & 7))) && *str != 0)
-       {
-               str++;
-       }
-
-       _String = (char*)str;
-
-       /* Find the end of the token. If it is not the end of the string,
-       * put a null there. */
-       for ( ; *str != 0 ; str++ )
-       {
-               if (map[*str >> 3] & (1 << (*str & 7)))
-               {
-                       *str++ = 0;
-                       break;
-               }
-       }
-
-       /* Update context */
-       *_Context = (char*)str;
-
-       /* Determine if a token has been found. */
-       if (_String == (char*)str)
-       {
-               return NULL;
-       }
-       else
-       {
-               return _String;
-       }
-}
-
 void setcolor(int color_code)
 {
        SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), color_code);
@@ -197,17 +159,106 @@ const char * dlerror()
        return errormessage;
 }
 
-int arg_counter = 1;
+#define TRED FOREGROUND_RED | FOREGROUND_INTENSITY
+#define TGREEN FOREGROUND_GREEN | FOREGROUND_INTENSITY
+#define TYELLOW FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY
+#define TNORMAL FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE
+#define TWHITE TNORMAL | FOREGROUND_INTENSITY
+#define TBLUE FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_INTENSITY
+
+/* Handles colors in printf */
+int printf_c(const char * format, ...)
+{
+       // Better hope we're not multithreaded, otherwise we'll have chickens crossing the road other side to get the to :P
+       static char message[MAXBUF];
+       static char temp[MAXBUF];
+       int color1, color2;
+
+       /* parse arguments */
+       va_list ap;
+       va_start(ap, format);
+       vsnprintf(message, 500, format, ap);
+       va_end(ap);
+
+       /* search for unix-style escape sequences */
+       int t;
+       int c = 0;
+       const char * p = message;
+       while (*p != 0)
+       {
+               if (*p == '\033')
+               {
+                       // Escape sequence -> copy into the temp buffer, and parse the color.
+                       p++;
+                       t = 0;
+                       while ((*p) && (*p != 'm'))
+                       {
+                               temp[t++] = *p;
+                               ++p;
+                       }
+
+                       temp[t] = 0;
+                       p++;
+
+                       if (*temp == '[')
+                       {
+                               if (sscanf(temp, "[%u;%u", &color1, &color2) == 2)
+                               {
+                                       switch(color2)
+                                       {
+                                       case 32:                // Green
+                                               SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_GREEN | FOREGROUND_INTENSITY);              // Yellow
+                                               break;
+
+                                       default:                // Unknown
+                                               // White
+                                               SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY);
+                                               break;
+                                       }
+                               }
+                               else
+                               {
+                                       switch (*(temp+1))
+                                       {
+                                               case '0':
+                                                       // Returning to normal colour.
+                                                       SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
+                                                       break;
+
+                                               case '1':
+                                                       // White
+                                                       SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), TWHITE);
+                                                       break;
+
+                                               default:
+                                                       char message[50];
+                                                       sprintf(message, "Unknown color code: %s", temp);
+                                                       MessageBox(0, message, message, MB_OK);
+                                                       break;
+                                       }
+                               }
+                       }
+               }
+
+               putchar(*p);
+               ++c;
+               ++p;
+       }
+
+       return c;
+}
+
+int optind = 1;
 char optarg[514];
-int getopt_long_only(int ___argc, char *const *___argv, const char *__shortopts, const struct option *__longopts, int *__longind)
+int getopt_long(int ___argc, char *const *___argv, const char *__shortopts, const struct option *__longopts, int *__longind)
 {
        // burlex todo: handle the shortops, at the moment it only works with longopts.
 
-       if (___argc == 1 || arg_counter == ___argc)                     // No arguments (apart from filename)
+       if (___argc == 1 || optind == ___argc)                  // No arguments (apart from filename)
                return -1;
 
-       const char * opt = ___argv[arg_counter];
-       int return_val = 0;
+       const char * opt = ___argv[optind];
+       optind++;
 
        // if we're not an option, return an error.
        if (strnicmp(opt, "--", 2) != 0)
@@ -224,18 +275,18 @@ int getopt_long_only(int ___argc, char *const *___argv, const char *__shortopts,
                {
                        // woot, found a valid argument =)
                        char * par = 0;
-                       if ((arg_counter + 1) != ___argc)
+                       if ((optind) != ___argc)
                        {
                                // grab the parameter from the next argument (if its not another argument)
-                               if (strnicmp(___argv[arg_counter+1], "--", 2) != 0)
+                               if (strnicmp(___argv[optind], "--", 2) != 0)
                                {
-                                       arg_counter++;          // Trash this next argument, we won't be needing it.
-                                       par = ___argv[arg_counter];
+//                                     optind++;               // Trash this next argument, we won't be needing it.
+                                       par = ___argv[optind-1];
                                }
                        }                       
 
                        // increment the argument for next time
-                       arg_counter++;
+//                     optind++;
 
                        // determine action based on type
                        if (__longopts[i].has_arg == required_argument && !par)
@@ -269,58 +320,6 @@ int getopt_long_only(int ___argc, char *const *___argv, const char *__shortopts,
        return 1;
 }
 
-/* IPC Messages */
-#define IPC_MESSAGE_REHASH     1
-#define IPC_MESSAGE_DIE                2
-#define IPC_MESSAGE_RESTART    3
-
-void InitIPC()
-{
-       static DWORD buflen = 1024;
-       static const char * pipename = "\\\\.\\mailslot\\Inspircd";
-       hIPCPipe = CreateMailslot(pipename, buflen, 0, 0);
-       if (hIPCPipe == INVALID_HANDLE_VALUE)
-               printf("IPC Pipe could not be created. Are you sure you didn't start InspIRCd twice?\n");
-}
-
-void CheckIPC(InspIRCd * Instance)
-{
-       if (hIPCPipe == INVALID_HANDLE_VALUE)
-               return;
-
-       DWORD bytes;
-       DWORD action;
-
-       BOOL res = ReadFile(hIPCPipe, &action, sizeof(DWORD), &bytes, 0);
-       if (!res)
-       {
-               if (GetLastError() != ERROR_SEM_TIMEOUT)
-                       Instance->Log(DEFAULT, "IPC Pipe Error %u: %s", GetLastError(), dlerror());
-               return;
-       }
-
-       switch (action)
-       {
-               case IPC_MESSAGE_REHASH:
-                       InspIRCd::Rehash(0);
-               break;
-               
-               case IPC_MESSAGE_DIE:
-                       InspIRCd::Exit(0);
-               break;
-
-               case IPC_MESSAGE_RESTART:
-                       Instance->Restart("IPC_MESSAGE_RESTART received by mailslot.");
-               break;
-       }
-}
-
-void CloseIPC()
-{
-       CloseHandle(hIPCPipe);
-}
-
-
 /* These three functions were created from looking at how ares does it
  * (...and they look far tidier in C++)
  */
@@ -367,7 +366,7 @@ bool GetInterface(HKEY regkey, const char *key, char* &output)
 
 std::string FindNameServerWin()
 {
-       std::string returnval = "127.0.0.1";
+       std::string returnval;
        HKEY top, key;
        char* dns = NULL;
 
@@ -422,3 +421,344 @@ 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()
+{
+       ServerInstance->Logs->Log("win32",DEBUG,"Changing to windows specific pointer and functor set");
+}
+
+DWORD WindowsForkStart()
+{
+        /* 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()
+{
+        HANDLE hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, owner_processid);
+        if(!hProcess || !owner_processid)
+        {
+                printf("Could not open process id %u: %s.\n", owner_processid, dlerror());
+                ServerInstance->Exit(14);
+        }
+
+        // die die die
+        if(!TerminateProcess(hProcess, 0))
+        {
+                printf("Could not TerminateProcess(): %s\n", dlerror());
+                ServerInstance->Exit(14);
+        }
+
+        CloseHandle(hProcess);
+}
+
+void FindDNS(std::string& server)
+{
+       if (!server.empty())
+               return;
+
+       ServerInstance->Logs->Log("CONFIG",DEFAULT,"WARNING: <dns:server> not defined, attempting to find working server in the registry...");
+       std::string nameserver = FindNameServerWin();
+
+       /* If empty use default to 127.0.0.1 */
+       if (nameserver.empty())
+       {
+               ServerInstance->Logs->Log("CONFIG",DEFAULT,"No viable nameserver found in registry! Defaulting to nameserver '127.0.0.1'!");
+               server = "127.0.0.1";
+               return;
+       }
+
+       /* 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(' '));
+
+       server = nameserver;
+       ServerInstance->Logs->Log("CONFIG",DEFAULT,"<dns:server> set to '%s' as first active resolver in registry.", nameserver.c_str());
+}
+
+int clock_gettime(int clock, struct timespec * tv)
+{
+       if(tv == NULL)
+               return -1;
+
+       DWORD mstime = timeGetTime();
+       tv->tv_sec   = time(NULL);
+       tv->tv_nsec  = (mstime - (tv->tv_sec * 1000)) * 1000000;
+       return 0;       
+}
+
+/* Initialise WMI. Microsoft have the silliest ideas about easy ways to
+ * obtain the CPU percentage of a running process!
+ * The whole API for this uses evil DCOM and is entirely unicode, giving
+ * all results and accepting queries as wide strings.
+ */
+bool initwmi()
+{
+       HRESULT hres;
+
+       /* Initialise COM. This can kill babies. */
+       hres =  CoInitializeEx(0, COINIT_MULTITHREADED); 
+       if (FAILED(hres))
+               return false;
+
+       /* COM security. This stuff kills kittens */
+       hres =  CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_DEFAULT,
+               RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, NULL);
+
+       if (FAILED(hres))
+       {
+               CoUninitialize();
+               return false;
+       }
+    
+       /* Instance to COM object */
+       pLoc = NULL;
+       hres = CoCreateInstance(CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID*)&pLoc);
+       if (FAILED(hres))
+       {
+               CoUninitialize();
+               return false;
+       }
+
+       pSvc = NULL;
+
+       /* Connect to DCOM server */
+       hres = pLoc->ConnectServer(_bstr_t(L"ROOT\\CIMV2"), NULL, NULL, 0, NULL, 0, 0, &pSvc);
+    
+       /* That didn't work, maybe no kittens found to kill? */
+       if (FAILED(hres))
+       {
+               pLoc->Release();
+               CoUninitialize();
+               return false;
+       }
+
+       /* Don't even ASK what this does. I'm still not too sure myself. */
+       hres = CoSetProxyBlanket(pSvc, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL, RPC_C_AUTHN_LEVEL_CALL,
+               RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE);
+
+       if (FAILED(hres))
+       {
+               pSvc->Release();
+               pLoc->Release();     
+               CoUninitialize();
+               return false;
+       }
+       return true;
+}
+
+void donewmi()
+{
+       pSvc->Release();
+       pLoc->Release();
+       CoUninitialize();
+}
+
+/* Return the CPU usage in percent of this process */
+int getcpu()
+{
+       HRESULT hres;
+       int cpu = -1;
+
+       /* Use WQL, similar to SQL, to construct a query that lists the cpu usage and pid of all processes */
+       IEnumWbemClassObject* pEnumerator = NULL;
+
+       BSTR Language = SysAllocString(L"WQL");
+       BSTR Query    = SysAllocString(L"Select PercentProcessorTime,IDProcess from Win32_PerfFormattedData_PerfProc_Process");
+
+       hres = pSvc->ExecQuery(Language, Query, WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, NULL, &pEnumerator);
+
+       /* Query didn't work */
+       if (!FAILED(hres))
+       {
+               IWbemClassObject *pclsObj = NULL;
+               ULONG uReturn = 0;
+
+               /* Iterate the query results */
+               while (pEnumerator)
+               {
+                       VARIANT vtProp;
+                       VariantInit(&vtProp);
+                       /* Next item */
+                       HRESULT hr = pEnumerator->Next(WBEM_INFINITE, 1, &pclsObj, &uReturn);
+
+                       /* No more items left */
+                       if (uReturn == 0)
+                               break;
+
+                       /* Find process ID */
+                       hr = pclsObj->Get(L"IDProcess", 0, &vtProp, 0, 0);
+                       if (!FAILED(hr))
+                       {
+                               /* Matches our process ID? */
+                               UINT pid = vtProp.uintVal;
+                               VariantClear(&vtProp);
+                               if (pid == GetCurrentProcessId())
+                               {                                       
+                                       /* Get CPU percentage for this process */
+                                       hr = pclsObj->Get(L"PercentProcessorTime", 0, &vtProp, 0, 0);
+                                       if (!FAILED(hr))
+                                       {
+                                               /* Deal with wide string ickyness. Who in their right
+                                                * mind puts a number in a bstrVal wide string item?!
+                                                */
+                                               cpu = 0;
+                                               std::wstringstream out(vtProp.bstrVal);
+                                               out >> cpu;
+                                               VariantClear(&vtProp);
+                                       }
+                                       pclsObj->Release();
+                                       break;
+                               }
+                               pclsObj->Release();
+                       }
+               }
+
+               pEnumerator->Release();
+       }
+
+       SysFreeString(Language);
+       SysFreeString(Query);
+
+       return cpu;
+}
+
+int random()
+{
+       return rand();
+}
+
+void srandom(unsigned int seed)
+{
+       srand(seed);
+}
+
+int gettimeofday(timeval *tv, void *)
+{
+       SYSTEMTIME st;
+       GetSystemTime(&st);
+
+       tv->tv_sec = time(NULL);
+       tv->tv_usec = st.wMilliseconds;
+
+       return 0;
+}
+
+/* World's largest hack to make reference<> work */
+#include "../src/modules/m_spanningtree/link.h"
+#include "../src/modules/ssl.h"
+static void unused_function()
+{
+       reference<Link> unused_Link;
+       reference<Autoconnect> unused_Autoconnect;
+       reference<ssl_cert> unused_Cert;
+
+       if (unused_Link)
+               unused_Link->Port = -1;
+       if (unused_Autoconnect)
+               unused_Autoconnect->NextConnectTime = -1;
+       if (unused_Cert)
+               unused_Cert->dn = "";
+
+       Autoconnect *a = unused_Autoconnect;
+       Link *l = unused_Link;
+       ssl_cert *s = unused_Cert;
+
+       unused_Link = reference<Link>(unused_Link);
+       unused_Autoconnect = reference<Autoconnect>(unused_Autoconnect);
+       unused_Cert = reference<ssl_cert>(unused_Cert);
+
+       unused_Link = reference<Link>(l);
+       unused_Autoconnect = reference<Autoconnect>(a);
+       unused_Cert = reference<ssl_cert>(s);
+
+       delete unused_Link;
+       delete unused_Autoconnect;
+       delete unused_Cert;
+}