]> jfr.im git - irc/rqf/shadowircd.git/blob - libratbox/src/win32.c
autogen.sh is not necessary at this time, and did not work anyway.
[irc/rqf/shadowircd.git] / libratbox / src / win32.c
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
57 rb_getpid()
58 {
59 return GetCurrentProcessId();
60 }
61
62
63 int
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
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
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
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
155 rb_kill(int pid, int sig)
156 {
157 HANDLE hProcess;
158 int ret = -1;
159 hProcess = OpenProcess(PROCESS_ALL_ACCESS, TRUE, pid);
160
161 if(hProcess)
162 {
163 switch (sig)
164 {
165 case 0:
166 ret = 0;
167 break;
168
169 default:
170 if(TerminateProcess(hProcess, sig))
171 ret = 0;
172 break;
173 }
174 CloseHandle(hProcess);
175 }
176 else
177 errno = EINVAL;
178
179 return ret;
180
181
182 }
183
184 /*
185 * packet format is
186 uint32_t magic
187 uint8_t protocol count
188 WSAPROTOCOL_INFO * count
189 size_t datasize
190 data
191
192 */
193
194 static int
195 make_wsaprotocol_info(pid_t process, rb_fde_t *F, WSAPROTOCOL_INFO * inf)
196 {
197 WSAPROTOCOL_INFO info;
198 if(!WSADuplicateSocket((SOCKET) rb_get_fd(F), process, &info))
199 {
200 memcpy(inf, &info, sizeof(WSAPROTOCOL_INFO));
201 return 1;
202 }
203 return 0;
204 }
205
206 static rb_fde_t *
207 make_fde_from_wsaprotocol_info(void *data)
208 {
209 WSAPROTOCOL_INFO *info = data;
210 SOCKET t;
211 t = WSASocket(FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO, info, 0, 0);
212 if(t == INVALID_SOCKET)
213 {
214 rb_get_errno();
215 return NULL;
216 }
217 return rb_open(t, RB_FD_SOCKET, "remote_socket");
218 }
219
220 static uint8_t fd_buf[16384];
221 #define MAGIC_CONTROL 0xFF0ACAFE
222
223 int
224 rb_send_fd_buf(rb_fde_t *xF, rb_fde_t **F, int count, void *data, size_t datasize, pid_t pid)
225 {
226 size_t bufsize =
227 sizeof(uint32_t) + sizeof(uint8_t) + (sizeof(WSAPROTOCOL_INFO) * (size_t)count) +
228 sizeof(size_t) + datasize;
229 int i;
230 uint32_t magic = MAGIC_CONTROL;
231 void *ptr;
232 if(count > 4)
233 {
234 errno = EINVAL;
235 return -1;
236 }
237 if(bufsize > sizeof(fd_buf))
238 {
239 errno = EINVAL;
240 return -1;
241 }
242 memset(fd_buf, 0, sizeof(fd_buf));
243
244 ptr = fd_buf;
245 memcpy(ptr, &magic, sizeof(magic));
246 ptr = (void *)((uintptr_t)ptr + (uintptr_t)sizeof(magic));
247 *((uint8_t *)ptr) = count;
248 ptr = (void *)((uintptr_t)ptr + (uintptr_t)sizeof(uint8_t));
249
250 for(i = 0; i < count; i++)
251 {
252 make_wsaprotocol_info(pid, F[i], (WSAPROTOCOL_INFO *) ptr);
253 ptr = (void *)((uintptr_t)ptr + (uintptr_t)sizeof(WSAPROTOCOL_INFO));
254 }
255 memcpy(ptr, &datasize, sizeof(size_t));
256 ptr = (void *)((uintptr_t)ptr + (uintptr_t)sizeof(size_t));
257 memcpy(ptr, data, datasize);
258 return rb_write(xF, fd_buf, bufsize);
259 }
260
261 #ifdef MYMIN
262 #undef MYMIN
263 #endif
264 #define MYMIN(a, b) ((a) < (b) ? (a) : (b))
265
266 int
267 rb_recv_fd_buf(rb_fde_t *F, void *data, size_t datasize, rb_fde_t **xF, int nfds)
268 {
269 size_t minsize = sizeof(uint32_t) + sizeof(uint8_t) + sizeof(size_t);
270 size_t datalen;
271 ssize_t retlen;
272 uint32_t magic;
273 uint8_t count;
274 unsigned int i;
275 void *ptr;
276 ssize_t ret;
277 memset(fd_buf, 0, sizeof(fd_buf)); /* some paranoia here... */
278 ret = rb_read(F, fd_buf, sizeof(fd_buf));
279 if(ret <= 0)
280 {
281 return ret;
282 }
283 if(ret < (ssize_t) minsize)
284 {
285 errno = EINVAL;
286 return -1;
287 }
288 ptr = fd_buf;
289 memcpy(&magic, ptr, sizeof(uint32_t));
290 if(magic != MAGIC_CONTROL)
291 {
292 errno = EAGAIN;
293 return -1;
294 }
295 ptr = (void *)((uintptr_t)ptr + (uintptr_t)sizeof(uint32_t));
296 memcpy(&count, ptr, sizeof(uint8_t));
297 ptr = (void *)((uintptr_t)ptr + (uintptr_t)sizeof(uint8_t));
298 for(i = 0; i < count && i < (unsigned int)nfds; i++)
299 {
300 rb_fde_t *tF = make_fde_from_wsaprotocol_info(ptr);
301 if(tF == NULL)
302 return -1;
303 xF[i] = tF;
304 ptr = (void *)((uintptr_t)ptr + (uintptr_t)sizeof(WSAPROTOCOL_INFO));
305 }
306 memcpy(&datalen, ptr, sizeof(size_t));
307 ptr = (void *)((uintptr_t)ptr + (uintptr_t)sizeof(size_t));
308 retlen = MYMIN(datalen, datasize);
309 memcpy(data, ptr, datalen);
310 return retlen;
311 }
312
313 static LRESULT CALLBACK
314 rb_process_events(HWND nhwnd, UINT umsg, WPARAM wparam, LPARAM lparam)
315 {
316 rb_fde_t *F;
317 PF *hdl;
318 void *data;
319 switch (umsg)
320 {
321 case WM_SOCKET:
322 {
323 F = rb_find_fd(wparam);
324
325 if(F != NULL && IsFDOpen(F))
326 {
327 switch (WSAGETSELECTEVENT(lparam))
328 {
329 case FD_ACCEPT:
330 case FD_CLOSE:
331 case FD_READ:
332 {
333 if((hdl = F->read_handler) != NULL)
334 {
335 F->read_handler = NULL;
336 data = F->read_data;
337 F->read_data = NULL;
338 hdl(F, data);
339 }
340 break;
341 }
342
343 case FD_CONNECT:
344 case FD_WRITE:
345 {
346 if((hdl = F->write_handler) != NULL)
347 {
348 F->write_handler = NULL;
349 data = F->write_data;
350 F->write_data = NULL;
351 hdl(F, data);
352 }
353 }
354 }
355
356 }
357 return 0;
358 }
359 case WM_DESTROY:
360 {
361 PostQuitMessage(0);
362 return 0;
363 }
364
365 default:
366 return DefWindowProc(nhwnd, umsg, wparam, lparam);
367 }
368 return 0;
369 }
370
371 int
372 rb_init_netio_win32(void)
373 {
374 /* this muchly sucks, but i'm too lazy to do overlapped i/o, maybe someday... -androsyn */
375 WNDCLASS wc;
376 static const char *classname = "ircd-ratbox-class";
377
378 wc.style = 0;
379 wc.lpfnWndProc = (WNDPROC) rb_process_events;
380 wc.cbClsExtra = 0;
381 wc.cbWndExtra = 0;
382 wc.hIcon = NULL;
383 wc.hCursor = NULL;
384 wc.hbrBackground = NULL;
385 wc.lpszMenuName = NULL;
386 wc.lpszClassName = classname;
387 wc.hInstance = GetModuleHandle(NULL);
388
389 if(!RegisterClass(&wc))
390 rb_lib_die("cannot register window class");
391
392 hwnd = CreateWindow(classname, classname, WS_POPUP, CW_USEDEFAULT,
393 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
394 (HWND) NULL, (HMENU) NULL, wc.hInstance, NULL);
395 if(!hwnd)
396 rb_lib_die("could not create window");
397 return 0;
398 }
399
400 void
401 rb_sleep(unsigned int seconds, unsigned int useconds)
402 {
403 DWORD msec = seconds * 1000;;
404 Sleep(msec);
405 }
406
407 int
408 rb_setup_fd_win32(rb_fde_t *F)
409 {
410 if(F == NULL)
411 return 0;
412
413 SetHandleInformation((HANDLE) F->fd, HANDLE_FLAG_INHERIT, 0);
414 switch (F->type)
415 {
416 case RB_FD_SOCKET:
417 {
418 u_long nonb = 1;
419 if(ioctlsocket((SOCKET) F->fd, FIONBIO, &nonb) == -1)
420 {
421 rb_get_errno();
422 return 0;
423 }
424 return 1;
425 }
426 default:
427 return 1;
428
429 }
430 }
431
432 void
433 rb_setselect_win32(rb_fde_t *F, unsigned int type, PF * handler, void *client_data)
434 {
435 int old_flags = F->pflags;
436
437 lrb_assert(IsFDOpen(F));
438
439 /* Update the list, even though we're not using it .. */
440 if(type & RB_SELECT_READ)
441 {
442 if(handler != NULL)
443 F->pflags |= FD_CLOSE | FD_READ | FD_ACCEPT;
444 else
445 F->pflags &= ~(FD_CLOSE | FD_READ | FD_ACCEPT);
446 F->read_handler = handler;
447 F->read_data = client_data;
448 }
449
450 if(type & RB_SELECT_WRITE)
451 {
452 if(handler != NULL)
453 F->pflags |= FD_WRITE | FD_CONNECT;
454 else
455 F->pflags &= ~(FD_WRITE | FD_CONNECT);
456 F->write_handler = handler;
457 F->write_data = client_data;
458 }
459
460 if(old_flags == 0 && F->pflags == 0)
461 return;
462
463 if(F->pflags != old_flags)
464 {
465 WSAAsyncSelect(F->fd, hwnd, WM_SOCKET, F->pflags);
466 }
467
468 }
469
470
471 static int has_set_timer = 0;
472
473 int
474 rb_select_win32(long delay)
475 {
476 MSG msg;
477 if(has_set_timer == 0)
478 {
479 /* XXX should probably have this handle all the events
480 * instead of busy looping
481 */
482 SetTimer(hwnd, 0, delay, NULL);
483 has_set_timer = 1;
484 }
485
486 if(GetMessage(&msg, NULL, 0, 0) == FALSE)
487 {
488 rb_lib_die("GetMessage failed..byebye");
489 }
490 rb_set_time();
491
492 DispatchMessage(&msg);
493 return RB_OK;
494 }
495
496 #ifdef strerror
497 #undef strerror
498 #endif
499
500 static const char *
501 _rb_strerror(int error)
502 {
503 switch (error)
504 {
505 case 0:
506 return "Success";
507 case WSAEINTR:
508 return "Interrupted system call";
509 case WSAEBADF:
510 return "Bad file number";
511 case WSAEACCES:
512 return "Permission denied";
513 case WSAEFAULT:
514 return "Bad address";
515 case WSAEINVAL:
516 return "Invalid argument";
517 case WSAEMFILE:
518 return "Too many open sockets";
519 case WSAEWOULDBLOCK:
520 return "Operation would block";
521 case WSAEINPROGRESS:
522 return "Operation now in progress";
523 case WSAEALREADY:
524 return "Operation already in progress";
525 case WSAENOTSOCK:
526 return "Socket operation on non-socket";
527 case WSAEDESTADDRREQ:
528 return "Destination address required";
529 case WSAEMSGSIZE:
530 return "Message too long";
531 case WSAEPROTOTYPE:
532 return "Protocol wrong type for socket";
533 case WSAENOPROTOOPT:
534 return "Bad protocol option";
535 case WSAEPROTONOSUPPORT:
536 return "Protocol not supported";
537 case WSAESOCKTNOSUPPORT:
538 return "Socket type not supported";
539 case WSAEOPNOTSUPP:
540 return "Operation not supported on socket";
541 case WSAEPFNOSUPPORT:
542 return "Protocol family not supported";
543 case WSAEAFNOSUPPORT:
544 return "Address family not supported";
545 case WSAEADDRINUSE:
546 return "Address already in use";
547 case WSAEADDRNOTAVAIL:
548 return "Can't assign requested address";
549 case WSAENETDOWN:
550 return "Network is down";
551 case WSAENETUNREACH:
552 return "Network is unreachable";
553 case WSAENETRESET:
554 return "Net connection reset";
555 case WSAECONNABORTED:
556 return "Software caused connection abort";
557 case WSAECONNRESET:
558 return "Connection reset by peer";
559 case WSAENOBUFS:
560 return "No buffer space available";
561 case WSAEISCONN:
562 return "Socket is already connected";
563 case WSAENOTCONN:
564 return "Socket is not connected";
565 case WSAESHUTDOWN:
566 return "Can't send after socket shutdown";
567 case WSAETOOMANYREFS:
568 return "Too many references, can't splice";
569 case WSAETIMEDOUT:
570 return "Connection timed out";
571 case WSAECONNREFUSED:
572 return "Connection refused";
573 case WSAELOOP:
574 return "Too many levels of symbolic links";
575 case WSAENAMETOOLONG:
576 return "File name too long";
577 case WSAEHOSTDOWN:
578 return "Host is down";
579 case WSAEHOSTUNREACH:
580 return "No route to host";
581 case WSAENOTEMPTY:
582 return "Directory not empty";
583 case WSAEPROCLIM:
584 return "Too many processes";
585 case WSAEUSERS:
586 return "Too many users";
587 case WSAEDQUOT:
588 return "Disc quota exceeded";
589 case WSAESTALE:
590 return "Stale NFS file handle";
591 case WSAEREMOTE:
592 return "Too many levels of remote in path";
593 case WSASYSNOTREADY:
594 return "Network system is unavailable";
595 case WSAVERNOTSUPPORTED:
596 return "Winsock version out of range";
597 case WSANOTINITIALISED:
598 return "WSAStartup not yet called";
599 case WSAEDISCON:
600 return "Graceful shutdown in progress";
601 case WSAHOST_NOT_FOUND:
602 return "Host not found";
603 case WSANO_DATA:
604 return "No host data of that type was found";
605 default:
606 return strerror(error);
607 }
608 };
609
610 char *
611 rb_strerror(int error)
612 {
613 static char buf[128];
614 rb_strlcpy(buf, _rb_strerror(error), sizeof(buf));
615 return buf;
616 }
617 #else /* win32 not supported */
618 int
619 rb_init_netio_win32(void)
620 {
621 errno = ENOSYS;
622 return -1;
623 }
624
625 void
626 rb_setselect_win32(rb_fde_t *F, unsigned int type, PF * handler, void *client_data)
627 {
628 errno = ENOSYS;
629 return;
630 }
631
632 int
633 rb_select_win32(long delay)
634 {
635 errno = ENOSYS;
636 return -1;
637 }
638
639 int
640 rb_setup_fd_win32(rb_fde_t *F)
641 {
642 errno = ENOSYS;
643 return -1;
644 }
645 #endif /* _WIN32 */