8d435538e29940d4ad0ce6a3f0b0852c86164e1b
[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   {
732     /* Tell select_thread() to exit */
733     channel->needs_close = 1;
734     /* Wake up select_thread() from its blocking select() */
735     send (channel->reset_send, send_buffer, sizeof (send_buffer), 0);
736   }
737
738   g_io_channel_unref (watch->channel);
739   UNLOCK (channel->mutex);
740 }
741
742 GSourceFuncs g_io_watch_funcs = {
743   g_io_win32_prepare,
744   g_io_win32_check,
745   g_io_win32_dispatch,
746   g_io_win32_finalize
747 };
748
749 static GSource *
750 g_io_win32_create_watch (GIOChannel    *channel,
751                          GIOCondition   condition,
752                          unsigned (__stdcall *thread) (void *parameter))
753 {
754   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
755   GIOWin32Watch *watch;
756   GSource *source;
757   char send_buffer[] = "c";
758
759   source = g_source_new (&g_io_watch_funcs, sizeof (GIOWin32Watch));
760   watch = (GIOWin32Watch *)source;
761   
762   watch->channel = channel;
763   g_io_channel_ref (channel);
764   
765   watch->condition = condition;
766   
767   if (win32_channel->data_avail_event == NULL)
768     create_events (win32_channel);
769
770   watch->pollfd.fd = (gint) win32_channel->data_avail_event;
771   watch->pollfd.events = condition;
772   
773   if (win32_channel->debug)
774     g_print ("g_io_win32_create_watch: fd:%d condition:%#x handle:%#x\n",
775              win32_channel->fd, condition, watch->pollfd.fd);
776
777   LOCK (win32_channel->mutex);
778   win32_channel->watches = g_slist_append (win32_channel->watches, watch);
779
780   if (win32_channel->thread_id == 0)
781     create_thread (win32_channel, condition, thread);
782   else
783     send (win32_channel->reset_send, send_buffer, sizeof (send_buffer), 0);
784
785   g_source_add_poll (source, &watch->pollfd);
786   UNLOCK (win32_channel->mutex);
787
788   return source;
789 }
790
791 static GIOStatus
792 g_io_win32_msg_read (GIOChannel *channel,
793                      gchar      *buf,
794                      gsize       count,
795                      gsize      *bytes_read,
796                      GError    **err)
797 {
798   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
799   MSG msg;               /* In case of alignment problems */
800   
801   if (count < sizeof (MSG))
802     {
803       g_set_error (err, G_IO_CHANNEL_ERROR, G_IO_CHANNEL_ERROR_INVAL,
804                    "Incorrect message size"); /* Informative enough error message? */
805       return G_IO_STATUS_ERROR;
806     }
807   
808   if (win32_channel->debug)
809     g_print ("g_io_win32_msg_read: for %#x\n",
810              (guint) win32_channel->hwnd);
811   if (!PeekMessage (&msg, win32_channel->hwnd, 0, 0, PM_REMOVE))
812     return G_IO_STATUS_AGAIN;
813
814   memmove (buf, &msg, sizeof (MSG));
815   *bytes_read = sizeof (MSG);
816
817   return G_IO_STATUS_NORMAL;
818 }
819
820 static GIOStatus
821 g_io_win32_msg_write (GIOChannel  *channel,
822                       const gchar *buf,
823                       gsize        count,
824                       gsize       *bytes_written,
825                       GError     **err)
826 {
827   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
828   MSG msg;
829   
830   if (count != sizeof (MSG))
831     {
832       g_set_error (err, G_IO_CHANNEL_ERROR, G_IO_CHANNEL_ERROR_INVAL,
833                    "Incorrect message size"); /* Informative enough error message? */
834       return G_IO_STATUS_ERROR;
835     }
836   
837   /* In case of alignment problems */
838   memmove (&msg, buf, sizeof (MSG));
839   if (!PostMessage (win32_channel->hwnd, msg.message, msg.wParam, msg.lParam))
840     {
841       gchar *emsg = g_win32_error_message (GetLastError ());
842       g_set_error (err, G_IO_CHANNEL_ERROR, G_IO_CHANNEL_ERROR_FAILED, emsg);
843       g_free (emsg);
844       return G_IO_STATUS_ERROR;
845     }
846
847   *bytes_written = sizeof (MSG);
848
849   return G_IO_STATUS_NORMAL;
850 }
851
852 static GIOStatus
853 g_io_win32_msg_close (GIOChannel *channel,
854                       GError    **err)
855 {
856   /* Nothing to be done. Or should we set hwnd to some invalid value? */
857
858   return G_IO_STATUS_NORMAL;
859 }
860
861 static void
862 g_io_win32_free (GIOChannel *channel)
863 {
864   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
865   
866   if (win32_channel->debug)
867     g_print ("thread %#x: freeing channel, fd: %d\n",
868              win32_channel->thread_id,
869              win32_channel->fd);
870
871   if (win32_channel->reset_send && win32_channel->reset_send != INVALID_SOCKET)
872     closesocket (win32_channel->reset_send);
873   if (win32_channel->reset_recv && win32_channel->reset_recv != INVALID_SOCKET)
874     closesocket (win32_channel->reset_recv);
875   if (win32_channel->data_avail_event)
876     CloseHandle (win32_channel->data_avail_event);
877   if (win32_channel->space_avail_event)
878     CloseHandle (win32_channel->space_avail_event);
879   if (win32_channel->data_avail_noticed_event)
880     CloseHandle (win32_channel->data_avail_noticed_event);
881   DeleteCriticalSection (&win32_channel->mutex);
882
883   g_free (win32_channel->buffer);
884   g_slist_free (win32_channel->watches);
885   g_free (win32_channel);
886 }
887
888 static GSource *
889 g_io_win32_msg_create_watch (GIOChannel    *channel,
890                              GIOCondition   condition)
891 {
892   GIOWin32Watch *watch;
893   GSource *source;
894
895   source = g_source_new (&g_io_watch_funcs, sizeof (GIOWin32Watch));
896   watch = (GIOWin32Watch *)source;
897   
898   watch->channel = channel;
899   g_io_channel_ref (channel);
900   
901   watch->condition = condition;
902   
903   watch->pollfd.fd = G_WIN32_MSG_HANDLE;
904   watch->pollfd.events = condition;
905   
906   g_source_add_poll (source, &watch->pollfd);
907   
908   return source;
909 }
910
911 static GIOStatus
912 g_io_win32_fd_read (GIOChannel *channel,
913                     gchar      *buf,
914                     gsize       count,
915                     gsize      *bytes_read,
916                     GError    **err)
917 {
918   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
919   gint result;
920   
921   if (win32_channel->debug)
922     g_print ("g_io_win32_fd_read: fd:%d count:%d\n",
923              win32_channel->fd, count);
924   
925   if (win32_channel->thread_id)
926     {
927       return buffer_read (win32_channel, buf, count, bytes_read, err);
928     }
929
930   result = read (win32_channel->fd, buf, count);
931
932   if (win32_channel->debug)
933     g_print ("g_io_win32_fd_read: read() = %d\n", result);
934
935   if (result < 0)
936     {
937       *bytes_read = 0;
938
939       switch (errno)
940         {
941 #ifdef EAGAIN
942         case EAGAIN:
943           return G_IO_STATUS_AGAIN;
944 #endif
945         default:
946           g_set_error (err, G_IO_CHANNEL_ERROR,
947                        g_io_channel_error_from_errno (errno),
948                        g_strerror (errno));
949           return G_IO_STATUS_ERROR;
950         }
951     }
952
953   *bytes_read = result;
954
955   return (result > 0) ? G_IO_STATUS_NORMAL : G_IO_STATUS_EOF;
956 }
957
958 static GIOStatus
959 g_io_win32_fd_write (GIOChannel  *channel,
960                      const gchar *buf,
961                      gsize        count,
962                      gsize       *bytes_written,
963                      GError     **err)
964 {
965   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
966   gint result;
967   
968   result = write (win32_channel->fd, buf, count);
969   if (win32_channel->debug)
970     g_print ("g_io_win32_fd_write: fd:%d count:%d = %d\n",
971              win32_channel->fd, count, result);
972
973   if (result < 0)
974     {
975       *bytes_written = 0;
976
977       switch (errno)
978         {
979 #ifdef EAGAIN
980         case EAGAIN:
981           return G_IO_STATUS_AGAIN;
982 #endif
983         default:
984           g_set_error (err, G_IO_CHANNEL_ERROR,
985                        g_io_channel_error_from_errno (errno),
986                        g_strerror (errno));
987           return G_IO_STATUS_ERROR;
988         }
989     }
990
991   *bytes_written = result;
992
993   return G_IO_STATUS_NORMAL;
994 }
995
996 static GIOStatus
997 g_io_win32_fd_seek (GIOChannel *channel,
998                     gint64      offset,
999                     GSeekType   type,
1000                     GError    **err)
1001 {
1002   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
1003   int whence;
1004   off_t tmp_offset;
1005   off_t result;
1006   
1007   switch (type)
1008     {
1009     case G_SEEK_SET:
1010       whence = SEEK_SET;
1011       break;
1012     case G_SEEK_CUR:
1013       whence = SEEK_CUR;
1014       break;
1015     case G_SEEK_END:
1016       whence = SEEK_END;
1017       break;
1018     default:
1019       whence = -1; /* Keep the compiler quiet */
1020       g_assert_not_reached ();
1021     }
1022
1023   tmp_offset = offset;
1024   if (tmp_offset != offset)
1025     {
1026       g_set_error (err, G_IO_CHANNEL_ERROR,
1027                    g_io_channel_error_from_errno (EINVAL),
1028                    g_strerror (EINVAL));
1029       return G_IO_STATUS_ERROR;
1030     }
1031   
1032   result = lseek (win32_channel->fd, tmp_offset, whence);
1033   
1034   if (result < 0)
1035     {
1036       g_set_error (err, G_IO_CHANNEL_ERROR,
1037                    g_io_channel_error_from_errno (errno),
1038                    g_strerror (errno));
1039       return G_IO_STATUS_ERROR;
1040     }
1041
1042   return G_IO_STATUS_NORMAL;
1043 }
1044
1045 static GIOStatus
1046 g_io_win32_fd_close (GIOChannel *channel,
1047                      GError    **err)
1048 {
1049   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
1050   
1051   if (win32_channel->debug)
1052     g_print ("thread %#x: closing fd %d\n",
1053              win32_channel->thread_id,
1054              win32_channel->fd);
1055   LOCK (win32_channel->mutex);
1056   if (win32_channel->running)
1057     {
1058       if (win32_channel->debug)
1059         g_print ("thread %#x: running, marking fd %d for later close\n",
1060                  win32_channel->thread_id, win32_channel->fd);
1061       win32_channel->running = FALSE;
1062       win32_channel->needs_close = TRUE;
1063       SetEvent (win32_channel->data_avail_event);
1064     }
1065   else
1066     {
1067       if (win32_channel->debug)
1068         g_print ("closing fd %d\n", win32_channel->fd);
1069       close (win32_channel->fd);
1070       if (win32_channel->debug)
1071         g_print ("closed fd %d, setting to -1\n",
1072                  win32_channel->fd);
1073       win32_channel->fd = -1;
1074     }
1075   UNLOCK (win32_channel->mutex);
1076
1077   /* FIXME error detection? */
1078
1079   return G_IO_STATUS_NORMAL;
1080 }
1081
1082 static GSource *
1083 g_io_win32_fd_create_watch (GIOChannel    *channel,
1084                             GIOCondition   condition)
1085 {
1086   return g_io_win32_create_watch (channel, condition, read_thread);
1087 }
1088
1089 static GIOStatus
1090 g_io_win32_sock_read (GIOChannel *channel,
1091                       gchar      *buf,
1092                       gsize       count,
1093                       gsize      *bytes_read,
1094                       GError    **err)
1095 {
1096   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
1097   gint result;
1098   GIOChannelError error = G_IO_STATUS_NORMAL;
1099   GIOStatus internal_status = G_IO_STATUS_NORMAL;
1100   char send_buffer[] = "sr";
1101
1102   if (win32_channel->debug)
1103     g_print ("g_io_win32_sock_read: sockfd:%d count:%d\n",
1104              win32_channel->fd, count);
1105 #ifdef WE_NEED_TO_HANDLE_WSAEINTR
1106 repeat:
1107 #endif
1108   result = recv (win32_channel->fd, buf, count, 0);
1109
1110   if (win32_channel->debug)
1111     g_print ("g_io_win32_sock_read: recv:%d\n", result);
1112   
1113   if (result == SOCKET_ERROR)
1114     {
1115       *bytes_read = 0;
1116
1117       switch (WSAGetLastError ())
1118         {
1119         case WSAEINVAL:
1120           error = G_IO_CHANNEL_ERROR_INVAL;
1121           break;
1122         case WSAEWOULDBLOCK:
1123           return G_IO_STATUS_AGAIN;
1124 #ifdef WE_NEED_TO_HANDLE_WSAEINTR /* not anymore with wsock2 ? */
1125         case WSAEINTR:
1126           goto repeat;
1127 #endif
1128         default:
1129           error = G_IO_CHANNEL_ERROR_FAILED;
1130           break;
1131         }
1132       g_set_error (err, G_IO_CHANNEL_ERROR, error, "Socket read error");
1133       internal_status = G_IO_STATUS_ERROR;
1134       /* FIXME get all errors, better error messages */
1135     }
1136   else
1137     {
1138       *bytes_read = result;
1139       if (result == 0)
1140         internal_status = G_IO_STATUS_EOF;
1141     }
1142
1143   if ((internal_status == G_IO_STATUS_EOF) || 
1144       (internal_status == G_IO_STATUS_ERROR))
1145     {
1146       LOCK (win32_channel->mutex);
1147       SetEvent (win32_channel->data_avail_noticed_event);
1148       win32_channel->needs_close = 1;
1149       send (win32_channel->reset_send, send_buffer, sizeof (send_buffer), 0);
1150       UNLOCK (win32_channel->mutex);
1151     }
1152   return internal_status;
1153 }
1154
1155 static GIOStatus
1156 g_io_win32_sock_write (GIOChannel  *channel,
1157                        const gchar *buf,
1158                        gsize        count,
1159                        gsize       *bytes_written,
1160                        GError     **err)
1161 {
1162   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
1163   gint result;
1164   GIOChannelError error = G_IO_STATUS_NORMAL;
1165   char send_buffer[] = "sw";
1166   
1167   if (win32_channel->debug)
1168     g_print ("g_io_win32_sock_write: sockfd:%d count:%d\n",
1169              win32_channel->fd, count);
1170 #ifdef WE_NEED_TO_HANDLE_WSAEINTR
1171 repeat:
1172 #endif
1173   result = send (win32_channel->fd, buf, count, 0);
1174   
1175   if (win32_channel->debug)
1176     g_print ("g_io_win32_sock_write: send:%d\n", result);
1177   
1178   if (result == SOCKET_ERROR)
1179     {
1180       *bytes_written = 0;
1181
1182       switch (WSAGetLastError ())
1183         {
1184         case WSAEINVAL:
1185           error = G_IO_CHANNEL_ERROR_INVAL;
1186           break;
1187         case WSAEWOULDBLOCK:
1188           return G_IO_STATUS_AGAIN;
1189 #ifdef WE_NEED_TO_HANDLE_WSAEINTR /* not anymore with wsock2 ? */
1190         case WSAEINTR:
1191           goto repeat;
1192 #endif
1193         default:
1194           error = G_IO_CHANNEL_ERROR_FAILED;
1195           break;
1196         }
1197       g_set_error (err, G_IO_CHANNEL_ERROR, error, "Socket write error");
1198       LOCK (win32_channel->mutex);
1199       SetEvent (win32_channel->data_avail_noticed_event);
1200       win32_channel->needs_close = 1;
1201       send (win32_channel->reset_send, send_buffer, sizeof (send_buffer), 0);
1202       UNLOCK (win32_channel->mutex);
1203       return G_IO_STATUS_ERROR;
1204       /* FIXME get all errors, better error messages */
1205     }
1206   else
1207     {
1208       *bytes_written = result;
1209
1210       return G_IO_STATUS_NORMAL;
1211     }
1212 }
1213
1214 static GIOStatus
1215 g_io_win32_sock_close (GIOChannel *channel,
1216                        GError    **err)
1217 {
1218   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
1219
1220   LOCK (win32_channel->mutex);
1221   if (win32_channel->running)
1222     {
1223       if (win32_channel->debug)
1224         g_print ("thread %#x: running, marking for later close\n",
1225                  win32_channel->thread_id);
1226       win32_channel->running = FALSE;
1227       win32_channel->needs_close = TRUE;
1228       SetEvent(win32_channel->data_avail_noticed_event);
1229     }
1230   if (win32_channel->fd != -1)
1231     {
1232       if (win32_channel->debug)
1233         g_print ("thread %#x: closing socket %d\n",
1234                  win32_channel->thread_id,
1235                  win32_channel->fd);
1236       
1237       closesocket (win32_channel->fd);
1238       win32_channel->fd = -1;
1239     }
1240   UNLOCK (win32_channel->mutex);
1241
1242   /* FIXME error detection? */
1243
1244   return G_IO_STATUS_NORMAL;
1245 }
1246
1247 static GSource *
1248 g_io_win32_sock_create_watch (GIOChannel    *channel,
1249                               GIOCondition   condition)
1250 {
1251   return g_io_win32_create_watch (channel, condition, select_thread);
1252 }
1253
1254 GIOChannel *
1255 g_io_channel_new_file (const gchar  *filename,
1256                        const gchar  *mode,
1257                        GError      **error)
1258 {
1259   int fid, flags, pmode;
1260   GIOChannel *channel;
1261
1262   enum { /* Cheesy hack */
1263     MODE_R = 1 << 0,
1264     MODE_W = 1 << 1,
1265     MODE_A = 1 << 2,
1266     MODE_PLUS = 1 << 3,
1267   } mode_num;
1268
1269   g_return_val_if_fail (filename != NULL, NULL);
1270   g_return_val_if_fail (mode != NULL, NULL);
1271   g_return_val_if_fail ((error == NULL) || (*error == NULL), NULL);
1272
1273   switch (mode[0])
1274     {
1275       case 'r':
1276         mode_num = MODE_R;
1277         break;
1278       case 'w':
1279         mode_num = MODE_W;
1280         break;
1281       case 'a':
1282         mode_num = MODE_A;
1283         break;
1284       default:
1285         g_warning ("Invalid GIOFileMode %s.\n", mode);
1286         return NULL;
1287     }
1288
1289   switch (mode[1])
1290     {
1291       case '\0':
1292         break;
1293       case '+':
1294         if (mode[2] == '\0')
1295           {
1296             mode_num |= MODE_PLUS;
1297             break;
1298           }
1299         /* Fall through */
1300       default:
1301         g_warning ("Invalid GIOFileMode %s.\n", mode);
1302         return NULL;
1303     }
1304
1305   switch (mode_num)
1306     {
1307       case MODE_R:
1308         flags = O_RDONLY;
1309         pmode = _S_IREAD;
1310         break;
1311       case MODE_W:
1312         flags = O_WRONLY | O_TRUNC | O_CREAT;
1313         pmode = _S_IWRITE;
1314         break;
1315       case MODE_A:
1316         flags = O_WRONLY | O_APPEND | O_CREAT;
1317         pmode = _S_IWRITE;
1318         break;
1319       case MODE_R | MODE_PLUS:
1320         flags = O_RDWR;
1321         pmode = _S_IREAD | _S_IWRITE;
1322         break;
1323       case MODE_W | MODE_PLUS:
1324         flags = O_RDWR | O_TRUNC | O_CREAT;
1325         pmode = _S_IREAD | _S_IWRITE;
1326         break;
1327       case MODE_A | MODE_PLUS:
1328         flags = O_RDWR | O_APPEND | O_CREAT;
1329         pmode = _S_IREAD | _S_IWRITE;
1330         break;
1331       default:
1332         g_assert_not_reached ();
1333         flags = 0;
1334         pmode = 0;
1335     }
1336
1337   /* always open 'untranslated' */
1338   fid = open (filename, flags | _O_BINARY, pmode);
1339
1340   if (g_io_win32_get_debug_flag ())
1341     {
1342       g_print ("g_io_channel_win32_new_file: open(\"%s\", ", filename);
1343       g_win32_print_access_mode (flags|_O_BINARY);
1344       g_print (",%#o)=%d\n", pmode, fid);
1345     }
1346
1347   if (fid < 0)
1348     {
1349       g_set_error (error, G_FILE_ERROR,
1350                    g_file_error_from_errno (errno),
1351                    g_strerror (errno));
1352       return (GIOChannel *)NULL;
1353     }
1354
1355   channel = g_io_channel_win32_new_fd (fid);
1356
1357   /* XXX: move this to g_io_channel_win32_new_fd () */
1358   channel->close_on_unref = TRUE;
1359   channel->is_seekable = TRUE;
1360
1361   /* g_io_channel_win32_new_fd sets is_readable and is_writeable to
1362    * correspond to actual readability/writeability. Set to FALSE those
1363    * that mode doesn't allow
1364    */
1365   switch (mode_num)
1366     {
1367       case MODE_R:
1368         channel->is_writeable = FALSE;
1369         break;
1370       case MODE_W:
1371       case MODE_A:
1372         channel->is_readable = FALSE;
1373         break;
1374       case MODE_R | MODE_PLUS:
1375       case MODE_W | MODE_PLUS:
1376       case MODE_A | MODE_PLUS:
1377         break;
1378       default:
1379         g_assert_not_reached ();
1380     }
1381
1382   return channel;
1383 }
1384
1385 static GIOStatus
1386 g_io_win32_set_flags (GIOChannel *channel,
1387                       GIOFlags    flags,
1388                       GError    **err)
1389 {
1390   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
1391
1392   if (win32_channel->debug)
1393     {
1394       g_print ("g_io_win32_set_flags: ");
1395       g_win32_print_gioflags (flags);
1396       g_print ("\n");
1397     }
1398
1399   g_warning ("g_io_win32_set_flags () not implemented.\n");
1400
1401   return G_IO_STATUS_NORMAL;
1402 }
1403
1404 static GIOFlags
1405 g_io_win32_fd_get_flags_internal (GIOChannel  *channel,
1406                                   struct stat *st)
1407 {
1408   GIOWin32Channel *win32_channel = (GIOWin32Channel *) channel;
1409   gchar c;
1410   DWORD count;
1411
1412   if (st->st_mode & _S_IFIFO)
1413     {
1414       channel->is_readable =
1415         (PeekNamedPipe ((HANDLE) _get_osfhandle (win32_channel->fd), &c, 0, &count, NULL, NULL) != 0) || GetLastError () == ERROR_BROKEN_PIPE;
1416       channel->is_writeable =
1417         (WriteFile ((HANDLE) _get_osfhandle (win32_channel->fd), &c, 0, &count, NULL) != 0);
1418       channel->is_seekable  = FALSE;
1419     }
1420   else if (st->st_mode & _S_IFCHR)
1421     {
1422       /* XXX Seems there is no way to find out the readability of file
1423        * handles to device files (consoles, mostly) without doing a
1424        * blocking read. So punt, use st->st_mode.
1425        */
1426       channel->is_readable  = !!(st->st_mode & _S_IREAD);
1427
1428       channel->is_writeable =
1429         (WriteFile ((HANDLE) _get_osfhandle (win32_channel->fd), &c, 0, &count, NULL) != 0);
1430
1431       /* XXX What about devices that actually *are* seekable? But
1432        * those would probably not be handled using the C runtime
1433        * anyway, but using Windows-specific code.
1434        */
1435       channel->is_seekable = FALSE;
1436     }
1437   else
1438     {
1439       channel->is_readable =
1440         (ReadFile ((HANDLE) _get_osfhandle (win32_channel->fd), &c, 0, &count, NULL) != 0);
1441       channel->is_writeable =
1442         (WriteFile ((HANDLE) _get_osfhandle (win32_channel->fd), &c, 0, &count, NULL) != 0);
1443       channel->is_seekable = TRUE;
1444     }
1445
1446   /* XXX: G_IO_FLAG_APPEND */
1447   /* XXX: G_IO_FLAG_NONBLOCK */
1448
1449   return 0;
1450 }
1451
1452 static GIOFlags
1453 g_io_win32_fd_get_flags (GIOChannel *channel)
1454 {
1455   struct stat st;
1456   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
1457
1458   g_return_val_if_fail (win32_channel != NULL, 0);
1459   g_return_val_if_fail (win32_channel->type == G_IO_WIN32_FILE_DESC, 0);
1460
1461   if (0 == fstat (win32_channel->fd, &st))
1462     return g_io_win32_fd_get_flags_internal (channel, &st);
1463   else
1464     return 0;
1465 }
1466
1467 static GIOFlags
1468 g_io_win32_msg_get_flags (GIOChannel *channel)
1469 {
1470   return 0;
1471 }
1472
1473 static GIOFlags
1474 g_io_win32_sock_get_flags (GIOChannel *channel)
1475 {
1476   /* XXX Could do something here. */
1477   return 0;
1478 }
1479
1480 static GIOFuncs win32_channel_msg_funcs = {
1481   g_io_win32_msg_read,
1482   g_io_win32_msg_write,
1483   NULL,
1484   g_io_win32_msg_close,
1485   g_io_win32_msg_create_watch,
1486   g_io_win32_free,
1487   g_io_win32_set_flags,
1488   g_io_win32_msg_get_flags,
1489 };
1490
1491 static GIOFuncs win32_channel_fd_funcs = {
1492   g_io_win32_fd_read,
1493   g_io_win32_fd_write,
1494   g_io_win32_fd_seek,
1495   g_io_win32_fd_close,
1496   g_io_win32_fd_create_watch,
1497   g_io_win32_free,
1498   g_io_win32_set_flags,
1499   g_io_win32_fd_get_flags,
1500 };
1501
1502 static GIOFuncs win32_channel_sock_funcs = {
1503   g_io_win32_sock_read,
1504   g_io_win32_sock_write,
1505   NULL,
1506   g_io_win32_sock_close,
1507   g_io_win32_sock_create_watch,
1508   g_io_win32_free,
1509   g_io_win32_set_flags,
1510   g_io_win32_sock_get_flags,
1511 };
1512
1513 GIOChannel *
1514 g_io_channel_win32_new_messages (guint hwnd)
1515 {
1516   GIOWin32Channel *win32_channel = g_new (GIOWin32Channel, 1);
1517   GIOChannel *channel = (GIOChannel *)win32_channel;
1518
1519   g_io_channel_init (channel);
1520   g_io_channel_win32_init (win32_channel);
1521   if (win32_channel->debug)
1522     g_print ("g_io_channel_win32_new_messages: hwnd = %ud\n", hwnd);
1523   channel->funcs = &win32_channel_msg_funcs;
1524   win32_channel->type = G_IO_WIN32_WINDOWS_MESSAGES;
1525   win32_channel->hwnd = (HWND) hwnd;
1526
1527   /* XXX: check this. */
1528   channel->is_readable = IsWindow (win32_channel->hwnd);
1529   channel->is_writeable = IsWindow (win32_channel->hwnd);
1530
1531   channel->is_seekable = FALSE;
1532
1533   return channel;
1534 }
1535
1536 static GIOChannel *
1537 g_io_channel_win32_new_fd_internal (gint         fd,
1538                                     struct stat *st)
1539 {
1540   GIOWin32Channel *win32_channel;
1541   GIOChannel *channel;
1542
1543   win32_channel = g_new (GIOWin32Channel, 1);
1544   channel = (GIOChannel *)win32_channel;
1545
1546   g_io_channel_init (channel);
1547   g_io_channel_win32_init (win32_channel);
1548   if (win32_channel->debug)
1549     g_print ("g_io_channel_win32_new_fd: %u\n", fd);
1550   channel->funcs = &win32_channel_fd_funcs;
1551   win32_channel->type = G_IO_WIN32_FILE_DESC;
1552   win32_channel->fd = fd;
1553
1554   g_io_win32_fd_get_flags_internal (channel, st);
1555   
1556   return channel;
1557 }
1558
1559 GIOChannel *
1560 g_io_channel_win32_new_fd (gint fd)
1561 {
1562   struct stat st;
1563
1564   if (fstat (fd, &st) == -1)
1565     {
1566       g_warning (G_STRLOC ": %d isn't a C library file descriptor", fd);
1567       return NULL;
1568     }
1569
1570   return g_io_channel_win32_new_fd_internal (fd, &st);
1571 }
1572
1573 gint
1574 g_io_channel_win32_get_fd (GIOChannel *channel)
1575 {
1576   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
1577
1578   return win32_channel->fd;
1579 }
1580
1581 GIOChannel *
1582 g_io_channel_win32_new_socket (int socket)
1583 {
1584   GIOWin32Channel *win32_channel = g_new (GIOWin32Channel, 1);
1585   GIOChannel *channel = (GIOChannel *)win32_channel;
1586
1587   g_io_channel_init (channel);
1588   g_io_channel_win32_init (win32_channel);
1589   init_reset_sockets (win32_channel);
1590   if (win32_channel->debug)
1591     g_print ("g_io_channel_win32_new_socket: sockfd:%d\n", socket);
1592   channel->funcs = &win32_channel_sock_funcs;
1593   win32_channel->type = G_IO_WIN32_SOCKET;
1594   win32_channel->fd = socket;
1595
1596   /* XXX: check this */
1597   channel->is_readable = TRUE;
1598   channel->is_writeable = TRUE;
1599
1600   channel->is_seekable = FALSE;
1601
1602   return channel;
1603 }
1604
1605 GIOChannel *
1606 g_io_channel_unix_new (gint fd)
1607 {
1608   gboolean is_fd, is_socket;
1609   struct stat st;
1610   int optval, optlen;
1611
1612   is_fd = (fstat (fd, &st) == 0);
1613
1614   optlen = sizeof (optval);
1615   is_socket = (getsockopt (fd, SOL_SOCKET, SO_TYPE, (char *) &optval, &optlen) != SOCKET_ERROR);
1616
1617   if (is_fd && is_socket)
1618     g_warning (G_STRLOC ": %d is both a file descriptor and a socket, file descriptor interpretation assumed.", fd);
1619
1620   if (is_fd)
1621     return g_io_channel_win32_new_fd_internal (fd, &st);
1622
1623   if (is_socket)
1624     return g_io_channel_win32_new_socket(fd);
1625
1626   g_warning (G_STRLOC ": %d is neither a file descriptor or a socket", fd);
1627
1628   return NULL;
1629 }
1630
1631 gint
1632 g_io_channel_unix_get_fd (GIOChannel *channel)
1633 {
1634   return g_io_channel_win32_get_fd (channel);
1635 }
1636
1637 void
1638 g_io_channel_win32_set_debug (GIOChannel *channel,
1639                               gboolean    flag)
1640 {
1641   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
1642
1643   win32_channel->debug = flag;
1644 }
1645
1646 gint
1647 g_io_channel_win32_poll (GPollFD *fds,
1648                          gint     n_fds,
1649                          gint     timeout)
1650 {
1651   int result;
1652
1653   g_return_val_if_fail (n_fds >= 0, 0);
1654
1655   result = (*g_main_context_get_poll_func (NULL)) (fds, n_fds, timeout);
1656
1657   return result;
1658 }
1659
1660 void
1661 g_io_channel_win32_make_pollfd (GIOChannel   *channel,
1662                                 GIOCondition  condition,
1663                                 GPollFD      *fd)
1664 {
1665   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
1666
1667   if (win32_channel->data_avail_event == NULL)
1668     create_events (win32_channel);
1669   
1670   fd->fd = (gint) win32_channel->data_avail_event;
1671   fd->events = condition;
1672
1673   if (win32_channel->thread_id == 0)
1674     {
1675       if ((condition & G_IO_IN) && win32_channel->type == G_IO_WIN32_FILE_DESC)
1676         create_thread (win32_channel, condition, read_thread);
1677       else if (win32_channel->type == G_IO_WIN32_SOCKET)
1678         create_thread (win32_channel, condition, select_thread);
1679     }
1680 }
1681
1682 /* Binary compatibility */
1683 GIOChannel *
1684 g_io_channel_win32_new_stream_socket (int socket)
1685 {
1686   return g_io_channel_win32_new_socket (socket);
1687 }