1 /* Win32 ioset backend for srvx
2 * Copyright 2006 srvx Development Team
4 * This file is part of srvx.
6 * srvx is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with srvx; if not, write to the Free Software Foundation,
18 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
21 #include "ioset-impl.h"
25 /* This is massively kludgy. Unfortunately, the only performant I/O
26 * multiplexer with halfway decent semantics under Windows is
27 * WSAAsyncSelect() -- which requires a window that can receive
30 * So ioset_win32_init() creates a hidden window and sets it up for
31 * asynchronous socket notifications.
34 #define IDT_TIMER1 1000
35 #define IDT_SOCKET 1001
37 static HWND ioset_window;
38 static struct io_fd **fds;
39 static unsigned int fds_used;
40 static unsigned int fds_size;
46 int upper = fds_used - 1;
48 while (lower <= upper)
50 int mid = (upper + lower) / 2;
51 if (fd < fds[mid]->fd)
53 else if (fd > fds[mid]->fd)
62 io_fd_from_socket(int fd)
66 return ((ii < fds_used) && (fds[ii]->fd == fd)) ? fds[ii] : NULL;
69 static LRESULT CALLBACK
70 ioset_win32_wndproc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
76 if (hWnd == ioset_window) switch (uMsg)
81 fd = io_fd_from_socket(wParam);
82 events = WSAGETSELECTEVENT(lParam);
83 err = WSAGETSELECTERROR(lParam);
84 ioset_events(fd, (events & (FD_READ | FD_ACCEPT | FD_CLOSE)) != 0, (events & (FD_WRITE | FD_CONNECT)) != 0);
87 quit_services = wParam;
90 return DefWindowProc(hWnd, uMsg, wParam, lParam);
94 ioset_win32_init(void)
101 // Start Windows Sockets.
102 res = WSAStartup(MAKEWORD(2, 0), &wsadata);
105 log_module(MAIN_LOG, LOG_FATAL, "Unable to start Windows Sockets (%d)", res);
109 // Get Windows HINSTANCE.
110 hinst = GetModuleHandle(NULL);
112 // Describe and register a window class.
113 memset(&wcx, 0, sizeof(wcx));
114 wcx.cbSize = sizeof(wcx);
115 wcx.lpfnWndProc = ioset_win32_wndproc;
116 wcx.hInstance = hinst;
117 wcx.lpszClassName = "srvxMainWindow";
118 if (!RegisterClassEx(&wcx))
120 log_module(MAIN_LOG, LOG_FATAL, "Unable to register window class (%lu)", GetLastError());
124 ioset_window = CreateWindow("srvxMainWindow", PACKAGE_STRING, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hinst, NULL);
127 log_module(MAIN_LOG, LOG_FATAL, "Unable to create window (%lu)", GetLastError());
135 ioset_win32_events(const struct io_fd *fd)
146 return FD_READ | FD_CLOSE | (fd_wants_writes(fd) ? FD_WRITE : 0);
151 ioset_win32_update(struct io_fd *fd)
156 events = ioset_win32_events(fd);
157 rc = WSAAsyncSelect(fd->fd, ioset_window, IDT_SOCKET, events);
160 log_module(MAIN_LOG, LOG_ERROR, "Unable to add events %#lx for fd %#x (%d)", events, fd->fd, WSAGetLastError());
165 ioset_win32_add(struct io_fd *fd)
170 // Make sure fds[] can hold a new entry.
171 if (fds_used + 1 >= fds_size)
173 struct io_fd **new_fds;
174 unsigned int new_size;
176 new_size = (fds_size < 8) ? 8 : fds_size * 2;
177 new_fds = calloc(new_size * 2, sizeof(new_fds[0]));
180 log_module(MAIN_LOG, LOG_FATAL, "Unable to allocate %u-entry socket array.", new_size);
182 for (ii = 0; ii < fds_used; ++ii)
183 new_fds[ii] = fds[ii];
189 // Insert fd into the appropriate spot in fds[].
190 pos = io_fd_pos(fd->fd);
191 for (ii = pos; ii < fds_used; ++ii)
192 fds[ii + 1] = fds[ii];
196 // Ask the OS for future notifications.
197 ioset_win32_update(fd);
201 ioset_win32_remove(struct io_fd *fd, int os_closed)
206 // Unregister from the OS.
211 rc = WSAAsyncSelect(fd->fd, ioset_window, IDT_SOCKET, 0);
214 log_module(MAIN_LOG, LOG_ERROR, "Unable to remove events for fd %#x (%d)", fd->fd, WSAGetLastError());
218 ioctlsocket(fd->fd, FIONBIO, &ulong);
221 // Remove from the fds[] array.
222 pos = io_fd_pos(fd->fd);
223 for (--fds_used; pos < fds_used; ++pos)
224 fds[pos] = fds[pos + 1];
228 ioset_win32_cleanup(void)
230 DestroyWindow(ioset_window);
236 ioset_win32_loop(struct timeval *timeout)
239 BOOL not_really_bool;
242 // Make sure we are woken up after the appropriate time.
243 msec = (timeout->tv_sec * 1000) + (timeout->tv_usec / 1000);
244 SetTimer(ioset_window, IDT_TIMER1, msec, NULL);
245 // Do a blocking read of the message queue.
246 not_really_bool = GetMessage(&msg, NULL, 0, 0);
247 KillTimer(ioset_window, IDT_TIMER1);
248 if (not_really_bool < 0)
252 else if (not_really_bool == 0)
259 extern int clock_skew;
261 now = time(NULL) + clock_skew;
262 TranslateMessage(&msg);
263 DispatchMessage(&msg);
268 struct io_engine io_engine_win32 = {
270 .init = ioset_win32_init,
271 .add = ioset_win32_add,
272 .remove = ioset_win32_remove,
273 .update = ioset_win32_update,
274 .loop = ioset_win32_loop,
275 .cleanup = ioset_win32_cleanup,