1 /* GLIB - Library of useful routines for C programming
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
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
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.
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.
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.
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/.
32 /* Define this to get (very) verbose logging of all channels */
33 /* #define G_IO_WIN32_DEBUG */
41 #include <winsock.h> /* Not everybody has winsock2 */
50 typedef struct _GIOWin32Channel GIOWin32Channel;
51 typedef struct _GIOWin32Watch GIOWin32Watch;
53 #define BUFFER_SIZE 4096
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.
61 G_IO_WIN32_SOCKET /* Sockets. A separate thread is blocked
62 * in select() most of the time.
64 } GIOWin32ChannelType;
66 struct _GIOWin32Channel {
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.
72 GIOWin32ChannelType type;
76 CRITICAL_SECTION mutex;
78 /* This is used by G_IO_WIN32_WINDOWS_MESSAGES channels */
79 HWND hwnd; /* handle of window, or NULL */
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.
85 gboolean needs_close; /* If the channel has been closed while
86 * the reader thread was still running.
88 guint thread_id; /* If non-NULL has a reader thread, or has
91 HANDLE data_avail_event;
95 /* Following fields used by fd channels for input */
97 /* Data is kept in a circular buffer. To be able to distinguish between
98 * empty and full buffer, we cannot fill it completely, but have to
99 * leave a one character gap.
101 * Data available is between indexes rdp and wrp-1 (modulo BUFFER_SIZE).
104 * Full: (wrp + 1) % BUFFER_SIZE == rdp
107 guchar *buffer; /* (Circular) buffer */
108 gint wrp, rdp; /* Buffer indices for writing and reading */
109 HANDLE space_avail_event;
111 /* Following fields used by socket channels */
113 HANDLE data_avail_noticed_event;
116 #define LOCK(mutex) EnterCriticalSection (&mutex)
117 #define UNLOCK(mutex) LeaveCriticalSection (&mutex)
119 struct _GIOWin32Watch {
123 GIOCondition condition;
127 g_win32_print_access_mode (int flags)
129 g_print ("%s%s%s%s%s%s%s%s%s%s",
130 ((flags & 0x3) == _O_RDWR ? "O_RDWR" :
131 ((flags & 0x3) == _O_RDONLY ? "O_RDONLY" :
132 ((flags & 0x3) == _O_WRONLY ? "O_WRONLY" : "0"))),
133 (flags & _O_APPEND ? "|O_APPEND" : ""),
134 (flags & _O_RANDOM ? "|O_RANDOM" : ""),
135 (flags & _O_SEQUENTIAL ? "|O_SEQUENTIAL" : ""),
136 (flags & _O_TEMPORARY ? "|O_TEMPORARY" : ""),
137 (flags & _O_CREAT ? "|O_CREAT" : ""),
138 (flags & _O_TRUNC ? "|O_TRUNC" : ""),
139 (flags & _O_EXCL ? "|O_EXCL" : ""),
140 (flags & _O_TEXT ? "|O_TEXT" : ""),
141 (flags & _O_BINARY ? "|O_BINARY" : ""));
145 g_win32_print_gioflags (GIOFlags flags)
149 if (flags & G_IO_FLAG_APPEND)
150 bar = "|", g_print ("APPEND");
151 if (flags & G_IO_FLAG_NONBLOCK)
152 g_print ("%sNONBLOCK", bar), bar = "|";
153 if (flags & G_IO_FLAG_IS_READABLE)
154 g_print ("%sREADABLE", bar), bar = "|";
155 if (flags & G_IO_FLAG_IS_WRITEABLE)
156 g_print ("%sWRITEABLE", bar), bar = "|";
157 if (flags & G_IO_FLAG_IS_WRITEABLE)
158 g_print ("%sWRITEABLE", bar), bar = "|";
159 if (flags & G_IO_FLAG_IS_SEEKABLE)
160 g_print ("%sSEEKABLE", bar), bar = "|";
164 g_io_win32_get_debug_flag (void)
166 #ifdef G_IO_WIN32_DEBUG
169 if (getenv ("G_IO_WIN32_DEBUG") != NULL)
177 g_io_channel_win32_init (GIOWin32Channel *channel)
179 channel->debug = g_io_win32_get_debug_flag ();
180 channel->buffer = NULL;
181 channel->running = FALSE;
182 channel->needs_close = FALSE;
183 channel->thread_id = 0;
184 channel->data_avail_event = NULL;
185 channel->revents = 0;
186 channel->space_avail_event = NULL;
187 channel->data_avail_noticed_event = NULL;
188 channel->watches = NULL;
189 InitializeCriticalSection (&channel->mutex);
193 create_events (GIOWin32Channel *channel)
195 SECURITY_ATTRIBUTES sec_attrs;
197 sec_attrs.nLength = sizeof (SECURITY_ATTRIBUTES);
198 sec_attrs.lpSecurityDescriptor = NULL;
199 sec_attrs.bInheritHandle = FALSE;
201 /* The data available event is manual reset, the space available event
202 * is automatic reset.
204 if (!(channel->data_avail_event = CreateEvent (&sec_attrs, TRUE, FALSE, NULL))
205 || !(channel->space_avail_event = CreateEvent (&sec_attrs, FALSE, FALSE, NULL))
206 || !(channel->data_avail_noticed_event = CreateEvent (&sec_attrs, FALSE, FALSE, NULL)))
208 gchar *emsg = g_win32_error_message (GetLastError ());
209 g_error ("Error creating event: %s", emsg);
214 static unsigned __stdcall
215 read_thread (void *parameter)
217 GIOWin32Channel *channel = parameter;
221 g_io_channel_ref ((GIOChannel *)channel);
224 g_print ("read_thread %#x: start fd:%d, data_avail:%#x, space_avail:%#x\n",
227 (guint) channel->data_avail_event,
228 (guint) channel->space_avail_event);
230 channel->buffer = g_malloc (BUFFER_SIZE);
231 channel->rdp = channel->wrp = 0;
232 channel->running = TRUE;
234 SetEvent (channel->space_avail_event);
236 while (channel->running)
238 LOCK (channel->mutex);
240 g_print ("read_thread %#x: rdp=%d, wrp=%d\n",
241 channel->thread_id, channel->rdp, channel->wrp);
242 if ((channel->wrp + 1) % BUFFER_SIZE == channel->rdp)
246 g_print ("read_thread %#x: resetting space_avail\n",
248 ResetEvent (channel->space_avail_event);
250 g_print ("read_thread %#x: waiting for space\n",
252 UNLOCK (channel->mutex);
253 WaitForSingleObject (channel->space_avail_event, INFINITE);
254 LOCK (channel->mutex);
256 g_print ("read_thread %#x: rdp=%d, wrp=%d\n",
257 channel->thread_id, channel->rdp, channel->wrp);
260 buffer = channel->buffer + channel->wrp;
262 /* Always leave at least one byte unused gap to be able to
263 * distinguish between the full and empty condition...
265 nbytes = MIN ((channel->rdp + BUFFER_SIZE - channel->wrp - 1) % BUFFER_SIZE,
266 BUFFER_SIZE - channel->wrp);
269 g_print ("read_thread %#x: calling read() for %d bytes\n",
270 channel->thread_id, nbytes);
272 UNLOCK (channel->mutex);
274 nbytes = read (channel->fd, buffer, nbytes);
276 LOCK (channel->mutex);
278 channel->revents = G_IO_IN;
280 channel->revents |= G_IO_HUP;
282 channel->revents |= G_IO_ERR;
285 g_print ("read_thread %#x: read() returned %d, rdp=%d, wrp=%d\n",
286 channel->thread_id, nbytes, channel->rdp, channel->wrp);
291 channel->wrp = (channel->wrp + nbytes) % BUFFER_SIZE;
293 g_print ("read_thread %#x: rdp=%d, wrp=%d, setting data_avail\n",
294 channel->thread_id, channel->rdp, channel->wrp);
295 SetEvent (channel->data_avail_event);
296 UNLOCK (channel->mutex);
299 channel->running = FALSE;
300 if (channel->needs_close)
303 g_print ("read_thread %#x: channel fd %d needs closing\n",
304 channel->thread_id, channel->fd);
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);
315 g_io_channel_unref((GIOChannel *)channel);
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.
322 CloseHandle (channel->thread_handle);
328 create_thread (GIOWin32Channel *channel,
329 GIOCondition condition,
330 unsigned (__stdcall *thread) (void *parameter))
332 channel->thread_handle =
333 (HANDLE) _beginthreadex (NULL, 0, thread, channel, 0,
334 &channel->thread_id);
335 if (channel->thread_handle == 0)
336 g_warning (G_STRLOC ": Error creating reader thread: %s",
338 WaitForSingleObject (channel->space_avail_event, INFINITE);
342 buffer_read (GIOWin32Channel *channel,
351 LOCK (channel->mutex);
353 g_print ("reading from thread %#x %d bytes, rdp=%d, wrp=%d\n",
354 channel->thread_id, count, channel->rdp, channel->wrp);
356 if (channel->wrp == channel->rdp)
358 UNLOCK (channel->mutex);
360 g_print ("waiting for data from thread %#x\n", channel->thread_id);
361 WaitForSingleObject (channel->data_avail_event, INFINITE);
363 g_print ("done waiting for data from thread %#x\n", channel->thread_id);
364 LOCK (channel->mutex);
365 if (channel->wrp == channel->rdp && !channel->running)
368 g_print ("wrp==rdp, !running\n");
369 UNLOCK (channel->mutex);
371 return G_IO_STATUS_EOF;
375 if (channel->rdp < channel->wrp)
376 nbytes = channel->wrp - channel->rdp;
378 nbytes = BUFFER_SIZE - channel->rdp;
379 UNLOCK (channel->mutex);
380 nbytes = MIN (left, nbytes);
382 g_print ("moving %d bytes from thread %#x\n",
383 nbytes, channel->thread_id);
384 memcpy (dest, channel->buffer + channel->rdp, nbytes);
387 LOCK (channel->mutex);
388 channel->rdp = (channel->rdp + nbytes) % BUFFER_SIZE;
390 g_print ("setting space_avail for thread %#x\n", channel->thread_id);
391 SetEvent (channel->space_avail_event);
393 g_print ("for thread %#x: rdp=%d, wrp=%d\n",
394 channel->thread_id, channel->rdp, channel->wrp);
395 if (channel->running && channel->wrp == channel->rdp)
398 g_print ("resetting data_avail of thread %#x\n",
400 ResetEvent (channel->data_avail_event);
402 UNLOCK (channel->mutex);
404 /* We have no way to indicate any errors form the actual
405 * read() or recv() call in the reader thread. Should we have?
407 *bytes_read = count - left;
408 return (*bytes_read > 0) ? G_IO_STATUS_NORMAL : G_IO_STATUS_EOF;
411 static unsigned __stdcall
412 select_thread (void *parameter)
414 GIOWin32Channel *channel = parameter;
415 fd_set read_fds, write_fds, except_fds;
419 g_io_channel_ref ((GIOChannel *)channel);
422 g_print ("select_thread %#x: start fd:%d,\n\tdata_avail:%#x, data_avail_noticed:%#x\n",
425 (guint) channel->data_avail_event,
426 (guint) channel->data_avail_noticed_event);
428 channel->rdp = channel->wrp = 0;
429 channel->running = TRUE;
431 SetEvent (channel->space_avail_event);
433 while (channel->running)
436 FD_ZERO (&write_fds);
437 FD_ZERO (&except_fds);
439 tmp = channel->watches;
442 GIOWin32Watch *watch = (GIOWin32Watch *)tmp->data;
444 if (watch->condition & (G_IO_IN | G_IO_HUP))
445 FD_SET (channel->fd, &read_fds);
446 if (watch->condition & G_IO_OUT)
447 FD_SET (channel->fd, &write_fds);
448 if (watch->condition & G_IO_ERR)
449 FD_SET (channel->fd, &except_fds);
454 g_print ("select_thread %#x: calling select() for%s%s%s\n",
456 (FD_ISSET (channel->fd, &read_fds) ? " IN" : ""),
457 (FD_ISSET (channel->fd, &write_fds) ? " OUT" : ""),
458 (FD_ISSET (channel->fd, &except_fds) ? " ERR" : ""));
460 n = select (1, &read_fds, &write_fds, &except_fds, NULL);
462 if (n == SOCKET_ERROR)
465 g_print ("select_thread %#x: select returned SOCKET_ERROR\n",
471 g_print ("select_thread %#x: got%s%s%s\n",
473 (FD_ISSET (channel->fd, &read_fds) ? " IN" : ""),
474 (FD_ISSET (channel->fd, &write_fds) ? " OUT" : ""),
475 (FD_ISSET (channel->fd, &except_fds) ? " ERR" : ""));
477 if (FD_ISSET (channel->fd, &read_fds))
478 channel->revents |= G_IO_IN;
479 if (FD_ISSET (channel->fd, &write_fds))
480 channel->revents |= G_IO_OUT;
481 if (FD_ISSET (channel->fd, &except_fds))
482 channel->revents |= G_IO_ERR;
485 g_print ("select_thread %#x: resetting data_avail_noticed,\n"
486 "\tsetting data_avail\n",
488 ResetEvent (channel->data_avail_noticed_event);
489 SetEvent (channel->data_avail_event);
491 LOCK (channel->mutex);
492 if (channel->needs_close)
494 UNLOCK (channel->mutex);
497 UNLOCK (channel->mutex);
500 g_print ("select_thread %#x: waiting for data_avail_noticed\n",
503 WaitForSingleObject (channel->data_avail_noticed_event, INFINITE);
505 g_print ("select_thread %#x: got data_avail_noticed\n",
509 channel->running = FALSE;
510 LOCK (channel->mutex);
511 if (channel->fd != -1)
513 /* DO NOT close the fd here */
518 g_print ("select_thread %#x: got error, setting data_avail\n",
520 SetEvent (channel->data_avail_event);
521 UNLOCK (channel->mutex);
523 g_io_channel_unref((GIOChannel *)channel);
525 /* No need to call _endthreadex(), the actual thread starter routine
526 * in MSVCRT (see crt/src/threadex.c:_threadstartex) calls
527 * _endthreadex() for us.
530 CloseHandle (channel->thread_handle);
536 g_io_win32_prepare (GSource *source,
539 GIOWin32Watch *watch = (GIOWin32Watch *)source;
540 GIOWin32Channel *channel = (GIOWin32Channel *)watch->channel;
544 if (channel->type == G_IO_WIN32_FILE_DESC)
546 LOCK (channel->mutex);
547 if (channel->running && channel->wrp == channel->rdp)
548 channel->revents = 0;
549 UNLOCK (channel->mutex);
551 else if (channel->type == G_IO_WIN32_SOCKET)
553 channel->revents = 0;
556 g_print ("g_io_win32_prepare: thread %#x, setting data_avail_noticed\n",
558 SetEvent (channel->data_avail_noticed_event);
560 g_print ("g_io_win32_prepare: thread %#x, there.\n",
565 /* XXX: why should we want to do this ? */
566 watch->condition = g_io_channel_get_buffer_condition (watch->channel);
568 return (watch->pollfd.revents & (G_IO_IN | G_IO_OUT)) == watch->condition;
572 g_io_win32_check (GSource *source)
575 GIOWin32Watch *watch = (GIOWin32Watch *)source;
576 GIOWin32Channel *channel = (GIOWin32Channel *)watch->channel;
577 GIOCondition buffer_condition = g_io_channel_get_buffer_condition (watch->channel);
580 g_print ("g_io_win32_check: for thread %#x:\n"
581 "\twatch->pollfd.events:%#x, watch->pollfd.revents:%#x, channel->revents:%#x\n",
583 watch->pollfd.events, watch->pollfd.revents, channel->revents);
585 if (channel->type != G_IO_WIN32_WINDOWS_MESSAGES)
587 watch->pollfd.revents = (watch->pollfd.events & channel->revents);
591 return (PeekMessage (&msg, channel->hwnd, 0, 0, PM_NOREMOVE));
594 if (channel->type == G_IO_WIN32_SOCKET)
597 g_print ("g_io_win32_check: thread %#x, resetting data_avail\n",
599 ResetEvent (channel->data_avail_event);
601 g_print ("g_io_win32_check: thread %#x, there.\n",
605 return (watch->pollfd.revents & watch->condition);
609 g_io_win32_dispatch (GSource *source,
610 GSourceFunc callback,
613 GIOFunc func = (GIOFunc)callback;
614 GIOWin32Watch *watch = (GIOWin32Watch *)source;
618 g_warning (G_STRLOC ": GIOWin32Watch dispatched without callback\n"
619 "You must call g_source_connect().");
623 return (*func) (watch->channel,
624 watch->pollfd.revents & watch->condition,
629 g_io_win32_finalize (GSource *source)
631 GIOWin32Watch *watch = (GIOWin32Watch *)source;
632 GIOWin32Channel *channel = (GIOWin32Channel *)watch->channel;
635 g_print ("g_io_win32_finalize: channel with thread %#x\n",
638 channel->watches = g_slist_remove (channel->watches, watch);
640 SetEvent (channel->data_avail_noticed_event);
641 g_io_channel_unref (watch->channel);
644 #if defined(G_PLATFORM_WIN32) && defined(__GNUC__)
645 __declspec(dllexport)
647 GSourceFuncs g_io_watch_funcs = {
655 g_io_win32_create_watch (GIOChannel *channel,
656 GIOCondition condition,
657 unsigned (__stdcall *thread) (void *parameter))
659 GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
660 GIOWin32Watch *watch;
663 source = g_source_new (&g_io_watch_funcs, sizeof (GIOWin32Watch));
664 watch = (GIOWin32Watch *)source;
666 watch->channel = channel;
667 g_io_channel_ref (channel);
669 watch->condition = condition;
671 if (win32_channel->data_avail_event == NULL)
672 create_events (win32_channel);
674 watch->pollfd.fd = (gint) win32_channel->data_avail_event;
675 watch->pollfd.events = condition;
677 if (win32_channel->debug)
678 g_print ("g_io_win32_create_watch: fd:%d condition:%#x handle:%#x\n",
679 win32_channel->fd, condition, watch->pollfd.fd);
681 win32_channel->watches = g_slist_append (win32_channel->watches, watch);
683 if (win32_channel->thread_id == 0)
684 create_thread (win32_channel, condition, thread);
686 g_source_add_poll (source, &watch->pollfd);
692 g_io_win32_msg_read (GIOChannel *channel,
698 GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
699 MSG msg; /* In case of alignment problems */
701 if (count < sizeof (MSG))
703 g_set_error(err, G_IO_CHANNEL_ERROR, G_IO_CHANNEL_ERROR_INVAL,
704 _("Incorrect message size")); /* Informative enough error message? */
705 return G_IO_STATUS_ERROR;
708 if (win32_channel->debug)
709 g_print ("g_io_win32_msg_read: for %#x\n",
710 (guint) win32_channel->hwnd);
711 if (!PeekMessage (&msg, win32_channel->hwnd, 0, 0, PM_REMOVE))
712 return G_IO_STATUS_AGAIN;
714 memmove (buf, &msg, sizeof (MSG));
715 *bytes_read = sizeof (MSG);
717 return G_IO_STATUS_NORMAL;
721 g_io_win32_msg_write (GIOChannel *channel,
724 gsize *bytes_written,
727 GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
730 if (count != sizeof (MSG))
732 g_set_error(err, G_IO_CHANNEL_ERROR, G_IO_CHANNEL_ERROR_INVAL,
733 _("Incorrect message size")); /* Informative enough error message? */
734 return G_IO_STATUS_ERROR;
737 /* In case of alignment problems */
738 memmove (&msg, buf, sizeof (MSG));
739 if (!PostMessage (win32_channel->hwnd, msg.message, msg.wParam, msg.lParam))
741 gchar *emsg = g_win32_error_message (GetLastError ());
742 g_set_error(err, G_IO_CHANNEL_ERROR, G_IO_CHANNEL_ERROR_FAILED, emsg);
744 return G_IO_STATUS_ERROR;
747 *bytes_written = sizeof (MSG);
749 return G_IO_STATUS_NORMAL;
753 g_io_win32_no_seek (GIOChannel *channel,
758 g_assert_not_reached ();
760 return G_IO_STATUS_ERROR;
764 g_io_win32_msg_close (GIOChannel *channel,
767 /* Nothing to be done. Or should we set hwnd to some invalid value? */
769 return G_IO_STATUS_NORMAL;
773 g_io_win32_free (GIOChannel *channel)
775 GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
777 if (win32_channel->debug)
778 g_print ("thread %#x: freeing channel, fd: %d\n",
779 win32_channel->thread_id,
782 if (win32_channel->data_avail_event)
783 CloseHandle (win32_channel->data_avail_event);
784 if (win32_channel->space_avail_event)
785 CloseHandle (win32_channel->space_avail_event);
786 if (win32_channel->data_avail_noticed_event)
787 CloseHandle (win32_channel->data_avail_noticed_event);
788 DeleteCriticalSection (&win32_channel->mutex);
790 g_free (win32_channel->buffer);
791 g_slist_free (win32_channel->watches);
792 g_free (win32_channel);
796 g_io_win32_msg_create_watch (GIOChannel *channel,
797 GIOCondition condition)
799 GIOWin32Watch *watch;
802 source = g_source_new (&g_io_watch_funcs, sizeof (GIOWin32Watch));
803 watch = (GIOWin32Watch *)source;
805 watch->channel = channel;
806 g_io_channel_ref (channel);
808 watch->condition = condition;
810 watch->pollfd.fd = G_WIN32_MSG_HANDLE;
811 watch->pollfd.events = condition;
813 g_source_add_poll (source, &watch->pollfd);
819 g_io_win32_fd_read (GIOChannel *channel,
825 GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
828 if (win32_channel->debug)
829 g_print ("g_io_win32_fd_read: fd:%d count:%d\n",
830 win32_channel->fd, count);
832 if (win32_channel->thread_id)
834 return buffer_read (win32_channel, buf, count, bytes_read, err);
837 result = read (win32_channel->fd, buf, count);
839 if (win32_channel->debug)
840 g_print ("g_io_win32_fd_read: read() = %d\n", result);
850 return G_IO_STATUS_AGAIN;
853 g_set_error (err, G_IO_CHANNEL_ERROR,
854 g_io_channel_error_from_errno (errno),
856 return G_IO_STATUS_ERROR;
860 *bytes_read = result;
862 return (result > 0) ? G_IO_STATUS_NORMAL : G_IO_STATUS_EOF;
866 g_io_win32_fd_write (GIOChannel *channel,
869 gsize *bytes_written,
872 GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
875 result = write (win32_channel->fd, buf, count);
876 if (win32_channel->debug)
877 g_print ("g_io_win32_fd_write: fd:%d count:%d = %d\n",
878 win32_channel->fd, count, result);
888 return G_IO_STATUS_AGAIN;
891 g_set_error (err, G_IO_CHANNEL_ERROR,
892 g_io_channel_error_from_errno (errno),
894 return G_IO_STATUS_ERROR;
898 *bytes_written = result;
900 return G_IO_STATUS_NORMAL;
904 g_io_win32_fd_seek (GIOChannel *channel,
909 GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
926 whence = -1; /* Keep the compiler quiet */
927 g_assert_not_reached();
931 if (tmp_offset != offset)
933 g_set_error (err, G_IO_CHANNEL_ERROR,
934 g_io_channel_error_from_errno (EINVAL),
935 g_strerror (EINVAL));
936 return G_IO_STATUS_ERROR;
939 result = lseek (win32_channel->fd, tmp_offset, whence);
943 g_set_error (err, G_IO_CHANNEL_ERROR,
944 g_io_channel_error_from_errno (errno),
946 return G_IO_STATUS_ERROR;
949 return G_IO_STATUS_NORMAL;
953 g_io_win32_fd_close (GIOChannel *channel,
956 GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
958 if (win32_channel->debug)
959 g_print ("thread %#x: closing fd %d\n",
960 win32_channel->thread_id,
962 LOCK (win32_channel->mutex);
963 if (win32_channel->running)
965 if (win32_channel->debug)
966 g_print ("thread %#x: running, marking fd %d for later close\n",
967 win32_channel->thread_id, win32_channel->fd);
968 win32_channel->running = FALSE;
969 win32_channel->needs_close = TRUE;
970 SetEvent (win32_channel->data_avail_event);
974 if (win32_channel->debug)
975 g_print ("closing fd %d\n", win32_channel->fd);
976 close (win32_channel->fd);
977 if (win32_channel->debug)
978 g_print ("closed fd %d, setting to -1\n",
980 win32_channel->fd = -1;
982 UNLOCK (win32_channel->mutex);
984 /* FIXME error detection? */
986 return G_IO_STATUS_NORMAL;
990 g_io_win32_fd_create_watch (GIOChannel *channel,
991 GIOCondition condition)
993 return g_io_win32_create_watch (channel, condition, read_thread);
997 g_io_win32_sock_read (GIOChannel *channel,
1003 GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
1005 GIOChannelError error;
1007 if (win32_channel->debug)
1008 g_print ("g_io_win32_sock_read: sockfd:%d count:%d\n",
1009 win32_channel->fd, count);
1010 #ifdef WE_NEED_TO_HANDLE_WSAEINTR
1013 result = recv (win32_channel->fd, buf, count, 0);
1015 if (win32_channel->debug)
1016 g_print ("g_io_win32_sock_read: recv:%d\n", result);
1018 if (result == SOCKET_ERROR)
1022 switch (WSAGetLastError ())
1025 error = G_IO_CHANNEL_ERROR_INVAL;
1027 case WSAEWOULDBLOCK:
1028 return G_IO_STATUS_AGAIN;
1029 #ifdef WE_NEED_TO_HANDLE_WSAEINTR /* not anymore with wsock2 ? */
1034 error = G_IO_CHANNEL_ERROR_FAILED;
1037 g_set_error(err, G_IO_CHANNEL_ERROR, error, _("Socket error"));
1038 return G_IO_STATUS_ERROR;
1039 /* FIXME get all errors, better error messages */
1043 *bytes_read = result;
1045 return (result > 0) ? G_IO_STATUS_NORMAL : G_IO_STATUS_EOF;
1050 g_io_win32_sock_write (GIOChannel *channel,
1053 gsize *bytes_written,
1056 GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
1058 GIOChannelError error;
1060 if (win32_channel->debug)
1061 g_print ("g_io_win32_sock_write: sockfd:%d count:%d\n",
1062 win32_channel->fd, count);
1063 #ifdef WE_NEED_TO_HANDLE_WSAEINTR
1066 result = send (win32_channel->fd, buf, count, 0);
1068 if (win32_channel->debug)
1069 g_print ("g_io_win32_sock_write: send:%d\n", result);
1071 if (result == SOCKET_ERROR)
1075 switch (WSAGetLastError ())
1078 error = G_IO_CHANNEL_ERROR_INVAL;
1080 case WSAEWOULDBLOCK:
1081 return G_IO_STATUS_AGAIN;
1082 #ifdef WE_NEED_TO_HANDLE_WSAEINTR /* not anymore with wsock2 ? */
1087 error = G_IO_CHANNEL_ERROR_FAILED;
1090 g_set_error(err, G_IO_CHANNEL_ERROR, error, _("Socket error"));
1091 return G_IO_STATUS_ERROR;
1092 /* FIXME get all errors, better error messages */
1096 *bytes_written = result;
1098 return G_IO_STATUS_NORMAL;
1103 g_io_win32_sock_close (GIOChannel *channel,
1106 GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
1108 LOCK(win32_channel->mutex);
1109 if (win32_channel->running)
1111 if (win32_channel->debug)
1112 g_print ("thread %#x: running, marking for later close\n",
1113 win32_channel->thread_id);
1114 win32_channel->running = FALSE;
1115 win32_channel->needs_close = TRUE;
1116 SetEvent(win32_channel->data_avail_noticed_event);
1118 if (win32_channel->fd != -1)
1120 if (win32_channel->debug)
1121 g_print ("thread %#x: closing socket %d\n",
1122 win32_channel->thread_id,
1125 closesocket (win32_channel->fd);
1126 win32_channel->fd = -1;
1128 UNLOCK(win32_channel->mutex);
1130 /* FIXME error detection? */
1132 return G_IO_STATUS_NORMAL;
1136 g_io_win32_sock_create_watch (GIOChannel *channel,
1137 GIOCondition condition)
1139 return g_io_win32_create_watch (channel, condition, select_thread);
1143 g_io_channel_new_file (const gchar *filename,
1147 int fid, flags, pmode;
1148 GIOChannel *channel;
1150 enum { /* Cheesy hack */
1157 g_return_val_if_fail (filename != NULL, NULL);
1158 g_return_val_if_fail (mode != NULL, NULL);
1159 g_return_val_if_fail ((error == NULL) || (*error == NULL), NULL);
1173 g_warning (G_STRLOC ": Invalid GIOFileMode %s.\n", mode);
1182 if (mode[2] == '\0')
1184 mode_num |= MODE_PLUS;
1189 g_warning (G_STRLOC ": Invalid GIOFileMode %s.\n", mode);
1200 flags = O_WRONLY | O_TRUNC | O_CREAT;
1204 flags = O_WRONLY | O_APPEND | O_CREAT;
1207 case MODE_R | MODE_PLUS:
1209 pmode = _S_IREAD | _S_IWRITE;
1211 case MODE_W | MODE_PLUS:
1212 flags = O_RDWR | O_TRUNC | O_CREAT;
1213 pmode = _S_IREAD | _S_IWRITE;
1215 case MODE_A | MODE_PLUS:
1216 flags = O_RDWR | O_APPEND | O_CREAT;
1217 pmode = _S_IREAD | _S_IWRITE;
1220 g_assert_not_reached ();
1225 /* always open 'untranslated' */
1226 fid = open (filename, flags | _O_BINARY, pmode);
1228 if (g_io_win32_get_debug_flag ())
1230 g_print ("g_io_channel_win32_new_file: open(\"%s\", ", filename);
1231 g_win32_print_access_mode (flags|_O_BINARY);
1232 g_print (",%#o)=%d\n", pmode, fid);
1237 g_set_error (error, G_FILE_ERROR,
1238 g_file_error_from_errno (errno),
1239 g_strerror (errno));
1240 return (GIOChannel *)NULL;
1243 channel = g_io_channel_win32_new_fd (fid);
1245 /* XXX: move this to g_io_channel_win32_new_fd () */
1246 channel->close_on_unref = TRUE;
1247 channel->is_seekable = TRUE;
1252 channel->is_readable = TRUE;
1253 channel->is_writeable = FALSE;
1257 channel->is_readable = FALSE;
1258 channel->is_writeable = TRUE;
1260 case MODE_R | MODE_PLUS:
1261 case MODE_W | MODE_PLUS:
1262 case MODE_A | MODE_PLUS:
1263 channel->is_readable = TRUE;
1264 channel->is_writeable = TRUE;
1267 g_assert_not_reached ();
1274 g_io_win32_set_flags (GIOChannel *channel,
1278 GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
1280 if (win32_channel->debug)
1282 g_print ("g_io_win32_set_flags: ");
1283 g_win32_print_gioflags (flags);
1289 g_file_error_from_errno (EACCES),
1290 _("Channel set flags unsupported"));
1291 return G_IO_STATUS_ERROR;
1295 g_io_win32_fd_get_flags (GIOChannel *channel)
1299 GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
1301 g_return_val_if_fail (win32_channel != NULL, 0);
1302 g_return_val_if_fail (win32_channel->type == G_IO_WIN32_FILE_DESC, 0);
1304 if (0 == _fstat (win32_channel->fd, &st))
1306 /* XXX: G_IO_FLAG_APPEND */
1307 /* XXX: G_IO_FLAG_NONBLOCK */
1308 if (st.st_mode & _S_IREAD) flags |= G_IO_FLAG_IS_READABLE;
1309 if (st.st_mode & _S_IWRITE) flags |= G_IO_FLAG_IS_WRITEABLE;
1311 if (!(st.st_mode & _S_IFIFO)) flags |= G_IO_FLAG_IS_SEEKABLE;
1318 * Generic implementation, just translating createion flags
1321 g_io_win32_get_flags (GIOChannel *channel)
1325 flags = (channel->is_readable ? G_IO_FLAG_IS_READABLE : 0)
1326 | (channel->is_writeable ? G_IO_FLAG_IS_READABLE : 0)
1327 | (channel->is_seekable ? G_IO_FLAG_IS_SEEKABLE : 0);
1332 static GIOFuncs win32_channel_msg_funcs = {
1333 g_io_win32_msg_read,
1334 g_io_win32_msg_write,
1336 g_io_win32_msg_close,
1337 g_io_win32_msg_create_watch,
1339 g_io_win32_set_flags,
1340 g_io_win32_get_flags,
1343 static GIOFuncs win32_channel_fd_funcs = {
1345 g_io_win32_fd_write,
1347 g_io_win32_fd_close,
1348 g_io_win32_fd_create_watch,
1350 g_io_win32_set_flags,
1351 g_io_win32_fd_get_flags,
1354 static GIOFuncs win32_channel_sock_funcs = {
1355 g_io_win32_sock_read,
1356 g_io_win32_sock_write,
1358 g_io_win32_sock_close,
1359 g_io_win32_sock_create_watch,
1361 g_io_win32_set_flags,
1362 g_io_win32_get_flags,
1366 g_io_channel_win32_new_messages (guint hwnd)
1368 GIOWin32Channel *win32_channel = g_new (GIOWin32Channel, 1);
1369 GIOChannel *channel = (GIOChannel *)win32_channel;
1371 g_io_channel_init (channel);
1372 g_io_channel_win32_init (win32_channel);
1373 if (win32_channel->debug)
1374 g_print ("g_io_channel_win32_new_messages: hwnd = %ud\n", hwnd);
1375 channel->funcs = &win32_channel_msg_funcs;
1376 win32_channel->type = G_IO_WIN32_WINDOWS_MESSAGES;
1377 win32_channel->hwnd = (HWND) hwnd;
1379 /* XXX: check this. */
1380 channel->is_readable = IsWindow (win32_channel->hwnd);
1381 channel->is_writeable = IsWindow (win32_channel->hwnd);
1383 channel->is_seekable = FALSE;
1389 g_io_channel_win32_new_fd (gint fd)
1391 GIOWin32Channel *win32_channel;
1392 GIOChannel *channel;
1395 if (fstat (fd, &st) == -1)
1397 g_warning (G_STRLOC ": %d isn't a (emulated) file descriptor", fd);
1401 win32_channel = g_new (GIOWin32Channel, 1);
1402 channel = (GIOChannel *)win32_channel;
1404 g_io_channel_init (channel);
1405 g_io_channel_win32_init (win32_channel);
1406 if (win32_channel->debug)
1407 g_print ("g_io_channel_win32_new_fd: %u\n", fd);
1408 channel->funcs = &win32_channel_fd_funcs;
1409 win32_channel->type = G_IO_WIN32_FILE_DESC;
1410 win32_channel->fd = fd;
1413 /* fstat doesn't deliver senseful values, but
1414 * fcntl isn't available, so guess ...
1416 if (st.st_mode & _S_IFIFO)
1418 channel->is_readable = TRUE;
1419 channel->is_writeable = TRUE;
1420 channel->is_seekable = FALSE;
1424 channel->is_readable = !!(st.st_mode & _S_IREAD);
1425 channel->is_writeable = !!(st.st_mode & _S_IWRITE);
1426 /* XXX What about "device files" (COM1: and the like) */
1427 channel->is_seekable = TRUE;
1434 g_io_channel_win32_get_fd (GIOChannel *channel)
1436 GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
1438 return win32_channel->fd;
1442 g_io_channel_win32_new_socket (int socket)
1444 GIOWin32Channel *win32_channel = g_new (GIOWin32Channel, 1);
1445 GIOChannel *channel = (GIOChannel *)win32_channel;
1447 g_io_channel_init (channel);
1448 g_io_channel_win32_init (win32_channel);
1449 if (win32_channel->debug)
1450 g_print ("g_io_channel_win32_new_socket: sockfd:%d\n", socket);
1451 channel->funcs = &win32_channel_sock_funcs;
1452 win32_channel->type = G_IO_WIN32_SOCKET;
1453 win32_channel->fd = socket;
1455 /* XXX: check this */
1456 channel->is_readable = TRUE;
1457 channel->is_writeable = TRUE;
1458 channel->is_seekable = FALSE;
1464 g_io_channel_unix_new (gint fd)
1468 if (fstat (fd, &st) == 0)
1469 return g_io_channel_win32_new_fd (fd);
1471 if (getsockopt (fd, SOL_SOCKET, SO_TYPE, NULL, NULL) != SO_ERROR)
1472 return g_io_channel_win32_new_socket(fd);
1474 g_warning (G_STRLOC ": %d is neither a file descriptor or a socket", fd);
1479 g_io_channel_unix_get_fd (GIOChannel *channel)
1481 return g_io_channel_win32_get_fd (channel);
1485 g_io_channel_win32_set_debug (GIOChannel *channel,
1488 GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
1490 win32_channel->debug = flag;
1494 g_io_channel_win32_poll (GPollFD *fds,
1500 g_return_val_if_fail (n_fds >= 0, 0);
1502 result = (*g_main_context_get_poll_func (NULL)) (fds, n_fds, timeout);
1508 g_io_channel_win32_make_pollfd (GIOChannel *channel,
1509 GIOCondition condition,
1512 GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
1514 if (win32_channel->data_avail_event == NULL)
1515 create_events (win32_channel);
1517 fd->fd = (gint) win32_channel->data_avail_event;
1518 fd->events = condition;
1520 if (win32_channel->thread_id == 0)
1522 if ((condition & G_IO_IN) && win32_channel->type == G_IO_WIN32_FILE_DESC)
1523 create_thread (win32_channel, condition, read_thread);
1524 else if (win32_channel->type == G_IO_WIN32_SOCKET)
1525 create_thread (win32_channel, condition, select_thread);
1529 /* Binary compatibility */
1531 g_io_channel_win32_new_stream_socket (int socket)
1533 return g_io_channel_win32_new_socket (socket);