* giowin32.c: IO Channels for Win32.
* Copyright 1998 Owen Taylor and Tor Lillqvist
* Copyright 1999-2000 Tor Lillqvist and Craig Setera
- * Copyright 2001 Andrew Lanoix
+ * Copyright 2001-2003 Andrew Lanoix
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
/* Define this to get (very) verbose logging of all channels */
/* #define G_IO_WIN32_DEBUG */
+#include "config.h"
+
#include "glib.h"
#include <stdlib.h>
*/
guint thread_id; /* If non-NULL has a reader thread, or has
* had.*/
- HANDLE thread_handle;
HANDLE data_avail_event;
gushort revents;
/* Following fields used by socket channels */
GSList *watches;
HANDLE data_avail_noticed_event;
+ gint reset_send; /* socket used to send data so select_thread() can reset/re-loop */
+ gint reset_recv; /* socket used to recv data so select_thread() can reset/re-loop */
};
#define LOCK(mutex) EnterCriticalSection (&mutex)
GPollFD pollfd;
GIOChannel *channel;
GIOCondition condition;
- GIOFunc callback;
};
static void
g_io_channel_ref ((GIOChannel *)channel);
if (channel->debug)
- g_print ("read_thread %#x: start fd:%d, data_avail:%#x, space_avail:%#x\n",
+ g_print ("read_thread %#x: start fd:%d, data_avail:%#x space_avail:%#x\n",
channel->thread_id,
channel->fd,
(guint) channel->data_avail_event,
SetEvent (channel->space_avail_event);
+ LOCK (channel->mutex);
while (channel->running)
{
- LOCK (channel->mutex);
if (channel->debug)
g_print ("read_thread %#x: rdp=%d, wrp=%d\n",
channel->thread_id, channel->rdp, channel->wrp);
g_print ("read_thread %#x: rdp=%d, wrp=%d, setting data_avail\n",
channel->thread_id, channel->rdp, channel->wrp);
SetEvent (channel->data_avail_event);
- UNLOCK (channel->mutex);
}
channel->running = FALSE;
SetEvent (channel->data_avail_event);
UNLOCK (channel->mutex);
- g_io_channel_unref((GIOChannel *)channel);
+ g_io_channel_unref ((GIOChannel *)channel);
/* No need to call _endthreadex(), the actual thread starter routine
* in MSVCRT (see crt/src/threadex.c:_threadstartex) calls
* _endthreadex() for us.
*/
- CloseHandle (channel->thread_handle);
-
return 0;
}
GIOCondition condition,
unsigned (__stdcall *thread) (void *parameter))
{
- channel->thread_handle =
- (HANDLE) _beginthreadex (NULL, 0, thread, channel, 0,
- &channel->thread_id);
- if (channel->thread_handle == 0)
+ HANDLE thread_handle;
+
+ thread_handle = (HANDLE) _beginthreadex (NULL, 0, thread, channel, 0,
+ &channel->thread_id);
+ if (thread_handle == 0)
g_warning (G_STRLOC ": Error creating reader thread: %s",
- strerror (errno));
+ g_strerror (errno));
+ else if (!CloseHandle (thread_handle))
+ g_warning (G_STRLOC ": Error closing thread handle: %s\n",
+ g_win32_error_message (GetLastError ()));
+
WaitForSingleObject (channel->space_avail_event, INFINITE);
}
+static void
+init_reset_sockets (GIOWin32Channel *channel)
+{
+ struct sockaddr_in local, local2, server;
+ int len;
+
+ channel->reset_send = (gint) socket (AF_INET, SOCK_DGRAM, 0);
+ if (channel->reset_send == INVALID_SOCKET)
+ {
+ g_warning (G_STRLOC ": Error creating reset_send socket: %s\n",
+ g_win32_error_message (WSAGetLastError ()));
+ }
+
+ local.sin_family = AF_INET;
+ local.sin_port = 0;
+ local.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
+
+ if (bind (channel->reset_send, (struct sockaddr *)&local, sizeof (local)) == SOCKET_ERROR)
+ {
+ g_warning (G_STRLOC ": Error binding to reset_send socket: %s\n",
+ g_win32_error_message (WSAGetLastError ()));
+ }
+
+ local2.sin_family = AF_INET;
+ local2.sin_port = 0;
+ local2.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
+
+ channel->reset_recv = (gint) socket (AF_INET, SOCK_DGRAM, 0);
+ if (channel->reset_recv == INVALID_SOCKET)
+ {
+ g_warning (G_STRLOC ": Error creating reset_recv socket: %s\n",
+ g_win32_error_message (WSAGetLastError ()));
+ }
+
+ if (bind (channel->reset_recv, (struct sockaddr *)&local2, sizeof (local)) == SOCKET_ERROR)
+ {
+ g_warning (G_STRLOC ": Error binding to reset_recv socket: %s\n",
+ g_win32_error_message (WSAGetLastError ()));
+ }
+
+ len = sizeof (local2);
+ if (getsockname (channel->reset_recv, (struct sockaddr *)&local2, &len) == SOCKET_ERROR)
+ {
+ g_warning (G_STRLOC ": Error getsockname with reset_recv socket: %s\n",
+ g_win32_error_message (WSAGetLastError ()));
+ }
+
+ memset (&server, 0, sizeof (server));
+ server.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
+ server.sin_family = AF_INET;
+ server.sin_port = local2.sin_port;
+
+ if (connect (channel->reset_send, (struct sockaddr *)&server, sizeof (server)) == SOCKET_ERROR)
+ {
+ g_warning (G_STRLOC ": connect to reset_recv socket: %s\n",
+ g_win32_error_message (WSAGetLastError ()));
+ }
+
+}
+
static GIOStatus
buffer_read (GIOWin32Channel *channel,
guchar *dest,
LOCK (channel->mutex);
if (channel->wrp == channel->rdp && !channel->running)
{
+ if (channel->debug)
+ g_print ("wrp==rdp, !running\n");
UNLOCK (channel->mutex);
*bytes_read = 0;
- return G_IO_STATUS_NORMAL; /* as before, normal case ? */
+ return G_IO_STATUS_EOF;
}
}
fd_set read_fds, write_fds, except_fds;
GSList *tmp;
int n;
+ char buffer[8];
g_io_channel_ref ((GIOChannel *)channel);
if (channel->debug)
- g_print ("select_thread %#x: start fd:%d,\n\tdata_avail:%#x, data_avail_noticed:%#x\n",
+ g_print ("select_thread %#x: start fd:%d data_avail:%#x data_avail_noticed:%#x\n",
channel->thread_id,
channel->fd,
(guint) channel->data_avail_event,
FD_ZERO (&read_fds);
FD_ZERO (&write_fds);
FD_ZERO (&except_fds);
+ FD_SET (channel->reset_recv, &read_fds);
+ LOCK (channel->mutex);
tmp = channel->watches;
while (tmp)
{
tmp = tmp->next;
}
+ UNLOCK (channel->mutex);
+
if (channel->debug)
g_print ("select_thread %#x: calling select() for%s%s%s\n",
channel->thread_id,
(FD_ISSET (channel->fd, &read_fds) ? " IN" : ""),
(FD_ISSET (channel->fd, &write_fds) ? " OUT" : ""),
(FD_ISSET (channel->fd, &except_fds) ? " ERR" : ""));
-
+
n = select (1, &read_fds, &write_fds, &except_fds, NULL);
+ LOCK (channel->mutex);
+ if (channel->needs_close)
+ {
+ UNLOCK (channel->mutex);
+ break;
+ }
+ UNLOCK (channel->mutex);
+
if (n == SOCKET_ERROR)
{
if (channel->debug)
break;
}
+ if (FD_ISSET (channel->reset_recv, &read_fds))
+ {
if (channel->debug)
- g_print ("select_thread %#x: got%s%s%s\n",
- channel->thread_id,
- (FD_ISSET (channel->fd, &read_fds) ? " IN" : ""),
- (FD_ISSET (channel->fd, &write_fds) ? " OUT" : ""),
- (FD_ISSET (channel->fd, &except_fds) ? " ERR" : ""));
-
- if (FD_ISSET (channel->fd, &read_fds))
- channel->revents |= G_IO_IN;
- if (FD_ISSET (channel->fd, &write_fds))
- channel->revents |= G_IO_OUT;
- if (FD_ISSET (channel->fd, &except_fds))
- channel->revents |= G_IO_ERR;
-
- if (channel->debug)
- g_print ("select_thread %#x: resetting data_avail_noticed,\n"
- "\tsetting data_avail\n",
- channel->thread_id);
- ResetEvent (channel->data_avail_noticed_event);
- SetEvent (channel->data_avail_event);
+ g_print ("select_thread %#x: re-looping\n",
+ channel->thread_id);
+ recv (channel->reset_recv, (char *)&buffer, (int) sizeof (buffer), 0);
+ continue;
+ }
- LOCK (channel->mutex);
- if (channel->needs_close)
- {
- UNLOCK (channel->mutex);
- break;
- }
- UNLOCK (channel->mutex);
+ if (channel->debug)
+ g_print ("select_thread %#x: got%s%s%s\n",
+ channel->thread_id,
+ (FD_ISSET (channel->fd, &read_fds) ? " IN" : ""),
+ (FD_ISSET (channel->fd, &write_fds) ? " OUT" : ""),
+ (FD_ISSET (channel->fd, &except_fds) ? " ERR" : ""));
+
+ if (FD_ISSET (channel->fd, &read_fds))
+ channel->revents |= G_IO_IN;
+ if (FD_ISSET (channel->fd, &write_fds))
+ channel->revents |= G_IO_OUT;
+ if (FD_ISSET (channel->fd, &except_fds))
+ channel->revents |= G_IO_ERR;
+
+ if (channel->debug)
+ g_print ("select_thread %#x: resetting data_avail_noticed, setting data_avail\n",
+ channel->thread_id);
+
+ LOCK (channel->mutex);
+ ResetEvent (channel->data_avail_noticed_event);
+ SetEvent (channel->data_avail_event);
+ if (channel->needs_close)
+ {
+ UNLOCK (channel->mutex);
+ break;
+ }
+ UNLOCK (channel->mutex);
- if (channel->debug)
- g_print ("select_thread %#x: waiting for data_avail_noticed\n",
- channel->thread_id);
+ if (channel->debug)
+ g_print ("select_thread %#x: waiting for data_avail_noticed\n",
+ channel->thread_id);
- WaitForSingleObject (channel->data_avail_noticed_event, INFINITE);
- if (channel->debug)
- g_print ("select_thread %#x: got data_avail_noticed\n",
+ WaitForSingleObject (channel->data_avail_noticed_event, INFINITE);
+ if (channel->debug)
+ g_print ("select_thread %#x: got data_avail_noticed\n",
channel->thread_id);
}
-
- channel->running = FALSE;
- LOCK (channel->mutex);
- if (channel->fd != -1)
- {
- /* DO NOT close the fd here */
- channel->fd = -1;
- }
+ LOCK (channel->mutex);
+ channel->running = FALSE;
if (channel->debug)
g_print ("select_thread %#x: got error, setting data_avail\n",
channel->thread_id);
SetEvent (channel->data_avail_event);
+ g_io_channel_unref ((GIOChannel *)channel);
UNLOCK (channel->mutex);
-
- g_io_channel_unref((GIOChannel *)channel);
-
+
/* No need to call _endthreadex(), the actual thread starter routine
* in MSVCRT (see crt/src/threadex.c:_threadstartex) calls
* _endthreadex() for us.
*/
- CloseHandle (channel->thread_handle);
-
return 0;
}
gint *timeout)
{
GIOWin32Watch *watch = (GIOWin32Watch *)source;
+ GIOCondition buffer_condition = g_io_channel_get_buffer_condition (watch->channel);
GIOWin32Channel *channel = (GIOWin32Channel *)watch->channel;
*timeout = -1;
+ if (channel->debug)
+ g_print ("g_io_win32_prepare: for thread %#x buffer_condition:%#x\n"
+ " watch->pollfd.events:%#x watch->pollfd.revents:%#x channel->revents:%#x\n",
+ channel->thread_id, buffer_condition,
+ watch->pollfd.events, watch->pollfd.revents, channel->revents);
+
if (channel->type == G_IO_WIN32_FILE_DESC)
{
LOCK (channel->mutex);
if (channel->running && channel->wrp == channel->rdp)
- channel->revents = 0;
+ {
+ if (channel->debug)
+ g_print ("g_io_win32_prepare: for thread %#x, setting channel->revents = 0\n",
+ channel->thread_id);
+ channel->revents = 0;
+ }
UNLOCK (channel->mutex);
}
else if (channel->type == G_IO_WIN32_SOCKET)
{
+ LOCK (channel->mutex);
channel->revents = 0;
-
if (channel->debug)
- g_print ("g_io_win32_prepare: thread %#x, setting data_avail_noticed\n",
+ g_print ("g_io_win32_prepare: for thread %#x, setting data_avail_noticed\n",
channel->thread_id);
SetEvent (channel->data_avail_noticed_event);
if (channel->debug)
g_print ("g_io_win32_prepare: thread %#x, there.\n",
channel->thread_id);
+ UNLOCK (channel->mutex);
}
- return FALSE;
- /* XXX: why should we want to do this ? */
- watch->condition = g_io_channel_get_buffer_condition (watch->channel);
-
- return (watch->pollfd.revents & (G_IO_IN | G_IO_OUT)) == watch->condition;
+ return ((watch->condition & buffer_condition) == watch->condition);
}
static gboolean
GIOCondition buffer_condition = g_io_channel_get_buffer_condition (watch->channel);
if (channel->debug)
- g_print ("g_io_win32_check: for thread %#x:\n"
- "\twatch->pollfd.events:%#x, watch->pollfd.revents:%#x, channel->revents:%#x\n",
- channel->thread_id,
+ g_print ("g_io_win32_check: for thread %#x buffer_condition:%#x\n"
+ " watch->pollfd.events:%#x watch->pollfd.revents:%#x channel->revents:%#x\n",
+ channel->thread_id, buffer_condition,
watch->pollfd.events, watch->pollfd.revents, channel->revents);
if (channel->type != G_IO_WIN32_WINDOWS_MESSAGES)
if (channel->type == G_IO_WIN32_SOCKET)
{
+ LOCK (channel->mutex);
if (channel->debug)
g_print ("g_io_win32_check: thread %#x, resetting data_avail\n",
channel->thread_id);
if (channel->debug)
g_print ("g_io_win32_check: thread %#x, there.\n",
channel->thread_id);
+ UNLOCK (channel->mutex);
}
- return (watch->pollfd.revents & watch->condition);
+ return ((watch->pollfd.revents | buffer_condition) & watch->condition);
}
static gboolean
{
GIOFunc func = (GIOFunc)callback;
GIOWin32Watch *watch = (GIOWin32Watch *)source;
+ GIOCondition buffer_condition = g_io_channel_get_buffer_condition (watch->channel);
if (!func)
{
}
return (*func) (watch->channel,
- watch->pollfd.revents & watch->condition,
+ (watch->pollfd.revents | buffer_condition) & watch->condition,
user_data);
}
{
GIOWin32Watch *watch = (GIOWin32Watch *)source;
GIOWin32Channel *channel = (GIOWin32Channel *)watch->channel;
+ char send_buffer[] = "f";
+ LOCK (channel->mutex);
if (channel->debug)
g_print ("g_io_win32_finalize: channel with thread %#x\n",
channel->thread_id);
channel->watches = g_slist_remove (channel->watches, watch);
SetEvent (channel->data_avail_noticed_event);
+ if (channel->type == G_IO_WIN32_SOCKET)
+ send (channel->reset_send, send_buffer, sizeof (send_buffer), 0);
+
g_io_channel_unref (watch->channel);
+ UNLOCK (channel->mutex);
}
-#if defined(G_PLATFORM_WIN32) && defined(__GNUC__)
-__declspec(dllexport)
-#endif
GSourceFuncs g_io_watch_funcs = {
g_io_win32_prepare,
g_io_win32_check,
GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
GIOWin32Watch *watch;
GSource *source;
+ char send_buffer[] = "c";
source = g_source_new (&g_io_watch_funcs, sizeof (GIOWin32Watch));
watch = (GIOWin32Watch *)source;
if (win32_channel->debug)
g_print ("g_io_win32_create_watch: fd:%d condition:%#x handle:%#x\n",
win32_channel->fd, condition, watch->pollfd.fd);
-
+
+ LOCK (win32_channel->mutex);
win32_channel->watches = g_slist_append (win32_channel->watches, watch);
if (win32_channel->thread_id == 0)
create_thread (win32_channel, condition, thread);
+ else
+ send (win32_channel->reset_send, send_buffer, sizeof (send_buffer), 0);
g_source_add_poll (source, &watch->pollfd);
-
+ UNLOCK (win32_channel->mutex);
+
return source;
}
if (count < sizeof (MSG))
{
- g_set_error(err, G_IO_CHANNEL_ERROR, G_IO_CHANNEL_ERROR_INVAL,
- _("Incorrect message size")); /* Informative enough error message? */
+ g_set_error (err, G_IO_CHANNEL_ERROR, G_IO_CHANNEL_ERROR_INVAL,
+ "Incorrect message size"); /* Informative enough error message? */
return G_IO_STATUS_ERROR;
}
if (count != sizeof (MSG))
{
- g_set_error(err, G_IO_CHANNEL_ERROR, G_IO_CHANNEL_ERROR_INVAL,
- _("Incorrect message size")); /* Informative enough error message? */
+ g_set_error (err, G_IO_CHANNEL_ERROR, G_IO_CHANNEL_ERROR_INVAL,
+ "Incorrect message size"); /* Informative enough error message? */
return G_IO_STATUS_ERROR;
}
if (!PostMessage (win32_channel->hwnd, msg.message, msg.wParam, msg.lParam))
{
gchar *emsg = g_win32_error_message (GetLastError ());
- g_set_error(err, G_IO_CHANNEL_ERROR, G_IO_CHANNEL_ERROR_FAILED, emsg);
+ g_set_error (err, G_IO_CHANNEL_ERROR, G_IO_CHANNEL_ERROR_FAILED, emsg);
g_free (emsg);
return G_IO_STATUS_ERROR;
}
}
static GIOStatus
-g_io_win32_no_seek (GIOChannel *channel,
- glong offset,
- GSeekType type,
- GError **err)
-{
- g_assert_not_reached ();
-
- return G_IO_STATUS_ERROR;
-}
-
-static GIOStatus
g_io_win32_msg_close (GIOChannel *channel,
GError **err)
{
win32_channel->thread_id,
win32_channel->fd);
+ if (win32_channel->reset_send)
+ closesocket (win32_channel->reset_send);
+ if (win32_channel->reset_recv)
+ closesocket (win32_channel->reset_recv);
if (win32_channel->data_avail_event)
CloseHandle (win32_channel->data_avail_event);
if (win32_channel->space_avail_event)
{
*bytes_read = 0;
- switch(errno)
+ switch (errno)
{
#ifdef EAGAIN
- case EAGAIN:
- return G_IO_STATUS_AGAIN;
+ case EAGAIN:
+ return G_IO_STATUS_AGAIN;
#endif
- default:
- g_set_error (err, G_IO_CHANNEL_ERROR,
- g_io_channel_error_from_errno (errno),
- strerror (errno));
- return G_IO_STATUS_ERROR;
+ default:
+ g_set_error (err, G_IO_CHANNEL_ERROR,
+ g_io_channel_error_from_errno (errno),
+ g_strerror (errno));
+ return G_IO_STATUS_ERROR;
}
}
{
*bytes_written = 0;
- switch(errno)
+ switch (errno)
{
#ifdef EAGAIN
- case EAGAIN:
- return G_IO_STATUS_AGAIN;
+ case EAGAIN:
+ return G_IO_STATUS_AGAIN;
#endif
- default:
- g_set_error (err, G_IO_CHANNEL_ERROR,
- g_io_channel_error_from_errno (errno),
- strerror (errno));
- return G_IO_STATUS_ERROR;
+ default:
+ g_set_error (err, G_IO_CHANNEL_ERROR,
+ g_io_channel_error_from_errno (errno),
+ g_strerror (errno));
+ return G_IO_STATUS_ERROR;
}
}
static GIOStatus
g_io_win32_fd_seek (GIOChannel *channel,
- glong offset,
+ gint64 offset,
GSeekType type,
GError **err)
{
GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
int whence;
+ off_t tmp_offset;
off_t result;
switch (type)
break;
default:
whence = -1; /* Keep the compiler quiet */
- g_assert_not_reached();
+ g_assert_not_reached ();
+ }
+
+ tmp_offset = offset;
+ if (tmp_offset != offset)
+ {
+ g_set_error (err, G_IO_CHANNEL_ERROR,
+ g_io_channel_error_from_errno (EINVAL),
+ g_strerror (EINVAL));
+ return G_IO_STATUS_ERROR;
}
- result = lseek (win32_channel->fd, offset, whence);
+ result = lseek (win32_channel->fd, tmp_offset, whence);
if (result < 0)
{
g_set_error (err, G_IO_CHANNEL_ERROR,
g_io_channel_error_from_errno (errno),
- strerror (errno));
+ g_strerror (errno));
return G_IO_STATUS_ERROR;
}
{
GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
gint result;
- GIOChannelError error;
+ GIOChannelError error = G_IO_STATUS_NORMAL;
+ GIOStatus internal_status = G_IO_STATUS_NORMAL;
+ char send_buffer[] = "sr";
if (win32_channel->debug)
g_print ("g_io_win32_sock_read: sockfd:%d count:%d\n",
error = G_IO_CHANNEL_ERROR_FAILED;
break;
}
- g_set_error(err, G_IO_CHANNEL_ERROR, error, _("Socket error"));
- return G_IO_STATUS_ERROR;
+ g_set_error (err, G_IO_CHANNEL_ERROR, error, "Socket read error");
+ internal_status = G_IO_STATUS_ERROR;
/* FIXME get all errors, better error messages */
}
else
{
*bytes_read = result;
+ if (result == 0)
+ internal_status = G_IO_STATUS_EOF;
+ }
- return (result > 0) ? G_IO_STATUS_NORMAL : G_IO_STATUS_EOF;
+ if ((internal_status == G_IO_STATUS_EOF) ||
+ (internal_status == G_IO_STATUS_ERROR))
+ {
+ LOCK (win32_channel->mutex);
+ SetEvent (win32_channel->data_avail_noticed_event);
+ win32_channel->needs_close = 1;
+ send (win32_channel->reset_send, send_buffer, sizeof (send_buffer), 0);
+ UNLOCK (win32_channel->mutex);
}
+ return internal_status;
}
static GIOStatus
{
GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
gint result;
- GIOChannelError error;
+ GIOChannelError error = G_IO_STATUS_NORMAL;
+ char send_buffer[] = "sw";
if (win32_channel->debug)
g_print ("g_io_win32_sock_write: sockfd:%d count:%d\n",
error = G_IO_CHANNEL_ERROR_FAILED;
break;
}
- g_set_error(err, G_IO_CHANNEL_ERROR, error, _("Socket error"));
+ g_set_error (err, G_IO_CHANNEL_ERROR, error, "Socket write error");
+ LOCK (win32_channel->mutex);
+ SetEvent (win32_channel->data_avail_noticed_event);
+ win32_channel->needs_close = 1;
+ send (win32_channel->reset_send, send_buffer, sizeof (send_buffer), 0);
+ UNLOCK (win32_channel->mutex);
return G_IO_STATUS_ERROR;
/* FIXME get all errors, better error messages */
}
{
GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
- LOCK(win32_channel->mutex);
+ LOCK (win32_channel->mutex);
if (win32_channel->running)
- {
- if (win32_channel->debug)
+ {
+ if (win32_channel->debug)
g_print ("thread %#x: running, marking for later close\n",
win32_channel->thread_id);
- win32_channel->running = FALSE;
- win32_channel->needs_close = TRUE;
- SetEvent(win32_channel->data_avail_noticed_event);
- }
+ win32_channel->running = FALSE;
+ win32_channel->needs_close = TRUE;
+ SetEvent(win32_channel->data_avail_noticed_event);
+ }
if (win32_channel->fd != -1)
- {
- if (win32_channel->debug)
- g_print ("thread %#x: closing socket %d\n",
- win32_channel->thread_id,
- win32_channel->fd);
-
- closesocket (win32_channel->fd);
- win32_channel->fd = -1;
- }
- UNLOCK(win32_channel->mutex);
+ {
+ if (win32_channel->debug)
+ g_print ("thread %#x: closing socket %d\n",
+ win32_channel->thread_id,
+ win32_channel->fd);
+
+ closesocket (win32_channel->fd);
+ win32_channel->fd = -1;
+ }
+ UNLOCK (win32_channel->mutex);
/* FIXME error detection? */
mode_num = MODE_A;
break;
default:
- g_warning (G_STRLOC ": Invalid GIOFileMode %s.\n", mode);
+ g_warning ("Invalid GIOFileMode %s.\n", mode);
return NULL;
}
}
/* Fall through */
default:
- g_warning (G_STRLOC ": Invalid GIOFileMode %s.\n", mode);
+ g_warning ("Invalid GIOFileMode %s.\n", mode);
return NULL;
}
{
g_set_error (error, G_FILE_ERROR,
g_file_error_from_errno (errno),
- strerror (errno));
+ g_strerror (errno));
return (GIOChannel *)NULL;
}
channel->close_on_unref = TRUE;
channel->is_seekable = TRUE;
+ /* g_io_channel_win32_new_fd sets is_readable and is_writeable to
+ * correspond to actual readability/writeability. Set to FALSE those
+ * that mode doesn't allow
+ */
switch (mode_num)
{
case MODE_R:
- channel->is_readable = TRUE;
channel->is_writeable = FALSE;
break;
case MODE_W:
case MODE_A:
channel->is_readable = FALSE;
- channel->is_writeable = TRUE;
break;
case MODE_R | MODE_PLUS:
case MODE_W | MODE_PLUS:
case MODE_A | MODE_PLUS:
- channel->is_readable = TRUE;
- channel->is_writeable = TRUE;
break;
default:
g_assert_not_reached ();
}
static GIOStatus
-g_io_win32_set_flags (GIOChannel *channel,
- GIOFlags flags,
- GError **err)
+g_io_win32_set_flags (GIOChannel *channel,
+ GIOFlags flags,
+ GError **err)
{
GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
g_print ("\n");
}
- g_set_error (err,
- G_IO_CHANNEL_ERROR,
- g_file_error_from_errno (EACCES),
- _("Channel set flags unsupported"));
- return G_IO_STATUS_ERROR;
+ g_warning ("g_io_win32_set_flags () not implemented.\n");
+
+ return G_IO_STATUS_NORMAL;
}
static GIOFlags
-g_io_win32_fd_get_flags (GIOChannel *channel)
+g_io_win32_fd_get_flags_internal (GIOChannel *channel,
+ struct stat *st)
{
- GIOFlags flags = 0;
- struct _stat st;
- GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
+ GIOWin32Channel *win32_channel = (GIOWin32Channel *) channel;
+ gchar c;
+ DWORD count;
- g_return_val_if_fail (win32_channel != NULL, 0);
- g_return_val_if_fail (win32_channel->type == G_IO_WIN32_FILE_DESC, 0);
+ if (st->st_mode & _S_IFIFO)
+ {
+ channel->is_readable =
+ (PeekNamedPipe ((HANDLE) _get_osfhandle (win32_channel->fd), &c, 0, &count, NULL, NULL) != 0) || GetLastError () == ERROR_BROKEN_PIPE;
+ channel->is_writeable =
+ (WriteFile ((HANDLE) _get_osfhandle (win32_channel->fd), &c, 0, &count, NULL) != 0);
+ channel->is_seekable = FALSE;
+ }
+ else if (st->st_mode & _S_IFCHR)
+ {
+ /* XXX Seems there is no way to find out the readability of file
+ * handles to device files (consoles, mostly) without doing a
+ * blocking read. So punt, use st->st_mode.
+ */
+ channel->is_readable = !!(st->st_mode & _S_IREAD);
- if (0 == _fstat (win32_channel->fd, &st))
+ channel->is_writeable =
+ (WriteFile ((HANDLE) _get_osfhandle (win32_channel->fd), &c, 0, &count, NULL) != 0);
+
+ /* XXX What about devices that actually *are* seekable? But
+ * those would probably not be handled using the C runtime
+ * anyway, but using Windows-specific code.
+ */
+ channel->is_seekable = FALSE;
+ }
+ else
{
- /* XXX: G_IO_FLAG_APPEND */
- /* XXX: G_IO_FLAG_NONBLOCK */
- if (st.st_mode & _S_IREAD) flags |= G_IO_FLAG_IS_READABLE;
- if (st.st_mode & _S_IWRITE) flags |= G_IO_FLAG_IS_WRITEABLE;
- /* XXX: */
- if (!(st.st_mode & _S_IFIFO)) flags |= G_IO_FLAG_IS_SEEKABLE;
+ channel->is_readable =
+ (ReadFile ((HANDLE) _get_osfhandle (win32_channel->fd), &c, 0, &count, NULL) != 0);
+ channel->is_writeable =
+ (WriteFile ((HANDLE) _get_osfhandle (win32_channel->fd), &c, 0, &count, NULL) != 0);
+ channel->is_seekable = TRUE;
}
- return flags;
+ /* XXX: G_IO_FLAG_APPEND */
+ /* XXX: G_IO_FLAG_NONBLOCK */
+
+ return 0;
}
-/*
- * Generic implementation, just translating createion flags
- */
static GIOFlags
-g_io_win32_get_flags (GIOChannel *channel)
+g_io_win32_fd_get_flags (GIOChannel *channel)
{
- GIOFlags flags;
+ struct stat st;
+ GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
- flags = (channel->is_readable ? G_IO_FLAG_IS_READABLE : 0)
- | (channel->is_writeable ? G_IO_FLAG_IS_READABLE : 0)
- | (channel->is_seekable ? G_IO_FLAG_IS_SEEKABLE : 0);
+ g_return_val_if_fail (win32_channel != NULL, 0);
+ g_return_val_if_fail (win32_channel->type == G_IO_WIN32_FILE_DESC, 0);
- return flags;
+ if (0 == fstat (win32_channel->fd, &st))
+ return g_io_win32_fd_get_flags_internal (channel, &st);
+ else
+ return 0;
+}
+
+static GIOFlags
+g_io_win32_msg_get_flags (GIOChannel *channel)
+{
+ return 0;
+}
+
+static GIOFlags
+g_io_win32_sock_get_flags (GIOChannel *channel)
+{
+ /* XXX Could do something here. */
+ return 0;
}
static GIOFuncs win32_channel_msg_funcs = {
g_io_win32_msg_read,
g_io_win32_msg_write,
- g_io_win32_no_seek,
+ NULL,
g_io_win32_msg_close,
g_io_win32_msg_create_watch,
g_io_win32_free,
g_io_win32_set_flags,
- g_io_win32_get_flags,
+ g_io_win32_msg_get_flags,
};
static GIOFuncs win32_channel_fd_funcs = {
static GIOFuncs win32_channel_sock_funcs = {
g_io_win32_sock_read,
g_io_win32_sock_write,
- g_io_win32_no_seek,
+ NULL,
g_io_win32_sock_close,
g_io_win32_sock_create_watch,
g_io_win32_free,
g_io_win32_set_flags,
- g_io_win32_get_flags,
+ g_io_win32_sock_get_flags,
};
GIOChannel *
return channel;
}
-GIOChannel *
-g_io_channel_win32_new_fd (gint fd)
+static GIOChannel *
+g_io_channel_win32_new_fd_internal (gint fd,
+ struct stat *st)
{
GIOWin32Channel *win32_channel;
GIOChannel *channel;
- struct stat st;
-
- if (fstat (fd, &st) == -1)
- {
- g_warning (G_STRLOC ": %d isn't a (emulated) file descriptor", fd);
- return NULL;
- }
win32_channel = g_new (GIOWin32Channel, 1);
channel = (GIOChannel *)win32_channel;
win32_channel->type = G_IO_WIN32_FILE_DESC;
win32_channel->fd = fd;
+ g_io_win32_fd_get_flags_internal (channel, st);
+
+ return channel;
+}
- /* fstat doesn't deliver senseful values, but
- * fcntl isn't available, so guess ...
- */
- if (st.st_mode & _S_IFIFO)
- {
- channel->is_readable = TRUE;
- channel->is_writeable = TRUE;
- channel->is_seekable = FALSE;
- }
- else
+GIOChannel *
+g_io_channel_win32_new_fd (gint fd)
+{
+ struct stat st;
+
+ if (fstat (fd, &st) == -1)
{
- channel->is_readable = !!(st.st_mode & _S_IREAD);
- channel->is_writeable = !!(st.st_mode & _S_IWRITE);
- /* XXX What about "device files" (COM1: and the like) */
- channel->is_seekable = TRUE;
+ g_warning (G_STRLOC ": %d isn't a C library file descriptor", fd);
+ return NULL;
}
- return channel;
+ return g_io_channel_win32_new_fd_internal (fd, &st);
}
gint
g_io_channel_init (channel);
g_io_channel_win32_init (win32_channel);
+ init_reset_sockets (win32_channel);
if (win32_channel->debug)
g_print ("g_io_channel_win32_new_socket: sockfd:%d\n", socket);
channel->funcs = &win32_channel_sock_funcs;
/* XXX: check this */
channel->is_readable = TRUE;
channel->is_writeable = TRUE;
+
channel->is_seekable = FALSE;
return channel;
GIOChannel *
g_io_channel_unix_new (gint fd)
{
+ gboolean is_fd, is_socket;
struct stat st;
+ int optval, optlen;
- if (fstat (fd, &st) == 0)
- return g_io_channel_win32_new_fd (fd);
-
- if (getsockopt (fd, SOL_SOCKET, SO_TYPE, NULL, NULL) != SO_ERROR)
+ is_fd = (fstat (fd, &st) == 0);
+
+ optlen = sizeof (optval);
+ is_socket = (getsockopt (fd, SOL_SOCKET, SO_TYPE, (char *) &optval, &optlen) != SOCKET_ERROR);
+
+ if (is_fd && is_socket)
+ g_warning (G_STRLOC ": %d is both a file descriptor and a socket, file descriptor interpretation assumed.", fd);
+
+ if (is_fd)
+ return g_io_channel_win32_new_fd_internal (fd, &st);
+
+ if (is_socket)
return g_io_channel_win32_new_socket(fd);
g_warning (G_STRLOC ": %d is neither a file descriptor or a socket", fd);
+
return NULL;
}