updates.
[silc.git] / lib / silcutil / win32 / silcwin32schedule.c
1 /*
2
3   silcwin32schedule.c
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 2001 Pekka Riikonen
8
9   This program is free software; you can redistribute it and/or modify
10   it under the terms of the GNU General Public License as published by
11   the Free Software Foundation; either version 2 of the License, or
12   (at your option) any later version.
13   
14   This program is distributed in the hope that it will be useful,
15   but WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   GNU General Public License for more details.
18
19 */
20 /* $Id$ */
21
22 #include "silcincludes.h"
23
24 /* XXX This probably does not work at all the way we want. We mostly
25    need the scheduler to handle socket connections. The MSDN says the 
26    WaitForMultipleObjects should not be used for sockets. Instead they
27    should be handled through windows messages (Like WSAAsyncSelect) but
28    that would require some different approach to this whole thing. Also,
29    I don't know whether I could use the Winsock's select()?? Maybe it would
30    be possible to use select(), WaitForMultipleObjects and handle the
31    windows messages with the PeekMessage() etc... Dunno... Someone who
32    knows these things should take a look at this. Also, If it requires
33    some more tweaking I can abandon this silc_select() thingy all together
34    and move the generic code to unix/ and program the SILC Scheduler
35    interface all together as platform specific. It is here just to
36    use as much common code as possible... -Pekka */
37
38 /* Our "select()" for WIN32. This actually is not the select() and does
39    not call Winsock's select() (since it cannot be used for our purposes)
40    but mimics the functions of select(). 
41
42    This is taken from the GLib and is the g_poll function in the Glib.
43    It has been *heavily* modified to be select() like and fit for SILC. */
44
45 int silc_select(int n, fd_set *readfds, fd_set *writefds,
46                 fd_set *exceptfds, struct timeval *timeout)
47 {
48   HANDLE handles[MAXIMUM_WAIT_OBJECTS];
49   DWORD ready;
50   int nhandles = 0;
51   int timeo, i;
52
53   /* Check fd sets (ignoring the exceptfds for now) */
54
55   if (readfds) {
56     for (i = 0; i < n - 1; i++)
57       if (FD_ISSET(i, readfds))
58         handles[nhandles++] = (HANDLE)i;
59   }
60
61   if (writefds) {
62     /* If write fd is set then we just return */
63     for (i = 0; i < n - 1; i++)
64       if (FD_ISSET(i, writefds))
65         return 1;
66   }
67
68   if (!timeout)
69     timeo = INFINITE;
70   else
71     timeo = (timeout.tv_sec * 1000) + (timeout.tv_usec / 1000);
72
73  retry:
74   if (nhandles == 0)
75     return -1;
76   else
77     ready = WaitForMultipleObjects(nhandles, handles, FALSE, timeo,
78                                    QS_ALLINPUT);
79
80   if (ready == WAIT_FAILED) {
81     SILC_LOG_WARNING(("WaitForMultipleObjects() failed"));
82     return -1;
83   } else if (ready == WAIT_TIMEOUT) {
84     return 0;
85   } else if (ready == WAIT_OBJECT_0 + nhandles) {
86     /* For Windows messages. The MSDN online says that if the application
87        creates a window then its main loop (and we're assuming that
88        it is our SILC Scheduler) must handle the Windows messages, so do
89        it here as the MSDN suggests. -Pekka */
90     /* For reference: http://msdn.microsoft.com/library/default.asp?
91        url=/library/en-us/winui/hh/winui/messques_77zk.asp */
92     MSG msg;
93
94     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
95       TranslateMessage(&msg); 
96       DispatchMessage(&msg); 
97     }
98
99     /* Bad thing is that I don't know what to return, since actually
100        nothing for us happened. So, make another try with the waiting
101        and do not return. This of course may fuck up the timeouts! */
102     goto retry;
103   } else if (ready >= WAIT_OBJECT_0 && ready < WAIT_OBJECT_0 + nhandles &&
104              readfds) {
105     for (i = 0; i < n - 1; i++) {
106       if (ready - WAIT_OBJECT_0 != i)
107         FD_CLR(i, readfds);
108     }
109
110     /* Always one entry in the fd set. */
111     return 1;
112   }
113
114   return -1;
115 }