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