d6b38827c5e20b597a429f3282ca3d3d98e15f65
[platform/upstream/glib.git] / glib / giowin32.c
1 /* GLIB - Library of useful routines for C programming
2  * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * giowin32.c: IO Channels for Win32.
5  * Copyright 1998 Owen Taylor and Tor Lillqvist
6  * Copyright 1999-2000 Tor Lillqvist and Craig Setera
7  * Copyright 2001-2003 Andrew Lanoix
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2 of the License, or (at your option) any later version.
13  *
14  * This library 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 GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the
21  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22  * Boston, MA 02111-1307, USA.
23  */
24
25 /*
26  * Modified by the GLib Team and others 1997-2000.  See the AUTHORS
27  * file for a list of people on the GLib Team.  See the ChangeLog
28  * files for a list of changes.  These files are distributed with
29  * GLib at ftp://ftp.gtk.org/pub/gtk/.
30  */
31
32 /* Define this to get (very) verbose logging of all channels */
33 /* #define G_IO_WIN32_DEBUG */
34
35 #include "config.h"
36
37 #include "glib.h"
38
39 #include <stdlib.h>
40 #include <windows.h>
41 #include <winsock.h>          /* Not everybody has winsock2 */
42 #include <fcntl.h>
43 #include <io.h>
44 #include <process.h>
45 #include <errno.h>
46 #include <sys/stat.h>
47
48 #include "glibintl.h"
49
50 typedef struct _GIOWin32Channel GIOWin32Channel;
51 typedef struct _GIOWin32Watch GIOWin32Watch;
52
53 #define BUFFER_SIZE 4096
54
55 typedef enum {
56   G_IO_WIN32_WINDOWS_MESSAGES,  /* Windows messages */
57   G_IO_WIN32_FILE_DESC,         /* Unix-like file descriptors from
58                                  * _open() or _pipe(). Read with read().
59                                  * Have to create separate thread to read.
60                                  */
61   G_IO_WIN32_SOCKET             /* Sockets. A separate thread is blocked
62                                  * in select() most of the time.
63                                  */
64 } GIOWin32ChannelType;
65
66 struct _GIOWin32Channel {
67   GIOChannel channel;
68   gint fd;                      /* Either a Unix-like file handle as provided
69                                  * by the Microsoft C runtime, or a SOCKET
70                                  * as provided by WinSock.
71                                  */
72   GIOWin32ChannelType type;
73   
74   gboolean debug;
75
76   CRITICAL_SECTION mutex;
77
78   /* This is used by G_IO_WIN32_WINDOWS_MESSAGES channels */
79   HWND hwnd;                    /* handle of window, or NULL */
80   
81   /* Following fields are used by both fd and socket channels. */
82   gboolean running;             /* Is reader thread running. FALSE if
83                                  * EOF has been reached.
84                                  */
85   gboolean needs_close;         /* If the channel has been closed while
86                                  * the reader thread was still running.
87                                  */
88   guint thread_id;              /* If non-NULL has a reader thread, or has
89                                  * had.*/
90   HANDLE data_avail_event;
91
92   gushort revents;
93
94   /* Following fields used by fd channels for input */
95   
96   /* Data is kept in a circular buffer. To be able to distinguish between
97    * empty and full buffer, we cannot fill it completely, but have to
98    * leave a one character gap.
99    *
100    * Data available is between indexes rdp and wrp-1 (modulo BUFFER_SIZE).
101    *
102    * Empty:    wrp == rdp
103    * Full:     (wrp + 1) % BUFFER_SIZE == rdp
104    * Partial:  otherwise
105    */
106   guchar *buffer;               /* (Circular) buffer */
107   gint wrp, rdp;                /* Buffer indices for writing and reading */
108   HANDLE space_avail_event;
109
110   /* Following fields used by socket channels */
111   GSList *watches;
112   HANDLE data_avail_noticed_event;
113   gint reset_send; /* socket used to send data so select_thread() can reset/re-loop */
114   gint reset_recv; /* socket used to recv data so select_thread() can reset/re-loop */
115 };
116
117 #define LOCK(mutex) EnterCriticalSection (&mutex)
118 #define UNLOCK(mutex) LeaveCriticalSection (&mutex)
119
120 struct _GIOWin32Watch {
121   GSource       source;
122   GPollFD       pollfd;
123   GIOChannel   *channel;
124   GIOCondition  condition;
125 };
126
127 static void
128 g_win32_print_access_mode (int flags)
129 {
130   g_print ("%s%s%s%s%s%s%s%s%s%s",
131            ((flags & 0x3) == _O_RDWR ? "O_RDWR" :
132             ((flags & 0x3) == _O_RDONLY ? "O_RDONLY" :
133              ((flags & 0x3) == _O_WRONLY ? "O_WRONLY" : "0"))),
134            (flags & _O_APPEND ? "|O_APPEND" : ""),
135            (flags & _O_RANDOM ? "|O_RANDOM" : ""),
136            (flags & _O_SEQUENTIAL ? "|O_SEQUENTIAL" : ""),
137            (flags & _O_TEMPORARY ? "|O_TEMPORARY" : ""),
138            (flags & _O_CREAT ? "|O_CREAT" : ""),
139            (flags & _O_TRUNC ? "|O_TRUNC" : ""),
140            (flags & _O_EXCL ? "|O_EXCL" : ""),
141            (flags & _O_TEXT ? "|O_TEXT" : ""),
142            (flags & _O_BINARY ? "|O_BINARY" : ""));
143 }
144
145 static void
146 g_win32_print_gioflags (GIOFlags flags)
147 {
148   char *bar = "";
149
150   if (flags & G_IO_FLAG_APPEND)
151     bar = "|", g_print ("APPEND");
152   if (flags & G_IO_FLAG_NONBLOCK)
153     g_print ("%sNONBLOCK", bar), bar = "|";
154   if (flags & G_IO_FLAG_IS_READABLE)
155     g_print ("%sREADABLE", bar), bar = "|";
156   if (flags & G_IO_FLAG_IS_WRITEABLE)
157     g_print ("%sWRITEABLE", bar), bar = "|";
158   if (flags & G_IO_FLAG_IS_WRITEABLE)
159     g_print ("%sWRITEABLE", bar), bar = "|";
160   if (flags & G_IO_FLAG_IS_SEEKABLE)
161     g_print ("%sSEEKABLE", bar), bar = "|";
162 }
163
164 static gboolean
165 g_io_win32_get_debug_flag (void)
166 {
167 #ifdef G_IO_WIN32_DEBUG
168   return TRUE;
169 #else
170   if (getenv ("G_IO_WIN32_DEBUG") != NULL)
171     return TRUE;
172   else
173     return FALSE;
174 #endif
175 }  
176
177 static void
178 g_io_channel_win32_init (GIOWin32Channel *channel)
179 {
180   channel->debug = g_io_win32_get_debug_flag ();
181   channel->buffer = NULL;
182   channel->running = FALSE;
183   channel->needs_close = FALSE;
184   channel->thread_id = 0;
185   channel->data_avail_event = NULL;
186   channel->revents = 0;
187   channel->space_avail_event = NULL;
188   channel->data_avail_noticed_event = NULL;
189   channel->watches = NULL;
190   InitializeCriticalSection (&channel->mutex);
191 }
192
193 static void
194 create_events (GIOWin32Channel *channel)
195 {
196   SECURITY_ATTRIBUTES sec_attrs;
197   
198   sec_attrs.nLength = sizeof (SECURITY_ATTRIBUTES);
199   sec_attrs.lpSecurityDescriptor = NULL;
200   sec_attrs.bInheritHandle = FALSE;
201
202   /* The data available event is manual reset, the space available event
203    * is automatic reset.
204    */
205   if (!(channel->data_avail_event = CreateEvent (&sec_attrs, TRUE, FALSE, NULL))
206       || !(channel->space_avail_event = CreateEvent (&sec_attrs, FALSE, FALSE, NULL))
207       || !(channel->data_avail_noticed_event = CreateEvent (&sec_attrs, FALSE, FALSE, NULL)))
208     {
209       gchar *emsg = g_win32_error_message (GetLastError ());
210       g_error ("Error creating event: %s", emsg);
211       g_free (emsg);
212     }
213 }
214
215 static unsigned __stdcall
216 read_thread (void *parameter)
217 {
218   GIOWin32Channel *channel = parameter;
219   guchar *buffer;
220   guint nbytes;
221
222   g_io_channel_ref ((GIOChannel *)channel);
223
224   if (channel->debug)
225     g_print ("read_thread %#x: start fd:%d, data_avail:%#x space_avail:%#x\n",
226              channel->thread_id,
227              channel->fd,
228              (guint) channel->data_avail_event,
229              (guint) channel->space_avail_event);
230   
231   channel->buffer = g_malloc (BUFFER_SIZE);
232   channel->rdp = channel->wrp = 0;
233   channel->running = TRUE;
234
235   SetEvent (channel->space_avail_event);
236   
237   while (channel->running)
238     {
239       LOCK (channel->mutex);
240       if (channel->debug)
241         g_print ("read_thread %#x: rdp=%d, wrp=%d\n",
242                  channel->thread_id, channel->rdp, channel->wrp);
243       if ((channel->wrp + 1) % BUFFER_SIZE == channel->rdp)
244         {
245           /* Buffer is full */
246           if (channel->debug)
247             g_print ("read_thread %#x: resetting space_avail\n",
248                      channel->thread_id);
249           ResetEvent (channel->space_avail_event);
250           if (channel->debug)
251             g_print ("read_thread %#x: waiting for space\n",
252                      channel->thread_id);
253           UNLOCK (channel->mutex);
254           WaitForSingleObject (channel->space_avail_event, INFINITE);
255           LOCK (channel->mutex);
256           if (channel->debug)
257             g_print ("read_thread %#x: rdp=%d, wrp=%d\n",
258                      channel->thread_id, channel->rdp, channel->wrp);
259         }
260       
261       buffer = channel->buffer + channel->wrp;
262       
263       /* Always leave at least one byte unused gap to be able to
264        * distinguish between the full and empty condition...
265        */
266       nbytes = MIN ((channel->rdp + BUFFER_SIZE - channel->wrp - 1) % BUFFER_SIZE,
267                     BUFFER_SIZE - channel->wrp);
268
269       if (channel->debug)
270         g_print ("read_thread %#x: calling read() for %d bytes\n",
271                  channel->thread_id, nbytes);
272
273       UNLOCK (channel->mutex);
274
275       nbytes = read (channel->fd, buffer, nbytes);
276       
277       LOCK (channel->mutex);
278
279       channel->revents = G_IO_IN;
280       if (nbytes == 0)
281         channel->revents |= G_IO_HUP;
282       else if (nbytes < 0)
283         channel->revents |= G_IO_ERR;
284
285       if (channel->debug)
286         g_print ("read_thread %#x: read() returned %d, rdp=%d, wrp=%d\n",
287                  channel->thread_id, nbytes, channel->rdp, channel->wrp);
288
289       if (nbytes <= 0)
290         break;
291
292       channel->wrp = (channel->wrp + nbytes) % BUFFER_SIZE;
293       if (channel->debug)
294         g_print ("read_thread %#x: rdp=%d, wrp=%d, setting data_avail\n",
295                  channel->thread_id, channel->rdp, channel->wrp);
296       SetEvent (channel->data_avail_event);
297       UNLOCK (channel->mutex);
298     }
299   
300   channel->running = FALSE;
301   if (channel->needs_close)
302     {
303       if (channel->debug)
304         g_print ("read_thread %#x: channel fd %d needs closing\n",
305                  channel->thread_id, channel->fd);
306       close (channel->fd);
307       channel->fd = -1;
308     }
309
310   if (channel->debug)
311     g_print ("read_thread %#x: EOF, rdp=%d, wrp=%d, setting data_avail\n",
312              channel->thread_id, channel->rdp, channel->wrp);
313   SetEvent (channel->data_avail_event);
314   UNLOCK (channel->mutex);
315   
316   g_io_channel_unref((GIOChannel *)channel);
317   
318   /* No need to call _endthreadex(), the actual thread starter routine
319    * in MSVCRT (see crt/src/threadex.c:_threadstartex) calls
320    * _endthreadex() for us.
321    */
322
323   return 0;
324 }
325
326 static void
327 create_thread (GIOWin32Channel     *channel,
328                GIOCondition         condition,
329                unsigned (__stdcall *thread) (void *parameter))
330 {
331   HANDLE thread_handle;
332
333   thread_handle = (HANDLE) _beginthreadex (NULL, 0, thread, channel, 0,
334                                            &channel->thread_id);
335   if (thread_handle == 0)
336     g_warning (G_STRLOC ": Error creating reader thread: %s",
337                g_strerror (errno));
338   else if (!CloseHandle (thread_handle))
339     g_warning (G_STRLOC ": Error closing thread handle: %s\n",
340                g_win32_error_message (GetLastError ()));
341
342   WaitForSingleObject (channel->space_avail_event, INFINITE);
343 }
344
345 static void
346 init_reset_sockets(GIOWin32Channel *channel)
347 {
348   struct sockaddr_in local, local2, server;
349   unsigned int addr;
350   int len;
351   struct hostent *hp;
352
353   channel->reset_send = (gint) socket(AF_INET, SOCK_DGRAM, 0);
354   if (channel->reset_send == INVALID_SOCKET)
355   {
356           g_warning (G_STRLOC ": Error creating reset_send socket: %s\n",
357               g_win32_error_message (WSAGetLastError ()));
358   }
359
360   local.sin_family = AF_INET;
361   local.sin_port = 0;
362   local.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
363
364   if (bind(channel->reset_send, (struct sockaddr *)&local, sizeof(local)) == SOCKET_ERROR)
365   {
366     g_warning (G_STRLOC ": Error binding to reset_send socket: %s\n",
367             g_win32_error_message (WSAGetLastError ()));
368   }
369
370   local2.sin_family = AF_INET;
371   local2.sin_port = 0;
372   local2.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
373
374   channel->reset_recv = (gint) socket(AF_INET, SOCK_DGRAM, 0);
375   if (channel->reset_recv == INVALID_SOCKET)
376   {
377           g_warning (G_STRLOC ": Error creating reset_recv socket: %s\n",
378               g_win32_error_message (WSAGetLastError ()));
379   }
380
381   if (bind(channel->reset_recv, (struct sockaddr *)&local2, sizeof(local)) == SOCKET_ERROR)
382   {
383     g_warning (G_STRLOC ": Error binding to reset_recv socket: %s\n",
384             g_win32_error_message (WSAGetLastError ()));
385   }
386   
387   len = sizeof(local2);
388   if (getsockname(channel->reset_recv, (struct sockaddr *)&local2, &len) == SOCKET_ERROR)
389   {
390     g_warning (G_STRLOC ": Error getsockname with reset_recv socket: %s\n",
391             g_win32_error_message (WSAGetLastError ()));
392   }
393
394   addr = inet_addr("127.0.0.1");
395   hp = gethostbyaddr((char *)&addr,4,AF_INET);
396
397   memset(&server,0,sizeof(server));
398   memcpy(&(server.sin_addr),hp->h_addr,hp->h_length);
399   server.sin_family = hp->h_addrtype;
400   server.sin_port = local2.sin_port;
401
402   if (connect(channel->reset_send, (struct sockaddr  *)&server, sizeof(server)) == SOCKET_ERROR)
403   {
404     g_warning (G_STRLOC ": connect to reset_recv socket: %s\n",
405             g_win32_error_message (WSAGetLastError ()));
406   }
407
408 }
409
410 static GIOStatus
411 buffer_read (GIOWin32Channel *channel,
412              guchar          *dest,
413              gsize            count,
414              gsize           *bytes_read,
415              GError         **err)
416 {
417   guint nbytes;
418   guint left = count;
419   
420   LOCK (channel->mutex);
421   if (channel->debug)
422     g_print ("reading from thread %#x %d bytes, rdp=%d, wrp=%d\n",
423              channel->thread_id, count, channel->rdp, channel->wrp);
424   
425   if (channel->wrp == channel->rdp)
426     {
427       UNLOCK (channel->mutex);
428       if (channel->debug)
429         g_print ("waiting for data from thread %#x\n", channel->thread_id);
430       WaitForSingleObject (channel->data_avail_event, INFINITE);
431       if (channel->debug)
432         g_print ("done waiting for data from thread %#x\n", channel->thread_id);
433       LOCK (channel->mutex);
434       if (channel->wrp == channel->rdp && !channel->running)
435         {
436           if (channel->debug)
437             g_print ("wrp==rdp, !running\n");
438           UNLOCK (channel->mutex);
439           *bytes_read = 0;
440           return G_IO_STATUS_EOF;
441         }
442     }
443   
444   if (channel->rdp < channel->wrp)
445     nbytes = channel->wrp - channel->rdp;
446   else
447     nbytes = BUFFER_SIZE - channel->rdp;
448   UNLOCK (channel->mutex);
449   nbytes = MIN (left, nbytes);
450   if (channel->debug)
451     g_print ("moving %d bytes from thread %#x\n",
452              nbytes, channel->thread_id);
453   memcpy (dest, channel->buffer + channel->rdp, nbytes);
454   dest += nbytes;
455   left -= nbytes;
456   LOCK (channel->mutex);
457   channel->rdp = (channel->rdp + nbytes) % BUFFER_SIZE;
458   if (channel->debug)
459     g_print ("setting space_avail for thread %#x\n", channel->thread_id);
460   SetEvent (channel->space_avail_event);
461   if (channel->debug)
462     g_print ("for thread %#x: rdp=%d, wrp=%d\n",
463              channel->thread_id, channel->rdp, channel->wrp);
464   if (channel->running && channel->wrp == channel->rdp)
465     {
466       if (channel->debug)
467         g_print ("resetting data_avail of thread %#x\n",
468                  channel->thread_id);
469       ResetEvent (channel->data_avail_event);
470     };
471   UNLOCK (channel->mutex);
472   
473   /* We have no way to indicate any errors form the actual
474    * read() or recv() call in the reader thread. Should we have?
475    */
476   *bytes_read = count - left;
477   return (*bytes_read > 0) ? G_IO_STATUS_NORMAL : G_IO_STATUS_EOF;
478 }
479
480 static unsigned __stdcall
481 select_thread (void *parameter)
482 {
483   GIOWin32Channel *channel = parameter;
484   fd_set read_fds, write_fds, except_fds;
485   GSList *tmp;
486   int n;
487   char buffer[8];
488
489   g_io_channel_ref ((GIOChannel *)channel);
490
491   if (channel->debug)
492     g_print ("select_thread %#x: start fd:%d data_avail:%#x data_avail_noticed:%#x\n",
493              channel->thread_id,
494              channel->fd,
495              (guint) channel->data_avail_event,
496              (guint) channel->data_avail_noticed_event);
497   
498   channel->rdp = channel->wrp = 0;
499   channel->running = TRUE;
500
501   SetEvent (channel->space_avail_event);
502   
503   while (channel->running)
504     {
505       FD_ZERO (&read_fds);
506       FD_ZERO (&write_fds);
507       FD_ZERO (&except_fds);
508       FD_SET(channel->reset_recv, &read_fds);
509
510       LOCK (channel->mutex);
511       tmp = channel->watches;
512       while (tmp)
513           {
514             GIOWin32Watch *watch = (GIOWin32Watch *)tmp->data;
515
516             if (watch->condition & (G_IO_IN | G_IO_HUP))
517               FD_SET (channel->fd, &read_fds);
518             if (watch->condition & G_IO_OUT)
519               FD_SET (channel->fd, &write_fds);
520             if (watch->condition & G_IO_ERR)
521               FD_SET (channel->fd, &except_fds);
522           
523             tmp = tmp->next;
524           }
525       UNLOCK (channel->mutex);
526
527       if (channel->debug)
528             g_print ("select_thread %#x: calling select() for%s%s%s\n",
529                   channel->thread_id,
530                   (FD_ISSET (channel->fd, &read_fds) ? " IN" : ""),
531                   (FD_ISSET (channel->fd, &write_fds) ? " OUT" : ""),
532                   (FD_ISSET (channel->fd, &except_fds) ? " ERR" : ""));
533
534       n = select (1, &read_fds, &write_fds, &except_fds, NULL);
535       
536           LOCK (channel->mutex);
537       if (channel->needs_close)
538       {
539         UNLOCK (channel->mutex);
540         break;
541       }
542       UNLOCK (channel->mutex);
543
544       if (n == SOCKET_ERROR)
545         {
546           if (channel->debug)
547             g_print ("select_thread %#x: select returned SOCKET_ERROR\n",
548                      channel->thread_id);
549           break;
550         }
551
552     if (FD_ISSET(channel->reset_recv, &read_fds))
553     {
554       if (channel->debug)
555         g_print ("select_thread %#x: re-looping\n",
556             channel->thread_id);
557       recv(channel->reset_recv,  (char *)&buffer, (int) sizeof(buffer), 0);
558       continue;
559     }
560
561     if (channel->debug)
562           g_print ("select_thread %#x: got%s%s%s\n",
563         channel->thread_id,
564                   (FD_ISSET (channel->fd, &read_fds) ? " IN" : ""),
565                   (FD_ISSET (channel->fd, &write_fds) ? " OUT" : ""),
566                   (FD_ISSET (channel->fd, &except_fds) ? " ERR" : ""));
567
568     if (FD_ISSET (channel->fd, &read_fds))
569       channel->revents |= G_IO_IN;
570     if (FD_ISSET (channel->fd, &write_fds))
571       channel->revents |= G_IO_OUT;
572     if (FD_ISSET (channel->fd, &except_fds))
573       channel->revents |= G_IO_ERR;
574
575     if (channel->debug)
576       g_print ("select_thread %#x: resetting data_avail_noticed, setting data_avail\n",
577         channel->thread_id);
578
579     LOCK (channel->mutex);
580     ResetEvent (channel->data_avail_noticed_event);
581     SetEvent (channel->data_avail_event);
582     if (channel->needs_close)
583     {
584       UNLOCK (channel->mutex);
585       break;
586     }
587     UNLOCK (channel->mutex);
588
589     if (channel->debug)
590       g_print ("select_thread %#x: waiting for data_avail_noticed\n",
591         channel->thread_id);
592
593     WaitForSingleObject (channel->data_avail_noticed_event, INFINITE);
594     if (channel->debug)
595       g_print ("select_thread %#x: got data_avail_noticed\n",
596                  channel->thread_id);
597     }
598
599   LOCK (channel->mutex);
600   channel->running = FALSE;
601   if (channel->debug)
602     g_print ("select_thread %#x: got error, setting data_avail\n",
603              channel->thread_id);
604   SetEvent (channel->data_avail_event);
605   g_io_channel_unref((GIOChannel *)channel);
606   UNLOCK (channel->mutex);
607
608   /* No need to call _endthreadex(), the actual thread starter routine
609    * in MSVCRT (see crt/src/threadex.c:_threadstartex) calls
610    * _endthreadex() for us.
611    */
612
613   return 0;
614 }
615
616 static gboolean
617 g_io_win32_prepare (GSource *source,
618                     gint    *timeout)
619 {
620   GIOWin32Watch *watch = (GIOWin32Watch *)source;
621   GIOCondition buffer_condition = g_io_channel_get_buffer_condition (watch->channel);
622   GIOWin32Channel *channel = (GIOWin32Channel *)watch->channel;
623   
624   *timeout = -1;
625   
626   if (channel->debug)
627     g_print ("g_io_win32_prepare: for thread %#x buffer_condition:%#x\n"
628              "  watch->pollfd.events:%#x watch->pollfd.revents:%#x channel->revents:%#x\n",
629              channel->thread_id, buffer_condition,
630              watch->pollfd.events, watch->pollfd.revents, channel->revents);
631
632   if (channel->type == G_IO_WIN32_FILE_DESC)
633     {
634       LOCK (channel->mutex);
635       if (channel->running && channel->wrp == channel->rdp)
636         {
637           if (channel->debug)
638             g_print ("g_io_win32_prepare: for thread %#x, setting channel->revents = 0\n",
639                      channel->thread_id);
640           channel->revents = 0;
641         }
642       UNLOCK (channel->mutex);
643     }
644   else if (channel->type == G_IO_WIN32_SOCKET)
645     {
646       LOCK (channel->mutex);
647       channel->revents = 0;
648       if (channel->debug)
649         g_print ("g_io_win32_prepare: for thread %#x, setting data_avail_noticed\n",
650                  channel->thread_id);
651       SetEvent (channel->data_avail_noticed_event);
652       if (channel->debug)
653         g_print ("g_io_win32_prepare: thread %#x, there.\n",
654                  channel->thread_id);
655       UNLOCK (channel->mutex);
656     }
657
658   return ((watch->condition & buffer_condition) == watch->condition);
659 }
660
661 static gboolean
662 g_io_win32_check (GSource *source)
663 {
664   MSG msg;
665   GIOWin32Watch *watch = (GIOWin32Watch *)source;
666   GIOWin32Channel *channel = (GIOWin32Channel *)watch->channel;
667   GIOCondition buffer_condition = g_io_channel_get_buffer_condition (watch->channel);
668
669   if (channel->debug)
670     g_print ("g_io_win32_check: for thread %#x buffer_condition:%#x\n"
671              "  watch->pollfd.events:%#x watch->pollfd.revents:%#x channel->revents:%#x\n",
672              channel->thread_id, buffer_condition,
673              watch->pollfd.events, watch->pollfd.revents, channel->revents);
674
675   if (channel->type != G_IO_WIN32_WINDOWS_MESSAGES)
676     {
677       watch->pollfd.revents = (watch->pollfd.events & channel->revents);
678     }
679   else
680     {
681       return (PeekMessage (&msg, channel->hwnd, 0, 0, PM_NOREMOVE));
682     }
683   
684   if (channel->type == G_IO_WIN32_SOCKET)
685     {
686       LOCK (channel->mutex);
687       if (channel->debug)
688         g_print ("g_io_win32_check: thread %#x, resetting data_avail\n",
689                  channel->thread_id);
690       ResetEvent (channel->data_avail_event);
691       if (channel->debug)
692         g_print ("g_io_win32_check: thread %#x, there.\n",
693                  channel->thread_id);
694       UNLOCK (channel->mutex);
695     }
696
697   return ((watch->pollfd.revents | buffer_condition) & watch->condition);
698 }
699
700 static gboolean
701 g_io_win32_dispatch (GSource     *source,
702                      GSourceFunc  callback,
703                      gpointer     user_data)
704 {
705   GIOFunc func = (GIOFunc)callback;
706   GIOWin32Watch *watch = (GIOWin32Watch *)source;
707   GIOCondition buffer_condition = g_io_channel_get_buffer_condition (watch->channel);
708   
709   if (!func)
710     {
711       g_warning (G_STRLOC ": GIOWin32Watch dispatched without callback\n"
712                  "You must call g_source_connect().");
713       return FALSE;
714     }
715   
716   return (*func) (watch->channel,
717                   (watch->pollfd.revents | buffer_condition) & watch->condition,
718                   user_data);
719 }
720
721 static void
722 g_io_win32_finalize (GSource *source)
723 {
724   GIOWin32Watch *watch = (GIOWin32Watch *)source;
725   GIOWin32Channel *channel = (GIOWin32Channel *)watch->channel;
726   char send_buffer[] = "f";
727   
728   LOCK (channel->mutex);
729   if (channel->debug)
730     g_print ("g_io_win32_finalize: channel with thread %#x\n",
731              channel->thread_id);
732
733   channel->watches = g_slist_remove (channel->watches, watch);
734
735   SetEvent (channel->data_avail_noticed_event);
736   if (channel->type == G_IO_WIN32_SOCKET)
737     send(channel->reset_send, send_buffer, sizeof(send_buffer), 0);
738
739   g_io_channel_unref (watch->channel);
740   UNLOCK (channel->mutex);
741 }
742
743 #if defined(G_PLATFORM_WIN32) && defined(__GNUC__)
744 __declspec(dllexport)
745 #endif
746 GSourceFuncs g_io_watch_funcs = {
747   g_io_win32_prepare,
748   g_io_win32_check,
749   g_io_win32_dispatch,
750   g_io_win32_finalize
751 };
752
753 static GSource *
754 g_io_win32_create_watch (GIOChannel    *channel,
755                          GIOCondition   condition,
756                          unsigned (__stdcall *thread) (void *parameter))
757 {
758   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
759   GIOWin32Watch *watch;
760   GSource *source;
761   char send_buffer[] = "c";
762
763   source = g_source_new (&g_io_watch_funcs, sizeof (GIOWin32Watch));
764   watch = (GIOWin32Watch *)source;
765   
766   watch->channel = channel;
767   g_io_channel_ref (channel);
768   
769   watch->condition = condition;
770   
771   if (win32_channel->data_avail_event == NULL)
772     create_events (win32_channel);
773
774   watch->pollfd.fd = (gint) win32_channel->data_avail_event;
775   watch->pollfd.events = condition;
776   
777   if (win32_channel->debug)
778     g_print ("g_io_win32_create_watch: fd:%d condition:%#x handle:%#x\n",
779              win32_channel->fd, condition, watch->pollfd.fd);
780
781   LOCK (win32_channel->mutex);
782   win32_channel->watches = g_slist_append (win32_channel->watches, watch);
783
784   if (win32_channel->thread_id == 0)
785     create_thread (win32_channel, condition, thread);
786   else
787     send(win32_channel->reset_send, send_buffer, sizeof(send_buffer), 0);
788
789   g_source_add_poll (source, &watch->pollfd);
790   UNLOCK (win32_channel->mutex);
791
792   return source;
793 }
794
795 static GIOStatus
796 g_io_win32_msg_read (GIOChannel *channel,
797                      gchar      *buf,
798                      gsize       count,
799                      gsize      *bytes_read,
800                      GError    **err)
801 {
802   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
803   MSG msg;               /* In case of alignment problems */
804   
805   if (count < sizeof (MSG))
806     {
807       g_set_error(err, G_IO_CHANNEL_ERROR, G_IO_CHANNEL_ERROR_INVAL,
808         "Incorrect message size"); /* Informative enough error message? */
809       return G_IO_STATUS_ERROR;
810     }
811   
812   if (win32_channel->debug)
813     g_print ("g_io_win32_msg_read: for %#x\n",
814              (guint) win32_channel->hwnd);
815   if (!PeekMessage (&msg, win32_channel->hwnd, 0, 0, PM_REMOVE))
816     return G_IO_STATUS_AGAIN;
817
818   memmove (buf, &msg, sizeof (MSG));
819   *bytes_read = sizeof (MSG);
820
821   return G_IO_STATUS_NORMAL;
822 }
823
824 static GIOStatus
825 g_io_win32_msg_write (GIOChannel  *channel,
826                       const gchar *buf,
827                       gsize        count,
828                       gsize       *bytes_written,
829                       GError     **err)
830 {
831   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
832   MSG msg;
833   
834   if (count != sizeof (MSG))
835     {
836       g_set_error(err, G_IO_CHANNEL_ERROR, G_IO_CHANNEL_ERROR_INVAL,
837         "Incorrect message size"); /* Informative enough error message? */
838       return G_IO_STATUS_ERROR;
839     }
840   
841   /* In case of alignment problems */
842   memmove (&msg, buf, sizeof (MSG));
843   if (!PostMessage (win32_channel->hwnd, msg.message, msg.wParam, msg.lParam))
844     {
845       gchar *emsg = g_win32_error_message (GetLastError ());
846       g_set_error(err, G_IO_CHANNEL_ERROR, G_IO_CHANNEL_ERROR_FAILED, emsg);
847       g_free (emsg);
848       return G_IO_STATUS_ERROR;
849     }
850
851   *bytes_written = sizeof (MSG);
852
853   return G_IO_STATUS_NORMAL;
854 }
855
856 static GIOStatus
857 g_io_win32_msg_close (GIOChannel *channel,
858                       GError    **err)
859 {
860   /* Nothing to be done. Or should we set hwnd to some invalid value? */
861
862   return G_IO_STATUS_NORMAL;
863 }
864
865 static void
866 g_io_win32_free (GIOChannel *channel)
867 {
868   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
869   
870   if (win32_channel->debug)
871     g_print ("thread %#x: freeing channel, fd: %d\n",
872              win32_channel->thread_id,
873              win32_channel->fd);
874
875   if (win32_channel->reset_send)
876     closesocket(win32_channel->reset_send);
877   if (win32_channel->reset_recv)
878     closesocket(win32_channel->reset_recv);
879   if (win32_channel->data_avail_event)
880     CloseHandle (win32_channel->data_avail_event);
881   if (win32_channel->space_avail_event)
882     CloseHandle (win32_channel->space_avail_event);
883   if (win32_channel->data_avail_noticed_event)
884     CloseHandle (win32_channel->data_avail_noticed_event);
885   DeleteCriticalSection (&win32_channel->mutex);
886
887   g_free (win32_channel->buffer);
888   g_slist_free (win32_channel->watches);
889   g_free (win32_channel);
890 }
891
892 static GSource *
893 g_io_win32_msg_create_watch (GIOChannel    *channel,
894                              GIOCondition   condition)
895 {
896   GIOWin32Watch *watch;
897   GSource *source;
898
899   source = g_source_new (&g_io_watch_funcs, sizeof (GIOWin32Watch));
900   watch = (GIOWin32Watch *)source;
901   
902   watch->channel = channel;
903   g_io_channel_ref (channel);
904   
905   watch->condition = condition;
906   
907   watch->pollfd.fd = G_WIN32_MSG_HANDLE;
908   watch->pollfd.events = condition;
909   
910   g_source_add_poll (source, &watch->pollfd);
911   
912   return source;
913 }
914
915 static GIOStatus
916 g_io_win32_fd_read (GIOChannel *channel,
917                     gchar      *buf,
918                     gsize       count,
919                     gsize      *bytes_read,
920                     GError    **err)
921 {
922   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
923   gint result;
924   
925   if (win32_channel->debug)
926     g_print ("g_io_win32_fd_read: fd:%d count:%d\n",
927              win32_channel->fd, count);
928   
929   if (win32_channel->thread_id)
930     {
931       return buffer_read (win32_channel, buf, count, bytes_read, err);
932     }
933
934   result = read (win32_channel->fd, buf, count);
935
936   if (win32_channel->debug)
937     g_print ("g_io_win32_fd_read: read() = %d\n", result);
938
939   if (result < 0)
940     {
941       *bytes_read = 0;
942
943       switch(errno)
944         {
945 #ifdef EAGAIN
946           case EAGAIN:
947             return G_IO_STATUS_AGAIN;
948 #endif
949           default:
950             g_set_error (err, G_IO_CHANNEL_ERROR,
951                          g_io_channel_error_from_errno (errno),
952                          g_strerror (errno));
953             return G_IO_STATUS_ERROR;
954         }
955     }
956
957   *bytes_read = result;
958
959   return (result > 0) ? G_IO_STATUS_NORMAL : G_IO_STATUS_EOF;
960 }
961
962 static GIOStatus
963 g_io_win32_fd_write (GIOChannel  *channel,
964                      const gchar *buf,
965                      gsize        count,
966                      gsize       *bytes_written,
967                      GError     **err)
968 {
969   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
970   gint result;
971   
972   result = write (win32_channel->fd, buf, count);
973   if (win32_channel->debug)
974     g_print ("g_io_win32_fd_write: fd:%d count:%d = %d\n",
975              win32_channel->fd, count, result);
976
977   if (result < 0)
978     {
979       *bytes_written = 0;
980
981       switch(errno)
982         {
983 #ifdef EAGAIN
984           case EAGAIN:
985             return G_IO_STATUS_AGAIN;
986 #endif
987           default:
988             g_set_error (err, G_IO_CHANNEL_ERROR,
989                          g_io_channel_error_from_errno (errno),
990                          g_strerror (errno));
991             return G_IO_STATUS_ERROR;
992         }
993     }
994
995   *bytes_written = result;
996
997   return G_IO_STATUS_NORMAL;
998 }
999
1000 static GIOStatus
1001 g_io_win32_fd_seek (GIOChannel *channel,
1002                     gint64      offset,
1003                     GSeekType   type,
1004                     GError    **err)
1005 {
1006   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
1007   int whence;
1008   off_t tmp_offset;
1009   off_t result;
1010   
1011   switch (type)
1012     {
1013     case G_SEEK_SET:
1014       whence = SEEK_SET;
1015       break;
1016     case G_SEEK_CUR:
1017       whence = SEEK_CUR;
1018       break;
1019     case G_SEEK_END:
1020       whence = SEEK_END;
1021       break;
1022     default:
1023       whence = -1; /* Keep the compiler quiet */
1024       g_assert_not_reached();
1025     }
1026
1027   tmp_offset = offset;
1028   if (tmp_offset != offset)
1029     {
1030       g_set_error (err, G_IO_CHANNEL_ERROR,
1031                    g_io_channel_error_from_errno (EINVAL),
1032                    g_strerror (EINVAL));
1033       return G_IO_STATUS_ERROR;
1034     }
1035   
1036   result = lseek (win32_channel->fd, tmp_offset, whence);
1037   
1038   if (result < 0)
1039     {
1040       g_set_error (err, G_IO_CHANNEL_ERROR,
1041                    g_io_channel_error_from_errno (errno),
1042                    g_strerror (errno));
1043       return G_IO_STATUS_ERROR;
1044     }
1045
1046   return G_IO_STATUS_NORMAL;
1047 }
1048
1049 static GIOStatus
1050 g_io_win32_fd_close (GIOChannel *channel,
1051                      GError    **err)
1052 {
1053   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
1054   
1055   if (win32_channel->debug)
1056     g_print ("thread %#x: closing fd %d\n",
1057              win32_channel->thread_id,
1058              win32_channel->fd);
1059   LOCK (win32_channel->mutex);
1060   if (win32_channel->running)
1061     {
1062       if (win32_channel->debug)
1063         g_print ("thread %#x: running, marking fd %d for later close\n",
1064                  win32_channel->thread_id, win32_channel->fd);
1065       win32_channel->running = FALSE;
1066       win32_channel->needs_close = TRUE;
1067       SetEvent (win32_channel->data_avail_event);
1068     }
1069   else
1070     {
1071       if (win32_channel->debug)
1072         g_print ("closing fd %d\n", win32_channel->fd);
1073       close (win32_channel->fd);
1074       if (win32_channel->debug)
1075         g_print ("closed fd %d, setting to -1\n",
1076                  win32_channel->fd);
1077       win32_channel->fd = -1;
1078     }
1079   UNLOCK (win32_channel->mutex);
1080
1081   /* FIXME error detection? */
1082
1083   return G_IO_STATUS_NORMAL;
1084 }
1085
1086 static GSource *
1087 g_io_win32_fd_create_watch (GIOChannel    *channel,
1088                             GIOCondition   condition)
1089 {
1090   return g_io_win32_create_watch (channel, condition, read_thread);
1091 }
1092
1093 static GIOStatus
1094 g_io_win32_sock_read (GIOChannel *channel,
1095                       gchar      *buf,
1096                       gsize       count,
1097                       gsize      *bytes_read,
1098                       GError    **err)
1099 {
1100   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
1101   gint result;
1102   GIOChannelError error = G_IO_STATUS_NORMAL;
1103   GIOStatus internal_status = G_IO_STATUS_NORMAL;
1104   char send_buffer[] = "sr";
1105
1106   if (win32_channel->debug)
1107     g_print ("g_io_win32_sock_read: sockfd:%d count:%d\n",
1108              win32_channel->fd, count);
1109 #ifdef WE_NEED_TO_HANDLE_WSAEINTR
1110 repeat:
1111 #endif
1112   result = recv (win32_channel->fd, buf, count, 0);
1113
1114   if (win32_channel->debug)
1115     g_print ("g_io_win32_sock_read: recv:%d\n", result);
1116   
1117   if (result == SOCKET_ERROR)
1118     {
1119       *bytes_read = 0;
1120
1121       switch (WSAGetLastError ())
1122         {
1123         case WSAEINVAL:
1124           error = G_IO_CHANNEL_ERROR_INVAL;
1125           break;
1126         case WSAEWOULDBLOCK:
1127           return G_IO_STATUS_AGAIN;
1128 #ifdef WE_NEED_TO_HANDLE_WSAEINTR /* not anymore with wsock2 ? */
1129         case WSAEINTR:
1130           goto repeat;
1131 #endif
1132         default:
1133           error = G_IO_CHANNEL_ERROR_FAILED;
1134           break;
1135         }
1136       g_set_error(err, G_IO_CHANNEL_ERROR, error, "Socket read error");
1137       internal_status = G_IO_STATUS_ERROR;
1138       /* FIXME get all errors, better error messages */
1139     }
1140   else
1141     {
1142       *bytes_read = result;
1143       if (result == 0)
1144             internal_status = G_IO_STATUS_EOF;
1145     }
1146
1147   if ((internal_status == G_IO_STATUS_EOF) || 
1148      (internal_status == G_IO_STATUS_ERROR))
1149   {
1150     LOCK (win32_channel->mutex);
1151     SetEvent(win32_channel->data_avail_noticed_event);
1152     win32_channel->needs_close = 1;
1153     send(win32_channel->reset_send, send_buffer, sizeof(send_buffer), 0);
1154     UNLOCK (win32_channel->mutex);
1155   }
1156   return internal_status;
1157 }
1158
1159 static GIOStatus
1160 g_io_win32_sock_write (GIOChannel  *channel,
1161                        const gchar *buf,
1162                        gsize        count,
1163                        gsize       *bytes_written,
1164                        GError     **err)
1165 {
1166   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
1167   gint result;
1168   GIOChannelError error = G_IO_STATUS_NORMAL;
1169   char send_buffer[] = "sw";
1170   
1171   if (win32_channel->debug)
1172     g_print ("g_io_win32_sock_write: sockfd:%d count:%d\n",
1173              win32_channel->fd, count);
1174 #ifdef WE_NEED_TO_HANDLE_WSAEINTR
1175 repeat:
1176 #endif
1177   result = send (win32_channel->fd, buf, count, 0);
1178   
1179   if (win32_channel->debug)
1180     g_print ("g_io_win32_sock_write: send:%d\n", result);
1181   
1182   if (result == SOCKET_ERROR)
1183     {
1184       *bytes_written = 0;
1185
1186       switch (WSAGetLastError ())
1187         {
1188         case WSAEINVAL:
1189           error = G_IO_CHANNEL_ERROR_INVAL;
1190           break;
1191         case WSAEWOULDBLOCK:
1192           return G_IO_STATUS_AGAIN;
1193 #ifdef WE_NEED_TO_HANDLE_WSAEINTR /* not anymore with wsock2 ? */
1194         case WSAEINTR:
1195           goto repeat;
1196 #endif
1197         default:
1198           error = G_IO_CHANNEL_ERROR_FAILED;
1199           break;
1200         }
1201       g_set_error(err, G_IO_CHANNEL_ERROR, error, "Socket write error");
1202       LOCK (win32_channel->mutex);
1203       SetEvent(win32_channel->data_avail_noticed_event);
1204       win32_channel->needs_close = 1;
1205       send(win32_channel->reset_send, send_buffer, sizeof(send_buffer), 0);
1206       UNLOCK (win32_channel->mutex);
1207           return G_IO_STATUS_ERROR;
1208       /* FIXME get all errors, better error messages */
1209     }
1210   else
1211     {
1212       *bytes_written = result;
1213
1214       return G_IO_STATUS_NORMAL;
1215     }
1216 }
1217
1218 static GIOStatus
1219 g_io_win32_sock_close (GIOChannel *channel,
1220                        GError    **err)
1221 {
1222   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
1223
1224   LOCK(win32_channel->mutex);
1225   if (win32_channel->running)
1226     {
1227       if (win32_channel->debug)
1228         g_print ("thread %#x: running, marking for later close\n",
1229                  win32_channel->thread_id);
1230       win32_channel->running = FALSE;
1231       win32_channel->needs_close = TRUE;
1232       SetEvent(win32_channel->data_avail_noticed_event);
1233     }
1234   if (win32_channel->fd != -1)
1235     {
1236       if (win32_channel->debug)
1237         g_print ("thread %#x: closing socket %d\n",
1238                  win32_channel->thread_id,
1239                  win32_channel->fd);
1240       
1241       closesocket (win32_channel->fd);
1242       win32_channel->fd = -1;
1243     }
1244   UNLOCK(win32_channel->mutex);
1245
1246   /* FIXME error detection? */
1247
1248   return G_IO_STATUS_NORMAL;
1249 }
1250
1251 static GSource *
1252 g_io_win32_sock_create_watch (GIOChannel    *channel,
1253                               GIOCondition   condition)
1254 {
1255   return g_io_win32_create_watch (channel, condition, select_thread);
1256 }
1257
1258 GIOChannel *
1259 g_io_channel_new_file (const gchar  *filename,
1260                        const gchar  *mode,
1261                        GError      **error)
1262 {
1263   int fid, flags, pmode;
1264   GIOChannel *channel;
1265
1266   enum { /* Cheesy hack */
1267     MODE_R = 1 << 0,
1268     MODE_W = 1 << 1,
1269     MODE_A = 1 << 2,
1270     MODE_PLUS = 1 << 3,
1271   } mode_num;
1272
1273   g_return_val_if_fail (filename != NULL, NULL);
1274   g_return_val_if_fail (mode != NULL, NULL);
1275   g_return_val_if_fail ((error == NULL) || (*error == NULL), NULL);
1276
1277   switch (mode[0])
1278     {
1279       case 'r':
1280         mode_num = MODE_R;
1281         break;
1282       case 'w':
1283         mode_num = MODE_W;
1284         break;
1285       case 'a':
1286         mode_num = MODE_A;
1287         break;
1288       default:
1289         g_warning ("Invalid GIOFileMode %s.\n", mode);
1290         return NULL;
1291     }
1292
1293   switch (mode[1])
1294     {
1295       case '\0':
1296         break;
1297       case '+':
1298         if (mode[2] == '\0')
1299           {
1300             mode_num |= MODE_PLUS;
1301             break;
1302           }
1303         /* Fall through */
1304       default:
1305         g_warning ("Invalid GIOFileMode %s.\n", mode);
1306         return NULL;
1307     }
1308
1309   switch (mode_num)
1310     {
1311       case MODE_R:
1312         flags = O_RDONLY;
1313         pmode = _S_IREAD;
1314         break;
1315       case MODE_W:
1316         flags = O_WRONLY | O_TRUNC | O_CREAT;
1317         pmode = _S_IWRITE;
1318         break;
1319       case MODE_A:
1320         flags = O_WRONLY | O_APPEND | O_CREAT;
1321         pmode = _S_IWRITE;
1322         break;
1323       case MODE_R | MODE_PLUS:
1324         flags = O_RDWR;
1325         pmode = _S_IREAD | _S_IWRITE;
1326         break;
1327       case MODE_W | MODE_PLUS:
1328         flags = O_RDWR | O_TRUNC | O_CREAT;
1329         pmode = _S_IREAD | _S_IWRITE;
1330         break;
1331       case MODE_A | MODE_PLUS:
1332         flags = O_RDWR | O_APPEND | O_CREAT;
1333         pmode = _S_IREAD | _S_IWRITE;
1334         break;
1335       default:
1336         g_assert_not_reached ();
1337         flags = 0;
1338         pmode = 0;
1339     }
1340
1341   /* always open 'untranslated' */
1342   fid = open (filename, flags | _O_BINARY, pmode);
1343
1344   if (g_io_win32_get_debug_flag ())
1345     {
1346       g_print ("g_io_channel_win32_new_file: open(\"%s\", ", filename);
1347       g_win32_print_access_mode (flags|_O_BINARY);
1348       g_print (",%#o)=%d\n", pmode, fid);
1349     }
1350
1351   if (fid < 0)
1352     {
1353       g_set_error (error, G_FILE_ERROR,
1354                    g_file_error_from_errno (errno),
1355                    g_strerror (errno));
1356       return (GIOChannel *)NULL;
1357     }
1358
1359   channel = g_io_channel_win32_new_fd (fid);
1360
1361   /* XXX: move this to g_io_channel_win32_new_fd () */
1362   channel->close_on_unref = TRUE;
1363   channel->is_seekable = TRUE;
1364
1365   /* g_io_channel_win32_new_fd sets is_readable and is_writeable to
1366    * correspond to actual readability/writeability. Set to FALSE those
1367    * that mode doesn't allow
1368    */
1369   switch (mode_num)
1370     {
1371       case MODE_R:
1372         channel->is_writeable = FALSE;
1373         break;
1374       case MODE_W:
1375       case MODE_A:
1376         channel->is_readable = FALSE;
1377         break;
1378       case MODE_R | MODE_PLUS:
1379       case MODE_W | MODE_PLUS:
1380       case MODE_A | MODE_PLUS:
1381         break;
1382       default:
1383         g_assert_not_reached ();
1384     }
1385
1386   return channel;
1387 }
1388
1389 static GIOStatus
1390 g_io_win32_set_flags (GIOChannel *channel,
1391                       GIOFlags    flags,
1392                       GError    **err)
1393 {
1394   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
1395
1396   if (win32_channel->debug)
1397     {
1398       g_print ("g_io_win32_set_flags: ");
1399       g_win32_print_gioflags (flags);
1400       g_print ("\n");
1401     }
1402
1403   g_warning ("g_io_win32_set_flags () not implemented.\n");
1404
1405   return G_IO_STATUS_NORMAL;
1406 }
1407
1408 static GIOFlags
1409 g_io_win32_fd_get_flags_internal (GIOChannel  *channel,
1410                                   struct stat *st)
1411 {
1412   GIOWin32Channel *win32_channel = (GIOWin32Channel *) channel;
1413   gchar c;
1414   DWORD count;
1415
1416   if (st->st_mode & _S_IFIFO)
1417     {
1418       channel->is_readable =
1419         (PeekNamedPipe ((HANDLE) _get_osfhandle (win32_channel->fd), &c, 0, &count, NULL, NULL) != 0) || GetLastError () == ERROR_BROKEN_PIPE;
1420       channel->is_writeable =
1421         (WriteFile ((HANDLE) _get_osfhandle (win32_channel->fd), &c, 0, &count, NULL) != 0);
1422       channel->is_seekable  = FALSE;
1423     }
1424   else if (st->st_mode & _S_IFCHR)
1425     {
1426       /* XXX Seems there is no way to find out the readability of file
1427        * handles to device files (consoles, mostly) without doing a
1428        * blocking read. So punt, use st->st_mode.
1429        */
1430       channel->is_readable  = !!(st->st_mode & _S_IREAD);
1431
1432       channel->is_writeable =
1433         (WriteFile ((HANDLE) _get_osfhandle (win32_channel->fd), &c, 0, &count, NULL) != 0);
1434
1435       /* XXX What about devices that actually *are* seekable? But
1436        * those would probably not be handled using the C runtime
1437        * anyway, but using Windows-specific code.
1438        */
1439       channel->is_seekable = FALSE;
1440     }
1441   else
1442     {
1443       channel->is_readable =
1444         (ReadFile ((HANDLE) _get_osfhandle (win32_channel->fd), &c, 0, &count, NULL) != 0);
1445       channel->is_writeable =
1446         (WriteFile ((HANDLE) _get_osfhandle (win32_channel->fd), &c, 0, &count, NULL) != 0);
1447       channel->is_seekable = TRUE;
1448     }
1449
1450   /* XXX: G_IO_FLAG_APPEND */
1451   /* XXX: G_IO_FLAG_NONBLOCK */
1452
1453   return 0;
1454 }
1455
1456 static GIOFlags
1457 g_io_win32_fd_get_flags (GIOChannel *channel)
1458 {
1459   struct stat st;
1460   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
1461
1462   g_return_val_if_fail (win32_channel != NULL, 0);
1463   g_return_val_if_fail (win32_channel->type == G_IO_WIN32_FILE_DESC, 0);
1464
1465   if (0 == fstat (win32_channel->fd, &st))
1466     return g_io_win32_fd_get_flags_internal (channel, &st);
1467   else
1468     return 0;
1469 }
1470
1471 static GIOFlags
1472 g_io_win32_msg_get_flags (GIOChannel *channel)
1473 {
1474   return 0;
1475 }
1476
1477 static GIOFlags
1478 g_io_win32_sock_get_flags (GIOChannel *channel)
1479 {
1480   /* XXX Could do something here. */
1481   return 0;
1482 }
1483
1484 static GIOFuncs win32_channel_msg_funcs = {
1485   g_io_win32_msg_read,
1486   g_io_win32_msg_write,
1487   NULL,
1488   g_io_win32_msg_close,
1489   g_io_win32_msg_create_watch,
1490   g_io_win32_free,
1491   g_io_win32_set_flags,
1492   g_io_win32_msg_get_flags,
1493 };
1494
1495 static GIOFuncs win32_channel_fd_funcs = {
1496   g_io_win32_fd_read,
1497   g_io_win32_fd_write,
1498   g_io_win32_fd_seek,
1499   g_io_win32_fd_close,
1500   g_io_win32_fd_create_watch,
1501   g_io_win32_free,
1502   g_io_win32_set_flags,
1503   g_io_win32_fd_get_flags,
1504 };
1505
1506 static GIOFuncs win32_channel_sock_funcs = {
1507   g_io_win32_sock_read,
1508   g_io_win32_sock_write,
1509   NULL,
1510   g_io_win32_sock_close,
1511   g_io_win32_sock_create_watch,
1512   g_io_win32_free,
1513   g_io_win32_set_flags,
1514   g_io_win32_sock_get_flags,
1515 };
1516
1517 GIOChannel *
1518 g_io_channel_win32_new_messages (guint hwnd)
1519 {
1520   GIOWin32Channel *win32_channel = g_new (GIOWin32Channel, 1);
1521   GIOChannel *channel = (GIOChannel *)win32_channel;
1522
1523   g_io_channel_init (channel);
1524   g_io_channel_win32_init (win32_channel);
1525   if (win32_channel->debug)
1526     g_print ("g_io_channel_win32_new_messages: hwnd = %ud\n", hwnd);
1527   channel->funcs = &win32_channel_msg_funcs;
1528   win32_channel->type = G_IO_WIN32_WINDOWS_MESSAGES;
1529   win32_channel->hwnd = (HWND) hwnd;
1530
1531   /* XXX: check this. */
1532   channel->is_readable = IsWindow (win32_channel->hwnd);
1533   channel->is_writeable = IsWindow (win32_channel->hwnd);
1534
1535   channel->is_seekable = FALSE;
1536
1537   return channel;
1538 }
1539
1540 static GIOChannel *
1541 g_io_channel_win32_new_fd_internal (gint         fd,
1542                                     struct stat *st)
1543 {
1544   GIOWin32Channel *win32_channel;
1545   GIOChannel *channel;
1546
1547   win32_channel = g_new (GIOWin32Channel, 1);
1548   channel = (GIOChannel *)win32_channel;
1549
1550   g_io_channel_init (channel);
1551   g_io_channel_win32_init (win32_channel);
1552   if (win32_channel->debug)
1553     g_print ("g_io_channel_win32_new_fd: %u\n", fd);
1554   channel->funcs = &win32_channel_fd_funcs;
1555   win32_channel->type = G_IO_WIN32_FILE_DESC;
1556   win32_channel->fd = fd;
1557
1558   g_io_win32_fd_get_flags_internal (channel, st);
1559   
1560   return channel;
1561 }
1562
1563 GIOChannel *
1564 g_io_channel_win32_new_fd (gint fd)
1565 {
1566   struct stat st;
1567
1568   if (fstat (fd, &st) == -1)
1569     {
1570       g_warning (G_STRLOC ": %d isn't a C library file descriptor", fd);
1571       return NULL;
1572     }
1573
1574   return g_io_channel_win32_new_fd_internal (fd, &st);
1575 }
1576
1577 gint
1578 g_io_channel_win32_get_fd (GIOChannel *channel)
1579 {
1580   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
1581
1582   return win32_channel->fd;
1583 }
1584
1585 GIOChannel *
1586 g_io_channel_win32_new_socket (int socket)
1587 {
1588   GIOWin32Channel *win32_channel = g_new (GIOWin32Channel, 1);
1589   GIOChannel *channel = (GIOChannel *)win32_channel;
1590
1591   g_io_channel_init (channel);
1592   g_io_channel_win32_init (win32_channel);
1593   init_reset_sockets(channel);
1594   if (win32_channel->debug)
1595     g_print ("g_io_channel_win32_new_socket: sockfd:%d\n", socket);
1596   channel->funcs = &win32_channel_sock_funcs;
1597   win32_channel->type = G_IO_WIN32_SOCKET;
1598   win32_channel->fd = socket;
1599
1600   /* XXX: check this */
1601   channel->is_readable = TRUE;
1602   channel->is_writeable = TRUE;
1603
1604   channel->is_seekable = FALSE;
1605
1606   return channel;
1607 }
1608
1609 GIOChannel *
1610 g_io_channel_unix_new (gint fd)
1611 {
1612   struct stat st;
1613
1614   if (fstat (fd, &st) == 0)
1615     return g_io_channel_win32_new_fd_internal (fd, &st);
1616   
1617   if (getsockopt (fd, SOL_SOCKET, SO_TYPE, NULL, NULL) != SOCKET_ERROR)
1618     return g_io_channel_win32_new_socket(fd);
1619
1620   g_warning (G_STRLOC ": %d is neither a file descriptor or a socket", fd);
1621   return NULL;
1622 }
1623
1624 gint
1625 g_io_channel_unix_get_fd (GIOChannel *channel)
1626 {
1627   return g_io_channel_win32_get_fd (channel);
1628 }
1629
1630 void
1631 g_io_channel_win32_set_debug (GIOChannel *channel,
1632                               gboolean    flag)
1633 {
1634   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
1635
1636   win32_channel->debug = flag;
1637 }
1638
1639 gint
1640 g_io_channel_win32_poll (GPollFD *fds,
1641                          gint     n_fds,
1642                          gint     timeout)
1643 {
1644   int result;
1645
1646   g_return_val_if_fail (n_fds >= 0, 0);
1647
1648   result = (*g_main_context_get_poll_func (NULL)) (fds, n_fds, timeout);
1649
1650   return result;
1651 }
1652
1653 void
1654 g_io_channel_win32_make_pollfd (GIOChannel   *channel,
1655                                 GIOCondition  condition,
1656                                 GPollFD      *fd)
1657 {
1658   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
1659
1660   if (win32_channel->data_avail_event == NULL)
1661     create_events (win32_channel);
1662   
1663   fd->fd = (gint) win32_channel->data_avail_event;
1664   fd->events = condition;
1665
1666   if (win32_channel->thread_id == 0)
1667     {
1668       if ((condition & G_IO_IN) && win32_channel->type == G_IO_WIN32_FILE_DESC)
1669         create_thread (win32_channel, condition, read_thread);
1670       else if (win32_channel->type == G_IO_WIN32_SOCKET)
1671         create_thread (win32_channel, condition, select_thread);
1672     }
1673 }
1674
1675 /* Binary compatibility */
1676 GIOChannel *
1677 g_io_channel_win32_new_stream_socket (int socket)
1678 {
1679   return g_io_channel_win32_new_socket (socket);
1680 }