1 /* IOEngine_win32.c - IOMultiplexer
2 * Copyright (C) 2014 Philipp Kreil (pk910)
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 #define _IOHandler_internals
18 #include "IOInternal.h"
19 #include "IOHandler.h"
21 #include "IOSockets.h"
28 #define _WIN32_WINNT 0x501
32 /* This is massively kludgy. Unfortunately, the only performant I/O
33 * multiplexer with halfway decent semantics under Windows is
34 * WSAAsyncSelect() -- which requires a window that can receive
37 * So ioset_win32_init() creates a hidden window and sets it up for
38 * asynchronous socket notifications.
41 #define IDT_TIMER1 1000
42 #define IDT_TIMER2 1001
43 #define IDT_SOCKET 1002
45 static HWND ioset_window;
47 static struct _IOSocket *engine_win32_get_iosock(int fd) {
48 struct _IOSocket *iosock;
49 for(iosock = iosocket_first; iosock; iosock = iosock->next) {
56 static LRESULT CALLBACK engine_win32_wndproc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
57 struct _IOSocket *iosock;
60 if (hWnd == ioset_window) {
69 iosock = engine_win32_get_iosock(wParam);
72 events = WSAGETSELECTEVENT(lParam);
74 if((events & FD_CONNECT)) {
76 if((err = WSAGETSELECTERROR(lParam)))
77 iosocket_events_callback(iosock, err, 0);
79 iosocket_events_callback(iosock, 0, 1);
81 iosocket_events_callback(iosock, (events & (FD_READ | FD_ACCEPT | FD_CLOSE)) != 0, (events & FD_WRITE) != 0);
87 return DefWindowProc(hWnd, uMsg, wParam, lParam);
90 static int engine_win32_init() {
95 // Start Windows Sockets.
96 if (WSAStartup(MAKEWORD(2, 0), &wsadata)) {
97 iolog_trigger(IOLOG_FATAL, "Unable to start Windows Sockets");
101 // Get Windows HINSTANCE.
102 hinst = GetModuleHandle(NULL);
104 // Describe and register a window class.
105 memset(&wcx, 0, sizeof(wcx));
106 wcx.cbSize = sizeof(wcx);
107 wcx.lpfnWndProc = engine_win32_wndproc;
108 wcx.hInstance = hinst;
109 wcx.lpszClassName = "IOMultiplexerMainWindow";
110 if (!RegisterClassEx(&wcx))
113 ioset_window = CreateWindow("IOMultiplexerMainWindow", "IOMultiplexer", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hinst, NULL);
119 static long engine_win32_events(struct _IOSocket *iosock) {
120 if(iosock->socket_flags & IOSOCKETFLAG_LISTENING)
122 if(iosock->socket_flags & IOSOCKETFLAG_CONNECTING)
125 return FD_CLOSE | (iosocket_wants_reads(iosock) ? FD_READ : 0) | (iosocket_wants_writes(iosock) ? FD_WRITE : 0);
128 static void engine_win32_update(struct _IOSocket *iosock) {
130 events = engine_win32_events(iosock);
131 WSAAsyncSelect(iosock->fd, ioset_window, IDT_SOCKET, events);
134 static void engine_win32_add(struct _IOSocket *iosock) {
135 engine_win32_update(iosock);
138 static void engine_win32_remove(struct _IOSocket *iosock) {
139 unsigned long ulong = 0;
140 WSAAsyncSelect(iosock->fd, ioset_window, IDT_SOCKET, 0);
141 ioctlsocket(iosock->fd, FIONBIO, &ulong);
144 static void engine_win32_loop(struct timeval *timeout) {
151 gettimeofday(&now, NULL);
152 if(iotimer_sorted_descriptors && timeval_is_bigger(now, iotimer_sorted_descriptors->timeout))
155 //get timeout (timer or given timeout)
156 if(iotimer_sorted_descriptors) {
157 msec = (iotimer_sorted_descriptors->timeout.tv_sec - now.tv_sec) * 1000;
158 msec += (iotimer_sorted_descriptors->timeout.tv_usec - now.tv_usec) / 1000;
161 msec2 = (timeout->tv_sec * 1000 + timeout->tv_usec / 1000);
162 if(!iotimer_sorted_descriptors || msec2 < msec)
164 } else if(!iotimer_sorted_descriptors)
168 SetTimer(ioset_window, IDT_TIMER1, 1000, NULL);
170 SetTimer(ioset_window, IDT_TIMER2, msec, NULL);
172 //GetMessage system call
173 res = GetMessage(&msg, NULL, 0, 0);
176 KillTimer(ioset_window, IDT_TIMER1);
178 KillTimer(ioset_window, IDT_TIMER2);
183 TranslateMessage(&msg);
184 DispatchMessage(&msg);
188 static void engine_win32_cleanup() {
189 DestroyWindow(ioset_window);
194 struct IOEngine engine_win32 = {
196 .init = engine_win32_init,
197 .add = engine_win32_add,
198 .remove = engine_win32_remove,
199 .update = engine_win32_update,
200 .loop = engine_win32_loop,
201 .cleanup = engine_win32_cleanup,
206 struct IOEngine engine_win32 = {