summaryrefslogtreecommitdiff
path: root/win/inspircd_win32wrapper.cpp
blob: 6bea736406dbde2461cc90b2f453f1e491abfb3d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
/*       +------------------------------------+
 *       | Inspire Internet Relay Chat Daemon |
 *       +------------------------------------+
 *
 *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
 * See: http://www.inspircd.org/wiki/index.php/Credits
 *
 * This program is free but copyrighted software; see
 *            the file COPYING for details.
 *
 * ---------------------------------------------------
 */

#include "inspircd_win32wrapper.h"
#include "inspircd.h"
#include <string>
#include <errno.h>
#include <assert.h>
using namespace std;

#ifndef INADDR_NONE
#define INADDR_NONE 0xffffffff
#endif

HANDLE hIPCPipe;

int inet_aton(const char *cp, struct in_addr *addr)
{
	unsigned long ip = inet_addr(cp);
	addr->s_addr = ip;
	return (addr->s_addr == INADDR_NONE) ? 0 : 1;
}

const char *inet_ntop(int af, const void *src, char *dst, socklen_t cnt)
{

	if (af == AF_INET)
	{
		struct sockaddr_in in;
		memset(&in, 0, sizeof(in));
		in.sin_family = AF_INET;
		memcpy(&in.sin_addr, src, sizeof(struct in_addr));
		getnameinfo((struct sockaddr *)&in, sizeof(struct sockaddr_in), dst, cnt, NULL, 0, NI_NUMERICHOST);
		return dst;
	}
	else if (af == AF_INET6)
	{
		struct sockaddr_in6 in;
		memset(&in, 0, sizeof(in));
		in.sin6_family = AF_INET6;
		memcpy(&in.sin6_addr, src, sizeof(struct in_addr6));
		getnameinfo((struct sockaddr *)&in, sizeof(struct sockaddr_in6), dst, cnt, NULL, 0, NI_NUMERICHOST);
		return dst;
	}
	return NULL;
}

int geteuid()
{
	return 1;
}

int inet_pton(int af, const char *src, void *dst)
{
	sockaddr_in sa;
	int len = sizeof(SOCKADDR);
	int rv = WSAStringToAddress((LPSTR)src, af, NULL, (LPSOCKADDR)&sa, &len);
	memcpy(dst, &sa.sin_addr, sizeof(struct in_addr));
	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);
}

DIR * opendir(const char * path)
{
	std::string search_path = string(path) + "\\*.*";
	WIN32_FIND_DATA fd;
	HANDLE f = FindFirstFile(search_path.c_str(), &fd);
	if (f != INVALID_HANDLE_VALUE)
	{
		DIR * d = new DIR;
		memcpy(&d->find_data, &fd, sizeof(WIN32_FIND_DATA));
		d->find_handle = f;
		d->first = true;
		return d;
	}
	else
	{
		return 0;
	}
}

dirent * readdir(DIR * handle)
{
	if (handle->first)
		handle->first = false;
	else
	{
		if (!FindNextFile(handle->find_handle, &handle->find_data))
			return 0;
	}

	strncpy(handle->dirent_pointer.d_name, handle->find_data.cFileName, MAX_PATH);
	return &handle->dirent_pointer;
}

void closedir(DIR * handle)
{
	FindClose(handle->find_handle);
	delete handle;
}

const char * dlerror()
{
	static char errormessage[500];
	DWORD error = GetLastError();
	SetLastError(0);
	if (error == 0)
		return 0;

	FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, 0, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)errormessage, 500, 0);
	return errormessage;
}

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[500];
	static char temp[10];
	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 != 'm')
			{
				temp[t++] = *p;
				++p;
			}
			
			temp[t] = 0;
			p++;
			if (!_stricmp(temp, "[0"))
			{
				// Returning to normal colour.
				SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
			}
			else if (sscanf(temp, "[%u;%u", &color1, &color2) == 2)
			{
				switch(color2)
				{
					case 32:		// Green
						SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_GREEN | FOREGROUND_INTENSITY);
					break;
	
					default:		// Unknown
						SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY);
					break;
				}
			}
			else
			{
				char message[50];
				sprintf("Unknown color code: %s", temp);
				MessageBox(0, message, message, MB_OK);
			}
		}

		putchar(*p);
		++c;
		++p;
	}

	return c;
}

