source: trunk/ORBit2-2.14.0/linc2/src/linc-source.c

Last change on this file was 92, checked in by cinc, 19 years ago

Orbit2 modified for use with NOM

File size: 9.2 KB
Line 
1/*
2 * linc-source.c: This file is part of the linc library.
3 *
4 * Authors:
5 * Owen Taylor (owen@redhat.com)
6 * Michael Meeks (michael@ximian.com)
7 * Tor Lillqvist (tml@novell.com)
8 *
9 * Copyright 1998, 2001, 2005, Red Hat, Inc., Ximian, Inc., Novell, Inc.
10 */
11
12#include <sys/types.h>
13#include <sys/stat.h>
14#include <stdio.h>
15#ifdef HAVE_UNISTD_H
16# include <unistd.h>
17#endif
18#include <errno.h>
19#include <string.h>
20#include <fcntl.h>
21
22#include <glib.h>
23
24#include "linc-compat.h"
25#include "linc-private.h"
26
27#if defined (G_OS_WIN32) && defined (CONNECTION_DEBUG)
28
29static char *
30fd_mask (int mask)
31{
32 static char buf[100];
33 int checked_bits = 0;
34 char *bufp = buf;
35
36 if (mask == 0)
37 return "";
38
39#define BIT(n) checked_bits |= FD_##n; if (mask & FD_##n) bufp += sprintf (bufp, "%s" #n, (bufp>buf ? "|" : ""))
40
41 BIT (READ);
42 BIT (WRITE);
43 BIT (OOB);
44 BIT (ACCEPT);
45 BIT (CONNECT);
46 BIT (CLOSE);
47 BIT (QOS);
48 BIT (GROUP_QOS);
49 BIT (ROUTING_INTERFACE_CHANGE);
50 BIT (ADDRESS_LIST_CHANGE);
51
52#undef BIT
53
54 if ((mask & ~checked_bits) != 0)
55 bufp += sprintf (bufp, "|%#x", mask & ~checked_bits);
56
57 return buf;
58}
59
60#endif
61
62static gboolean
63link_source_prepare (GSource *source,
64 gint *timeout)
65{
66#ifdef G_OS_WIN32
67 LinkUnixWatch *watch = (LinkUnixWatch *) source;
68 int event_mask = 0;
69
70 if (watch->condition & G_IO_IN)
71 event_mask |= (FD_READ | FD_ACCEPT);
72 if (watch->condition & G_IO_OUT)
73 event_mask |= (FD_WRITE | FD_CONNECT);
74 if (watch->condition & G_IO_HUP)
75 event_mask |= FD_CLOSE;
76
77 if (watch->link_watch != NULL &&
78 watch->link_watch->last_polled_source != watch) {
79 watch->link_watch->last_polled_source = watch;
80 watch->event_mask = 0;
81 }
82
83 if (watch->event_mask != event_mask) {
84 d_printf ("prepare: WSAEventSelect(%d, %#x, {%s})\n",
85 watch->socket, watch->pollfd.fd, fd_mask (event_mask));
86 if (WSAEventSelect (watch->socket, (HANDLE) watch->pollfd.fd,
87 event_mask) == SOCKET_ERROR)
88 d_printf ("WSAEventSelect() failed: %s\n",
89 link_strerror (WSAGetLastError ()));
90 else
91 watch->event_mask = event_mask;
92 }
93#endif
94
95 *timeout = -1;
96
97 return FALSE;
98}
99
100static gboolean
101link_source_check (GSource *source)
102{
103 LinkUnixWatch *watch = (LinkUnixWatch *)source;
104
105#ifdef G_OS_WIN32
106 WSANETWORKEVENTS events;
107
108 d_printf ("check: sock=%d handle=%#x revents=%x condition=%x ",
109 watch->socket, watch->pollfd.fd,
110 watch->pollfd.revents, watch->condition);
111
112 if (WSAEnumNetworkEvents (watch->socket,
113 /* (HANDLE) watch->pollfd.fd, */ 0,
114 &events) == SOCKET_ERROR)
115 d_printf ("\nWSAEnumNetworkEvents failed: %s\n",
116 link_strerror (WSAGetLastError ()));
117 else {
118 d_printf ("events={%s}\n", fd_mask (events.lNetworkEvents));
119 if (watch->pollfd.revents != 0 &&
120 events.lNetworkEvents == 0) {
121 watch->event_mask = 0;
122 d_printf ("check: WSAEventSelect(%d, %#x, {})\n",
123 watch->socket, watch->pollfd.fd);
124 WSAEventSelect (watch->socket, (HANDLE) watch->pollfd.fd, 0);
125 d_printf ("check: ResetEvent(%#x)\n",
126 watch->pollfd.fd);
127 ResetEvent ((HANDLE) watch->pollfd.fd);
128 }
129 watch->pollfd.revents = 0;
130 if (events.lNetworkEvents & (FD_READ | FD_ACCEPT))
131 watch->pollfd.revents |= G_IO_IN;
132 if (events.lNetworkEvents & (FD_WRITE | FD_CONNECT))
133 watch->pollfd.revents |= G_IO_OUT;
134 if (events.lNetworkEvents & (FD_CLOSE))
135 watch->pollfd.revents |= G_IO_HUP;
136 }
137
138 if (!watch->write_would_have_blocked && (watch->event_mask & FD_WRITE))
139 watch->pollfd.revents |= G_IO_OUT; /* This sucks but... */
140#endif
141
142 return watch->pollfd.revents & watch->condition;
143}
144
145static gboolean
146link_source_dispatch (GSource *source,
147 GSourceFunc callback,
148 gpointer user_data)
149
150{
151 GIOFunc func;
152 LinkUnixWatch *watch = (LinkUnixWatch *) source;
153
154 if (!callback)
155 g_error ("No callback");
156
157 func = (GIOFunc) callback;
158
159 return (*func) (watch->channel,
160 watch->pollfd.revents & watch->condition,
161 user_data);
162}
163
164static void
165link_source_finalize (GSource *source)
166{
167 d_printf ("Finalize source %p\n", source);
168}
169
170static GSourceFuncs link_source_watch_funcs = {
171 link_source_prepare,
172 link_source_check,
173 link_source_dispatch,
174 link_source_finalize
175};
176
177/**
178 * link_source_set_condition:
179 * @source: a source created with #link_source_create_watch
180 * @condition: a new condition.
181 *
182 * This sets a new IO condition on an existing
183 * source very rapidly.
184 **/
185void
186link_source_set_condition (GSource *source,
187 GIOCondition condition)
188{
189 LinkUnixWatch *watch = (LinkUnixWatch *) source;
190
191 if (watch) {
192 watch->pollfd.events = condition;
193 watch->condition = condition;
194 }
195}
196
197/**
198 * link_source_create_watch:
199 * @context: context to add to (or NULL for default)
200 * @fd: file descriptor to poll on
201 * @opt_channel: channel, handed to the callback (can be NULL)
202 * @condition: IO condition eg. G_IO_IN|G_IO_PRI
203 * @func: callback when condition is met
204 * @user_data: callback closure.
205 *
206 * This adds a new source to the specified context.
207 *
208 * Return value: the source handle so you can remove it later.
209 **/
210GSource *
211link_source_create_watch (GMainContext *context,
212 int fd,
213 GIOChannel *opt_channel,
214 GIOCondition condition,
215 GIOFunc func,
216 gpointer user_data)
217{
218 GSource *source;
219 LinkUnixWatch *watch;
220
221 source = g_source_new (&link_source_watch_funcs,
222 sizeof (LinkUnixWatch));
223 watch = (LinkUnixWatch *) source;
224
225#ifdef G_OS_WIN32
226 watch->pollfd.fd = (int) WSACreateEvent ();
227 d_printf ("WSACreateEvent(): for socket %d: %#x\n", fd, watch->pollfd.fd);
228 watch->link_watch = NULL;
229 watch->socket = fd;
230 watch->event_mask = 0;
231 watch->write_would_have_blocked = FALSE;
232#else
233 watch->pollfd.fd = fd;
234#endif
235 watch->channel = opt_channel;
236 watch->condition = condition;
237 watch->callback = func;
238 watch->user_data = user_data;
239
240 link_source_set_condition (source, condition);
241
242 g_source_set_can_recurse (source, TRUE);
243 g_source_add_poll (source, &watch->pollfd);
244
245 g_source_set_callback (source, (GSourceFunc) func,
246 user_data, NULL);
247 g_source_attach (source, context);
248
249 return source;
250}
251
252static GSource *
253link_source_create_watch_for_watch (LinkWatch *watch,
254 GMainContext *context,
255 int fd,
256 GIOChannel *opt_channel,
257 GIOCondition condition,
258 GIOFunc func,
259 gpointer user_data)
260{
261 GSource *retval =
262 link_source_create_watch (context, fd, opt_channel,
263 condition, func, user_data);
264
265#ifdef G_OS_WIN32
266 ((LinkUnixWatch *) retval)->link_watch = watch;
267#endif
268
269 return retval;
270}
271
272#ifdef G_OS_WIN32
273
274void
275link_win32_watch_set_write_wouldblock (LinkWatch *w,
276 gboolean flag)
277{
278 if (w->link_source)
279 ((LinkUnixWatch *)w->link_source)->write_would_have_blocked = flag;
280 if (w->main_source)
281 ((LinkUnixWatch *)w->main_source)->write_would_have_blocked = flag;
282}
283
284#endif
285
286LinkWatch *
287link_io_add_watch_fd (int fd,
288 GIOCondition condition,
289 GIOFunc func,
290 gpointer user_data)
291{
292 LinkWatch *w;
293 GMainContext *thread_ctx;
294
295 w = g_new0 (LinkWatch, 1);
296
297 if ((thread_ctx = link_thread_io_context ())) {
298 /* Have a dedicated I/O worker thread */
299 w->link_source = link_source_create_watch_for_watch
300 (w, thread_ctx, fd, NULL, condition, func, user_data);
301
302 } else {
303 /* Have an inferior and hook into the glib context */
304
305 /* Link loop */
306 w->link_source = link_source_create_watch_for_watch
307 (w, link_main_get_context (), fd, NULL,
308 condition, func, user_data);
309
310 w->main_source = link_source_create_watch_for_watch
311 (w, NULL, fd, NULL,
312 condition, func, user_data);
313 }
314
315 return w;
316}
317
318static void
319link_watch_unlisten (LinkWatch *w)
320{
321 if (w->main_source) {
322 link_source_set_condition (w->main_source, 0);
323#ifdef G_OS_WIN32
324 d_printf ("CloseHandle(%#x)\n",
325 ((LinkUnixWatch *) w->main_source)->pollfd.fd);
326 if (!CloseHandle ((HANDLE) ((LinkUnixWatch *) w->main_source)->pollfd.fd))
327 d_printf ("CloseHandle failed: %ld\n", GetLastError ());
328#endif
329 g_source_destroy (w->main_source);
330 g_source_unref (w->main_source);
331 w->main_source = NULL;
332 }
333
334 if (w->link_source) {
335 link_source_set_condition (w->link_source, 0);
336#ifdef G_OS_WIN32
337 d_printf ("CloseHandle(%#x)\n",
338 ((LinkUnixWatch *) w->link_source)->pollfd.fd);
339 if (!CloseHandle ((HANDLE) ((LinkUnixWatch *) w->link_source)->pollfd.fd))
340 d_printf ("CloseHandle failed: %ld\n", GetLastError ());
341#endif
342 g_source_destroy (w->link_source);
343 g_source_unref (w->link_source);
344 w->link_source = NULL;
345 }
346#ifdef G_OS_WIN32
347 w->last_polled_source = NULL;
348#endif
349}
350
351void
352link_io_remove_watch (LinkWatch *w)
353{
354 if (!w)
355 return;
356
357 link_watch_unlisten (w);
358 g_free (w);
359}
360
361void
362link_watch_set_condition (LinkWatch *w,
363 GIOCondition condition)
364{
365 if (w) {
366 link_source_set_condition (
367 w->link_source, condition);
368
369 link_source_set_condition (
370 w->main_source, condition);
371 }
372}
373
374/*
375 * Migrates the source to/from the main thread.
376 */
377void
378link_watch_move_io (LinkWatch *w,
379 gboolean to_io_thread)
380{
381 LinkUnixWatch w_cpy;
382
383 if (!w)
384 return;
385
386 g_assert (to_io_thread); /* FIXME */
387
388 w_cpy = *(LinkUnixWatch *)w->link_source;
389
390 link_watch_unlisten (w);
391
392 w->link_source = link_source_create_watch_for_watch
393 (w, link_thread_io_context (),
394#ifdef G_OS_WIN32
395 w_cpy.socket,
396#else
397 w_cpy.pollfd.fd,
398#endif
399 w_cpy.channel, w_cpy.condition,
400 w_cpy.callback, w_cpy.user_data);
401}
Note: See TracBrowser for help on using the repository browser.