]> jfr.im git - irc/rqf/shadowircd.git/blob - libratbox/src/win32.c
abc8cc062a9b964dcb77f15f5edf8347061df067
[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 25038 2008-01-23 16:03:08Z 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 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 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 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 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 int
184 rb_pass_fd_to_process(int fd, pid_t process, rb_fde_t *F)
185 {
186 WSAPROTOCOL_INFO info;
187 WSADuplicateSocket((SOCKET)fd, process, &info);
188 rb_write(F, &info, sizeof(info));
189 return 0;
190 }
191
192
193 static LRESULT CALLBACK
194 rb_process_events(HWND nhwnd, UINT umsg, WPARAM wparam, LPARAM lparam)
195 {
196 rb_fde_t *F;
197 PF *hdl;
198 void *data;
199 switch (umsg)
200 {
201 case WM_SOCKET:
202 {
203 F = rb_find_fd(wparam);
204
205 if(F != NULL && IsFDOpen(F))
206 {
207 switch (WSAGETSELECTEVENT(lparam))
208 {
209 case FD_ACCEPT:
210 case FD_CLOSE:
211 case FD_READ:
212 {
213 if((hdl = F->read_handler) != NULL)
214 {
215 F->read_handler = NULL;
216 data = F->read_data;
217 F->read_data = NULL;
218 hdl(F, data);
219 }
220 break;
221 }
222
223 case FD_CONNECT:
224 case FD_WRITE:
225 {
226 if((hdl = F->write_handler) != NULL)
227 {
228 F->write_handler = NULL;
229 data = F->write_data;
230 F->write_data = NULL;
231 hdl(F, data);
232 }
233 }
234 }
235
236 }
237 return 0;
238 }
239 case WM_DESTROY:
240 {
241 PostQuitMessage(0);
242 return 0;
243 }
244
245 default:
246 return DefWindowProc(nhwnd, umsg, wparam, lparam);
247 }
248 return 0;
249 }
250
251 int
252 rb_init_netio_win32(void)
253 {
254 /* this muchly sucks, but i'm too lazy to do overlapped i/o, maybe someday... -androsyn */
255 WNDCLASS wc;
256 static const char *classname = "ircd-ratbox-class";
257
258 wc.style = 0;
259 wc.lpfnWndProc = (WNDPROC) rb_process_events;
260 wc.cbClsExtra = 0;
261 wc.cbWndExtra = 0;
262 wc.hIcon = NULL;
263 wc.hCursor = NULL;
264 wc.hbrBackground = NULL;
265 wc.lpszMenuName = NULL;
266 wc.lpszClassName = classname;
267 wc.hInstance = GetModuleHandle(NULL);
268
269 if(!RegisterClass(&wc))
270 rb_lib_die("cannot register window class");
271
272 hwnd = CreateWindow(classname, classname, WS_POPUP, CW_USEDEFAULT,
273 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
274 (HWND) NULL, (HMENU) NULL, wc.hInstance, NULL);
275 if(!hwnd)
276 rb_lib_die("could not create window");
277 return 0;
278 }
279
280 void
281 rb_sleep(unsigned int seconds, unsigned int useconds)
282 {
283 struct timeval tv;
284 tv.tv_sec = seconds;
285 tv.tv_usec = useconds;
286 select(0, NULL, NULL, NULL, &tv);
287 }
288
289 int
290 rb_setup_fd_win32(rb_fde_t * F)
291 {
292 if(F == NULL)
293 return 0;
294
295 SetHandleInformation((HANDLE) F->fd, HANDLE_FLAG_INHERIT, 0);
296 switch (F->type)
297 {
298 case RB_FD_SOCKET:
299 {
300 u_long nonb = 1;
301 if(ioctlsocket((SOCKET) F->fd, FIONBIO, &nonb) == -1)
302 {
303 rb_get_errno();
304 return 0;
305 }
306 return 1;
307 }
308 default:
309 return 1;
310
311 }
312 }
313
314 void
315 rb_setselect_win32(rb_fde_t * F, unsigned int type, PF * handler, void *client_data)
316 {
317 int old_flags = F->pflags;
318
319 lrb_assert(IsFDOpen(F));
320
321 /* Update the list, even though we're not using it .. */
322 if(type & RB_SELECT_READ)
323 {
324 if(handler != NULL)
325 F->pflags |= FD_CLOSE | FD_READ | FD_ACCEPT;
326 else
327 F->pflags &= ~(FD_CLOSE | FD_READ | FD_ACCEPT);
328 F->read_handler = handler;
329 F->read_data = client_data;
330 }
331
332 if(type & RB_SELECT_WRITE)
333 {
334 if(handler != NULL)
335 F->pflags |= FD_WRITE | FD_CONNECT;
336 else
337 F->pflags &= ~(FD_WRITE | FD_CONNECT);
338 F->write_handler = handler;
339 F->write_data = client_data;
340 }
341
342 if(old_flags == 0 && F->pflags == 0)
343 return;
344
345 if(F->pflags != old_flags)
346 {
347 WSAAsyncSelect(F->fd, hwnd, WM_SOCKET, F->pflags);
348 }
349
350 }
351
352
353 static int has_set_timer = 0;
354
355 int
356 rb_select_win32(long delay)
357 {
358 MSG msg;
359 if(has_set_timer == 0)
360 {
361 /* XXX should probably have this handle all the events
362 * instead of busy looping
363 */
364 SetTimer(hwnd, 0, delay, NULL);
365 has_set_timer = 1;
366 }
367
368 if(GetMessage(&msg, NULL, 0, 0) == FALSE)
369 {
370 rb_lib_die("GetMessage failed..byebye");
371 }
372 rb_set_time();
373
374 DispatchMessage(&msg);
375 return RB_OK;
376 }
377
378 #ifdef strerror
379 #undef strerror
380 #endif
381
382 const char *
383 wsock_strerror(int error)
384 {
385 switch (error)
386 {
387 case 0:
388 return "Success";
389 case WSAEINTR:
390 return "Interrupted system call";
391 case WSAEBADF:
392 return "Bad file number";
393 case WSAEACCES:
394 return "Permission denied";
395 case WSAEFAULT:
396 return "Bad address";
397 case WSAEINVAL:
398 return "Invalid argument";
399 case WSAEMFILE:
400 return "Too many open sockets";
401 case WSAEWOULDBLOCK:
402 return "Operation would block";
403 case WSAEINPROGRESS:
404 return "Operation now in progress";
405 case WSAEALREADY:
406 return "Operation already in progress";
407 case WSAENOTSOCK:
408 return "Socket operation on non-socket";
409 case WSAEDESTADDRREQ:
410 return "Destination address required";
411 case WSAEMSGSIZE:
412 return "Message too long";
413 case WSAEPROTOTYPE:
414 return "Protocol wrong type for socket";
415 case WSAENOPROTOOPT:
416 return "Bad protocol option";
417 case WSAEPROTONOSUPPORT:
418 return "Protocol not supported";
419 case WSAESOCKTNOSUPPORT:
420 return "Socket type not supported";
421 case WSAEOPNOTSUPP:
422 return "Operation not supported on socket";
423 case WSAEPFNOSUPPORT:
424 return "Protocol family not supported";
425 case WSAEAFNOSUPPORT:
426 return "Address family not supported";
427 case WSAEADDRINUSE:
428 return "Address already in use";
429 case WSAEADDRNOTAVAIL:
430 return "Can't assign requested address";
431 case WSAENETDOWN:
432 return "Network is down";
433 case WSAENETUNREACH:
434 return "Network is unreachable";
435 case WSAENETRESET:
436 return "Net connection reset";
437 case WSAECONNABORTED:
438 return "Software caused connection abort";
439 case WSAECONNRESET:
440 return "Connection reset by peer";
441 case WSAENOBUFS:
442 return "No buffer space available";
443 case WSAEISCONN:
444 return "Socket is already connected";
445 case WSAENOTCONN:
446 return "Socket is not connected";
447 case WSAESHUTDOWN:
448 return "Can't send after socket shutdown";
449 case WSAETOOMANYREFS:
450 return "Too many references, can't splice";
451 case WSAETIMEDOUT:
452 return "Connection timed out";
453 case WSAECONNREFUSED:
454 return "Connection refused";
455 case WSAELOOP:
456 return "Too many levels of symbolic links";
457 case WSAENAMETOOLONG:
458 return "File name too long";
459 case WSAEHOSTDOWN:
460 return "Host is down";
461 case WSAEHOSTUNREACH:
462 return "No route to host";
463 case WSAENOTEMPTY:
464 return "Directory not empty";
465 case WSAEPROCLIM:
466 return "Too many processes";
467 case WSAEUSERS:
468 return "Too many users";
469 case WSAEDQUOT:
470 return "Disc quota exceeded";
471 case WSAESTALE:
472 return "Stale NFS file handle";
473 case WSAEREMOTE:
474 return "Too many levels of remote in path";
475 case WSASYSNOTREADY:
476 return "Network system is unavailable";
477 case WSAVERNOTSUPPORTED:
478 return "Winsock version out of range";
479 case WSANOTINITIALISED:
480 return "WSAStartup not yet called";
481 case WSAEDISCON:
482 return "Graceful shutdown in progress";
483 case WSAHOST_NOT_FOUND:
484 return "Host not found";
485 case WSANO_DATA:
486 return "No host data of that type was found";
487 default:
488 return strerror(error);
489 }
490 };
491 #else /* win32 not supported */
492 int
493 rb_init_netio_win32(void)
494 {
495 errno = ENOSYS;
496 return -1;
497 }
498
499 void
500 rb_setselect_win32(rb_fde_t * F, unsigned int type, PF * handler, void *client_data)
501 {
502 errno = ENOSYS;
503 return;
504 }
505
506 int
507 rb_select_win32(long delay)
508 {
509 errno = ENOSYS;
510 return -1;
511 }
512
513 int
514 rb_setup_fd_win32(rb_fde_t * F)
515 {
516 errno = ENOSYS;
517 return -1;
518 }
519 #endif /* WIN32 */