]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - win/inspircd_win32wrapper.cpp
* Changed forking code, now the parent will attempt to retrieve the exit code of...
[user/henk/code/inspircd.git] / win / inspircd_win32wrapper.cpp
1 /*       +------------------------------------+\r
2  *       | Inspire Internet Relay Chat Daemon |\r
3  *       +------------------------------------+\r
4  *\r
5  *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r
6  * See: http://www.inspircd.org/wiki/index.php/Credits\r
7  *\r
8  * This program is free but copyrighted software; see\r
9  *            the file COPYING for details.\r
10  *\r
11  * ---------------------------------------------------\r
12  */\r
13 \r
14 #include "inspircd_win32wrapper.h"\r
15 #include "inspircd.h"\r
16 #include <string>\r
17 #include <errno.h>\r
18 #include <assert.h>\r
19 using namespace std;\r
20 \r
21 #ifndef INADDR_NONE\r
22 #define INADDR_NONE 0xffffffff\r
23 #endif\r
24 \r
25 HANDLE hIPCPipe;\r
26 \r
27 int inet_aton(const char *cp, struct in_addr *addr)\r
28 {\r
29         unsigned long ip = inet_addr(cp);\r
30         addr->s_addr = ip;\r
31         return (addr->s_addr == INADDR_NONE) ? 0 : 1;\r
32 }\r
33 \r
34 const char *inet_ntop(int af, const void *src, char *dst, socklen_t cnt)\r
35 {\r
36 \r
37         if (af == AF_INET)\r
38         {\r
39                 struct sockaddr_in in;\r
40                 memset(&in, 0, sizeof(in));\r
41                 in.sin_family = AF_INET;\r
42                 memcpy(&in.sin_addr, src, sizeof(struct in_addr));\r
43                 getnameinfo((struct sockaddr *)&in, sizeof(struct sockaddr_in), dst, cnt, NULL, 0, NI_NUMERICHOST);\r
44                 return dst;\r
45         }\r
46         else if (af == AF_INET6)\r
47         {\r
48                 struct sockaddr_in6 in;\r
49                 memset(&in, 0, sizeof(in));\r
50                 in.sin6_family = AF_INET6;\r
51                 memcpy(&in.sin6_addr, src, sizeof(struct in_addr6));\r
52                 getnameinfo((struct sockaddr *)&in, sizeof(struct sockaddr_in6), dst, cnt, NULL, 0, NI_NUMERICHOST);\r
53                 return dst;\r
54         }\r
55         return NULL;\r
56 }\r
57 \r
58 int geteuid()\r
59 {\r
60         return 1;\r
61 }\r
62 \r
63 int inet_pton(int af, const char *src, void *dst)\r
64 {\r
65         sockaddr_in sa;\r
66         int len = sizeof(SOCKADDR);\r
67         int rv = WSAStringToAddress((LPSTR)src, af, NULL, (LPSOCKADDR)&sa, &len);\r
68         memcpy(dst, &sa.sin_addr, sizeof(struct in_addr));\r
69         return rv;\r
70 }\r
71 \r
72 char * strtok_r(char *_String, const char *_Control, char **_Context)\r
73 {\r
74         unsigned char *str;\r
75         const unsigned char *ctl = (const unsigned char*)_Control;\r
76         unsigned char map[32];\r
77 \r
78         if (_Context == 0 || !_Control)\r
79                 return 0;\r
80 \r
81         if (!(_String != NULL || *_Context != NULL))\r
82                 return 0;\r
83 \r
84         memset(map, 0, 32);\r
85 \r
86         do {\r
87                 map[*ctl >> 3] |= (1 << (*ctl & 7));\r
88         } while (*ctl++);\r
89 \r
90         /* If string is NULL, set str to the saved\r
91         * pointer (i.e., continue breaking tokens out of the string\r
92         * from the last strtok call) */\r
93         if (_String != NULL)\r
94         {\r
95                 str = (unsigned char*)_String;\r
96         }\r
97         else\r
98         {\r
99                 str = (unsigned char*)*_Context;\r
100         }\r
101 \r
102         /* Find beginning of token (skip over leading delimiters). Note that\r
103         * there is no token iff this loop sets str to point to the terminal\r
104         * null (*str == 0) */\r
105         while ((map[*str >> 3] & (1 << (*str & 7))) && *str != 0)\r
106         {\r
107                 str++;\r
108         }\r
109 \r
110         _String = (char*)str;\r
111 \r
112         /* Find the end of the token. If it is not the end of the string,\r
113         * put a null there. */\r
114         for ( ; *str != 0 ; str++ )\r
115         {\r
116                 if (map[*str >> 3] & (1 << (*str & 7)))\r
117                 {\r
118                         *str++ = 0;\r
119                         break;\r
120                 }\r
121         }\r
122 \r
123         /* Update context */\r
124         *_Context = (char*)str;\r
125 \r
126         /* Determine if a token has been found. */\r
127         if (_String == (char*)str)\r
128         {\r
129                 return NULL;\r
130         }\r
131         else\r
132         {\r
133                 return _String;\r
134         }\r
135 }\r
136 \r
137 void setcolor(int color_code)\r
138 {\r
139         SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), color_code);\r
140 }\r
141 \r
142 DIR * opendir(const char * path)\r
143 {\r
144         std::string search_path = string(path) + "\\*.*";\r
145         WIN32_FIND_DATA fd;\r
146         HANDLE f = FindFirstFile(search_path.c_str(), &fd);\r
147         if (f != INVALID_HANDLE_VALUE)\r
148         {\r
149                 DIR * d = new DIR;\r
150                 memcpy(&d->find_data, &fd, sizeof(WIN32_FIND_DATA));\r
151                 d->find_handle = f;\r
152                 d->first = true;\r
153                 return d;\r
154         }\r
155         else\r
156         {\r
157                 return 0;\r
158         }\r
159 }\r
160 \r
161 dirent * readdir(DIR * handle)\r
162 {\r
163         if (handle->first)\r
164                 handle->first = false;\r
165         else\r
166         {\r
167                 if (!FindNextFile(handle->find_handle, &handle->find_data))\r
168                         return 0;\r
169         }\r
170 \r
171         strncpy(handle->dirent_pointer.d_name, handle->find_data.cFileName, MAX_PATH);\r
172         return &handle->dirent_pointer;\r
173 }\r
174 \r
175 void closedir(DIR * handle)\r
176 {\r
177         FindClose(handle->find_handle);\r
178         delete handle;\r
179 }\r
180 \r
181 const char * dlerror()\r
182 {\r
183         static char errormessage[500];\r
184         DWORD error = GetLastError();\r
185         SetLastError(0);\r
186         if (error == 0)\r
187                 return 0;\r
188 \r
189         FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, 0, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)errormessage, 500, 0);\r
190         return errormessage;\r
191 }\r
192 \r
193 int printf_c(const char * format, ...)\r
194 {\r
195         // Better hope we're not multithreaded, otherwise we'll have chickens crossing the road other side to get the to :P\r
196         static char message[500];\r
197         static char temp[10];\r
198         int color1, color2;\r
199         \r
200         /* parse arguments */\r
201         va_list ap;\r
202         va_start(ap, format);\r
203         vsnprintf(message, 500, format, ap);\r
204         va_end(ap);\r
205 \r
206         /* search for unix-style escape sequences */\r
207         int t;\r
208         int c = 0;\r
209         const char * p = message;\r
210         while(*p != 0)\r
211         {\r
212                 if (*p == '\033')\r
213                 {\r
214                         // Escape sequence -> copy into the temp buffer, and parse the color.\r
215                         p++;\r
216                         t = 0;\r
217                         while(*p != 'm')\r
218                         {\r
219                                 temp[t++] = *p;\r
220                                 ++p;\r
221                         }\r
222                         \r
223                         temp[t] = 0;\r
224                         p++;\r
225                         if (!_stricmp(temp, "[0"))\r
226                         {\r
227                                 // Returning to normal colour.\r
228                                 SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);\r
229                         }\r
230                         else if (sscanf(temp, "[%u;%u", &color1, &color2) == 2)\r
231                         {\r
232                                 switch(color2)\r
233                                 {\r
234                                         case 32:                // Green\r
235                                                 SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_GREEN | FOREGROUND_INTENSITY);\r
236                                         break;\r
237         \r
238                                         default:                // Unknown\r
239                                                 SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY);\r
240                                         break;\r
241                                 }\r
242                         }\r
243                         else\r
244                         {\r
245                                 char message[50];\r
246                                 sprintf("Unknown color code: %s", temp);\r
247                                 MessageBox(0, message, message, MB_OK);\r
248                         }\r
249                 }\r
250 \r
251                 putchar(*p);\r
252                 ++c;\r
253                 ++p;\r
254         }\r
255 \r
256         return c;\r
257 }\r
258 \r
259 int arg_counter = 1;\r
260 char optarg[514];\r
261 int getopt_long_only(int ___argc, char *const *___argv, const char *__shortopts, const struct option *__longopts, int *__longind)\r
262 {\r
263         // burlex todo: handle the shortops, at the moment it only works with longopts.\r
264 \r
265         if (___argc == 1 || arg_counter == ___argc)                     // No arguments (apart from filename)\r
266                 return -1;\r
267 \r
268         const char * opt = ___argv[arg_counter];\r
269         int return_val = 0;\r
270 \r
271         // if we're not an option, return an error.\r
272         if (strnicmp(opt, "--", 2) != 0)\r
273                 return 1;\r
274         else\r
275                 opt += 2;\r
276 \r
277 \r
278         // parse argument list\r
279         int i = 0;\r
280         for (; __longopts[i].name != 0; ++i)\r
281         {\r
282                 if (!strnicmp(__longopts[i].name, opt, strlen(__longopts[i].name)))\r
283                 {\r
284                         // woot, found a valid argument =)\r
285                         char * par = 0;\r
286                         if ((arg_counter + 1) != ___argc)\r
287                         {\r
288                                 // grab the parameter from the next argument (if its not another argument)\r
289                                 if (strnicmp(___argv[arg_counter+1], "--", 2) != 0)\r
290                                 {\r
291                                         arg_counter++;          // Trash this next argument, we won't be needing it.\r
292                                         par = ___argv[arg_counter];\r
293                                 }\r
294                         }                       \r
295 \r
296                         // increment the argument for next time\r
297                         arg_counter++;\r
298 \r
299                         // determine action based on type\r
300                         if (__longopts[i].has_arg == required_argument && !par)\r
301                         {\r
302                                 // parameter missing and its a required parameter option\r
303                                 return 1;\r
304                         }\r
305 \r
306                         // store argument in optarg\r
307                         if (par)\r
308                                 strncpy(optarg, par, 514);\r
309 \r
310                         if (__longopts[i].flag != 0)\r
311                         {\r
312                                 // this is a variable, we have to set it if this argument is found.\r
313                                 *__longopts[i].flag = 1;\r
314                                 return 0;\r
315                         }\r
316                         else\r
317                         {\r
318                                 if (__longopts[i].val == -1 || par == 0)\r
319                                         return 1;\r
320                                 \r
321                                 return __longopts[i].val;\r
322                         }                       \r
323                         break;\r
324                 }\r
325         }\r
326 \r
327         // return 1 (invalid argument)\r
328         return 1;\r
329 }\r
330 \r
331 /* IPC Messages */\r
332 #define IPC_MESSAGE_REHASH      1\r
333 #define IPC_MESSAGE_DIE         2\r
334 #define IPC_MESSAGE_RESTART     3\r
335 \r
336 void InitIPC()\r
337 {\r
338         static DWORD buflen = 1024;\r
339         static const char * pipename = "\\\\.\\mailslot\\Inspircd";\r
340         hIPCPipe = CreateMailslot(pipename, buflen, 0, 0);\r
341         if (hIPCPipe == INVALID_HANDLE_VALUE)\r
342                 printf("IPC Pipe could not be created. Are you sure you didn't start InspIRCd twice?\n");\r
343 }\r
344 \r
345 void CheckIPC(InspIRCd * Instance)\r
346 {\r
347         if (hIPCPipe == INVALID_HANDLE_VALUE)\r
348                 return;\r
349 \r
350         DWORD bytes;\r
351         DWORD action;\r
352 \r
353         BOOL res = ReadFile(hIPCPipe, &action, sizeof(DWORD), &bytes, 0);\r
354         if (!res)\r
355         {\r
356                 if (GetLastError() != ERROR_SEM_TIMEOUT)\r
357                         Instance->Log(DEFAULT, "IPC Pipe Error %u: %s", GetLastError(), dlerror());\r
358                 return;\r
359         }\r
360 \r
361         switch (action)\r
362         {\r
363                 case IPC_MESSAGE_REHASH:\r
364                         InspIRCd::Rehash(0);\r
365                 break;\r
366                 \r
367                 case IPC_MESSAGE_DIE:\r
368                         InspIRCd::Exit(0);\r
369                 break;\r
370 \r
371                 case IPC_MESSAGE_RESTART:\r
372                         Instance->Restart("IPC_MESSAGE_RESTART received by mailslot.");\r
373                 break;\r
374         }\r
375 }\r
376 \r
377 void CloseIPC()\r
378 {\r
379         CloseHandle(hIPCPipe);\r
380 }\r
381 \r
382 \r
383 /* These three functions were created from looking at how ares does it\r
384  * (...and they look far tidier in C++)\r
385  */\r
386 \r
387 /* Get active nameserver */\r
388 bool GetNameServer(HKEY regkey, const char *key, char* &output)\r
389 {\r
390         DWORD size = 0;\r
391         DWORD result = RegQueryValueEx(regkey, key, 0, NULL, NULL, &size);\r
392         if (((result != ERROR_SUCCESS) && (result != ERROR_MORE_DATA)) || (!size))\r
393                 return false;\r
394 \r
395         output = new char[size+1];\r
396 \r
397         if ((RegQueryValueEx(regkey, key, 0, NULL, (LPBYTE)output, &size) != ERROR_SUCCESS) || (!*output))\r
398         {\r
399                 delete output;\r
400                 return false;\r
401         }\r
402         return true;\r
403 }\r
404 \r
405 /* Check a network interface for its nameserver */\r
406 bool GetInterface(HKEY regkey, const char *key, char* &output)\r
407 {\r
408         char buf[39];\r
409         DWORD size = 39;\r
410         int idx = 0;\r
411         HKEY top;\r
412 \r
413         while (RegEnumKeyEx(regkey, idx++, buf, &size, 0, NULL, NULL, NULL) != ERROR_NO_MORE_ITEMS)\r
414         {\r
415                 size = 39;\r
416                 if (RegOpenKeyEx(regkey, buf, 0, KEY_QUERY_VALUE, &top) != ERROR_SUCCESS)\r
417                         continue;\r
418                 int rc = GetNameServer(top, key, output);\r
419                 RegCloseKey(top);\r
420                 if (rc)\r
421                         return true;\r
422         }\r
423         return false;\r
424 }\r
425 \r
426 \r
427 std::string FindNameServerWin()\r
428 {\r
429         std::string returnval = "127.0.0.1";\r
430         HKEY top, key;\r
431         char* dns = NULL;\r
432 \r
433         /* Lets see if the correct registry hive and tree exist */\r
434         if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, "System\\CurrentControlSet\\Services\\Tcpip\\Parameters", 0, KEY_READ, &top) == ERROR_SUCCESS)\r
435         {\r
436                 /* If they do, attempt to get the nameserver name */\r
437                 RegOpenKeyEx(top, "Interfaces", 0, KEY_QUERY_VALUE|KEY_ENUMERATE_SUB_KEYS, &key);\r
438                 if ((GetNameServer(top, "NameServer", dns)) || (GetNameServer(top, "DhcpNameServer", dns))\r
439                         || (GetInterface(key, "NameServer", dns)) || (GetInterface(key, "DhcpNameServer", dns)))\r
440                 {\r
441                         if (dns)\r
442                         {\r
443                                 returnval = dns;\r
444                                 delete dns;\r
445                         }\r
446                 }\r
447                 RegCloseKey(key);\r
448                 RegCloseKey(top);\r
449         }\r
450         return returnval;\r
451 }\r
452 \r
453 \r
454 void ClearConsole()\r
455 {\r
456         COORD coordScreen = { 0, 0 };    /* here's where we'll home the cursor */\r
457         HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);\r
458         BOOL bSuccess;\r
459         DWORD cCharsWritten;\r
460         CONSOLE_SCREEN_BUFFER_INFO csbi; /* to get buffer info */ \r
461         DWORD dwConSize;                 /* number of character cells in the current buffer */ \r
462 \r
463         /* get the number of character cells in the current buffer */ \r
464 \r
465         if (GetConsoleScreenBufferInfo( hConsole, &csbi ))\r
466         {\r
467                 dwConSize = csbi.dwSize.X * csbi.dwSize.Y;\r
468                 /* fill the entire screen with blanks */ \r
469                 if (FillConsoleOutputCharacter( hConsole, (TCHAR) ' ', dwConSize, coordScreen, &cCharsWritten ))\r
470                 {\r
471                         /* get the current text attribute */ \r
472                         if (GetConsoleScreenBufferInfo( hConsole, &csbi ))\r
473                         {\r
474                                 /* now set the buffer's attributes accordingly */\r
475                                 if (FillConsoleOutputAttribute( hConsole, csbi.wAttributes, dwConSize, coordScreen, &cCharsWritten ))\r
476                                 {\r
477                                         /* put the cursor at (0, 0) */\r
478                                         SetConsoleCursorPosition( hConsole, coordScreen );\r
479                                 }\r
480                         }\r
481                 }\r
482         }\r
483         return;\r
484 }\r