]> jfr.im git - solanum.git/blob - librb/src/win32.c
Fix Clang 6 compiler warnings
[solanum.git] / librb / 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 */
27
28 #include <librb_config.h>
29 #include <rb_lib.h>
30 #include <commio-int.h>
31
32 #ifdef _WIN32
33
34 static HWND hwnd;
35
36 #define WM_SOCKET WM_USER
37 /*
38 * having gettimeofday is nice...
39 */
40
41 typedef union
42 {
43 unsigned __int64 ft_i64;
44 FILETIME ft_val;
45 } FT_t;
46
47 #ifdef __GNUC__
48 #define Const64(x) x##LL
49 #else
50 #define Const64(x) x##i64
51 #endif
52 /* Number of 100 nanosecond units from 1/1/1601 to 1/1/1970 */
53 #define EPOCH_BIAS Const64(116444736000000000)
54
55 pid_t
56 rb_getpid()
57 {
58 return GetCurrentProcessId();
59 }
60
61
62 int
63 rb_gettimeofday(struct timeval *tp, void *not_used)
64 {
65 FT_t ft;
66
67 /* this returns time in 100-nanosecond units (i.e. tens of usecs) */
68 GetSystemTimeAsFileTime(&ft.ft_val);
69
70 /* seconds since epoch */
71 tp->tv_sec = (long)((ft.ft_i64 - EPOCH_BIAS) / Const64(10000000));
72
73 /* microseconds remaining */
74 tp->tv_usec = (long)((ft.ft_i64 / Const64(10)) % Const64(1000000));
75
76 return 0;
77 }
78
79
80 pid_t
81 rb_spawn_process(const char *path, const char **argv)
82 {
83 PROCESS_INFORMATION pi;
84 STARTUPINFO si;
85 char cmd[MAX_PATH];
86 memset(&pi, 0, sizeof(pi));
87 memset(&si, 0, sizeof(si));
88 rb_strlcpy(cmd, path, sizeof(cmd));
89 if(CreateProcess(cmd, cmd, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi) == FALSE)
90 return -1;
91
92 return (pi.dwProcessId);
93 }
94
95 pid_t
96 rb_waitpid(pid_t pid, int *status, int flags)
97 {
98 DWORD timeout = (flags & WNOHANG) ? 0 : INFINITE;
99 HANDLE hProcess;
100 DWORD waitcode;
101
102 hProcess = OpenProcess(PROCESS_ALL_ACCESS, TRUE, pid);
103 if(hProcess)
104 {
105 waitcode = WaitForSingleObject(hProcess, timeout);
106 if(waitcode == WAIT_TIMEOUT)
107 {
108 CloseHandle(hProcess);
109 return 0;
110 }
111 else if(waitcode == WAIT_OBJECT_0)
112 {
113 if(GetExitCodeProcess(hProcess, &waitcode))
114 {
115 *status = (int)((waitcode & 0xff) << 8);
116 CloseHandle(hProcess);
117 return pid;
118 }
119 }
120 CloseHandle(hProcess);
121 }
122 else
123 errno = ECHILD;
124
125 return -1;
126 }
127
128 int
129 rb_setenv(const char *name, const char *value, int overwrite)
130 {
131 char *buf;
132 int len;
133 if(!overwrite)
134 {
135 if((buf = getenv(name)) != NULL)
136 {
137 if(strlen(buf) > 0)
138 {
139 return 0;
140 }
141 }
142 }
143 if(name == NULL || value == NULL)
144 return -1;
145 len = strlen(name) + strlen(value) + 5;
146 buf = rb_malloc(len);
147 snprintf(buf, len, "%s=%s", name, value);
148 len = putenv(buf);
149 rb_free(buf);
150 return (len);
151 }
152
153 int
154 rb_kill(pid_t pid, int sig)
155 {
156 HANDLE hProcess;
157 int ret = -1;
158 hProcess = OpenProcess(PROCESS_ALL_ACCESS, TRUE, pid);
159
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
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 *
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
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
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
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
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 = "charybdis-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
400 rb_sleep(unsigned int seconds, unsigned int useconds)
401 {
402 DWORD msec = seconds * 1000;;
403 Sleep(msec);
404 }
405
406 int
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 if (F->type & RB_FD_SOCKET) {
414 unsigned long nonb = 1;
415 if (ioctlsocket((SOCKET) F->fd, FIONBIO, &nonb) == -1) {
416 rb_get_errno();
417 return 0;
418 }
419 }
420 return 1;
421 }
422
423 void
424 rb_setselect_win32(rb_fde_t *F, unsigned int type, PF * handler, void *client_data)
425 {
426 int old_flags = F->pflags;
427
428 lrb_assert(IsFDOpen(F));
429
430 /* Update the list, even though we're not using it .. */
431 if(type & RB_SELECT_READ)
432 {
433 if(handler != NULL)
434 F->pflags |= FD_CLOSE | FD_READ | FD_ACCEPT;
435 else
436 F->pflags &= ~(FD_CLOSE | FD_READ | FD_ACCEPT);
437 F->read_handler = handler;
438 F->read_data = client_data;
439 }
440
441 if(type & RB_SELECT_WRITE)
442 {
443 if(handler != NULL)
444 F->pflags |= FD_WRITE | FD_CONNECT;
445 else
446 F->pflags &= ~(FD_WRITE | FD_CONNECT);
447 F->write_handler = handler;
448 F->write_data = client_data;
449 }
450
451 if(old_flags == 0 && F->pflags == 0)
452 return;
453
454 if(F->pflags != old_flags)
455 {
456 WSAAsyncSelect(F->fd, hwnd, WM_SOCKET, F->pflags);
457 }
458
459 }
460
461
462 static int has_set_timer = 0;
463
464 int
465 rb_select_win32(long delay)
466 {
467 MSG msg;
468 if(has_set_timer == 0)
469 {
470 /* XXX should probably have this handle all the events
471 * instead of busy looping
472 */
473 SetTimer(hwnd, 0, delay, NULL);
474 has_set_timer = 1;
475 }
476
477 if(GetMessage(&msg, NULL, 0, 0) == FALSE)
478 {
479 rb_lib_die("GetMessage failed..byebye");
480 }
481 rb_set_time();
482
483 DispatchMessage(&msg);
484 return RB_OK;
485 }
486
487 #ifdef strerror
488 #undef strerror
489 #endif
490
491 static const char *
492 _rb_strerror(int error)
493 {
494 switch (error)
495 {
496 case 0:
497 return "Success";
498 case WSAEINTR:
499 return "Interrupted system call";
500 case WSAEBADF:
501 return "Bad file number";
502 case WSAEACCES:
503 return "Permission denied";
504 case WSAEFAULT:
505 return "Bad address";
506 case WSAEINVAL:
507 return "Invalid argument";
508 case WSAEMFILE:
509 return "Too many open sockets";
510 case WSAEWOULDBLOCK:
511 return "Operation would block";
512 case WSAEINPROGRESS:
513 return "Operation now in progress";
514 case WSAEALREADY:
515 return "Operation already in progress";
516 case WSAENOTSOCK:
517 return "Socket operation on non-socket";
518 case WSAEDESTADDRREQ:
519 return "Destination address required";
520 case WSAEMSGSIZE:
521 return "Message too long";
522 case WSAEPROTOTYPE:
523 return "Protocol wrong type for socket";
524 case WSAENOPROTOOPT:
525 return "Bad protocol option";
526 case WSAEPROTONOSUPPORT:
527 return "Protocol not supported";
528 case WSAESOCKTNOSUPPORT:
529 return "Socket type not supported";
530 case WSAEOPNOTSUPP:
531 return "Operation not supported on socket";
532 case WSAEPFNOSUPPORT:
533 return "Protocol family not supported";
534 case WSAEAFNOSUPPORT:
535 return "Address family not supported";
536 case WSAEADDRINUSE:
537 return "Address already in use";
538 case WSAEADDRNOTAVAIL:
539 return "Can't assign requested address";
540 case WSAENETDOWN:
541 return "Network is down";
542 case WSAENETUNREACH:
543 return "Network is unreachable";
544 case WSAENETRESET:
545 return "Net connection reset";
546 case WSAECONNABORTED:
547 return "Software caused connection abort";
548 case WSAECONNRESET:
549 return "Connection reset by peer";
550 case WSAENOBUFS:
551 return "No buffer space available";
552 case WSAEISCONN:
553 return "Socket is already connected";
554 case WSAENOTCONN:
555 return "Socket is not connected";
556 case WSAESHUTDOWN:
557 return "Can't send after socket shutdown";
558 case WSAETOOMANYREFS:
559 return "Too many references, can't splice";
560 case WSAETIMEDOUT:
561 return "Connection timed out";
562 case WSAECONNREFUSED:
563 return "Connection refused";
564 case WSAELOOP:
565 return "Too many levels of symbolic links";
566 case WSAENAMETOOLONG:
567 return "File name too long";
568 case WSAEHOSTDOWN:
569 return "Host is down";
570 case WSAEHOSTUNREACH:
571 return "No route to host";
572 case WSAENOTEMPTY:
573 return "Directory not empty";
574 case WSAEPROCLIM:
575 return "Too many processes";
576 case WSAEUSERS:
577 return "Too many users";
578 case WSAEDQUOT:
579 return "Disc quota exceeded";
580 case WSAESTALE:
581 return "Stale NFS file handle";
582 case WSAEREMOTE:
583 return "Too many levels of remote in path";
584 case WSASYSNOTREADY:
585 return "Network system is unavailable";
586 case WSAVERNOTSUPPORTED:
587 return "Winsock version out of range";
588 case WSANOTINITIALISED:
589 return "WSAStartup not yet called";
590 case WSAEDISCON:
591 return "Graceful shutdown in progress";
592 case WSAHOST_NOT_FOUND:
593 return "Host not found";
594 case WSANO_DATA:
595 return "No host data of that type was found";
596 default:
597 return strerror(error);
598 }
599 };
600
601 char *
602 rb_strerror(int error)
603 {
604 static char buf[128];
605 rb_strlcpy(buf, _rb_strerror(error), sizeof(buf));
606 return buf;
607 }
608
609 const char *
610 rb_path_to_self(void)
611 {
612 static char path_buf[MAX_PATH];
613 GetModuleFileName(NULL, path_buf, MAX_PATH);
614 return path_buf;
615 }
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 __attribute__((unused)), unsigned int type __attribute__((unused)), PF * handler __attribute__((unused)), void *client_data __attribute__((unused)))
627 {
628 errno = ENOSYS;
629 return;
630 }
631
632 int
633 rb_select_win32(long delay __attribute__((unused)))
634 {
635 errno = ENOSYS;
636 return -1;
637 }
638
639 int
640 rb_setup_fd_win32(rb_fde_t *F __attribute__((unused)))
641 {
642 errno = ENOSYS;
643 return -1;
644 }
645 #endif /* _WIN32 */