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 }