Finish ioset-win32 (not yet tested).
authorMichael Poole <mdpoole@troilus.org>
Tue, 6 Mar 2007 04:43:42 +0000 (23:43 -0500)
committerMichael Poole <mdpoole@troilus.org>
Tue, 6 Mar 2007 04:43:42 +0000 (23:43 -0500)
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.

src/compat.h
src/config.h.win32
src/ioset-win32.c
src/ioset.c

index 4968587e65159fc23f12d4fc0b95fbc1c7392557..d1508e25b0127fc02f15839f7c9dd88f8483a61b 100644 (file)
@@ -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 */
index 262ff37c377ebee7856d72ee8a5032fe633840f6..d58ae4c79896e6b2f5691e8d32b4b851da356813 100644 (file)
 #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"
index 018206a45143a2938de9fb9464b55955218496dc..7be12b06c70ca6dbaa300f7e23361af3528d6527 100644 (file)
  * 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;
 }
 
index d237a3b24bb931c70a3ee07ba67123ce80f82c8c..d2e1eb219dbcaaf7b4935278dd76dc302cfdf0bf 100644 (file)
@@ -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);
 }