30507fd5c0189129d9ab30e437b0c33f281220bb
[platform/upstream/glib.git] / 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 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 "glib.h"
36
37 #include <stdlib.h>
38 #include <windows.h>
39 #include <winsock.h>          /* Not everybody has winsock2 */
40 #include <fcntl.h>
41 #include <io.h>
42 #include <process.h>
43 #include <errno.h>
44 #include <sys/stat.h>
45
46 typedef struct _GIOWin32Channel GIOWin32Channel;
47 typedef struct _GIOWin32Watch GIOWin32Watch;
48
49 #define BUFFER_SIZE 4096
50
51 typedef enum {
52   G_IO_WIN32_WINDOWS_MESSAGES,  /* Windows messages */
53   G_IO_WIN32_FILE_DESC,         /* Unix-like file descriptors from
54                                  * _open() or _pipe(). Read with read().
55                                  * Have to create separate thread to read.
56                                  */
57   G_IO_WIN32_SOCKET             /* Sockets. A separate thread is blocked
58                                  * in select() most of the time.
59                                  */
60 } GIOWin32ChannelType;
61
62 struct _GIOWin32Channel {
63   GIOChannel channel;
64   gint fd;                      /* Either a Unix-like file handle as provided
65                                  * by the Microsoft C runtime, or a SOCKET
66                                  * as provided by WinSock.
67                                  */
68   GIOWin32ChannelType type;
69   
70   gboolean debug;
71
72   CRITICAL_SECTION mutex;
73
74   /* This is used by G_IO_WIN32_WINDOWS_MESSAGES channels */
75   HWND hwnd;                    /* handle of window, or NULL */
76   
77   /* Following fields are used by both fd and socket channels. */
78   gboolean running;             /* Is reader thread running. FALSE if
79                                  * EOF has been reached.
80                                  */
81   gboolean needs_close;         /* If the channel has been closed while
82                                  * the reader thread was still running.
83                                  */
84   guint thread_id;              /* If non-NULL has a reader thread, or has
85                                  * had.*/
86   HANDLE thread_handle;
87   HANDLE data_avail_event;
88
89   gushort revents;
90
91   /* Following fields used by fd channels for input */
92   
93   /* Data is kept in a circular buffer. To be able to distinguish between
94    * empty and full buffer, we cannot fill it completely, but have to
95    * leave a one character gap.
96    *
97    * Data available is between indexes rdp and wrp-1 (modulo BUFFER_SIZE).
98    *
99    * Empty:    wrp == rdp
100    * Full:     (wrp + 1) % BUFFER_SIZE == rdp
101    * Partial:  otherwise
102    */
103   guchar *buffer;               /* (Circular) buffer */
104   gint wrp, rdp;                /* Buffer indices for writing and reading */
105   HANDLE space_avail_event;
106
107   /* Following fields used by socket channels */
108   GSList *watches;
109   HANDLE data_avail_noticed_event;
110 };
111
112 #define LOCK(mutex) EnterCriticalSection (&mutex)
113 #define UNLOCK(mutex) LeaveCriticalSection (&mutex)
114
115 struct _GIOWin32Watch {
116   GSource       source;
117   GPollFD       pollfd;
118   GIOChannel   *channel;
119   GIOCondition  condition;
120   GIOFunc       callback;
121 };
122
123 static void
124 g_io_channel_win32_init (GIOWin32Channel *channel)
125 {
126 #ifdef G_IO_WIN32_DEBUG
127   channel->debug = TRUE;
128 #else
129   if (getenv ("G_IO_WIN32_DEBUG") != NULL)
130     channel->debug = TRUE;
131   else
132     channel->debug = FALSE;
133 #endif
134   channel->buffer = NULL;
135   channel->running = FALSE;
136   channel->needs_close = FALSE;
137   channel->thread_id = 0;
138   channel->data_avail_event = NULL;
139   channel->revents = 0;
140   channel->space_avail_event = NULL;
141   channel->data_avail_noticed_event = NULL;
142   channel->watches = NULL;
143   InitializeCriticalSection (&channel->mutex);
144 }
145
146 static void
147 create_events (GIOWin32Channel *channel)
148 {
149   SECURITY_ATTRIBUTES sec_attrs;
150   
151   sec_attrs.nLength = sizeof(SECURITY_ATTRIBUTES);
152   sec_attrs.lpSecurityDescriptor = NULL;
153   sec_attrs.bInheritHandle = FALSE;
154
155   /* The data available event is manual reset, the space available event
156    * is automatic reset.
157    */
158   if (!(channel->data_avail_event = CreateEvent (&sec_attrs, TRUE, FALSE, NULL))
159       || !(channel->space_avail_event = CreateEvent (&sec_attrs, FALSE, FALSE, NULL))
160       || !(channel->data_avail_noticed_event = CreateEvent (&sec_attrs, FALSE, FALSE, NULL)))
161     {
162       gchar *msg = g_win32_error_message (GetLastError ());
163       g_error ("Error creating event: %s", msg);
164     }
165 }
166
167 static unsigned __stdcall
168 read_thread (void *parameter)
169 {
170   GIOWin32Channel *channel = parameter;
171   GSList *tmp;
172   guchar *buffer;
173   guint nbytes;
174
175   g_io_channel_ref ((GIOChannel *)channel);
176
177   if (channel->debug)
178     g_print ("read_thread %#x: start fd:%d, data_avail:%#x, space_avail:%#x\n",
179              channel->thread_id,
180              channel->fd,
181              (guint) channel->data_avail_event,
182              (guint) channel->space_avail_event);
183   
184   channel->buffer = g_malloc (BUFFER_SIZE);
185   channel->rdp = channel->wrp = 0;
186   channel->running = TRUE;
187
188   SetEvent (channel->space_avail_event);
189   
190   while (channel->running)
191     {
192       LOCK (channel->mutex);
193       if (channel->debug)
194         g_print ("read_thread %#x: rdp=%d, wrp=%d\n",
195                  channel->thread_id, channel->rdp, channel->wrp);
196       if ((channel->wrp + 1) % BUFFER_SIZE == channel->rdp)
197         {
198           /* Buffer is full */
199           if (channel->debug)
200             g_print ("read_thread %#x: resetting space_avail\n",
201                      channel->thread_id);
202           ResetEvent (channel->space_avail_event);
203           if (channel->debug)
204             g_print ("read_thread %#x: waiting for space\n",
205                      channel->thread_id);
206           UNLOCK (channel->mutex);
207           WaitForSingleObject (channel->space_avail_event, INFINITE);
208           LOCK (channel->mutex);
209           if (channel->debug)
210             g_print ("read_thread %#x: rdp=%d, wrp=%d\n",
211                      channel->thread_id, channel->rdp, channel->wrp);
212         }
213       
214       buffer = channel->buffer + channel->wrp;
215       
216       /* Always leave at least one byte unused gap to be able to
217        * distinguish between the full and empty condition...
218        */
219       nbytes = MIN ((channel->rdp + BUFFER_SIZE - channel->wrp - 1) % BUFFER_SIZE,
220                     BUFFER_SIZE - channel->wrp);
221
222       if (channel->debug)
223         g_print ("read_thread %#x: calling read() for %d bytes\n",
224                  channel->thread_id, nbytes);
225
226       UNLOCK (channel->mutex);
227
228       nbytes = read (channel->fd, buffer, nbytes);
229       
230       LOCK (channel->mutex);
231
232       channel->revents = G_IO_IN;
233       if (nbytes == 0)
234         channel->revents |= G_IO_HUP;
235       else if (nbytes < 0)
236         channel->revents |= G_IO_ERR;
237
238       if (channel->debug)
239         g_print ("read_thread %#x: read() returned %d, rdp=%d, wrp=%d\n",
240                  channel->thread_id, nbytes, channel->rdp, channel->wrp);
241
242       if (nbytes <= 0)
243         break;
244
245       channel->wrp = (channel->wrp + nbytes) % BUFFER_SIZE;
246       if (channel->debug)
247         g_print ("read_thread %#x: rdp=%d, wrp=%d, setting data_avail\n",
248                  channel->thread_id, channel->rdp, channel->wrp);
249       SetEvent (channel->data_avail_event);
250       UNLOCK (channel->mutex);
251     }
252   
253   channel->running = FALSE;
254   if (channel->needs_close)
255     {
256       if (channel->debug)
257         g_print ("read_thread %#x: channel fd %d needs closing\n",
258                  channel->thread_id, channel->fd);
259       close (channel->fd);
260       channel->fd = -1;
261     }
262
263   if (channel->debug)
264     g_print ("read_thread %#x: EOF, rdp=%d, wrp=%d, setting data_avail\n",
265              channel->thread_id, channel->rdp, channel->wrp);
266   SetEvent (channel->data_avail_event);
267   UNLOCK (channel->mutex);
268   
269   g_io_channel_unref((GIOChannel *)channel);
270   
271   /* No need to call _endthreadex(), the actual thread starter routine
272    * in MSVCRT (see crt/src/threadex.c:_threadstartex) calls
273    * _endthreadex() for us.
274    */
275
276   CloseHandle (channel->thread_handle);
277
278   return 0;
279 }
280
281 static void
282 create_thread (GIOWin32Channel     *channel,
283                GIOCondition         condition,
284                unsigned (__stdcall *thread) (void *parameter))
285 {
286   channel->thread_handle =
287     (HANDLE) _beginthreadex (NULL, 0, thread, channel, 0,
288                              &channel->thread_id);
289   if (channel->thread_handle == 0)
290     g_warning (G_STRLOC ": Error creating reader thread: %s",
291                strerror (errno));
292   WaitForSingleObject (channel->space_avail_event, INFINITE);
293 }
294
295 static int
296 buffer_read (GIOWin32Channel *channel,
297              guchar          *dest,
298              guint            count,
299              GIOError        *error)
300 {
301   guint nbytes;
302   guint left = count;
303   
304   LOCK (channel->mutex);
305   if (channel->debug)
306     g_print ("reading from thread %#x %d bytes, rdp=%d, wrp=%d\n",
307              channel->thread_id, count, channel->rdp, channel->wrp);
308   
309   if (channel->wrp == channel->rdp)
310     {
311       UNLOCK (channel->mutex);
312       if (channel->debug)
313         g_print ("waiting for data from thread %#x\n", channel->thread_id);
314       WaitForSingleObject (channel->data_avail_event, INFINITE);
315       if (channel->debug)
316         g_print ("done waiting for data from thread %#x\n", channel->thread_id);
317       LOCK (channel->mutex);
318       if (channel->wrp == channel->rdp && !channel->running)
319         {
320           UNLOCK (channel->mutex);
321           return 0;
322         }
323     }
324   
325   if (channel->rdp < channel->wrp)
326     nbytes = channel->wrp - channel->rdp;
327   else
328     nbytes = BUFFER_SIZE - channel->rdp;
329   UNLOCK (channel->mutex);
330   nbytes = MIN (left, nbytes);
331   if (channel->debug)
332     g_print ("moving %d bytes from thread %#x\n",
333              nbytes, channel->thread_id);
334   memcpy (dest, channel->buffer + channel->rdp, nbytes);
335   dest += nbytes;
336   left -= nbytes;
337   LOCK (channel->mutex);
338   channel->rdp = (channel->rdp + nbytes) % BUFFER_SIZE;
339   if (channel->debug)
340     g_print ("setting space_avail for thread %#x\n", channel->thread_id);
341   SetEvent (channel->space_avail_event);
342   if (channel->debug)
343     g_print ("for thread %#x: rdp=%d, wrp=%d\n",
344              channel->thread_id, channel->rdp, channel->wrp);
345   if (channel->running && channel->wrp == channel->rdp)
346     {
347       if (channel->debug)
348         g_print ("resetting data_avail of thread %#x\n",
349                  channel->thread_id);
350       ResetEvent (channel->data_avail_event);
351     };
352   UNLOCK (channel->mutex);
353   
354   /* We have no way to indicate any errors form the actual
355    * read() or recv() call in the reader thread. Should we have?
356    */
357   *error = G_IO_ERROR_NONE;
358   return count - left;
359 }
360
361 static unsigned __stdcall
362 select_thread (void *parameter)
363 {
364   GIOWin32Channel *channel = parameter;
365   fd_set read_fds, write_fds, except_fds;
366   GSList *tmp;
367   int n;
368
369   g_io_channel_ref ((GIOChannel *)channel);
370
371   if (channel->debug)
372     g_print ("select_thread %#x: start fd:%d,\n\tdata_avail:%#x, data_avail_noticed:%#x\n",
373              channel->thread_id,
374              channel->fd,
375              (guint) channel->data_avail_event,
376              (guint) channel->data_avail_noticed_event);
377   
378   channel->rdp = channel->wrp = 0;
379   channel->running = TRUE;
380
381   SetEvent (channel->space_avail_event);
382   
383   while (channel->running)
384     {
385       FD_ZERO (&read_fds);
386       FD_ZERO (&write_fds);
387       FD_ZERO (&except_fds);
388
389       tmp = channel->watches;
390       while (tmp)
391         {
392           GIOWin32Watch *watch = (GIOWin32Watch *)tmp->data;
393
394           if (watch->condition & (G_IO_IN | G_IO_HUP))
395             FD_SET (channel->fd, &read_fds);
396           if (watch->condition & G_IO_OUT)
397             FD_SET (channel->fd, &write_fds);
398           if (watch->condition & G_IO_ERR)
399             FD_SET (channel->fd, &except_fds);
400           
401           tmp = tmp->next;
402         }
403       if (channel->debug)
404         g_print ("select_thread %#x: calling select() for%s%s%s\n",
405                  channel->thread_id,
406                  (FD_ISSET (channel->fd, &read_fds) ? " IN" : ""),
407                  (FD_ISSET (channel->fd, &write_fds) ? " OUT" : ""),
408                  (FD_ISSET (channel->fd, &except_fds) ? " ERR" : ""));
409
410       n = select (1, &read_fds, &write_fds, &except_fds, NULL);
411       
412       if (n == SOCKET_ERROR)
413         {
414           if (channel->debug)
415             g_print ("select_thread %#x: select returned SOCKET_ERROR\n",
416                      channel->thread_id);
417           break;
418         }
419
420       if (channel->debug)
421         g_print ("select_thread %#x: got%s%s%s\n",
422                  channel->thread_id,
423                  (FD_ISSET (channel->fd, &read_fds) ? " IN" : ""),
424                  (FD_ISSET (channel->fd, &write_fds) ? " OUT" : ""),
425                  (FD_ISSET (channel->fd, &except_fds) ? " ERR" : ""));
426
427       if (FD_ISSET (channel->fd, &read_fds))
428         channel->revents |= G_IO_IN;
429       if (FD_ISSET (channel->fd, &write_fds))
430         channel->revents |= G_IO_OUT;
431       if (FD_ISSET (channel->fd, &except_fds))
432         channel->revents |= G_IO_ERR;
433
434       if (channel->debug)
435         g_print ("select_thread %#x: resetting data_avail_noticed,\n"
436                  "\tsetting data_avail\n",
437                  channel->thread_id);
438       ResetEvent (channel->data_avail_noticed_event);
439       SetEvent (channel->data_avail_event);
440
441       LOCK (channel->mutex);
442       if (channel->needs_close)
443         {
444           UNLOCK (channel->mutex);
445           break;
446         }
447       UNLOCK (channel->mutex);
448
449       if (channel->debug)
450         g_print ("select_thread %#x: waiting for data_avail_noticed\n",
451                  channel->thread_id);
452
453       WaitForSingleObject (channel->data_avail_noticed_event, INFINITE);
454       if (channel->debug)
455         g_print ("select_thread %#x: got data_avail_noticed\n",
456                  channel->thread_id);
457     }
458   
459   channel->running = FALSE;
460   LOCK (channel->mutex);
461   if (channel->fd != -1)
462     {
463       if (channel->debug)
464         g_print ("select_thread %#x: channel fd %d needs closing\n",
465                  channel->thread_id, channel->fd);
466       closesocket (channel->fd);
467       channel->fd = -1;
468     }
469
470   if (channel->debug)
471     g_print ("select_thread %#x: got error, setting data_avail\n",
472              channel->thread_id);
473   SetEvent (channel->data_avail_event);
474   UNLOCK (channel->mutex);
475   
476   g_io_channel_unref((GIOChannel *)channel);
477   
478   /* No need to call _endthreadex(), the actual thread starter routine
479    * in MSVCRT (see crt/src/threadex.c:_threadstartex) calls
480    * _endthreadex() for us.
481    */
482
483   CloseHandle (channel->thread_handle);
484
485   return 0;
486 }
487
488 static gboolean
489 g_io_win32_prepare (GSource *source,
490                     gint    *timeout)
491 {
492   GIOWin32Watch *watch = (GIOWin32Watch *)source;
493   GIOWin32Channel *channel = (GIOWin32Channel *)watch->channel;
494   
495   *timeout = -1;
496   
497   if (channel->type == G_IO_WIN32_FILE_DESC)
498     {
499       LOCK (channel->mutex);
500       if (channel->running && channel->wrp == channel->rdp)
501         channel->revents = 0;
502       UNLOCK (channel->mutex);
503     }
504   else if (channel->type == G_IO_WIN32_SOCKET)
505     {
506       channel->revents = 0;
507
508       if (channel->debug)
509         g_print ("g_io_win32_prepare: thread %#x, setting data_avail_noticed\n",
510                  channel->thread_id);
511       SetEvent (channel->data_avail_noticed_event);
512       if (channel->debug)
513         g_print ("g_io_win32_prepare: thread %#x, there.\n",
514                  channel->thread_id);
515     }
516
517   return FALSE;
518 }
519
520 static gboolean
521 g_io_win32_check (GSource *source)
522 {
523         MSG msg;
524   GIOWin32Watch *watch = (GIOWin32Watch *)source;
525   GIOWin32Channel *channel = (GIOWin32Channel *)watch->channel;
526   
527   if (channel->debug)
528     g_print ("g_io_win32_check: for thread %#x:\n"
529              "\twatch->pollfd.events:%#x, watch->pollfd.revents:%#x, channel->revents:%#x\n",
530              channel->thread_id,
531              watch->pollfd.events, watch->pollfd.revents, channel->revents);
532
533   if (channel->type != G_IO_WIN32_WINDOWS_MESSAGES)
534         {
535      watch->pollfd.revents = (watch->pollfd.events & channel->revents);
536         }
537         else
538         {
539     return (PeekMessage (&msg, channel->hwnd, 0, 0, PM_NOREMOVE));
540         }
541
542   if (channel->type == G_IO_WIN32_SOCKET)
543     {
544       if (channel->debug)
545         g_print ("g_io_win32_check: thread %#x, resetting data_avail\n",
546                  channel->thread_id);
547       ResetEvent (channel->data_avail_event);
548       if (channel->debug)
549         g_print ("g_io_win32_check: thread %#x, there.\n",
550                  channel->thread_id);
551     }
552   
553   return (watch->pollfd.revents & watch->condition);
554 }
555
556 static gboolean
557 g_io_win32_dispatch (GSource     *source,
558                      GSourceFunc  callback,
559                      gpointer     user_data)
560 {
561   GIOFunc func = (GIOFunc)callback;
562   GIOWin32Watch *watch = (GIOWin32Watch *)source;
563   
564   if (!func)
565     {
566       g_warning (G_STRLOC ": GIOWin32Watch dispatched without callback\n"
567                  "You must call g_source_connect().");
568       return FALSE;
569     }
570   
571   return (*func) (watch->channel,
572                   watch->pollfd.revents & watch->condition,
573                   user_data);
574 }
575
576 static void
577 g_io_win32_destroy (GSource *source)
578 {
579   GIOWin32Watch *watch = (GIOWin32Watch *)source;
580   GIOWin32Channel *channel = (GIOWin32Channel *)watch->channel;
581   
582   if (channel->debug)
583     g_print ("g_io_win32_destroy: channel with thread %#x\n",
584              channel->thread_id);
585
586   channel->watches = g_slist_remove (channel->watches, watch);
587
588   SetEvent (channel->data_avail_noticed_event);
589   g_io_channel_unref (watch->channel);
590 }
591
592 static GSourceFuncs win32_watch_funcs = {
593   g_io_win32_prepare,
594   g_io_win32_check,
595   g_io_win32_dispatch,
596   g_io_win32_destroy
597 };
598
599 static GSource *
600 g_io_win32_create_watch (GIOChannel    *channel,
601                          GIOCondition   condition,
602                          unsigned (__stdcall *thread) (void *parameter))
603 {
604   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
605   GIOWin32Watch *watch;
606   GSource *source;
607
608   source = g_source_new (&win32_watch_funcs, sizeof (GIOWin32Watch));
609   watch = (GIOWin32Watch *)source;
610   
611   watch->channel = channel;
612   g_io_channel_ref (channel);
613   
614   watch->condition = condition;
615   
616   if (win32_channel->data_avail_event == NULL)
617     create_events (win32_channel);
618
619   watch->pollfd.fd = (gint) win32_channel->data_avail_event;
620   watch->pollfd.events = condition;
621   
622   if (win32_channel->debug)
623     g_print ("g_io_win32_create_watch: fd:%d condition:%#x handle:%#x\n",
624              win32_channel->fd, condition, watch->pollfd.fd);
625   
626   win32_channel->watches = g_slist_append (win32_channel->watches, watch);
627
628   if (win32_channel->thread_id == 0)
629     create_thread (win32_channel, condition, thread);
630
631   g_source_add_poll (source, &watch->pollfd);
632   
633   return source;
634 }
635
636 static GIOError
637 g_io_win32_msg_read (GIOChannel *channel,
638                      gchar      *buf,
639                      guint       count,
640                      guint      *bytes_read)
641 {
642   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
643   MSG msg;               /* In case of alignment problems */
644   
645   if (count < sizeof (MSG))
646     return G_IO_ERROR_INVAL;
647   
648   if (win32_channel->debug)
649     g_print ("g_io_win32_msg_read: for %#x\n",
650              win32_channel->hwnd);
651   if (!PeekMessage (&msg, win32_channel->hwnd, 0, 0, PM_REMOVE))
652     return G_IO_ERROR_AGAIN;
653   
654   memmove (buf, &msg, sizeof (MSG));
655   *bytes_read = sizeof (MSG);
656   return G_IO_ERROR_NONE;
657 }
658
659 static GIOError
660 g_io_win32_msg_write (GIOChannel *channel,
661                       gchar      *buf,
662                       guint       count,
663                       guint      *bytes_written)
664 {
665   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
666   MSG msg;
667   
668   if (count != sizeof (MSG))
669     return G_IO_ERROR_INVAL;
670   
671   /* In case of alignment problems */
672   memmove (&msg, buf, sizeof (MSG));
673   if (!PostMessage (win32_channel->hwnd, msg.message, msg.wParam, msg.lParam))
674     return G_IO_ERROR_UNKNOWN;
675   
676   *bytes_written = sizeof (MSG);
677   return G_IO_ERROR_NONE;
678 }
679
680 static GIOError
681 g_io_win32_no_seek (GIOChannel *channel,
682                     gint        offset,
683                     GSeekType   type)
684 {
685   return G_IO_ERROR_UNKNOWN;
686 }
687
688 static void
689 g_io_win32_msg_close (GIOChannel *channel)
690 {
691   /* Nothing to be done. Or should we set hwnd to some invalid value? */
692 }
693
694 static void
695 g_io_win32_free (GIOChannel *channel)
696 {
697   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
698   
699   if (win32_channel->debug)
700     g_print ("thread %#x: freeing channel, fd: %d\n",
701              win32_channel->thread_id,
702              win32_channel->fd);
703
704   if (win32_channel->data_avail_event)
705     CloseHandle (win32_channel->data_avail_event);
706   if (win32_channel->space_avail_event)
707     CloseHandle (win32_channel->space_avail_event);
708   if (win32_channel->data_avail_noticed_event)
709     CloseHandle (win32_channel->data_avail_noticed_event);
710   DeleteCriticalSection (&win32_channel->mutex);
711
712   g_free (win32_channel->buffer);
713   g_slist_free (win32_channel->watches);
714   g_free (win32_channel);
715 }
716
717 static GSource *
718 g_io_win32_msg_create_watch (GIOChannel    *channel,
719                              GIOCondition   condition)
720 {
721   GIOWin32Watch *watch;
722   GSource *source;
723
724   source = g_source_new (&win32_watch_funcs, sizeof (GIOWin32Watch));
725   watch = (GIOWin32Watch *)source;
726   
727   watch->channel = channel;
728   g_io_channel_ref (channel);
729   
730   watch->condition = condition;
731   
732   watch->pollfd.fd = G_WIN32_MSG_HANDLE;
733   watch->pollfd.events = condition;
734   
735   g_source_add_poll (source, &watch->pollfd);
736   
737   return source;
738 }
739
740 static GIOError
741 g_io_win32_fd_read (GIOChannel *channel,
742                     gchar      *buf,
743                     guint       count,
744                     guint      *bytes_read)
745 {
746   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
747   gint result;
748   GIOError error;
749   
750   if (win32_channel->debug)
751     g_print ("g_io_win32_fd_read: fd:%d count:%d\n",
752              win32_channel->fd, count);
753   
754   if (win32_channel->thread_id)
755     {
756       result = buffer_read (win32_channel, buf, count, &error);
757       if (result < 0)
758         {
759           *bytes_read = 0;
760           return error;
761         }
762       else
763         {
764           *bytes_read = result;
765           return G_IO_ERROR_NONE;
766         }
767     }
768
769   result = read (win32_channel->fd, buf, count);
770
771   if (result < 0)
772     {
773       *bytes_read = 0;
774       if (errno == EINVAL)
775         return G_IO_ERROR_INVAL;
776       else
777         return G_IO_ERROR_UNKNOWN;
778     }
779   else
780     {
781       *bytes_read = result;
782       return G_IO_ERROR_NONE;
783     }
784 }
785
786 static GIOError
787 g_io_win32_fd_write (GIOChannel *channel,
788                      gchar      *buf,
789                      guint       count,
790                      guint      *bytes_written)
791 {
792   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
793   gint result;
794   
795   result = write (win32_channel->fd, buf, count);
796   if (win32_channel->debug)
797     g_print ("g_io_win32_fd_write: fd:%d count:%d = %d\n",
798              win32_channel->fd, count, result);
799   
800   if (result < 0)
801     {
802       *bytes_written = 0;
803       switch (errno)
804         {
805         case EINVAL:
806           return G_IO_ERROR_INVAL;
807         case EAGAIN:
808           return G_IO_ERROR_AGAIN;
809         default:
810           return G_IO_ERROR_UNKNOWN;
811         }
812     }
813   else
814     {
815       *bytes_written = result;
816       return G_IO_ERROR_NONE;
817     }
818 }
819
820 static GIOError
821 g_io_win32_fd_seek (GIOChannel *channel,
822                     gint        offset,
823                     GSeekType   type)
824 {
825   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
826   int whence;
827   off_t result;
828   
829   switch (type)
830     {
831     case G_SEEK_SET:
832       whence = SEEK_SET;
833       break;
834     case G_SEEK_CUR:
835       whence = SEEK_CUR;
836       break;
837     case G_SEEK_END:
838       whence = SEEK_END;
839       break;
840     default:
841       g_warning (G_STRLOC ": Unknown seek type %d", (int) type);
842       return G_IO_ERROR_UNKNOWN;
843     }
844   
845   result = lseek (win32_channel->fd, offset, whence);
846   
847   if (result < 0)
848     {
849       switch (errno)
850         {
851         case EINVAL:
852           return G_IO_ERROR_INVAL;
853         default:
854           return G_IO_ERROR_UNKNOWN;
855         }
856     }
857   else
858     return G_IO_ERROR_NONE;
859 }
860
861 static void
862 g_io_win32_fd_close (GIOChannel *channel)
863 {
864   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
865   
866   if (win32_channel->debug)
867     g_print ("thread %#x: closing fd %d\n",
868              win32_channel->thread_id,
869              win32_channel->fd);
870   LOCK (win32_channel->mutex);
871   if (win32_channel->running)
872     {
873       if (win32_channel->debug)
874         g_print ("thread %#x: running, marking fd %d for later close\n",
875                  win32_channel->thread_id, win32_channel->fd);
876       win32_channel->running = FALSE;
877       win32_channel->needs_close = TRUE;
878       SetEvent (win32_channel->data_avail_event);
879     }
880   else
881     {
882       if (win32_channel->debug)
883         g_print ("closing fd %d\n", win32_channel->fd);
884       close (win32_channel->fd);
885       if (win32_channel->debug)
886         g_print ("closed fd %d, setting to -1\n",
887                  win32_channel->fd);
888       win32_channel->fd = -1;
889     }
890   UNLOCK (win32_channel->mutex);
891 }
892
893 static GSource *
894 g_io_win32_fd_create_watch (GIOChannel    *channel,
895                             GIOCondition   condition)
896 {
897   return g_io_win32_create_watch (channel, condition, read_thread);
898 }
899
900 static GIOError
901 g_io_win32_sock_read (GIOChannel *channel,
902                       gchar      *buf,
903                       guint       count,
904                       guint      *bytes_read)
905 {
906   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
907   gint result;
908   GIOError error;
909
910   if (win32_channel->debug)
911     g_print ("g_io_win32_sock_read: sockfd:%d count:%d\n",
912              win32_channel->fd, count);
913   
914   result = recv (win32_channel->fd, buf, count, 0);
915
916   if (win32_channel->debug)
917     g_print ("g_io_win32_sock_read: recv:%d\n", result);
918   
919   if (result == SOCKET_ERROR)
920     {
921       *bytes_read = 0;
922       switch (WSAGetLastError ())
923         {
924         case WSAEINVAL:
925           return G_IO_ERROR_INVAL;
926         case WSAEWOULDBLOCK:
927         case WSAEINTR:
928           return G_IO_ERROR_AGAIN;
929         default:
930           return G_IO_ERROR_UNKNOWN;
931         }
932     }
933   else
934     {
935       *bytes_read = result;
936       return G_IO_ERROR_NONE;
937     }
938 }
939
940 static GIOError
941 g_io_win32_sock_write (GIOChannel *channel,
942                        gchar      *buf,
943                        guint       count,
944                        guint      *bytes_written)
945 {
946   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
947   gint result;
948   
949   if (win32_channel->debug)
950     g_print ("g_io_win32_sock_write: sockfd:%d count:%d\n",
951              win32_channel->fd, count);
952   
953   result = send (win32_channel->fd, buf, count, 0);
954   
955   if (win32_channel->debug)
956     g_print ("g_io_win32_sock_write: send:%d\n", result);
957   
958   if (result == SOCKET_ERROR)
959     {
960       *bytes_written = 0;
961       switch (WSAGetLastError ())
962         {
963         case WSAEINVAL:
964           return G_IO_ERROR_INVAL;
965         case WSAEWOULDBLOCK:
966         case WSAEINTR:
967           return G_IO_ERROR_AGAIN;
968         default:
969           return G_IO_ERROR_UNKNOWN;
970         }
971     }
972   else
973     {
974       *bytes_written = result;
975       return G_IO_ERROR_NONE;
976     }
977 }
978
979 static void
980 g_io_win32_sock_close (GIOChannel *channel)
981 {
982   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
983
984   LOCK(win32_channel->mutex);
985   if (win32_channel->running)
986   {
987     if (win32_channel->debug)
988         g_print ("thread %#x: running, marking for later close\n",
989                  win32_channel->thread_id);
990     win32_channel->running = FALSE;
991     win32_channel->needs_close = TRUE;
992     SetEvent(win32_channel->data_avail_noticed_event);
993   }
994   if (win32_channel->fd != -1)
995   {
996     if (win32_channel->debug)
997        g_print ("thread %#x: closing socket %d\n",
998              win32_channel->thread_id,
999              win32_channel->fd);
1000   
1001     closesocket (win32_channel->fd);
1002     win32_channel->fd = -1;
1003   }
1004   UNLOCK(win32_channel->mutex);
1005 }
1006
1007 static GSource *
1008 g_io_win32_sock_create_watch (GIOChannel    *channel,
1009                               GIOCondition   condition)
1010 {
1011   return g_io_win32_create_watch (channel, condition, select_thread);
1012 }
1013
1014 static GIOFuncs win32_channel_msg_funcs = {
1015   g_io_win32_msg_read,
1016   g_io_win32_msg_write,
1017   g_io_win32_no_seek,
1018   g_io_win32_msg_close,
1019   g_io_win32_msg_create_watch,
1020   g_io_win32_free
1021 };
1022
1023 static GIOFuncs win32_channel_fd_funcs = {
1024   g_io_win32_fd_read,
1025   g_io_win32_fd_write,
1026   g_io_win32_fd_seek,
1027   g_io_win32_fd_close,
1028   g_io_win32_fd_create_watch,
1029   g_io_win32_free
1030 };
1031
1032 static GIOFuncs win32_channel_sock_funcs = {
1033   g_io_win32_sock_read,
1034   g_io_win32_sock_write,
1035   g_io_win32_no_seek,
1036   g_io_win32_sock_close,
1037   g_io_win32_sock_create_watch,
1038   g_io_win32_free
1039 };
1040
1041 GIOChannel *
1042 g_io_channel_win32_new_messages (guint hwnd)
1043 {
1044   GIOWin32Channel *win32_channel = g_new (GIOWin32Channel, 1);
1045   GIOChannel *channel = (GIOChannel *)win32_channel;
1046
1047   g_io_channel_init (channel);
1048   g_io_channel_win32_init (win32_channel);
1049   if (win32_channel->debug)
1050     g_print ("g_io_channel_win32_new_messages: hwnd = %ud\n", hwnd);
1051   channel->funcs = &win32_channel_msg_funcs;
1052   win32_channel->type = G_IO_WIN32_WINDOWS_MESSAGES;
1053   win32_channel->hwnd = (HWND) hwnd;
1054
1055   return channel;
1056 }
1057
1058 GIOChannel *
1059 g_io_channel_win32_new_fd (gint fd)
1060 {
1061   GIOWin32Channel *win32_channel;
1062   GIOChannel *channel;
1063   struct stat st;
1064
1065   if (fstat (fd, &st) == -1)
1066     {
1067       g_warning (G_STRLOC ": %d isn't a (emulated) file descriptor", fd);
1068       return NULL;
1069     }
1070
1071   win32_channel = g_new (GIOWin32Channel, 1);
1072   channel = (GIOChannel *)win32_channel;
1073
1074   g_io_channel_init (channel);
1075   g_io_channel_win32_init (win32_channel);
1076   if (win32_channel->debug)
1077     g_print ("g_io_channel_win32_new_fd: fd = %d\n", fd);
1078   channel->funcs = &win32_channel_fd_funcs;
1079   win32_channel->type = G_IO_WIN32_FILE_DESC;
1080   win32_channel->fd = fd;
1081
1082   return channel;
1083 }
1084
1085 gint
1086 g_io_channel_win32_get_fd (GIOChannel *channel)
1087 {
1088   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
1089
1090   return win32_channel->fd;
1091 }
1092
1093 GIOChannel *
1094 g_io_channel_win32_new_socket (int socket)
1095 {
1096   GIOWin32Channel *win32_channel = g_new (GIOWin32Channel, 1);
1097   GIOChannel *channel = (GIOChannel *)win32_channel;
1098
1099   g_io_channel_init (channel);
1100   g_io_channel_win32_init (win32_channel);
1101   if (win32_channel->debug)
1102     g_print ("g_io_channel_win32_new_socket: sockfd:%d\n", socket);
1103   channel->funcs = &win32_channel_sock_funcs;
1104   win32_channel->type = G_IO_WIN32_SOCKET;
1105   win32_channel->fd = socket;
1106
1107   return channel;
1108 }
1109
1110 GIOChannel *
1111 g_io_channel_unix_new (gint fd)
1112 {
1113   struct stat st;
1114
1115   if (fstat (fd, &st) == 0)
1116     return g_io_channel_win32_new_fd (fd);
1117   
1118   if (getsockopt (fd, SOL_SOCKET, SO_TYPE, NULL, NULL) != SO_ERROR)
1119     return g_io_channel_win32_new_socket(fd);
1120
1121   g_warning (G_STRLOC ": %d is neither a file descriptor or a socket", fd);
1122   return NULL;
1123 }
1124
1125 gint
1126 g_io_channel_unix_get_fd (GIOChannel *channel)
1127 {
1128   return g_io_channel_win32_get_fd (channel);
1129 }
1130
1131 void
1132 g_io_channel_win32_set_debug (GIOChannel *channel,
1133                               gboolean    flag)
1134 {
1135   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
1136
1137   win32_channel->debug = flag;
1138 }
1139
1140 gint
1141 g_io_channel_win32_poll (GPollFD *fds,
1142                          gint     n_fds,
1143                          gint     timeout)
1144 {
1145   int result;
1146
1147   g_return_val_if_fail (n_fds >= 0, 0);
1148
1149   result = (*g_main_context_get_poll_func (NULL)) (fds, n_fds, timeout);
1150
1151   return result;
1152 }
1153
1154 void
1155 g_io_channel_win32_make_pollfd (GIOChannel   *channel,
1156                                 GIOCondition  condition,
1157                                 GPollFD      *fd)
1158 {
1159   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
1160
1161   if (win32_channel->data_avail_event == NULL)
1162     create_events (win32_channel);
1163   
1164   fd->fd = (gint) win32_channel->data_avail_event;
1165   fd->events = condition;
1166
1167   if (win32_channel->thread_id == 0)
1168     if ((condition & G_IO_IN) && win32_channel->type == G_IO_WIN32_FILE_DESC)
1169       create_thread (win32_channel, condition, read_thread);
1170     else if (win32_channel->type == G_IO_WIN32_SOCKET)
1171       create_thread (win32_channel, condition, select_thread);
1172 }
1173
1174 /* Binary compatibility */
1175 GIOChannel *
1176 g_io_channel_win32_new_stream_socket (int socket)
1177 {
1178   return g_io_channel_win32_new_socket (socket);
1179 }