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