Mercurial > kinput2.yaz
comparison lib/imlib/imdispatch.c @ 0:92745d501b9a
initial import from kinput2-v3.1
author | Yoshiki Yazawa <yaz@honeyplanet.jp> |
---|---|
date | Mon, 08 Mar 2010 04:44:30 +0900 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:92745d501b9a |
---|---|
1 #ifndef lint | |
2 static char *rcsid = "$Id: imdispatch.c,v 1.9 1994/06/02 10:36:07 ishisone Exp $"; | |
3 #endif | |
4 /* | |
5 * Copyright (c) 1994 Software Research Associates, Inc. | |
6 * | |
7 * Permission to use, copy, modify, and distribute this software and its | |
8 * documentation for any purpose and without fee is hereby granted, provided | |
9 * that the above copyright notice appear in all copies and that both that | |
10 * copyright notice and this permission notice appear in supporting | |
11 * documentation, and that the name of Software Research Associates not be | |
12 * used in advertising or publicity pertaining to distribution of the | |
13 * software without specific, written prior permission. Software Research | |
14 * Associates makes no representations about the suitability of this software | |
15 * for any purpose. It is provided "as is" without express or implied | |
16 * warranty. | |
17 * | |
18 * Author: Makoto Ishisone, Software Research Associates, Inc., Japan | |
19 */ | |
20 | |
21 #include "im.h" | |
22 #include "imreq.h" | |
23 | |
24 static int checkRequest _Pt_((IMConnection *conn, | |
25 int *majorp, int *minorp, int *arglenp)); | |
26 static void ServerAuthPhase _Pt_((IMConnection *conn)); | |
27 static void CommunicationPhase _Pt_((IMConnection *conn)); | |
28 static int initialDispatcher _Pt_((IMConnection *conn)); | |
29 static int mainDispatcher _Pt_((IMConnection *conn)); | |
30 | |
31 /*- checkRequest: read and examine request header -*/ | |
32 static int | |
33 checkRequest(conn, majorp, minorp, arglenp) | |
34 IMConnection *conn; | |
35 int *majorp; | |
36 int *minorp; | |
37 int *arglenp; | |
38 { | |
39 IMBuffer *ibp = IM_INBUF(conn); | |
40 int len; | |
41 | |
42 /* check if there is enough data for the request header */ | |
43 if (IMBUFLEN(ibp) < 4) return 0; | |
44 | |
45 #ifdef XIM_BC | |
46 if (conn->has_length_bug) { | |
47 len = (int)IMGetC16(conn, 2); | |
48 } else { | |
49 len = (int)IMGetC16(conn, 2) * 4; | |
50 } | |
51 #else /* XIM_BC */ | |
52 len = (int)IMGetC16(conn, 2) * 4; | |
53 #endif /* XIM_BC */ | |
54 | |
55 TRACE(("checkRequest(): length=%d, buflen=%d\n", len, IMBUFLEN(ibp))); | |
56 | |
57 if (IMBUFLEN(ibp) >= len + 4) { | |
58 /* | |
59 * All the request data is in the buffer. | |
60 * Retrieve the request header, and discard it. | |
61 */ | |
62 *majorp = IMGetC8(conn, 0); | |
63 *minorp = IMGetC8(conn, 1); | |
64 *arglenp = len; | |
65 IMBufDiscard(ibp, 4); | |
66 return 1; | |
67 } else { | |
68 return 0; | |
69 } | |
70 } | |
71 | |
72 #ifdef XIM_BC | |
73 /*- countConnectRequestLen: count length of XIM_CONNECT request -*/ | |
74 int | |
75 countConnectRequestLen(conn) | |
76 IMConnection *conn; | |
77 { | |
78 IMBuffer *ibp = IM_INBUF(conn); | |
79 int data_length = IMBUFLEN(ibp); | |
80 int num_proto_names; | |
81 int offset; | |
82 int i; | |
83 | |
84 /* | |
85 * Encoding of XIM_CONNECT request is: | |
86 * | |
87 * 4 request header | |
88 * 1 CARD8 byte order | |
89 * 1 unused | |
90 * 2 CARD16 major protocol version | |
91 * 2 CARD16 minor protocol version | |
92 * 2 CARD16 number of auth protocol names | |
93 * N LISTofSTRING auth protocol names | |
94 * | |
95 * where STRING is: | |
96 * 2 CARD16 length (N) | |
97 * N LISTofChar string | |
98 * p pad, p = Pad(2+N) | |
99 */ | |
100 | |
101 /* skip request header */ | |
102 data_length -= 4; | |
103 offset = 4; | |
104 | |
105 if (data_length < 8) return 0; /* incomplete data */ | |
106 | |
107 /* get the number of auth protocol names */ | |
108 num_proto_names = (int)IMGetC16(conn, offset + 6); | |
109 | |
110 /* skip fixed part */ | |
111 data_length -= 8; | |
112 offset += 8; | |
113 | |
114 /* count variable (i.e. list of string) part */ | |
115 for (i = 0; i < num_proto_names; i++) { | |
116 int str_len, pad_len; | |
117 | |
118 if (data_length < 2) return 0; /* incomplete data */ | |
119 str_len = (int)IMGetC16(conn, offset); | |
120 pad_len = (4 - ((2 + str_len) % 4)) % 4; | |
121 data_length -= 2 + str_len + pad_len; | |
122 offset += 2 + str_len + pad_len; | |
123 if (data_length < 0) return 0; /* incomplete data */ | |
124 } | |
125 | |
126 return offset - 4; /* 4 for the header */ | |
127 } | |
128 #endif /* XIM_BC */ | |
129 | |
130 /* | |
131 * Phase shifters | |
132 */ | |
133 | |
134 /*- ServerAuthPhase: move to server authentication phase -*/ | |
135 static void | |
136 ServerAuthPhase(conn) | |
137 IMConnection *conn; | |
138 { | |
139 /* not yet implemented */ | |
140 IMSendSimpleRequest(conn, XIM_AUTH_NG, 0); | |
141 IMSchedule(conn, SCHED_CLOSE); | |
142 } | |
143 | |
144 /*- CommunicationPhase: move to comunication (i.e. main) phase -*/ | |
145 static void | |
146 CommunicationPhase(conn) | |
147 IMConnection *conn; | |
148 { | |
149 IMPutHeader(conn, XIM_CONNECT_REPLY, 0, 4); | |
150 IMPutC16(conn, XIM_MAJOR_PROTOCOL_VERSION); | |
151 IMPutC16(conn, XIM_MINOR_PROTOCOL_VERSION); | |
152 IMSchedule(conn, SCHED_WRITE); | |
153 | |
154 conn->dispatcher = mainDispatcher; | |
155 } | |
156 | |
157 /* | |
158 * Request dispatchers | |
159 */ | |
160 | |
161 /*- initialDispatcher: the initial dispatcher -*/ | |
162 static int | |
163 initialDispatcher(conn) | |
164 IMConnection *conn; | |
165 { | |
166 IMBuffer *ibp = IM_INBUF(conn); | |
167 int major, minor, arglen; | |
168 int major_protocol, minor_protocol; | |
169 int num_auth; | |
170 #ifdef XIM_BC | |
171 int counted_len; | |
172 int field_len; | |
173 #endif /* XIM_BC */ | |
174 | |
175 TRACE(("imlib:initialDispatcher(#%d)\n", conn->serial)); | |
176 | |
177 /* | |
178 * The first request must be 'XIM_CONNECT'. | |
179 */ | |
180 if (conn->byte_order == ORDER_UNKNOWN) { | |
181 char *p = IMBUFDATA(ibp); | |
182 | |
183 /* | |
184 * Check the byte-order first. | |
185 * In order to do it, we need at least 5 bytes of data. | |
186 */ | |
187 if (IMBUFLEN(ibp) < 5) return 0; | |
188 | |
189 /* | |
190 * Check the byte-order byte (5th byte of the data). | |
191 */ | |
192 switch (p[4]) { | |
193 case 0x42: /* 'B' -- big endian */ | |
194 conn->byte_order = ORDER_BIG; | |
195 TRACE(("\tbyte order is big endian\n")); | |
196 break; | |
197 case 0x6c: /* 'l' -- little endian */ | |
198 conn->byte_order = ORDER_LITTLE; | |
199 TRACE(("\tbyte order is little endian\n")); | |
200 break; | |
201 default: /* invalid request */ | |
202 /* | |
203 * what can we do here? since we don't know the byte order | |
204 * of the client, we cannot send error reply. but we can | |
205 * send XIM_AUTH_NG, because this request does not have | |
206 * byte order dependency. | |
207 */ | |
208 DDPRINT(2, ("invalid byte order field (%c)\n", p[4])); | |
209 goto send_ng; | |
210 } | |
211 } | |
212 | |
213 #ifdef XIM_BC | |
214 /* | |
215 * Xlib implementation of early X11R6 has a bug in the | |
216 * length field of request header. The field should | |
217 * represent the length of request data as the number | |
218 * of 4byte units, but the buggy Xlib puts number of | |
219 * bytes instead. | |
220 */ | |
221 | |
222 /* length of data by examining contents */ | |
223 counted_len = countConnectRequestLen(conn); /* in bytes */ | |
224 if (counted_len == 0) return 0; /* incomplete */ | |
225 /* length of data by reading length field */ | |
226 field_len = IMGetC16(conn, 2); /* num of 4byte element */ | |
227 | |
228 /* | |
229 * If the request packet comforms to the specification, | |
230 * field_len * 4 == counted_len | |
231 * but in case of buggy Xlib implementation, | |
232 * field_len == counted_len | |
233 */ | |
234 if (counted_len == field_len * 4) { | |
235 conn->has_length_bug = 0; | |
236 } else if (counted_len == field_len) { | |
237 /* buggy Xlib implementation */ | |
238 DPRINT(("connection #%d has length field bug\n", conn->serial)); | |
239 conn->has_length_bug = 1; | |
240 } else { | |
241 /* totally broken */ | |
242 DPRINT(("connection #%d is broken\n", conn->serial)); | |
243 goto send_ng; | |
244 } | |
245 #endif | |
246 | |
247 /* | |
248 * See if the entire data of the request is ready. | |
249 */ | |
250 if (!checkRequest(conn, &major, &minor, &arglen)) return 0; | |
251 | |
252 /* | |
253 * Check the arguments... | |
254 */ | |
255 if (major != XIM_CONNECT || minor != 0 || arglen < 8) { | |
256 DPRINT(("invalid initial request (major=%d, minor=%d, arglen=%d\n", | |
257 major, minor, arglen)); | |
258 goto send_ng; | |
259 } | |
260 | |
261 major_protocol = (int)IMGetC16(conn, 2); | |
262 minor_protocol = (int)IMGetC16(conn, 4); | |
263 TRACE(("\tprototol version: major=%d, minor=%d\n", | |
264 major_protocol, minor_protocol)); | |
265 conn->major_protocol_version = major_protocol; | |
266 conn->minor_protocol_version = minor_protocol; | |
267 | |
268 num_auth = (int)IMGetC16(conn, 6); | |
269 TRACE(("\tnumber of auth protocols: %d\n", num_auth)); | |
270 | |
271 if (major_protocol > XIM_MAJOR_PROTOCOL_VERSION || | |
272 (major_protocol == XIM_MAJOR_PROTOCOL_VERSION && | |
273 minor_protocol > XIM_MINOR_PROTOCOL_VERSION)) { | |
274 DPRINT(("unsupported protocol (%d,%d)\n", | |
275 major_protocol, minor_protocol)); | |
276 goto send_ng; | |
277 } | |
278 | |
279 if (num_auth > 0) { | |
280 ServerAuthPhase(conn); | |
281 #ifdef notdef | |
282 } else if (do_client_authentication) { | |
283 ClientAuthPhase(conn); | |
284 #endif | |
285 } else { | |
286 CommunicationPhase(conn); | |
287 } | |
288 | |
289 IMBufDiscard(ibp, arglen); | |
290 | |
291 return 1; | |
292 | |
293 send_ng: | |
294 DDPRINT(2, ("send XIM_AUTH_NG to #%d\n", conn->serial)); | |
295 IMSendSimpleRequest(conn, XIM_AUTH_NG, 0); | |
296 IMSchedule(conn, SCHED_SHUTDOWN); | |
297 return 0; | |
298 } | |
299 | |
300 /*- mainDispatcher: main dispatcher -*/ | |
301 static int | |
302 mainDispatcher(conn) | |
303 IMConnection *conn; | |
304 { | |
305 IMBuffer *ibp = IM_INBUF(conn); | |
306 int major, minor, arglen; | |
307 IMRequest *req; | |
308 | |
309 TRACE(("imlib:mainDispatcher(#%d)\n", conn->serial)); | |
310 | |
311 /* | |
312 * When X transport is used, NUL bytes might appear between | |
313 * requests. So discard them first. | |
314 */ | |
315 IMBufDiscardNUL(ibp); | |
316 | |
317 /* | |
318 * Check if the entire request data is on the input buffer. | |
319 */ | |
320 if (!checkRequest(conn, &major, &minor, &arglen)) return 0; | |
321 | |
322 /* | |
323 * Check major opcode. | |
324 */ | |
325 req = IMMainDispatchTable[major]; | |
326 if (req == NULL) { | |
327 DDPRINT(2, ("bad major opcode(%d)\n", major)); | |
328 IMSendBadProtocol(conn, "Invalid major opcode"); | |
329 goto ret; | |
330 } | |
331 | |
332 /* | |
333 * Then, check minor opcode. | |
334 */ | |
335 while (req != NULL) { | |
336 if (req->minor == minor) break; | |
337 req = req->next; | |
338 } | |
339 if (req == NULL) { | |
340 DDPRINT(2, ("bad minor opcode(%d,%d)\n", major, minor)); | |
341 IMSendBadProtocol(conn, "Invalid minor opcode"); | |
342 goto ret; | |
343 } | |
344 | |
345 /* | |
346 * Opcode is valid. Call the request processing routine. | |
347 */ | |
348 DDPRINT(2, ("** processing %s request...\n", req->name)); | |
349 (*req->proc)(conn, major, minor, arglen); | |
350 | |
351 ret: | |
352 /* | |
353 * Discard the argument portion. | |
354 */ | |
355 IMBufDiscard(ibp, arglen); | |
356 | |
357 return 1; | |
358 } | |
359 | |
360 /* | |
361 * Public functions | |
362 */ | |
363 | |
364 void | |
365 IMSetInitialDispatcher(conn) | |
366 IMConnection *conn; | |
367 { | |
368 TRACE(("IMSetInitialDispatcher(#%d)\n", conn->serial)); | |
369 conn->dispatcher = initialDispatcher; | |
370 } | |
371 | |
372 void | |
373 IMDispatch(conn, cond) | |
374 IMConnection *conn; | |
375 int cond; | |
376 { | |
377 TRACE(("IMDispatch(#%d)\n", conn->serial)); | |
378 | |
379 switch (cond) { | |
380 case TRANSPORT_OK: | |
381 /* | |
382 * Call dispatcher while data is ready. | |
383 */ | |
384 while ((*conn->dispatcher)(conn)) | |
385 /* empty body */; | |
386 | |
387 /* | |
388 * Do compaction to the input buffer. | |
389 */ | |
390 IMBufCompact(IM_INBUF(conn)); | |
391 break; | |
392 | |
393 case TRANSPORT_ERROR: | |
394 DDPRINT(2, ("transport error\n")); | |
395 IMSchedule(conn, SCHED_SHUTDOWN); | |
396 break; | |
397 | |
398 case TRANSPORT_EOF: | |
399 DDPRINT(2, ("transport EOF\n")); | |
400 IMSchedule(conn, SCHED_CLOSE); | |
401 break; | |
402 } | |
403 | |
404 /* | |
405 * If there's something to be done (i.e. scheduled), | |
406 * do it. | |
407 */ | |
408 if (!IMQueueEmpty(conn->proto_widget)) { | |
409 IMProcessQueue(conn->proto_widget); | |
410 } | |
411 } | |
412 | |
413 void | |
414 IMSchedule(conn, type) | |
415 IMConnection *conn; | |
416 int type; | |
417 { | |
418 TRACE(("IMSchedule(#%d, %d)\n", conn->serial, type)); | |
419 | |
420 if (conn->schedule & type) return; /* already scheduled */ | |
421 | |
422 if (conn->schedule == 0) { | |
423 TRACE(("insert into the queue\n")); | |
424 IMPushQueue(conn); | |
425 } | |
426 conn->schedule |= type; | |
427 } | |
428 | |
429 void | |
430 IMProcessQueue(w) | |
431 Widget w; | |
432 { | |
433 IMConnection *conn; | |
434 IMConnection *tmp = NULL; | |
435 | |
436 TRACE(("IMProcessQueue()\n")); | |
437 | |
438 while ((conn = IMPopQueue(w)) != NULL) { | |
439 int schedule; | |
440 | |
441 schedule = conn->schedule; | |
442 conn->schedule = 0; | |
443 | |
444 if (schedule & SCHED_SHUTDOWN) { | |
445 /* | |
446 * This connection is dead. Don't need to | |
447 * flush output before closing. | |
448 */ | |
449 IMCloseConnection(conn); | |
450 } else { | |
451 if (schedule & SCHED_WRITE) { | |
452 /* | |
453 * Flush output buffer. | |
454 */ | |
455 int ret; | |
456 | |
457 ret = IMFlush(conn); | |
458 switch (ret) { | |
459 case TRANSPORT_ERROR: | |
460 IMCloseConnection(conn); | |
461 continue; | |
462 case TRANSPORT_PARTIAL: | |
463 /* to be queued again */ | |
464 conn->schedule = schedule; | |
465 conn->queue_next = tmp; | |
466 tmp = conn; | |
467 continue; | |
468 } | |
469 } | |
470 if (schedule & SCHED_CLOSE) { | |
471 IMCloseConnection(conn); | |
472 } | |
473 } | |
474 } | |
475 | |
476 /* reschedule */ | |
477 while (tmp != NULL) { | |
478 IMConnection *next = tmp->queue_next; | |
479 | |
480 TRACE(("reschedule #%d\n", tmp->serial)); | |
481 IMPushQueue(tmp); | |
482 tmp = next; | |
483 } | |
484 } |