source: trunk/third/glib2/glib/giowin32.c @ 21369

Revision 21369, 44.9 KB checked in by ghudson, 20 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r21368, which included commits to RCS files with non-trunk default branches.
Line 
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
50typedef struct _GIOWin32Channel GIOWin32Channel;
51typedef struct _GIOWin32Watch GIOWin32Watch;
52
53#define BUFFER_SIZE 4096
54
55typedef 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
66struct _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
120struct _GIOWin32Watch {
121  GSource       source;
122  GPollFD       pollfd;
123  GIOChannel   *channel;
124  GIOCondition  condition;
125};
126
127static void
128g_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
145static void
146g_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
162static gboolean
163g_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
175static void
176g_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
193static void
194create_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
215static unsigned __stdcall
216read_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
325static void
326create_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
344static void
345init_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
404static GIOStatus
405buffer_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
474static unsigned __stdcall
475select_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
610static gboolean
611g_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
655static gboolean
656g_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
694static gboolean
695g_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
715static void
716g_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
742GSourceFuncs 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
749static GSource *
750g_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
791static GIOStatus
792g_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
820static GIOStatus
821g_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
852static GIOStatus
853g_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
861static void
862g_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
888static GSource *
889g_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
911static GIOStatus
912g_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
958static GIOStatus
959g_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
996static GIOStatus
997g_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
1045static GIOStatus
1046g_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
1082static GSource *
1083g_io_win32_fd_create_watch (GIOChannel    *channel,
1084                            GIOCondition   condition)
1085{
1086  return g_io_win32_create_watch (channel, condition, read_thread);
1087}
1088
1089static GIOStatus
1090g_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
1106repeat:
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
1155static GIOStatus
1156g_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
1171repeat:
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
1214static GIOStatus
1215g_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
1247static GSource *
1248g_io_win32_sock_create_watch (GIOChannel    *channel,
1249                              GIOCondition   condition)
1250{
1251  return g_io_win32_create_watch (channel, condition, select_thread);
1252}
1253
1254GIOChannel *
1255g_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
1385static GIOStatus
1386g_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
1404static GIOFlags
1405g_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
1452static GIOFlags
1453g_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
1467static GIOFlags
1468g_io_win32_msg_get_flags (GIOChannel *channel)
1469{
1470  return 0;
1471}
1472
1473static GIOFlags
1474g_io_win32_sock_get_flags (GIOChannel *channel)
1475{
1476  /* XXX Could do something here. */
1477  return 0;
1478}
1479
1480static 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
1491static 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
1502static 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
1513GIOChannel *
1514g_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
1536static GIOChannel *
1537g_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
1559GIOChannel *
1560g_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
1573gint
1574g_io_channel_win32_get_fd (GIOChannel *channel)
1575{
1576  GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
1577
1578  return win32_channel->fd;
1579}
1580
1581GIOChannel *
1582g_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
1605GIOChannel *
1606g_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
1631gint
1632g_io_channel_unix_get_fd (GIOChannel *channel)
1633{
1634  return g_io_channel_win32_get_fd (channel);
1635}
1636
1637void
1638g_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
1646gint
1647g_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
1660void
1661g_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 */
1683GIOChannel *
1684g_io_channel_win32_new_stream_socket (int socket)
1685{
1686  return g_io_channel_win32_new_socket (socket);
1687}
Note: See TracBrowser for help on using the repository browser.