Mercurial > pidgin.yaz
comparison libpurple/win32/giowin32.c @ 15374:5fe8042783c1
Rename gtk/ and libgaim/ to pidgin/ and libpurple/
author | Sean Egan <seanegan@gmail.com> |
---|---|
date | Sat, 20 Jan 2007 02:32:10 +0000 |
parents | |
children | 32c366eeeb99 |
comparison
equal
deleted
inserted
replaced
15373:f79e0f4df793 | 15374:5fe8042783c1 |
---|---|
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 <glib/gstdio.h> | |
49 | |
50 typedef struct _GIOWin32Channel GIOWin32Channel; | |
51 typedef struct _GIOWin32Watch GIOWin32Watch; | |
52 | |
53 #define BUFFER_SIZE 4096 | |
54 | |
55 typedef enum { | |
56 G_IO_WIN32_WINDOWS_MESSAGES, /* Windows messages */ | |
57 G_IO_WIN32_FILE_DESC, /* Unix-like file descriptors from | |
58 * _open() or _pipe(). Read with read(). | |
59 * Have to create separate thread to read. | |
60 */ | |
61 G_IO_WIN32_SOCKET /* Sockets. A separate thread is blocked | |
62 * in select() most of the time. | |
63 */ | |
64 } GIOWin32ChannelType; | |
65 | |
66 struct _GIOWin32Channel { | |
67 GIOChannel channel; | |
68 gint fd; /* Either a Unix-like file handle as provided | |
69 * by the Microsoft C runtime, or a SOCKET | |
70 * as provided by WinSock. | |
71 */ | |
72 GIOWin32ChannelType type; | |
73 | |
74 gboolean debug; | |
75 | |
76 CRITICAL_SECTION mutex; | |
77 | |
78 /* This is used by G_IO_WIN32_WINDOWS_MESSAGES channels */ | |
79 HWND hwnd; /* handle of window, or NULL */ | |
80 | |
81 /* Following fields are used by both fd and socket channels. */ | |
82 gboolean running; /* Is reader thread running. FALSE if | |
83 * EOF has been reached. | |
84 */ | |
85 gboolean needs_close; /* If the channel has been closed while | |
86 * the reader thread was still running. | |
87 */ | |
88 guint thread_id; /* If non-NULL has a reader thread, or has | |
89 * had.*/ | |
90 HANDLE data_avail_event; | |
91 | |
92 gushort revents; | |
93 | |
94 /* Following fields used by fd channels for input */ | |
95 | |
96 /* Data is kept in a circular buffer. To be able to distinguish between | |
97 * empty and full buffer, we cannot fill it completely, but have to | |
98 * leave a one character gap. | |
99 * | |
100 * Data available is between indexes rdp and wrp-1 (modulo BUFFER_SIZE). | |
101 * | |
102 * Empty: wrp == rdp | |
103 * Full: (wrp + 1) % BUFFER_SIZE == rdp | |
104 * Partial: otherwise | |
105 */ | |
106 guchar *buffer; /* (Circular) buffer */ | |
107 gint wrp, rdp; /* Buffer indices for writing and reading */ | |
108 HANDLE space_avail_event; | |
109 | |
110 /* Following fields used by socket channels */ | |
111 GSList *watches; | |
112 HANDLE data_avail_noticed_event; | |
113 gint reset_send; /* socket used to send data so select_thread() can reset/re-loop */ | |
114 gint reset_recv; /* socket used to recv data so select_thread() can reset/re-loop */ | |
115 }; | |
116 | |
117 #define LOCK(mutex) EnterCriticalSection (&mutex) | |
118 #define UNLOCK(mutex) LeaveCriticalSection (&mutex) | |
119 | |
120 struct _GIOWin32Watch { | |
121 GSource source; | |
122 GPollFD pollfd; | |
123 GIOChannel *channel; | |
124 GIOCondition condition; | |
125 }; | |
126 | |
127 static void | |
128 g_win32_print_gioflags (GIOFlags flags) | |
129 { | |
130 char *bar = ""; | |
131 | |
132 if (flags & G_IO_FLAG_APPEND) | |
133 bar = "|", g_print ("APPEND"); | |
134 if (flags & G_IO_FLAG_NONBLOCK) | |
135 g_print ("%sNONBLOCK", bar), bar = "|"; | |
136 if (flags & G_IO_FLAG_IS_READABLE) | |
137 g_print ("%sREADABLE", bar), bar = "|"; | |
138 if (flags & G_IO_FLAG_IS_WRITEABLE) | |
139 g_print ("%sWRITEABLE", bar), bar = "|"; | |
140 if (flags & G_IO_FLAG_IS_SEEKABLE) | |
141 g_print ("%sSEEKABLE", bar), bar = "|"; | |
142 } | |
143 | |
144 static gboolean | |
145 g_io_win32_get_debug_flag (void) | |
146 { | |
147 #ifdef G_IO_WIN32_DEBUG | |
148 return TRUE; | |
149 #else | |
150 if (getenv ("G_IO_WIN32_DEBUG") != NULL) | |
151 return TRUE; | |
152 else | |
153 return FALSE; | |
154 #endif | |
155 } | |
156 | |
157 static void | |
158 g_io_channel_win32_init (GIOWin32Channel *channel) | |
159 { | |
160 channel->debug = g_io_win32_get_debug_flag (); | |
161 channel->buffer = NULL; | |
162 channel->running = FALSE; | |
163 channel->needs_close = FALSE; | |
164 channel->thread_id = 0; | |
165 channel->data_avail_event = NULL; | |
166 channel->revents = 0; | |
167 channel->space_avail_event = NULL; | |
168 channel->reset_send = INVALID_SOCKET; | |
169 channel->reset_recv = INVALID_SOCKET; | |
170 channel->data_avail_noticed_event = NULL; | |
171 channel->watches = NULL; | |
172 InitializeCriticalSection (&channel->mutex); | |
173 } | |
174 | |
175 static void | |
176 create_events (GIOWin32Channel *channel) | |
177 { | |
178 SECURITY_ATTRIBUTES sec_attrs; | |
179 | |
180 sec_attrs.nLength = sizeof (SECURITY_ATTRIBUTES); | |
181 sec_attrs.lpSecurityDescriptor = NULL; | |
182 sec_attrs.bInheritHandle = FALSE; | |
183 | |
184 /* The data available event is manual reset, the space available event | |
185 * is automatic reset. | |
186 */ | |
187 if (!(channel->data_avail_event = CreateEvent (&sec_attrs, TRUE, FALSE, NULL)) | |
188 || !(channel->space_avail_event = CreateEvent (&sec_attrs, FALSE, FALSE, NULL)) | |
189 || !(channel->data_avail_noticed_event = CreateEvent (&sec_attrs, FALSE, FALSE, NULL))) | |
190 { | |
191 gchar *emsg = g_win32_error_message (GetLastError ()); | |
192 g_error ("Error creating event: %s", emsg); | |
193 g_free (emsg); | |
194 } | |
195 } | |
196 | |
197 static void | |
198 create_thread (GIOWin32Channel *channel, | |
199 GIOCondition condition, | |
200 unsigned (__stdcall *thread) (void *parameter)) | |
201 { | |
202 HANDLE thread_handle; | |
203 | |
204 thread_handle = (HANDLE) _beginthreadex (NULL, 0, thread, channel, 0, | |
205 &channel->thread_id); | |
206 if (thread_handle == 0) | |
207 g_warning (G_STRLOC ": Error creating reader thread: %s", | |
208 g_strerror (errno)); | |
209 else if (!CloseHandle (thread_handle)) | |
210 g_warning (G_STRLOC ": Error closing thread handle: %s\n", | |
211 g_win32_error_message (GetLastError ())); | |
212 | |
213 WaitForSingleObject (channel->space_avail_event, INFINITE); | |
214 } | |
215 | |
216 static void | |
217 init_reset_sockets (GIOWin32Channel *channel) | |
218 { | |
219 struct sockaddr_in local, local2, server; | |
220 int len; | |
221 | |
222 channel->reset_send = (gint) socket (AF_INET, SOCK_DGRAM, 0); | |
223 if (channel->reset_send == INVALID_SOCKET) | |
224 { | |
225 g_warning (G_STRLOC ": Error creating reset_send socket: %s\n", | |
226 g_win32_error_message (WSAGetLastError ())); | |
227 } | |
228 | |
229 local.sin_family = AF_INET; | |
230 local.sin_port = 0; | |
231 local.sin_addr.s_addr = htonl (INADDR_LOOPBACK); | |
232 | |
233 if (bind (channel->reset_send, (struct sockaddr *)&local, sizeof (local)) == SOCKET_ERROR) | |
234 { | |
235 g_warning (G_STRLOC ": Error binding to reset_send socket: %s\n", | |
236 g_win32_error_message (WSAGetLastError ())); | |
237 } | |
238 | |
239 local2.sin_family = AF_INET; | |
240 local2.sin_port = 0; | |
241 local2.sin_addr.s_addr = htonl (INADDR_LOOPBACK); | |
242 | |
243 channel->reset_recv = (gint) socket (AF_INET, SOCK_DGRAM, 0); | |
244 if (channel->reset_recv == INVALID_SOCKET) | |
245 { | |
246 g_warning (G_STRLOC ": Error creating reset_recv socket: %s\n", | |
247 g_win32_error_message (WSAGetLastError ())); | |
248 } | |
249 | |
250 if (bind (channel->reset_recv, (struct sockaddr *)&local2, sizeof (local)) == SOCKET_ERROR) | |
251 { | |
252 g_warning (G_STRLOC ": Error binding to reset_recv socket: %s\n", | |
253 g_win32_error_message (WSAGetLastError ())); | |
254 } | |
255 | |
256 len = sizeof (local2); | |
257 if (getsockname (channel->reset_recv, (struct sockaddr *)&local2, &len) == SOCKET_ERROR) | |
258 { | |
259 g_warning (G_STRLOC ": Error getsockname with reset_recv socket: %s\n", | |
260 g_win32_error_message (WSAGetLastError ())); | |
261 } | |
262 | |
263 memset (&server, 0, sizeof (server)); | |
264 server.sin_addr.s_addr = htonl (INADDR_LOOPBACK); | |
265 server.sin_family = AF_INET; | |
266 server.sin_port = local2.sin_port; | |
267 | |
268 if (connect (channel->reset_send, (struct sockaddr *)&server, sizeof (server)) == SOCKET_ERROR) | |
269 { | |
270 g_warning (G_STRLOC ": connect to reset_recv socket: %s\n", | |
271 g_win32_error_message (WSAGetLastError ())); | |
272 } | |
273 | |
274 } | |
275 | |
276 static unsigned __stdcall | |
277 select_thread (void *parameter) | |
278 { | |
279 GIOWin32Channel *channel = parameter; | |
280 fd_set read_fds, write_fds, except_fds; | |
281 GSList *tmp; | |
282 int n; | |
283 char buffer[8]; | |
284 | |
285 g_io_channel_ref ((GIOChannel *)channel); | |
286 | |
287 if (channel->debug) | |
288 g_print ("select_thread %#x: start fd:%d data_avail:%#x data_avail_noticed:%#x\n", | |
289 channel->thread_id, | |
290 channel->fd, | |
291 (guint) channel->data_avail_event, | |
292 (guint) channel->data_avail_noticed_event); | |
293 | |
294 channel->rdp = channel->wrp = 0; | |
295 channel->running = TRUE; | |
296 | |
297 SetEvent (channel->space_avail_event); | |
298 | |
299 while (channel->running) | |
300 { | |
301 FD_ZERO (&read_fds); | |
302 FD_ZERO (&write_fds); | |
303 FD_ZERO (&except_fds); | |
304 FD_SET (channel->reset_recv, &read_fds); | |
305 | |
306 LOCK (channel->mutex); | |
307 tmp = channel->watches; | |
308 while (tmp) | |
309 { | |
310 GIOWin32Watch *watch = (GIOWin32Watch *)tmp->data; | |
311 | |
312 if (watch->condition & (G_IO_IN | G_IO_HUP)) | |
313 FD_SET (channel->fd, &read_fds); | |
314 if (watch->condition & G_IO_OUT) | |
315 FD_SET (channel->fd, &write_fds); | |
316 if (watch->condition & G_IO_ERR) | |
317 FD_SET (channel->fd, &except_fds); | |
318 | |
319 tmp = tmp->next; | |
320 } | |
321 UNLOCK (channel->mutex); | |
322 | |
323 if (channel->debug) | |
324 g_print ("select_thread %#x: calling select() for%s%s%s\n", | |
325 channel->thread_id, | |
326 (FD_ISSET (channel->fd, &read_fds) ? " IN" : ""), | |
327 (FD_ISSET (channel->fd, &write_fds) ? " OUT" : ""), | |
328 (FD_ISSET (channel->fd, &except_fds) ? " ERR" : "")); | |
329 | |
330 n = select (1, &read_fds, &write_fds, &except_fds, NULL); | |
331 | |
332 LOCK (channel->mutex); | |
333 if (channel->needs_close) | |
334 { | |
335 UNLOCK (channel->mutex); | |
336 break; | |
337 } | |
338 UNLOCK (channel->mutex); | |
339 | |
340 if (n == SOCKET_ERROR) | |
341 { | |
342 if (channel->debug) | |
343 g_print ("select_thread %#x: select returned SOCKET_ERROR\n", | |
344 channel->thread_id); | |
345 break; | |
346 } | |
347 | |
348 if (FD_ISSET (channel->reset_recv, &read_fds)) | |
349 { | |
350 if (channel->debug) | |
351 g_print ("select_thread %#x: re-looping\n", | |
352 channel->thread_id); | |
353 recv (channel->reset_recv, (char *)&buffer, (int) sizeof (buffer), 0); | |
354 continue; | |
355 } | |
356 | |
357 if (channel->debug) | |
358 g_print ("select_thread %#x: got%s%s%s\n", | |
359 channel->thread_id, | |
360 (FD_ISSET (channel->fd, &read_fds) ? " IN" : ""), | |
361 (FD_ISSET (channel->fd, &write_fds) ? " OUT" : ""), | |
362 (FD_ISSET (channel->fd, &except_fds) ? " ERR" : "")); | |
363 | |
364 if (FD_ISSET (channel->fd, &read_fds)) | |
365 channel->revents |= G_IO_IN; | |
366 if (FD_ISSET (channel->fd, &write_fds)) | |
367 channel->revents |= G_IO_OUT; | |
368 if (FD_ISSET (channel->fd, &except_fds)) | |
369 channel->revents |= G_IO_ERR; | |
370 | |
371 if (channel->debug) | |
372 g_print ("select_thread %#x: resetting data_avail_noticed, setting data_avail\n", | |
373 channel->thread_id); | |
374 | |
375 LOCK (channel->mutex); | |
376 ResetEvent (channel->data_avail_noticed_event); | |
377 SetEvent (channel->data_avail_event); | |
378 if (channel->needs_close) | |
379 { | |
380 UNLOCK (channel->mutex); | |
381 break; | |
382 } | |
383 UNLOCK (channel->mutex); | |
384 | |
385 if (channel->debug) | |
386 g_print ("select_thread %#x: waiting for data_avail_noticed\n", | |
387 channel->thread_id); | |
388 | |
389 WaitForSingleObject (channel->data_avail_noticed_event, INFINITE); | |
390 if (channel->debug) | |
391 g_print ("select_thread %#x: got data_avail_noticed\n", | |
392 channel->thread_id); | |
393 } | |
394 | |
395 LOCK (channel->mutex); | |
396 channel->running = FALSE; | |
397 if (channel->debug) | |
398 g_print ("select_thread %#x: got error, setting data_avail\n", | |
399 channel->thread_id); | |
400 SetEvent (channel->data_avail_event); | |
401 g_io_channel_unref ((GIOChannel *)channel); | |
402 UNLOCK (channel->mutex); | |
403 | |
404 /* No need to call _endthreadex(), the actual thread starter routine | |
405 * in MSVCRT (see crt/src/threadex.c:_threadstartex) calls | |
406 * _endthreadex() for us. | |
407 */ | |
408 | |
409 return 0; | |
410 } | |
411 | |
412 static gboolean | |
413 g_io_win32_prepare (GSource *source, | |
414 gint *timeout) | |
415 { | |
416 GIOWin32Watch *watch = (GIOWin32Watch *)source; | |
417 GIOCondition buffer_condition = g_io_channel_get_buffer_condition (watch->channel); | |
418 GIOWin32Channel *channel = (GIOWin32Channel *)watch->channel; | |
419 | |
420 *timeout = -1; | |
421 | |
422 if (channel->debug) | |
423 g_print ("g_io_win32_prepare: for thread %#x buffer_condition:%#x\n" | |
424 " watch->pollfd.events:%#x watch->pollfd.revents:%#x channel->revents:%#x\n", | |
425 channel->thread_id, buffer_condition, | |
426 watch->pollfd.events, watch->pollfd.revents, channel->revents); | |
427 | |
428 if (channel->type == G_IO_WIN32_FILE_DESC) | |
429 { | |
430 LOCK (channel->mutex); | |
431 if (channel->running && channel->wrp == channel->rdp) | |
432 { | |
433 if (channel->debug) | |
434 g_print ("g_io_win32_prepare: for thread %#x, setting channel->revents = 0\n", | |
435 channel->thread_id); | |
436 channel->revents = 0; | |
437 } | |
438 UNLOCK (channel->mutex); | |
439 } | |
440 else if (channel->type == G_IO_WIN32_SOCKET) | |
441 { | |
442 LOCK (channel->mutex); | |
443 channel->revents = 0; | |
444 if (channel->debug) | |
445 g_print ("g_io_win32_prepare: for thread %#x, setting data_avail_noticed\n", | |
446 channel->thread_id); | |
447 SetEvent (channel->data_avail_noticed_event); | |
448 if (channel->debug) | |
449 g_print ("g_io_win32_prepare: thread %#x, there.\n", | |
450 channel->thread_id); | |
451 UNLOCK (channel->mutex); | |
452 } | |
453 | |
454 return ((watch->condition & buffer_condition) == watch->condition); | |
455 } | |
456 | |
457 static gboolean | |
458 g_io_win32_check (GSource *source) | |
459 { | |
460 MSG msg; | |
461 GIOWin32Watch *watch = (GIOWin32Watch *)source; | |
462 GIOWin32Channel *channel = (GIOWin32Channel *)watch->channel; | |
463 GIOCondition buffer_condition = g_io_channel_get_buffer_condition (watch->channel); | |
464 | |
465 if (channel->debug) | |
466 g_print ("g_io_win32_check: for thread %#x buffer_condition:%#x\n" | |
467 " watch->pollfd.events:%#x watch->pollfd.revents:%#x channel->revents:%#x\n", | |
468 channel->thread_id, buffer_condition, | |
469 watch->pollfd.events, watch->pollfd.revents, channel->revents); | |
470 | |
471 if (channel->type != G_IO_WIN32_WINDOWS_MESSAGES) | |
472 { | |
473 watch->pollfd.revents = (watch->pollfd.events & channel->revents); | |
474 } | |
475 else | |
476 { | |
477 return (PeekMessage (&msg, channel->hwnd, 0, 0, PM_NOREMOVE)); | |
478 } | |
479 | |
480 if (channel->type == G_IO_WIN32_SOCKET) | |
481 { | |
482 LOCK (channel->mutex); | |
483 if (channel->debug) | |
484 g_print ("g_io_win32_check: thread %#x, resetting data_avail\n", | |
485 channel->thread_id); | |
486 ResetEvent (channel->data_avail_event); | |
487 if (channel->debug) | |
488 g_print ("g_io_win32_check: thread %#x, there.\n", | |
489 channel->thread_id); | |
490 UNLOCK (channel->mutex); | |
491 } | |
492 | |
493 return ((watch->pollfd.revents | buffer_condition) & watch->condition); | |
494 } | |
495 | |
496 static gboolean | |
497 g_io_win32_dispatch (GSource *source, | |
498 GSourceFunc callback, | |
499 gpointer user_data) | |
500 { | |
501 GIOFunc func = (GIOFunc)callback; | |
502 GIOWin32Watch *watch = (GIOWin32Watch *)source; | |
503 GIOCondition buffer_condition = g_io_channel_get_buffer_condition (watch->channel); | |
504 | |
505 if (!func) | |
506 { | |
507 g_warning (G_STRLOC ": GIOWin32Watch dispatched without callback\n" | |
508 "You must call g_source_connect()."); | |
509 return FALSE; | |
510 } | |
511 | |
512 return (*func) (watch->channel, | |
513 (watch->pollfd.revents | buffer_condition) & watch->condition, | |
514 user_data); | |
515 } | |
516 | |
517 static void | |
518 g_io_win32_finalize (GSource *source) | |
519 { | |
520 GIOWin32Watch *watch = (GIOWin32Watch *)source; | |
521 GIOWin32Channel *channel = (GIOWin32Channel *)watch->channel; | |
522 char send_buffer[] = "f"; | |
523 | |
524 LOCK (channel->mutex); | |
525 if (channel->debug) | |
526 g_print ("g_io_win32_finalize: channel with thread %#x\n", | |
527 channel->thread_id); | |
528 | |
529 channel->watches = g_slist_remove (channel->watches, watch); | |
530 | |
531 SetEvent (channel->data_avail_noticed_event); | |
532 if (channel->type == G_IO_WIN32_SOCKET) | |
533 { | |
534 /* Tell select_thread() to exit */ | |
535 channel->needs_close = 1; | |
536 /* Wake up select_thread() from its blocking select() */ | |
537 send (channel->reset_send, send_buffer, sizeof (send_buffer), 0); | |
538 } | |
539 | |
540 UNLOCK (channel->mutex); | |
541 g_io_channel_unref (watch->channel); | |
542 } | |
543 | |
544 GSourceFuncs g_io_watch_funcs = { | |
545 g_io_win32_prepare, | |
546 g_io_win32_check, | |
547 g_io_win32_dispatch, | |
548 g_io_win32_finalize, | |
549 NULL, NULL | |
550 }; | |
551 | |
552 static GSource * | |
553 g_io_win32_create_watch (GIOChannel *channel, | |
554 GIOCondition condition, | |
555 unsigned (__stdcall *thread) (void *parameter)) | |
556 { | |
557 GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel; | |
558 GIOWin32Watch *watch; | |
559 GSource *source; | |
560 char send_buffer[] = "c"; | |
561 | |
562 source = g_source_new (&g_io_watch_funcs, sizeof (GIOWin32Watch)); | |
563 watch = (GIOWin32Watch *)source; | |
564 | |
565 watch->channel = channel; | |
566 g_io_channel_ref (channel); | |
567 | |
568 watch->condition = condition; | |
569 | |
570 if (win32_channel->data_avail_event == NULL) | |
571 create_events (win32_channel); | |
572 | |
573 watch->pollfd.fd = (gint) win32_channel->data_avail_event; | |
574 watch->pollfd.events = condition; | |
575 | |
576 if (win32_channel->debug) | |
577 g_print ("g_io_win32_create_watch: fd:%d condition:%#x handle:%#x\n", | |
578 win32_channel->fd, condition, watch->pollfd.fd); | |
579 | |
580 LOCK (win32_channel->mutex); | |
581 win32_channel->watches = g_slist_append (win32_channel->watches, watch); | |
582 | |
583 if (win32_channel->thread_id == 0) | |
584 create_thread (win32_channel, condition, thread); | |
585 else | |
586 send (win32_channel->reset_send, send_buffer, sizeof (send_buffer), 0); | |
587 | |
588 g_source_add_poll (source, &watch->pollfd); | |
589 UNLOCK (win32_channel->mutex); | |
590 | |
591 return source; | |
592 } | |
593 | |
594 static void | |
595 g_io_win32_free (GIOChannel *channel) | |
596 { | |
597 GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel; | |
598 | |
599 if (win32_channel->debug) | |
600 g_print ("thread %#x: freeing channel, fd: %d\n", | |
601 win32_channel->thread_id, | |
602 win32_channel->fd); | |
603 | |
604 if (win32_channel->reset_send && win32_channel->reset_send != INVALID_SOCKET) | |
605 closesocket (win32_channel->reset_send); | |
606 if (win32_channel->reset_recv && win32_channel->reset_recv != INVALID_SOCKET) | |
607 closesocket (win32_channel->reset_recv); | |
608 if (win32_channel->data_avail_event) | |
609 CloseHandle (win32_channel->data_avail_event); | |
610 if (win32_channel->space_avail_event) | |
611 CloseHandle (win32_channel->space_avail_event); | |
612 if (win32_channel->data_avail_noticed_event) | |
613 CloseHandle (win32_channel->data_avail_noticed_event); | |
614 DeleteCriticalSection (&win32_channel->mutex); | |
615 | |
616 g_free (win32_channel->buffer); | |
617 g_slist_free (win32_channel->watches); | |
618 g_free (win32_channel); | |
619 } | |
620 | |
621 static GIOStatus | |
622 g_io_win32_sock_read (GIOChannel *channel, | |
623 gchar *buf, | |
624 gsize count, | |
625 gsize *bytes_read, | |
626 GError **err) | |
627 { | |
628 GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel; | |
629 gint result; | |
630 GIOChannelError error = G_IO_STATUS_NORMAL; | |
631 GIOStatus internal_status = G_IO_STATUS_NORMAL; | |
632 char send_buffer[] = "sr"; | |
633 | |
634 if (win32_channel->debug) | |
635 g_print ("g_io_win32_sock_read: sockfd:%d count:%d\n", | |
636 win32_channel->fd, count); | |
637 #ifdef WE_NEED_TO_HANDLE_WSAEINTR | |
638 repeat: | |
639 #endif | |
640 result = recv (win32_channel->fd, buf, count, 0); | |
641 | |
642 if (win32_channel->debug) | |
643 g_print ("g_io_win32_sock_read: recv:%d\n", result); | |
644 | |
645 if (result == SOCKET_ERROR) | |
646 { | |
647 *bytes_read = 0; | |
648 | |
649 switch (WSAGetLastError ()) | |
650 { | |
651 case WSAEINVAL: | |
652 error = G_IO_CHANNEL_ERROR_INVAL; | |
653 break; | |
654 case WSAEWOULDBLOCK: | |
655 return G_IO_STATUS_AGAIN; | |
656 #ifdef WE_NEED_TO_HANDLE_WSAEINTR /* not anymore with wsock2 ? */ | |
657 case WSAEINTR: | |
658 goto repeat; | |
659 #endif | |
660 default: | |
661 error = G_IO_CHANNEL_ERROR_FAILED; | |
662 break; | |
663 } | |
664 g_set_error (err, G_IO_CHANNEL_ERROR, error, "Socket read error"); | |
665 internal_status = G_IO_STATUS_ERROR; | |
666 /* FIXME get all errors, better error messages */ | |
667 } | |
668 else | |
669 { | |
670 *bytes_read = result; | |
671 if (result == 0) | |
672 internal_status = G_IO_STATUS_EOF; | |
673 } | |
674 | |
675 if ((internal_status == G_IO_STATUS_EOF) || | |
676 (internal_status == G_IO_STATUS_ERROR)) | |
677 { | |
678 LOCK (win32_channel->mutex); | |
679 SetEvent (win32_channel->data_avail_noticed_event); | |
680 win32_channel->needs_close = 1; | |
681 send (win32_channel->reset_send, send_buffer, sizeof (send_buffer), 0); | |
682 UNLOCK (win32_channel->mutex); | |
683 } | |
684 return internal_status; | |
685 } | |
686 | |
687 static GIOStatus | |
688 g_io_win32_sock_write (GIOChannel *channel, | |
689 const gchar *buf, | |
690 gsize count, | |
691 gsize *bytes_written, | |
692 GError **err) | |
693 { | |
694 GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel; | |
695 gint result; | |
696 GIOChannelError error = G_IO_STATUS_NORMAL; | |
697 char send_buffer[] = "sw"; | |
698 | |
699 if (win32_channel->debug) | |
700 g_print ("g_io_win32_sock_write: sockfd:%d count:%d\n", | |
701 win32_channel->fd, count); | |
702 #ifdef WE_NEED_TO_HANDLE_WSAEINTR | |
703 repeat: | |
704 #endif | |
705 result = send (win32_channel->fd, buf, count, 0); | |
706 | |
707 if (win32_channel->debug) | |
708 g_print ("g_io_win32_sock_write: send:%d\n", result); | |
709 | |
710 if (result == SOCKET_ERROR) | |
711 { | |
712 *bytes_written = 0; | |
713 | |
714 switch (WSAGetLastError ()) | |
715 { | |
716 case WSAEINVAL: | |
717 error = G_IO_CHANNEL_ERROR_INVAL; | |
718 break; | |
719 case WSAEWOULDBLOCK: | |
720 return G_IO_STATUS_AGAIN; | |
721 #ifdef WE_NEED_TO_HANDLE_WSAEINTR /* not anymore with wsock2 ? */ | |
722 case WSAEINTR: | |
723 goto repeat; | |
724 #endif | |
725 default: | |
726 error = G_IO_CHANNEL_ERROR_FAILED; | |
727 break; | |
728 } | |
729 g_set_error (err, G_IO_CHANNEL_ERROR, error, "Socket write error"); | |
730 LOCK (win32_channel->mutex); | |
731 SetEvent (win32_channel->data_avail_noticed_event); | |
732 win32_channel->needs_close = 1; | |
733 send (win32_channel->reset_send, send_buffer, sizeof (send_buffer), 0); | |
734 UNLOCK (win32_channel->mutex); | |
735 return G_IO_STATUS_ERROR; | |
736 /* FIXME get all errors, better error messages */ | |
737 } | |
738 else | |
739 { | |
740 *bytes_written = result; | |
741 | |
742 return G_IO_STATUS_NORMAL; | |
743 } | |
744 } | |
745 | |
746 static GIOStatus | |
747 g_io_win32_sock_close (GIOChannel *channel, | |
748 GError **err) | |
749 { | |
750 GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel; | |
751 | |
752 LOCK (win32_channel->mutex); | |
753 if (win32_channel->running) | |
754 { | |
755 if (win32_channel->debug) | |
756 g_print ("thread %#x: running, marking for later close\n", | |
757 win32_channel->thread_id); | |
758 win32_channel->running = FALSE; | |
759 win32_channel->needs_close = TRUE; | |
760 SetEvent(win32_channel->data_avail_noticed_event); | |
761 } | |
762 if (win32_channel->fd != -1) | |
763 { | |
764 if (win32_channel->debug) | |
765 g_print ("thread %#x: closing socket %d\n", | |
766 win32_channel->thread_id, | |
767 win32_channel->fd); | |
768 | |
769 closesocket (win32_channel->fd); | |
770 win32_channel->fd = -1; | |
771 } | |
772 UNLOCK (win32_channel->mutex); | |
773 | |
774 /* FIXME error detection? */ | |
775 | |
776 return G_IO_STATUS_NORMAL; | |
777 } | |
778 | |
779 static GSource * | |
780 g_io_win32_sock_create_watch (GIOChannel *channel, | |
781 GIOCondition condition) | |
782 { | |
783 return g_io_win32_create_watch (channel, condition, select_thread); | |
784 } | |
785 | |
786 static GIOStatus | |
787 g_io_win32_set_flags (GIOChannel *channel, | |
788 GIOFlags flags, | |
789 GError **err) | |
790 { | |
791 GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel; | |
792 | |
793 if (win32_channel->debug) | |
794 { | |
795 g_print ("g_io_win32_set_flags: "); | |
796 g_win32_print_gioflags (flags); | |
797 g_print ("\n"); | |
798 } | |
799 | |
800 g_warning ("g_io_win32_set_flags () not implemented.\n"); | |
801 | |
802 return G_IO_STATUS_NORMAL; | |
803 } | |
804 | |
805 static GIOFlags | |
806 g_io_win32_sock_get_flags (GIOChannel *channel) | |
807 { | |
808 /* XXX Could do something here. */ | |
809 return 0; | |
810 } | |
811 | |
812 static GIOFuncs win32_channel_sock_funcs = { | |
813 g_io_win32_sock_read, | |
814 g_io_win32_sock_write, | |
815 NULL, | |
816 g_io_win32_sock_close, | |
817 g_io_win32_sock_create_watch, | |
818 g_io_win32_free, | |
819 g_io_win32_set_flags, | |
820 g_io_win32_sock_get_flags, | |
821 }; | |
822 | |
823 GIOChannel * | |
824 wgaim_g_io_channel_win32_new_socket (int socket) | |
825 { | |
826 GIOWin32Channel *win32_channel = g_new (GIOWin32Channel, 1); | |
827 GIOChannel *channel = (GIOChannel *)win32_channel; | |
828 | |
829 g_io_channel_init (channel); | |
830 g_io_channel_win32_init (win32_channel); | |
831 init_reset_sockets (win32_channel); | |
832 if (win32_channel->debug) | |
833 g_print ("g_io_channel_win32_new_socket: sockfd:%d\n", socket); | |
834 channel->funcs = &win32_channel_sock_funcs; | |
835 win32_channel->type = G_IO_WIN32_SOCKET; | |
836 win32_channel->fd = socket; | |
837 | |
838 /* XXX: check this */ | |
839 channel->is_readable = TRUE; | |
840 channel->is_writeable = TRUE; | |
841 | |
842 channel->is_seekable = FALSE; | |
843 | |
844 return channel; | |
845 } | |
846 | |
847 #if 0 | |
848 void | |
849 g_io_channel_win32_set_debug (GIOChannel *channel, | |
850 gboolean flag) | |
851 { | |
852 GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel; | |
853 | |
854 win32_channel->debug = flag; | |
855 } | |
856 #endif | |
857 |