int arg_counter = 1;
char optarg[514];
int getopt_long_only(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)
		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)
		return 1;
	else
		opt += 2;


	// parse argument list
	int i = 0;
	for (; __longopts[i].name != 0; ++i)
	{
		if (!strnicmp(__longopts[i].name, opt, strlen(__longopts[i].name)))
		{
			// woot, found a valid argument =)
			char * par = 0;
			if ((arg_counter + 1) != ___argc)
			{
				// grab the parameter from the next argument (if its not another argument)
				if (strnicmp(___argv[arg_counter+1], "--", 2) != 0)
				{
					arg_counter++;		// Trash this next argument, we won't be needing it.
					par = ___argv[arg_counter];
				}
			}			

			// increment the argument for next time
			arg_counter++;

			// determine action based on type
			if (__longopts[i].has_arg == required_argument && !par)
			{
				// parameter missing and its a required parameter option
				return 1;
			}

			// store argument in optarg
			if (par)
				strncpy(optarg, par, 514);

			if (__longopts[i].flag != 0)
			{
				// this is a variable, we have to set it if this argument is found.
				*__longopts[i].flag = 1;
				return 0;
			}
			else
			{
				if (__longopts[i].val == -1 || par == 0)
					return 1;
				
				return __longopts[i].val;
			}			
			break;
		}
	}

	// return 1 (invalid argument)
	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++)
 */

/* Get active nameserver */
bool GetNameServer(HKEY regkey, const char *key, char* &output)
{
	DWORD size = 0;
	DWORD result = RegQueryValueEx(regkey, key, 0, NULL, NULL, &size);
	if (((result != ERROR_SUCCESS) && (result != ERROR_MORE_DATA)) || (!size))
		return false;

	output = new char[size+1];

	if ((RegQueryValueEx(regkey, key, 0, NULL, (LPBYTE)output, &size) != ERROR_SUCCESS) || (!*output))
	{
		delete output;
		return false;
	}
	return true;
}

/* Check a network interface for its nameserver */
bool GetInterface(HKEY regkey, const char *key, char* &output)
{
	char buf[39];
	DWORD size = 39;
	int idx = 0;
	HKEY top;

	while (RegEnumKeyEx(regkey, idx++, buf, &size, 0, NULL, NULL, NULL) != ERROR_NO_MORE_ITEMS)
	{
		size = 39;
		if (RegOpenKeyEx(regkey, buf, 0, KEY_QUERY_VALUE, &top) != ERROR_SUCCESS)
			continue;
		int rc = GetNameServer(top, key, output);
		RegCloseKey(top);
		if (rc)
			return true;
	}
	return false;
}


std::string FindNameServerWin()
{
	std::string returnval = "127.0.0.1";
	HKEY top, key;
	char* dns = NULL;

	/* Lets see if the correct registry hive and tree exist */
	if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, "System\\CurrentControlSet\\Services\\Tcpip\\Parameters", 0, KEY_READ, &top) == ERROR_SUCCESS)
	{
		/* If they do, attempt to get the nameserver name */
		RegOpenKeyEx(top, "Interfaces", 0, KEY_QUERY_VALUE|KEY_ENUMERATE_SUB_KEYS, &key);
		if ((GetNameServer(top, "NameServer", dns)) || (GetNameServer(top, "DhcpNameServer", dns))
			|| (GetInterface(key, "NameServer", dns)) || (GetInterface(key, "DhcpNameServer", dns)))
		{
			if (dns)
			{
				returnval = dns;
				delete dns;
			}
		}
		RegCloseKey(key);
		RegCloseKey(top);
	}
	return returnval;
}


void ClearConsole()
{
	COORD coordScreen = { 0, 0 };    /* here's where we'll home the cursor */
	HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
	DWORD cCharsWritten;
	CONSOLE_SCREEN_BUFFER_INFO csbi; /* to get buffer info */ 
	DWORD dwConSize;                 /* number of character cells in the current buffer */ 

	/* get the number of character cells in the current buffer */ 

	if (GetConsoleScreenBufferInfo( hConsole, &csbi ))
	{
		dwConSize = csbi.dwSize.X * csbi.dwSize.Y;
		/* fill the entire screen with blanks */ 
		if (FillConsoleOutputCharacter( hConsole, (TCHAR) ' ', dwConSize, coordScreen, &cCharsWritten ))
		{
			/* get the current text attribute */ 
			if (GetConsoleScreenBufferInfo( hConsole, &csbi ))
			{
				/* now set the buffer's attributes accordingly */
				if (FillConsoleOutputAttribute( hConsole, csbi.wAttributes, dwConSize, coordScreen, &cCharsWritten ))
				{
					/* put the cursor at (0, 0) */
					SetConsoleCursorPosition( hConsole, coordScreen );
				}
			}
		}
	}
	return;
}