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