1 /* $Id: glibwww-callbacks.cc,v 1.1.1.1 2003/07/04 22:30:07 atterer Exp $ -*- C++ -*-
2
3 This code was taken from glibwww2
4 <http://cvs.gnome.org/lxr/source/glibwww2/>, main author: James
5 Henstdridge <james@daa.com.au>, distributable under GPL, v2 or
6 later.
7
8 Added support for compilation under Windows (mingw32).
9
10 */
11 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
12 #include <config.h>
13 #include <glibwww.hh>
14 #undef PACKAGE
15 #undef _
16 extern "C" {
17 #include <HTEvent.h>
18 #include <HTTimer.h>
19 }
20
21 #define WWW_HIGH_PRIORITY (G_PRIORITY_HIGH_IDLE + 50)
22 #define WWW_LOW_PRIORITY G_PRIORITY_LOW
23 #define WWW_SCALE_PRIORITY(p) ((WWW_HIGH_PRIORITY - WWW_LOW_PRIORITY) * p \
24 / HT_PRIORITY_MAX + WWW_LOW_PRIORITY)
25
26 #define READ_CONDITION (G_IO_IN | G_IO_HUP | G_IO_ERR)
27 #define WRITE_CONDITION (G_IO_OUT | G_IO_ERR)
28 #define EXCEPTION_CONDITION (G_IO_PRI)
29 /* Windows: Need G_IO_IN for WRITE_CONDITION, otherwise connect() hangs */
30 #ifdef G_OS_WIN32
31 # undef WRITE_CONDITION
32 # define WRITE_CONDITION (G_IO_IN | G_IO_OUT | G_IO_ERR)
33 #endif
34
35 #if HTEVENT_TYPES != 3
36 # warning "HTEVENT_TYPES != 3 not supported"
37 # warning "Compile libwww without WWW_WIN_ASYNC for Windows!"
38 #endif
39
40 typedef struct _SockEventInfo SockEventInfo;
41 struct _SockEventInfo {
42 SOCKET s;
43 HTEventType type;
44 HTEvent *event;
45 guint io_tag;
46 guint timer_tag;
47 };
48
49 typedef struct _SockInfo SockInfo;
50 struct _SockInfo {
51 SOCKET s;
52 GIOChannel *io;
53 SockEventInfo ev[HTEvent_TYPES];
54 };
55
56 static GHashTable *sockhash = NULL;
57
58
59 static SockInfo *
get_sock_info(SOCKET s,gboolean create)60 get_sock_info(SOCKET s, gboolean create)
61 {
62 SockInfo *info;
63
64 if (!sockhash)
65 sockhash = g_hash_table_new(g_direct_hash, g_direct_equal);
66
67 info = static_cast<SockInfo*>(
68 g_hash_table_lookup(sockhash, GINT_TO_POINTER(s)));
69 if (!info && create) {
70 info = g_new0(SockInfo, 1);
71 info->s = s;
72 # ifdef G_OS_WIN32
73 info->io = g_io_channel_win32_new_socket(s);
74 # else
75 info->io = g_io_channel_unix_new(s);
76 # endif
77 info->ev[0].s = info->ev[1].s = info->ev[2].s = s;
78 info->ev[0].type = HTEvent_READ;
79 info->ev[1].type = HTEvent_WRITE;
80 info->ev[2].type = HTEvent_OOB;
81 info->ev[0].io_tag = info->ev[1].io_tag = info->ev[2].io_tag = 0;
82 info->ev[0].timer_tag = info->ev[1].timer_tag = info->ev[2].timer_tag = 0;
83 g_hash_table_insert(sockhash, GINT_TO_POINTER(s), info);
84 }
85 return info;
86 }
87
88 static gboolean glibwww_timeout_func (gpointer data);
89 static gboolean glibwww_io_func(GIOChannel *source, GIOCondition condition,
90 gpointer data);
91
92 static int
glibwww_event_register(SOCKET s,HTEventType type,HTEvent * event)93 glibwww_event_register (SOCKET s, HTEventType type, HTEvent *event)
94 {
95 //fprintf(stderr, "glibwww_event_register socket=%d type=%d event=%p\n", s, int(type), event);
96 SockInfo *info;
97 gint priority = G_PRIORITY_DEFAULT;
98 GIOCondition condition;
99
100 if (s == INVSOC || HTEvent_INDEX(type) >= HTEvent_TYPES)
101 return 0;
102
103 info = get_sock_info(s, TRUE);
104 info->ev[HTEvent_INDEX(type)].event = event;
105
106 switch (HTEvent_INDEX(type)) {
107 case HTEvent_INDEX(HTEvent_READ):
108 condition = static_cast<GIOCondition>(READ_CONDITION); break;
109 case HTEvent_INDEX(HTEvent_WRITE):
110 condition = static_cast<GIOCondition>(WRITE_CONDITION); break;
111 case HTEvent_INDEX(HTEvent_OOB):
112 condition = static_cast<GIOCondition>(EXCEPTION_CONDITION); break;
113 default:
114 g_assert_not_reached ();
115 condition = static_cast<GIOCondition>(0); /* this should never occur */
116 }
117 if (event->priority != HT_PRIORITY_OFF)
118 priority = WWW_SCALE_PRIORITY(event->priority);
119
120 if (!info->ev[HTEvent_INDEX(type)].io_tag) {
121 info->ev[HTEvent_INDEX(type)].io_tag =
122 g_io_add_watch_full(info->io, priority, condition, glibwww_io_func,
123 &info->ev[HTEvent_INDEX(type)], NULL);
124 }
125
126 if (event->millis >= 0 && !info->ev[HTEvent_INDEX(type)].timer_tag) {
127 info->ev[HTEvent_INDEX(type)].timer_tag =
128 g_timeout_add_full(priority, event->millis, glibwww_timeout_func,
129 &info->ev[HTEvent_INDEX(type)], NULL);
130 }
131
132 return HT_OK;
133 }
134
135 static int
glibwww_event_unregister(SOCKET s,HTEventType type)136 glibwww_event_unregister (SOCKET s, HTEventType type)
137 {
138 SockInfo *info = get_sock_info(s, FALSE);
139 //fprintf(stderr, "glibwww_event_unregister socket=%d type=%d info=%p\n", s, int(type), info);
140
141 if (info) {
142 if (info->ev[HTEvent_INDEX(type)].io_tag)
143 g_source_remove(info->ev[HTEvent_INDEX(type)].io_tag);
144 if (info->ev[HTEvent_INDEX(type)].timer_tag)
145 g_source_remove(info->ev[HTEvent_INDEX(type)].timer_tag);
146
147 info->ev[HTEvent_INDEX(type)].event = NULL;
148 info->ev[HTEvent_INDEX(type)].io_tag = 0;
149 info->ev[HTEvent_INDEX(type)].timer_tag = 0;
150
151 # ifdef G_OS_WIN32
152 /* clean up sock hash if needed */
153 if (info->ev[0].io_tag == 0 && info->ev[1].io_tag == 0
154 && info->ev[2].io_tag == 0) {
155 /*g_message("Freeing sock:%d", s);*/
156 g_hash_table_remove(sockhash, GINT_TO_POINTER(s));
157 g_io_channel_unref(info->io);
158 g_free(info);
159 }
160 # endif
161
162 return HT_OK;
163 }
164 return HT_ERROR;
165 }
166
167 static gboolean
glibwww_timeout_func(gpointer data)168 glibwww_timeout_func (gpointer data)
169 {
170 SockEventInfo *info = (SockEventInfo *)data;
171 HTEvent *event = info->event;
172
173 if (event)
174 (* event->cbf) (info->s, event->param, HTEvent_TIMEOUT);
175 return info->timer_tag != 0; /* XXXX a hack */
176 }
177
178 static gboolean
glibwww_io_func(GIOChannel *,GIOCondition,gpointer data)179 glibwww_io_func(GIOChannel */*source*/, GIOCondition /*condition*/,
180 gpointer data)
181 {
182 SockEventInfo *info = (SockEventInfo *)data;
183 HTEvent *event = info->event;
184 //fprintf(stderr, "glibwww_io_func: event %p, event->cbf %p\n", event, event->cbf);
185
186 if (info->timer_tag) {
187 g_source_remove(info->timer_tag);
188 info->timer_tag = 0;
189 }
190 if (event && event->millis >= 0) {
191 gint priority = G_PRIORITY_DEFAULT;
192
193 if (event->priority != HT_PRIORITY_OFF)
194 priority = WWW_SCALE_PRIORITY(event->priority);
195 info->timer_tag =
196 g_timeout_add_full(priority, info->event->millis, glibwww_timeout_func,
197 info, NULL);
198 }
199
200 if (event)
201 (* event->cbf) (info->s, event->param, info->type);
202 return info->io_tag != 0; /* XXXX a hack */
203 }
204
205 static GHashTable *timers = NULL;
206
207 static gboolean
glibwww_dispatch_timer(gpointer data)208 glibwww_dispatch_timer(gpointer data)
209 {
210 HTTimer *timer = (HTTimer *)data;
211
212 HTTimer_dispatch(timer);
213 return FALSE;
214 }
215
216 static BOOL
glibwww_timer_register(HTTimer * timer)217 glibwww_timer_register(HTTimer *timer)
218 {
219 guint tag;
220
221 if (!timers)
222 timers = g_hash_table_new(g_direct_hash, g_direct_equal);
223
224 tag = g_timeout_add(HTTimer_expiresRelative(timer),
225 glibwww_dispatch_timer, timer);
226 g_hash_table_insert(timers, timer, GUINT_TO_POINTER(tag));
227 return YES;
228 }
229
230 static BOOL
glibwww_timer_unregister(HTTimer * timer)231 glibwww_timer_unregister(HTTimer *timer) {
232 guint tag;
233
234 if (!timers)
235 return NO;
236 tag = GPOINTER_TO_UINT(g_hash_table_lookup(timers, timer));
237 if (tag) {
238 g_source_remove(tag);
239 g_hash_table_remove(timers, timer);
240 return YES;
241 }
242 return NO;
243 }
244
245 void
glibwww_register_callbacks(void)246 glibwww_register_callbacks(void)
247 {
248 HTEvent_setRegisterCallback(glibwww_event_register);
249 HTEvent_setUnregisterCallback(glibwww_event_unregister);
250
251 HTTimer_registerSetTimerCallback(glibwww_timer_register);
252 HTTimer_registerDeleteTimerCallback(glibwww_timer_unregister);
253 }
254
255