1 /*
2  *  ircd-ratbox: A slightly useful ircd.
3  *  win32.c: select() compatible network routines.
4  *
5  *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
6  *  Copyright (C) 1996-2002 Hybrid Development Team
7  *  Copyright (C) 2001 Adrian Chadd <adrian@creative.net.au>
8  *  Copyright (C) 2005-2006 Aaron Sethman <androsyn@ratbox.org>
9  *  Copyright (C) 2002-2006 ircd-ratbox development team
10  *
11  *  This program is free software; you can redistribute it and/or modify
12  *  it under the terms of the GNU General Public License as published by
13  *  the Free Software Foundation; either version 2 of the License, or
14  *  (at your option) any later version.
15  *
16  *  This program is distributed in the hope that it will be useful,
17  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
18  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  *  GNU General Public License for more details.
20  *
21  *  You should have received a copy of the GNU General Public License
22  *  along with this program; if not, write to the Free Software
23  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301
24  *  USA
25  *
26  *  $Id: win32.c 26092 2008-09-19 15:13:52Z androsyn $
27  */
28 
29 #include <libratbox_config.h>
30 #include <ratbox_lib.h>
31 #include <commio-int.h>
32 
33 #ifdef _WIN32
34 
35 static HWND hwnd;
36 
37 #define WM_SOCKET WM_USER
38 /*
39  * having gettimeofday is nice...
40  */
41 
42 typedef union
43 {
44 	unsigned __int64 ft_i64;
45 	FILETIME ft_val;
46 } FT_t;
47 
48 #ifdef __GNUC__
49 #define Const64(x) x##LL
50 #else
51 #define Const64(x) x##i64
52 #endif
53 /* Number of 100 nanosecond units from 1/1/1601 to 1/1/1970 */
54 #define EPOCH_BIAS  Const64(116444736000000000)
55 
56 pid_t
rb_getpid()57 rb_getpid()
58 {
59 	return GetCurrentProcessId();
60 }
61 
62 
63 int
rb_gettimeofday(struct timeval * tp,void * not_used)64 rb_gettimeofday(struct timeval *tp, void *not_used)
65 {
66 	FT_t ft;
67 
68 	/* this returns time in 100-nanosecond units  (i.e. tens of usecs) */
69 	GetSystemTimeAsFileTime(&ft.ft_val);
70 
71 	/* seconds since epoch */
72 	tp->tv_sec = (long)((ft.ft_i64 - EPOCH_BIAS) / Const64(10000000));
73 
74 	/* microseconds remaining */
75 	tp->tv_usec = (long)((ft.ft_i64 / Const64(10)) % Const64(1000000));
76 
77 	return 0;
78 }
79 
80 
81 pid_t
rb_spawn_process(const char * path,const char ** argv)82 rb_spawn_process(const char *path, const char **argv)
83 {
84 	PROCESS_INFORMATION pi;
85 	STARTUPINFO si;
86 	char cmd[MAX_PATH];
87 	memset(&pi, 0, sizeof(pi));
88 	memset(&si, 0, sizeof(si));
89 	rb_strlcpy(cmd, path, sizeof(cmd));
90 	if(CreateProcess(cmd, cmd, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi) == FALSE)
91 		return -1;
92 
93 	return (pi.dwProcessId);
94 }
95 
96 pid_t
rb_waitpid(int pid,int * status,int flags)97 rb_waitpid(int pid, int *status, int flags)
98 {
99 	DWORD timeout = (flags & WNOHANG) ? 0 : INFINITE;
100 	HANDLE hProcess;
101 	DWORD waitcode;
102 
103 	hProcess = OpenProcess(PROCESS_ALL_ACCESS, TRUE, pid);
104 	if(hProcess)
105 	{
106 		waitcode = WaitForSingleObject(hProcess, timeout);
107 		if(waitcode == WAIT_TIMEOUT)
108 		{
109 			CloseHandle(hProcess);
110 			return 0;
111 		}
112 		else if(waitcode == WAIT_OBJECT_0)
113 		{
114 			if(GetExitCodeProcess(hProcess, &waitcode))
115 			{
116 				*status = (int)((waitcode & 0xff) << 8);
117 				CloseHandle(hProcess);
118 				return pid;
119 			}
120 		}
121 		CloseHandle(hProcess);
122 	}
123 	else
124 		errno = ECHILD;
125 
126 	return -1;
127 }
128 
129 int
rb_setenv(const char * name,const char * value,int overwrite)130 rb_setenv(const char *name, const char *value, int overwrite)
131 {
132 	char *buf;
133 	int len;
134 	if(!overwrite)
135 	{
136 		if((buf = getenv(name)) != NULL)
137 		{
138 			if(strlen(buf) > 0)
139 			{
140 				return 0;
141 			}
142 		}
143 	}
144 	if(name == NULL || value == NULL)
145 		return -1;
146 	len = strlen(name) + strlen(value) + 5;
147 	buf = rb_malloc(len);
148 	rb_snprintf(buf, len, "%s=%s", name, value);
149 	len = putenv(buf);
150 	rb_free(buf);
151 	return (len);
152 }
153 
154 int
rb_kill(int pid,int sig)155 rb_kill(int pid, int sig)
156 {
157 	HANDLE hProcess;
158 	hProcess = OpenProcess(PROCESS_ALL_ACCESS, TRUE, pid);
159 	int ret = -1;
160 	if(hProcess)
161 	{
162 		switch (sig)
163 		{
164 		case 0:
165 			ret = 0;
166 			break;
167 
168 		default:
169 			if(TerminateProcess(hProcess, sig))
170 				ret = 0;
171 			break;
172 		}
173 		CloseHandle(hProcess);
174 	}
175 	else
176 		errno = EINVAL;
177 
178 	return ret;
179 
180 
181 }
182 
183 /*
184  * packet format is
185  uint32_t magic
186  uint8_t protocol count
187  WSAPROTOCOL_INFO * count
188  size_t datasize
189  data
190 
191  */
192 
193 static int
make_wsaprotocol_info(pid_t process,rb_fde_t * F,WSAPROTOCOL_INFO * inf)194 make_wsaprotocol_info(pid_t process, rb_fde_t *F, WSAPROTOCOL_INFO * inf)
195 {
196 	WSAPROTOCOL_INFO info;
197 	if(!WSADuplicateSocket((SOCKET) rb_get_fd(F), process, &info))
198 	{
199 		memcpy(inf, &info, sizeof(WSAPROTOCOL_INFO));
200 		return 1;
201 	}
202 	return 0;
203 }
204 
205 static rb_fde_t *
make_fde_from_wsaprotocol_info(void * data)206 make_fde_from_wsaprotocol_info(void *data)
207 {
208 	WSAPROTOCOL_INFO *info = data;
209 	SOCKET t;
210 	t = WSASocket(FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO, info, 0, 0);
211 	if(t == INVALID_SOCKET)
212 	{
213 		rb_get_errno();
214 		return NULL;
215 	}
216 	return rb_open(t, RB_FD_SOCKET, "remote_socket");
217 }
218 
219 static uint8_t fd_buf[16384];
220 #define MAGIC_CONTROL 0xFF0ACAFE
221 
222 int
rb_send_fd_buf(rb_fde_t * xF,rb_fde_t ** F,int count,void * data,size_t datasize,pid_t pid)223 rb_send_fd_buf(rb_fde_t *xF, rb_fde_t **F, int count, void *data, size_t datasize, pid_t pid)
224 {
225 	size_t bufsize =
226 		sizeof(uint32_t) + sizeof(uint8_t) + (sizeof(WSAPROTOCOL_INFO) * (size_t)count) +
227 		sizeof(size_t) + datasize;
228 	int i;
229 	uint32_t magic = MAGIC_CONTROL;
230 	void *ptr;
231 	if(count > 4)
232 	{
233 		errno = EINVAL;
234 		return -1;
235 	}
236 	if(bufsize > sizeof(fd_buf))
237 	{
238 		errno = EINVAL;
239 		return -1;
240 	}
241 	memset(fd_buf, 0, sizeof(fd_buf));
242 
243 	ptr = fd_buf;
244 	memcpy(ptr, &magic, sizeof(magic));
245 	ptr = (void *)((uintptr_t)ptr + (uintptr_t)sizeof(magic));
246 	*((uint8_t *)ptr) = count;
247 	ptr = (void *)((uintptr_t)ptr + (uintptr_t)sizeof(uint8_t));
248 
249 	for(i = 0; i < count; i++)
250 	{
251 		make_wsaprotocol_info(pid, F[i], (WSAPROTOCOL_INFO *) ptr);
252 		ptr = (void *)((uintptr_t)ptr + (uintptr_t)sizeof(WSAPROTOCOL_INFO));
253 	}
254 	memcpy(ptr, &datasize, sizeof(size_t));
255 	ptr = (void *)((uintptr_t)ptr + (uintptr_t)sizeof(size_t));
256 	memcpy(ptr, data, datasize);
257 	return rb_write(xF, fd_buf, bufsize);
258 }
259 
260 #ifdef MYMIN
261 #undef MYMIN
262 #endif
263 #define MYMIN(a, b)  ((a) < (b) ? (a) : (b))
264 
265 int
rb_recv_fd_buf(rb_fde_t * F,void * data,size_t datasize,rb_fde_t ** xF,int nfds)266 rb_recv_fd_buf(rb_fde_t *F, void *data, size_t datasize, rb_fde_t **xF, int nfds)
267 {
268 	size_t minsize = sizeof(uint32_t) + sizeof(uint8_t) + sizeof(size_t);
269 	size_t datalen;
270 	ssize_t retlen;
271 	uint32_t magic;
272 	uint8_t count;
273 	unsigned int i;
274 	void *ptr;
275 	ssize_t ret;
276 	memset(fd_buf, 0, sizeof(fd_buf));	/* some paranoia here... */
277 	ret = rb_read(F, fd_buf, sizeof(fd_buf));
278 	if(ret <= 0)
279 	{
280 		return ret;
281 	}
282 	if(ret < (ssize_t) minsize)
283 	{
284 		errno = EINVAL;
285 		return -1;
286 	}
287 	ptr = fd_buf;
288 	memcpy(&magic, ptr, sizeof(uint32_t));
289 	if(magic != MAGIC_CONTROL)
290 	{
291 		errno = EAGAIN;
292 		return -1;
293 	}
294 	ptr = (void *)((uintptr_t)ptr + (uintptr_t)sizeof(uint32_t));
295 	memcpy(&count, ptr, sizeof(uint8_t));
296 	ptr = (void *)((uintptr_t)ptr + (uintptr_t)sizeof(uint8_t));
297 	for(i = 0; i < count && i < (unsigned int)nfds; i++)
298 	{
299 		rb_fde_t *tF = make_fde_from_wsaprotocol_info(ptr);
300 		if(tF == NULL)
301 			return -1;
302 		xF[i] = tF;
303 		ptr = (void *)((uintptr_t)ptr + (uintptr_t)sizeof(WSAPROTOCOL_INFO));
304 	}
305 	memcpy(&datalen, ptr, sizeof(size_t));
306 	ptr = (void *)((uintptr_t)ptr + (uintptr_t)sizeof(size_t));
307 	retlen = MYMIN(datalen, datasize);
308 	memcpy(data, ptr, datalen);
309 	return retlen;
310 }
311 
312 static LRESULT CALLBACK
rb_process_events(HWND nhwnd,UINT umsg,WPARAM wparam,LPARAM lparam)313 rb_process_events(HWND nhwnd, UINT umsg, WPARAM wparam, LPARAM lparam)
314 {
315 	rb_fde_t *F;
316 	PF *hdl;
317 	void *data;
318 	switch (umsg)
319 	{
320 	case WM_SOCKET:
321 		{
322 			F = rb_find_fd(wparam);
323 
324 			if(F != NULL && IsFDOpen(F))
325 			{
326 				switch (WSAGETSELECTEVENT(lparam))
327 				{
328 				case FD_ACCEPT:
329 				case FD_CLOSE:
330 				case FD_READ:
331 					{
332 						if((hdl = F->read_handler) != NULL)
333 						{
334 							F->read_handler = NULL;
335 							data = F->read_data;
336 							F->read_data = NULL;
337 							hdl(F, data);
338 						}
339 						break;
340 					}
341 
342 				case FD_CONNECT:
343 				case FD_WRITE:
344 					{
345 						if((hdl = F->write_handler) != NULL)
346 						{
347 							F->write_handler = NULL;
348 							data = F->write_data;
349 							F->write_data = NULL;
350 							hdl(F, data);
351 						}
352 					}
353 				}
354 
355 			}
356 			return 0;
357 		}
358 	case WM_DESTROY:
359 		{
360 			PostQuitMessage(0);
361 			return 0;
362 		}
363 
364 	default:
365 		return DefWindowProc(nhwnd, umsg, wparam, lparam);
366 	}
367 	return 0;
368 }
369 
370 int
rb_init_netio_win32(void)371 rb_init_netio_win32(void)
372 {
373 	/* this muchly sucks, but i'm too lazy to do overlapped i/o, maybe someday... -androsyn */
374 	WNDCLASS wc;
375 	static const char *classname = "ircd-ratbox-class";
376 
377 	wc.style = 0;
378 	wc.lpfnWndProc = (WNDPROC) rb_process_events;
379 	wc.cbClsExtra = 0;
380 	wc.cbWndExtra = 0;
381 	wc.hIcon = NULL;
382 	wc.hCursor = NULL;
383 	wc.hbrBackground = NULL;
384 	wc.lpszMenuName = NULL;
385 	wc.lpszClassName = classname;
386 	wc.hInstance = GetModuleHandle(NULL);
387 
388 	if(!RegisterClass(&wc))
389 		rb_lib_die("cannot register window class");
390 
391 	hwnd = CreateWindow(classname, classname, WS_POPUP, CW_USEDEFAULT,
392 			    CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
393 			    (HWND) NULL, (HMENU) NULL, wc.hInstance, NULL);
394 	if(!hwnd)
395 		rb_lib_die("could not create window");
396 	return 0;
397 }
398 
399 void
rb_sleep(unsigned int seconds,unsigned int useconds)400 rb_sleep(unsigned int seconds, unsigned int useconds)
401 {
402 	DWORD msec = seconds * 1000;;
403 	Sleep(msec);
404 }
405 
406 int
rb_setup_fd_win32(rb_fde_t * F)407 rb_setup_fd_win32(rb_fde_t *F)
408 {
409 	if(F == NULL)
410 		return 0;
411 
412 	SetHandleInformation((HANDLE) F->fd, HANDLE_FLAG_INHERIT, 0);
413 	switch (F->type)
414 	{
415 	case RB_FD_SOCKET:
416 		{
417 			u_long nonb = 1;
418 			if(ioctlsocket((SOCKET) F->fd, FIONBIO, &nonb) == -1)
419 			{
420 				rb_get_errno();
421 				return 0;
422 			}
423 			return 1;
424 		}
425 	default:
426 		return 1;
427 
428 	}
429 }
430 
431 void
rb_setselect_win32(rb_fde_t * F,unsigned int type,PF * handler,void * client_data)432 rb_setselect_win32(rb_fde_t *F, unsigned int type, PF * handler, void *client_data)
433 {
434 	int old_flags = F->pflags;
435 
436 	lrb_assert(IsFDOpen(F));
437 
438 	/* Update the list, even though we're not using it .. */
439 	if(type & RB_SELECT_READ)
440 	{
441 		if(handler != NULL)
442 			F->pflags |= FD_CLOSE | FD_READ | FD_ACCEPT;
443 		else
444 			F->pflags &= ~(FD_CLOSE | FD_READ | FD_ACCEPT);
445 		F->read_handler = handler;
446 		F->read_data = client_data;
447 	}
448 
449 	if(type & RB_SELECT_WRITE)
450 	{
451 		if(handler != NULL)
452 			F->pflags |= FD_WRITE | FD_CONNECT;
453 		else
454 			F->pflags &= ~(FD_WRITE | FD_CONNECT);
455 		F->write_handler = handler;
456 		F->write_data = client_data;
457 	}
458 
459 	if(old_flags == 0 && F->pflags == 0)
460 		return;
461 
462 	if(F->pflags != old_flags)
463 	{
464 		WSAAsyncSelect(F->fd, hwnd, WM_SOCKET, F->pflags);
465 	}
466 
467 }
468 
469 
470 static int has_set_timer = 0;
471 
472 int
rb_select_win32(long delay)473 rb_select_win32(long delay)
474 {
475 	MSG msg;
476 	if(has_set_timer == 0)
477 	{
478 		/* XXX should probably have this handle all the events
479 		 * instead of busy looping
480 		 */
481 		SetTimer(hwnd, 0, delay, NULL);
482 		has_set_timer = 1;
483 	}
484 
485 	if(GetMessage(&msg, NULL, 0, 0) == FALSE)
486 	{
487 		rb_lib_die("GetMessage failed..byebye");
488 	}
489 	rb_set_time();
490 
491 	DispatchMessage(&msg);
492 	return RB_OK;
493 }
494 
495 #ifdef strerror
496 #undef strerror
497 #endif
498 
499 static const char *
_rb_strerror(int error)500 _rb_strerror(int error)
501 {
502 	switch (error)
503 	{
504 	case 0:
505 		return "Success";
506 	case WSAEINTR:
507 		return "Interrupted system call";
508 	case WSAEBADF:
509 		return "Bad file number";
510 	case WSAEACCES:
511 		return "Permission denied";
512 	case WSAEFAULT:
513 		return "Bad address";
514 	case WSAEINVAL:
515 		return "Invalid argument";
516 	case WSAEMFILE:
517 		return "Too many open sockets";
518 	case WSAEWOULDBLOCK:
519 		return "Operation would block";
520 	case WSAEINPROGRESS:
521 		return "Operation now in progress";
522 	case WSAEALREADY:
523 		return "Operation already in progress";
524 	case WSAENOTSOCK:
525 		return "Socket operation on non-socket";
526 	case WSAEDESTADDRREQ:
527 		return "Destination address required";
528 	case WSAEMSGSIZE:
529 		return "Message too long";
530 	case WSAEPROTOTYPE:
531 		return "Protocol wrong type for socket";
532 	case WSAENOPROTOOPT:
533 		return "Bad protocol option";
534 	case WSAEPROTONOSUPPORT:
535 		return "Protocol not supported";
536 	case WSAESOCKTNOSUPPORT:
537 		return "Socket type not supported";
538 	case WSAEOPNOTSUPP:
539 		return "Operation not supported on socket";
540 	case WSAEPFNOSUPPORT:
541 		return "Protocol family not supported";
542 	case WSAEAFNOSUPPORT:
543 		return "Address family not supported";
544 	case WSAEADDRINUSE:
545 		return "Address already in use";
546 	case WSAEADDRNOTAVAIL:
547 		return "Can't assign requested address";
548 	case WSAENETDOWN:
549 		return "Network is down";
550 	case WSAENETUNREACH:
551 		return "Network is unreachable";
552 	case WSAENETRESET:
553 		return "Net connection reset";
554 	case WSAECONNABORTED:
555 		return "Software caused connection abort";
556 	case WSAECONNRESET:
557 		return "Connection reset by peer";
558 	case WSAENOBUFS:
559 		return "No buffer space available";
560 	case WSAEISCONN:
561 		return "Socket is already connected";
562 	case WSAENOTCONN:
563 		return "Socket is not connected";
564 	case WSAESHUTDOWN:
565 		return "Can't send after socket shutdown";
566 	case WSAETOOMANYREFS:
567 		return "Too many references, can't splice";
568 	case WSAETIMEDOUT:
569 		return "Connection timed out";
570 	case WSAECONNREFUSED:
571 		return "Connection refused";
572 	case WSAELOOP:
573 		return "Too many levels of symbolic links";
574 	case WSAENAMETOOLONG:
575 		return "File name too long";
576 	case WSAEHOSTDOWN:
577 		return "Host is down";
578 	case WSAEHOSTUNREACH:
579 		return "No route to host";
580 	case WSAENOTEMPTY:
581 		return "Directory not empty";
582 	case WSAEPROCLIM:
583 		return "Too many processes";
584 	case WSAEUSERS:
585 		return "Too many users";
586 	case WSAEDQUOT:
587 		return "Disc quota exceeded";
588 	case WSAESTALE:
589 		return "Stale NFS file handle";
590 	case WSAEREMOTE:
591 		return "Too many levels of remote in path";
592 	case WSASYSNOTREADY:
593 		return "Network system is unavailable";
594 	case WSAVERNOTSUPPORTED:
595 		return "Winsock version out of range";
596 	case WSANOTINITIALISED:
597 		return "WSAStartup not yet called";
598 	case WSAEDISCON:
599 		return "Graceful shutdown in progress";
600 	case WSAHOST_NOT_FOUND:
601 		return "Host not found";
602 	case WSANO_DATA:
603 		return "No host data of that type was found";
604 	default:
605 		return strerror(error);
606 	}
607 };
608 
609 char *
rb_strerror(int error)610 rb_strerror(int error)
611 {
612 	static char buf[128];
613 	rb_strlcpy(buf, _rb_strerror(error), sizeof(buf));
614 	return buf;
615 }
616 #else /* win32 not supported */
617 int
rb_init_netio_win32(void)618 rb_init_netio_win32(void)
619 {
620 	errno = ENOSYS;
621 	return -1;
622 }
623 
624 void
rb_setselect_win32(rb_fde_t * F,unsigned int type,PF * handler,void * client_data)625 rb_setselect_win32(rb_fde_t *F, unsigned int type, PF * handler, void *client_data)
626 {
627 	errno = ENOSYS;
628 	return;
629 }
630 
631 int
rb_select_win32(long delay)632 rb_select_win32(long delay)
633 {
634 	errno = ENOSYS;
635 	return -1;
636 }
637 
638 int
rb_setup_fd_win32(rb_fde_t * F)639 rb_setup_fd_win32(rb_fde_t *F)
640 {
641 	errno = ENOSYS;
642 	return -1;
643 }
644 #endif /* _WIN32 */
645