From: Michael Poole Date: Tue, 6 Mar 2007 04:43:42 +0000 (-0500) Subject: Finish ioset-win32 (not yet tested). X-Git-Tag: v1.4.0-rc1~67 X-Git-Url: http://git.pk910.de/?p=srvx.git;a=commitdiff_plain;h=f6e136248c4e58caa2cd0baa9581a9c085b0af80 Finish ioset-win32 (not yet tested). compat.h: Define BSD socket errors in terms of Windows socket errors. config.h.win32: Fix typo in PACKAGE_STRING. ioset-win32.c: Implement most of this file. ioset.c: Ifdef out the fcntl() calls to make Windows happier. --- diff --git a/src/compat.h b/src/compat.h index 4968587..d1508e2 100644 --- a/src/compat.h +++ b/src/compat.h @@ -132,4 +132,14 @@ void freeaddrinfo(struct addrinfo *res); #endif +#ifndef EINPROGRESS +# ifdef WSAEINPROGRESS +# define EINPROGRESS WSAEINPROGRESS +# define EHOSTUNREACH WSAEHOSTUNREACH +# define ECONNREFUSED WSAECONNREFUSED +# define ECONNRESET WSAECONNRESET +# define ETIMEDOUT WSAETIMEDOUT +# endif +#endif + #endif /* COMPAT_H */ diff --git a/src/config.h.win32 b/src/config.h.win32 index 262ff37..d58ae4c 100644 --- a/src/config.h.win32 +++ b/src/config.h.win32 @@ -251,7 +251,7 @@ #define PACKAGE_NAME "srvx" /* Define to the full name and version of this package. */ -#define PACKAGE_STRING "srvx 1.31-win" +#define PACKAGE_STRING "srvx 1.3.1-win" /* Define to the one symbol short name of this package. */ #define PACKAGE_TARNAME "srvx-1.3.1" diff --git a/src/ioset-win32.c b/src/ioset-win32.c index 018206a..7be12b0 100644 --- a/src/ioset-win32.c +++ b/src/ioset-win32.c @@ -31,46 +31,227 @@ * asynchronous socket notifications. */ +#define IDT_TIMER1 1000 +#define IDT_SOCKET 1001 + +static HWND ioset_window; +static struct io_fd **fds; +static unsigned int fds_used; +static unsigned int fds_size; + +static unsigned int +io_fd_pos(int fd) +{ + int lower = 0; + int upper = fds_used - 1; + + while (lower <= upper) + { + int mid = (upper + lower) / 2; + if (fd < fds[mid]->fd) + upper = mid - 1; + else if (fd > fds[mid]->fd) + lower = mid + 1; + else + break; + } + return lower; +} + +static struct io_fd * +io_fd_from_socket(int fd) +{ + unsigned int ii; + ii = io_fd_pos(fd); + return ((ii < fds_used) && (fds[ii]->fd == fd)) ? fds[ii] : NULL; +} + +static LRESULT CALLBACK +ioset_win32_wndproc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + struct io_fd *fd; + int events; + int err; + + if (hWnd == ioset_window) switch (uMsg) + { + case IDT_TIMER1: + return 0; + case IDT_SOCKET: + fd = io_fd_from_socket(wParam); + events = WSAGETSELECTEVENT(lParam); + err = WSAGETSELECTERROR(lParam); + ioset_events(fd, (events & (FD_READ | FD_ACCEPT | FD_CLOSE)) != 0, (events & (FD_WRITE | FD_CONNECT)) != 0); + } + return DefWindowProc(hWnd, uMsg, wParam, lParam); +} + static int ioset_win32_init(void) { WSADATA wsadata; + WNDCLASSEX wcx; + HINSTANCE hinst; int res; + // Start Windows Sockets. res = WSAStartup(MAKEWORD(2, 0), &wsadata); - // TODO: finish implementing ioset_win32_init() + if (res) + { + log_module(MAIN_LOG, LOG_FATAL, "Unable to start Windows Sockets (%d)", res); + } + + // Get Windows HINSTANCE. + hinst = GetModuleHandle(NULL); + + // Describe and register a window class. + memset(&wcx, 0, sizeof(wcx)); + wcx.cbSize = sizeof(wcx); + wcx.lpfnWndProc = ioset_win32_wndproc; + wcx.hInstance = hinst; + wcx.lpszClassName = "srvxMainWindow"; + if (!RegisterClassEx(&wcx)) + { + log_module(MAIN_LOG, LOG_FATAL, "Unable to register window class (%lu)", GetLastError()); + } + + ioset_window = CreateWindow("srvxMainWindow", PACKAGE_STRING, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hinst, NULL); + if (!ioset_window) + { + log_module(MAIN_LOG, LOG_FATAL, "Unable to create window (%lu)", GetLastError()); + } + return 0; } +static long +ioset_win32_events(const struct io_fd *fd) +{ + switch (fd->state) + { + case IO_CLOSED: + return 0; + case IO_LISTENING: + return FD_ACCEPT; + case IO_CONNECTING: + return FD_CONNECT; + case IO_CONNECTED: + return FD_READ | FD_CLOSE | (fd_wants_writes(fd) ? FD_WRITE : 0); + } +} + static void -ioset_win32_add(struct io_fd *fd) +ioset_win32_update(struct io_fd *fd) { - // TODO: implement ioset_win32_add() + int rc; + long events; + + events = ioset_win32_events(fd); + rc = WSAAsyncSelect(fd->fd, ioset_window, IDT_SOCKET, events); + if (rc) + { + log_module(MAIN_LOG, LOG_ERROR, "Unable to add events %#lx for fd %#x (%d)", events, fd->fd, WSAGetLastError()); + } } static void -ioset_win32_remove(struct io_fd *fd) +ioset_win32_add(struct io_fd *fd) { - // TODO: implement ioset_win32_remove() + unsigned int pos; + unsigned int ii; + + // Make sure fds[] can hold a new entry. + if (fds_used + 1 >= fds_size) + { + struct io_fd **new_fds; + unsigned int new_size; + + new_size = (fds_size < 8) ? 8 : fds_size * 2; + new_fds = calloc(new_size * 2, sizeof(new_fds[0])); + if (!new_fds) + { + log_module(MAIN_LOG, LOG_FATAL, "Unable to allocate %u-entry socket array.", new_size); + } + for (ii = 0; ii < fds_used; ++ii) + new_fds[ii] = fds[ii]; + free(fds); + fds = new_fds; + fds_size = new_size; + } + + // Insert fd into the appropriate spot in fds[]. + pos = io_fd_pos(fd->fd); + for (ii = pos; ii < fds_used; ++ii) + fds[ii + 1] = fds[ii]; + fds[pos] = fd; + ++fds_used; + + // Ask the OS for future notifications. + ioset_win32_update(fd); } static void -ioset_win32_update(struct io_fd *fd) +ioset_win32_remove(struct io_fd *fd, int os_closed) { - // TODO: implement ioset_win32_update() + unsigned int pos; + int rc; + + // Unregister from the OS. + if (!os_closed) + { + unsigned long ulong; + + rc = WSAAsyncSelect(fd->fd, ioset_window, IDT_SOCKET, 0); + if (rc) + { + log_module(MAIN_LOG, LOG_ERROR, "Unable to remove events for fd %#x (%d)", fd->fd, WSAGetLastError()); + } + + ulong = 0; + ioctlsocket(fd->fd, FIONBIO, &ulong); + } + + // Remove from the fds[] array. + pos = io_fd_pos(fd->fd); + for (--fds_used; pos < fds_used; ++pos) + fds[pos] = fds[pos + 1]; } static void ioset_win32_cleanup(void) { - // TODO: finish implementing ioset_win32_cleanup() + DestroyWindow(ioset_window); + ioset_window = NULL; WSACleanup(); } static int ioset_win32_loop(struct timeval *timeout) { - // TODO: implement ioset_win32_loop() + MSG msg; + BOOL not_really_bool; + int msec; + + // Make sure we are woken up after the appropriate time. + msec = (timeout->tv_sec * 1000) + (timeout->tv_usec / 1000); + SetTimer(ioset_window, IDT_TIMER1, msec, NULL); + // Do a blocking read of the message queue. + not_really_bool = GetMessage(&msg, NULL, 0, 0); + KillTimer(ioset_window, IDT_TIMER1); + if (not_really_bool < 0) + { + return 1; + } + else if (not_really_bool == 0) + { + quit_services = 1; + return 0; + } + else + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } return 0; } diff --git a/src/ioset.c b/src/ioset.c index d237a3b..d2e1eb2 100644 --- a/src/ioset.c +++ b/src/ioset.c @@ -142,10 +142,17 @@ ioset_add(int fd) { res->fd = fd; ioq_init(&res->send, 1024); ioq_init(&res->recv, 1024); +#if defined(F_GETFL) flags = fcntl(fd, F_GETFL); fcntl(fd, F_SETFL, flags|O_NONBLOCK); flags = fcntl(fd, F_GETFD); fcntl(fd, F_SETFD, flags|FD_CLOEXEC); +#else + /* I hope you're using the Win32 backend or something else that + * automatically marks the file descriptor non-blocking... + */ + (void)flags; +#endif engine->add(res); return res; } @@ -307,6 +314,20 @@ ioset_close(struct io_fd *fdp, int os_close) { active_fd = NULL; if (fdp->destroy_cb) fdp->destroy_cb(fdp); +#if defined(HAVE_WSAEVENTSELECT) + /* This is one huge kludge. Sorry! */ + if (fdp->send.get != fdp->send.put && (os_close & 2)) { + engine->remove(fdp, 0); + ioset_try_write(fdp); + /* it may need to send the beginning of the buffer now.. */ + if (fdp->send.get != fdp->send.put) + ioset_try_write(fdp); + } + free(fdp->send.buf); + free(fdp->recv.buf); + if (os_close & 1) + closesocket(fdp->fd); +#else if (fdp->send.get != fdp->send.put && (os_close & 2)) { int flags; @@ -322,6 +343,7 @@ ioset_close(struct io_fd *fdp, int os_close) { if (os_close & 1) close(fdp->fd); engine->remove(fdp, os_close & 1); +#endif free(fdp); }