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