Git init
[framework/uifw/xorg/lib/libice.git] / src / process.c
1 /******************************************************************************
2
3
4 Copyright 1993, 1998  The Open Group
5
6 Permission to use, copy, modify, distribute, and sell this software and its
7 documentation for any purpose is hereby granted without fee, provided that
8 the above copyright notice appear in all copies and that both that
9 copyright notice and this permission notice appear in supporting
10 documentation.
11
12 The above copyright notice and this permission notice shall be included in
13 all copies or substantial portions of the Software.
14
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
18 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
19 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
22 Except as contained in this notice, the name of The Open Group shall not be
23 used in advertising or otherwise to promote the sale, use or other dealings
24 in this Software without prior written authorization from The Open Group.
25
26 Author: Ralph Mor, X Consortium
27 ******************************************************************************/
28
29 #ifdef HAVE_CONFIG_H
30 #include <config.h>
31 #endif
32 #include <X11/ICE/ICElib.h>
33 #include "ICElibint.h"
34
35 #include <stdio.h> /* sprintf */
36
37 /*
38  * Check for bad length
39  */
40
41 #define CHECK_SIZE_MATCH(_iceConn, _opcode, _expected_len, _actual_len, _severity, _return) \
42     if ((((_actual_len) - SIZEOF (iceMsg)) >> 3) != _expected_len) \
43     { \
44        _IceErrorBadLength (_iceConn, 0, _opcode, _severity); \
45        return (_return); \
46     }
47
48 #define CHECK_AT_LEAST_SIZE(_iceConn, _opcode, _expected_len, _actual_len, _severity) \
49     if ((((_actual_len) - SIZEOF (iceMsg)) >> 3) > _expected_len) \
50     { \
51        _IceErrorBadLength (_iceConn, 0, _opcode, _severity); \
52        return (0); \
53     }
54
55 #define CHECK_COMPLETE_SIZE(_iceConn, _opcode, _expected_len, _actual_len, _pStart, _severity) \
56     if (((PADDED_BYTES64((_actual_len)) - SIZEOF (iceMsg)) >> 3) \
57         != _expected_len) \
58     { \
59        _IceErrorBadLength (_iceConn, 0, _opcode, _severity); \
60        IceDisposeCompleteMessage (iceConn, _pStart); \
61        return (0); \
62     }
63
64 #define BAIL_STRING(_iceConn, _opcode, _pStart) {\
65     _IceErrorBadLength (_iceConn, 0, _opcode, IceFatalToConnection);\
66     IceDisposeCompleteMessage (_iceConn, _pStart);\
67     return (0);\
68 }
69 \f
70 /*
71  * IceProcessMessages:
72  *
73  * If replyWait == NULL, the client is not waiting for a reply.
74  *
75  * If replyWait != NULL, the client is waiting for a reply...
76  *
77  *    - replyWait->sequence_of_request is the sequence number of the
78  *      message for which the client is waiting a reply.  This is needed
79  *      to determine if an error matches a replyWait.
80  *
81  *    - replyWait->major_opcode_of_request is the major opcode of the
82  *      message for which we are waiting a reply.
83  *
84  *    - replyWait->minor_opcode_of_request is the minor opcode of the
85  *      message for which we are waiting a reply.
86  *
87  *    - replyWait->reply is a pointer to the reply message which will be
88  *      filled in when the reply is ready (the protocol library should
89  *      cast this IcePointer to the appropriate reply type).  In most cases,
90  *      the reply will have some fixed-size part, and the sender function
91  *      will have provided a pointer to a structure (e.g.) to hold this
92  *      fixed-size data.  If there is variable-length data, it would be
93  *      expected that the reply function will have to allocate additional
94  *      memory and store pointer(s) to that memory in the fixed-size
95  *      structure.  If the entire data is variable length (e.g., a single
96  *      variable-length string), then the sender function would probably
97  *      just pass a pointer to fixed-size space to hold a pointer, and the
98  *      reply function would allocate the storage and store the pointer.
99  *      It is the responsibility of the client receiving the reply to
100  *      free up any memory allocated on it's behalf.
101  *
102  * We might be waiting for several different replies (a function can wait
103  * for a reply, and while calling IceProcessMessages, a callback can be
104  * invoked which will wait for another reply).  We take advantage of the
105  * fact that for a given protocol, we are guaranteed that messages are
106  * processed in the order we sent them.  So, everytime we have a new
107  * replyWait, we add it to the END of the 'saved_reply_waits' list.  When
108  * we read a message and want to see if it matches a replyWait, we use the
109  * FIRST replyWait in the list with the major opcode of the message.  If the
110  * reply is ready, we remove that replyWait from the list.
111  *
112  * If the reply/error is ready for the replyWait passed in to
113  * IceProcessMessages, *replyReadyRet is set to True.
114  *
115  * The return value of IceProcessMessages is one of the following:
116  *
117  * IceProcessMessagesSuccess - the message was processed successfully.
118  * IceProcessMessagesIOError - an IO error occured.  The caller should
119  *                             invoked IceCloseConnection.
120  * IceProcessMessagesConnectionClosed - the connection was closed as a
121  *                                      result of shutdown negotiation.
122  */
123
124 IceProcessMessagesStatus
125 IceProcessMessages (
126         IceConn          iceConn,
127         IceReplyWaitInfo *replyWait,
128         Bool             *replyReadyRet
129 )
130 {
131     iceMsg              *header;
132     Bool                replyReady = False;
133     IceReplyWaitInfo    *useThisReplyWait = NULL;
134     IceProcessMessagesStatus retStatus = IceProcessMessagesSuccess;
135
136     if (replyWait)
137         *replyReadyRet = False;
138
139     /*
140      * Each time IceProcessMessages is entered, we increment the dispatch
141      * level.  Each time we leave it, we decrement the dispatch level.
142      */
143
144     iceConn->dispatch_level++;
145
146
147     /*
148      * Read the ICE message header.
149      */
150
151     if (!_IceRead (iceConn, (unsigned long) SIZEOF (iceMsg), iceConn->inbuf))
152     {
153         /*
154          * If we previously sent a WantToClose and now we detected
155          * that the connection was closed, _IceRead returns status 0.
156          * Since the connection was closed, we just want to return here.
157          */
158
159         return (IceProcessMessagesConnectionClosed);
160     }
161
162     if (!iceConn->io_ok)
163     {
164         /*
165          * An unexpected IO error occured.  The caller of IceProcessMessages
166          * should call IceCloseConnection which will cause the watch procedures
167          * to be invoked and the ICE connection to be freed.
168          */
169
170         iceConn->dispatch_level--;
171         iceConn->connection_status = IceConnectIOError;
172         return (IceProcessMessagesIOError);
173     }
174
175     header = (iceMsg *) iceConn->inbuf;
176     iceConn->inbufptr = iceConn->inbuf + SIZEOF (iceMsg);
177
178     iceConn->receive_sequence++;
179
180     if (iceConn->waiting_for_byteorder)
181     {
182         if (header->majorOpcode == 0 &&
183             header->minorOpcode == ICE_ByteOrder)
184         {
185             char byteOrder = ((iceByteOrderMsg *) header)->byteOrder;
186             int endian = 1;
187
188             CHECK_SIZE_MATCH (iceConn, ICE_ByteOrder,
189                 header->length, SIZEOF (iceByteOrderMsg),
190                 IceFatalToConnection, IceProcessMessagesIOError);
191
192             if (byteOrder != IceMSBfirst && byteOrder != IceLSBfirst)
193             {
194                 _IceErrorBadValue (iceConn, 0,
195                     ICE_ByteOrder, 2, 1, &byteOrder);
196
197                 iceConn->connection_status = IceConnectRejected;
198             }
199             else
200             {
201                 iceConn->swap =
202                     (((*(char *) &endian) && byteOrder == IceMSBfirst) ||
203                      (!(*(char *) &endian) && byteOrder == IceLSBfirst));
204
205                 iceConn->waiting_for_byteorder = 0;
206             }
207         }
208         else
209         {
210             if (header->majorOpcode != 0)
211             {
212                 _IceErrorBadMajor (iceConn, header->majorOpcode,
213                     header->minorOpcode, IceFatalToConnection);
214             }
215             else
216             {
217                 _IceErrorBadState (iceConn, 0,
218                     header->minorOpcode, IceFatalToConnection);
219             }
220
221             iceConn->connection_status = IceConnectRejected;
222         }
223
224         iceConn->dispatch_level--;
225         if (!iceConn->io_ok)
226         {
227             iceConn->connection_status = IceConnectIOError;
228             retStatus = IceProcessMessagesIOError;
229         }
230
231         return (retStatus);
232     }
233
234     if (iceConn->swap)
235     {
236         /* swap the length field */
237
238         header->length = lswapl (header->length);
239     }
240
241     if (replyWait)
242     {
243         /*
244          * Add to the list of replyWaits (only if it doesn't exist
245          * in the list already.
246          */
247
248         _IceAddReplyWait (iceConn, replyWait);
249
250         /*
251          * Note that there are two different replyWaits.  The first is
252          * the one passed into IceProcessMessages, and is the replyWait
253          * for the message the client is blocking on.  The second is
254          * the replyWait for the message currently being processed
255          * by IceProcessMessages.  We call it "useThisReplyWait".
256          *
257          * Also, when two hosts communicate over an ICE connection and use
258          * different major opcodes for a subprotocol, it is impossible
259          * to use message replies unless we translate opcodes before
260          * comparing them.
261          */
262         
263         {
264             int op;
265
266             if (header->majorOpcode == 0)
267             {
268                 op = 0;
269             }
270             else
271             {
272                 int idx = header->majorOpcode - iceConn->his_min_opcode;
273                 op = iceConn->process_msg_info[idx].my_opcode;
274             }
275             useThisReplyWait = _IceSearchReplyWaits (iceConn, op);
276         }
277     }
278
279     if (header->majorOpcode == 0)
280     {
281         /*
282          * ICE protocol
283          */
284
285         Bool connectionClosed;
286
287         _IceProcessCoreMsgProc processIce =
288             _IceVersions[iceConn->my_ice_version_index].process_core_msg_proc;
289
290         (*processIce) (iceConn, header->minorOpcode,
291             header->length, iceConn->swap,
292             useThisReplyWait, &replyReady, &connectionClosed);
293
294         if (connectionClosed)
295         {
296             /*
297              * As a result of shutdown negotiation, the connection was closed.
298              */
299
300             return (IceProcessMessagesConnectionClosed);
301         }
302     }
303     else
304     {
305         /*
306          * Sub protocol
307          */
308
309         if ((int) header->majorOpcode < iceConn->his_min_opcode ||
310             (int) header->majorOpcode > iceConn->his_max_opcode ||
311             !(iceConn->process_msg_info[header->majorOpcode -
312             iceConn->his_min_opcode].in_use))
313         {
314             /*
315              * The protocol of the message we just read is not supported.
316              */
317
318             _IceErrorBadMajor (iceConn, header->majorOpcode,
319                 header->minorOpcode, IceCanContinue);
320
321             _IceReadSkip (iceConn, header->length << 3);
322         }
323         else
324         {
325             _IceProcessMsgInfo *processMsgInfo = &iceConn->process_msg_info[
326                 header->majorOpcode - iceConn->his_min_opcode];
327
328             if (processMsgInfo->accept_flag)
329             {
330                 IcePaProcessMsgProc processProc =
331                     processMsgInfo->process_msg_proc.accept_client;
332
333                 (*processProc) (iceConn, processMsgInfo->client_data,
334                     header->minorOpcode, header->length, iceConn->swap);
335             }
336             else
337             {
338                 IcePoProcessMsgProc processProc =
339                     processMsgInfo->process_msg_proc.orig_client;
340
341                 (*processProc) (iceConn,
342                     processMsgInfo->client_data, header->minorOpcode,
343                     header->length, iceConn->swap,
344                     useThisReplyWait, &replyReady);
345             }
346         }
347     }
348
349     if (replyReady)
350     {
351         _IceSetReplyReady (iceConn, useThisReplyWait);
352     }
353
354
355     /*
356      * Now we check if the reply is ready for the replyWait passed
357      * into IceProcessMessages.  The replyWait is removed from the
358      * replyWait list if it is ready.
359      */
360
361     if (replyWait)
362         *replyReadyRet = _IceCheckReplyReady (iceConn, replyWait);
363
364
365     /*
366      * Decrement the dispatch level.  If we reach level 0, and the
367      * free_asap bit is set, free the connection now.  Also check for
368      * possible bad IO status.
369      */
370
371     iceConn->dispatch_level--;
372
373     if (iceConn->dispatch_level == 0 && iceConn->free_asap)
374     {
375         _IceFreeConnection (iceConn);
376         retStatus = IceProcessMessagesConnectionClosed;
377     }
378     else if (!iceConn->io_ok)
379     {
380         iceConn->connection_status = IceConnectIOError;
381         retStatus = IceProcessMessagesIOError;
382     }
383
384     return (retStatus);
385 }
386
387
388 \f
389 static void
390 AuthRequired (
391         IceConn         iceConn,
392         int             authIndex,
393         int             authDataLen,
394         IcePointer      authData
395 )
396 {
397     iceAuthRequiredMsg *pMsg;
398
399     IceGetHeader (iceConn, 0, ICE_AuthRequired,
400         SIZEOF (iceAuthRequiredMsg), iceAuthRequiredMsg, pMsg);
401
402     pMsg->authIndex = authIndex;
403     pMsg->authDataLength = authDataLen;
404     pMsg->length += WORD64COUNT (authDataLen);
405
406     IceWriteData (iceConn, authDataLen, (char *) authData);
407
408     if (PAD64 (authDataLen))
409         IceWritePad (iceConn, PAD64 (authDataLen));
410
411     IceFlush (iceConn);
412 }
413
414
415 \f
416 static void
417 AuthReply (
418         IceConn         iceConn,
419         int             authDataLen,
420         IcePointer      authData
421 )
422 {
423     iceAuthReplyMsg *pMsg;
424
425     IceGetHeader (iceConn, 0, ICE_AuthReply,
426         SIZEOF (iceAuthReplyMsg), iceAuthReplyMsg, pMsg);
427
428     pMsg->authDataLength = authDataLen;
429     pMsg->length +=  WORD64COUNT (authDataLen);
430
431     IceWriteData (iceConn, authDataLen, (char *) authData);
432
433     if (PAD64 (authDataLen))
434         IceWritePad (iceConn, PAD64 (authDataLen));
435
436     IceFlush (iceConn);
437 }
438
439
440 \f
441 static void
442 AuthNextPhase (
443         IceConn         iceConn,
444         int             authDataLen,
445         IcePointer      authData
446 )
447 {
448     iceAuthNextPhaseMsg *pMsg;
449
450     IceGetHeader (iceConn, 0, ICE_AuthNextPhase,
451         SIZEOF (iceAuthNextPhaseMsg), iceAuthNextPhaseMsg, pMsg);
452
453     pMsg->authDataLength = authDataLen;
454     pMsg->length += WORD64COUNT (authDataLen);
455
456     IceWriteData (iceConn, authDataLen, (char *) authData);
457
458     if (PAD64 (authDataLen))
459         IceWritePad (iceConn, PAD64 (authDataLen));
460
461     IceFlush (iceConn);
462 }
463
464
465 \f
466 static void
467 AcceptConnection (
468         IceConn iceConn,
469         int     versionIndex
470 )
471 {
472     iceConnectionReplyMsg       *pMsg;
473     char                        *pData;
474     int                         extra;
475
476     extra = STRING_BYTES (IceVendorString) + STRING_BYTES (IceReleaseString);
477
478     IceGetHeaderExtra (iceConn, 0, ICE_ConnectionReply,
479         SIZEOF (iceConnectionReplyMsg), WORD64COUNT (extra),
480         iceConnectionReplyMsg, pMsg, pData);
481
482     pMsg->versionIndex = versionIndex;
483
484     STORE_STRING (pData, IceVendorString);
485     STORE_STRING (pData, IceReleaseString);
486
487     IceFlush (iceConn);
488
489     iceConn->connection_status = IceConnectAccepted;
490 }
491
492
493 \f
494 static void
495 AcceptProtocol (
496         IceConn iceConn,
497         int     hisOpcode,
498         int     myOpcode,
499         int     versionIndex,
500         char    *vendor,
501         char    *release
502 )
503 {
504     iceProtocolReplyMsg *pMsg;
505     char                *pData;
506     int                 extra;
507
508     extra = STRING_BYTES (vendor) + STRING_BYTES (release);
509
510     IceGetHeaderExtra (iceConn, 0, ICE_ProtocolReply,
511         SIZEOF (iceProtocolReplyMsg), WORD64COUNT (extra),
512         iceProtocolReplyMsg, pMsg, pData);
513
514     pMsg->protocolOpcode = myOpcode;
515     pMsg->versionIndex = versionIndex;
516
517     STORE_STRING (pData, vendor);
518     STORE_STRING (pData, release);
519
520     IceFlush (iceConn);
521
522
523     /*
524      * We may be using a different major opcode for this protocol
525      * than the other client.  Whenever we get a message, we must
526      * map to our own major opcode.
527      */
528
529     _IceAddOpcodeMapping (iceConn, hisOpcode, myOpcode);
530 }
531
532
533 \f
534 static void
535 PingReply (
536         IceConn iceConn
537 )
538 {
539     IceSimpleMessage (iceConn, 0, ICE_PingReply);
540     IceFlush (iceConn);
541 }
542
543
544 \f
545 static Bool
546 ProcessError (
547         IceConn          iceConn,
548         unsigned long    length,
549         Bool             swap,
550         IceReplyWaitInfo *replyWait
551 )
552 {
553     int         invokeHandler = 0;
554     Bool        errorReturned = False;
555     iceErrorMsg *message;
556     char        *pData, *pStart;
557     char        severity;
558
559     CHECK_AT_LEAST_SIZE (iceConn, ICE_Error,
560         length, SIZEOF (iceErrorMsg),
561         (iceConn->connect_to_you || iceConn->connect_to_me) ?
562         IceFatalToConnection : IceFatalToProtocol);
563
564     IceReadCompleteMessage (iceConn, SIZEOF (iceErrorMsg),
565         iceErrorMsg, message, pStart);
566
567     if (!IceValidIO (iceConn))
568     {
569         IceDisposeCompleteMessage (iceConn, pStart);
570         return (0);
571     }
572
573     severity = message->severity;
574
575     if (severity != IceCanContinue && severity != IceFatalToProtocol &&
576         severity != IceFatalToConnection)
577     {
578         _IceErrorBadValue (iceConn, 0,
579             ICE_Error, 9, 1, &severity);
580         IceDisposeCompleteMessage (iceConn, pStart);
581         return (0);
582     }
583
584     pData = pStart;
585
586     if (swap)
587     {
588         message->errorClass = lswaps (message->errorClass);
589         message->offendingSequenceNum = lswapl (message->offendingSequenceNum);
590     }
591
592     if (!replyWait ||
593         message->offendingSequenceNum != replyWait->sequence_of_request)
594     {
595         invokeHandler = 1;
596     }
597     else
598     {
599         if (iceConn->connect_to_you &&
600             ((!iceConn->connect_to_you->auth_active &&
601             message->offendingMinorOpcode == ICE_ConnectionSetup) ||
602             (iceConn->connect_to_you->auth_active &&
603             message->offendingMinorOpcode == ICE_AuthReply)))
604         {
605             _IceConnectionError *errorReply =
606                 &(((_IceReply *) (replyWait->reply))->connection_error);
607             char *errorStr = NULL;
608             const char *tempstr;
609             char *prefix, *temp;
610
611             invokeHandler = 0;
612             errorReturned = True;
613
614             switch (message->errorClass)
615             {
616             case IceNoVersion:
617
618                 tempstr =
619                     "None of the ICE versions specified are supported";
620                 errorStr = strdup(tempstr);
621                 break;
622
623             case IceNoAuth:
624
625                 tempstr =
626                     "None of the authentication protocols specified are supported";
627                 errorStr = strdup(tempstr);
628                 break;
629
630             case IceSetupFailed:
631
632                 prefix = "Connection Setup Failed, reason : ";
633
634                 EXTRACT_STRING (pData, swap, temp);
635                 errorStr = (char *) malloc (
636                     strlen (prefix) + strlen (temp) + 1);
637                 sprintf (errorStr, "%s%s", prefix, temp);
638                 free (temp);
639                 break;
640
641             case IceAuthRejected:
642
643                 prefix = "Authentication Rejected, reason : ";
644                 EXTRACT_STRING (pData, swap, temp);
645                 errorStr = (char *) malloc (
646                     strlen (prefix) + strlen (temp) + 1);
647                 sprintf (errorStr, "%s%s", prefix, temp);
648                 free (temp);
649                 break;
650
651             case IceAuthFailed:
652
653                 prefix = "Authentication Failed, reason : ";
654                 EXTRACT_STRING (pData, swap, temp);
655                 errorStr = (char *) malloc (
656                     strlen (prefix) + strlen (temp) + 1);
657                 sprintf (errorStr, "%s%s", prefix, temp);
658                 free (temp);
659                 break;
660
661             default:
662                 invokeHandler = 1;
663             }
664
665             errorReply->type = ICE_CONNECTION_ERROR;
666             errorReply->error_message = errorStr;
667         }
668         else if (iceConn->protosetup_to_you &&
669             ((!iceConn->protosetup_to_you->auth_active &&
670             message->offendingMinorOpcode == ICE_ProtocolSetup) ||
671             (iceConn->protosetup_to_you->auth_active &&
672             message->offendingMinorOpcode == ICE_AuthReply)))
673         {
674             _IceProtocolError *errorReply =
675                 &(((_IceReply *) (replyWait->reply))->protocol_error);
676             char *errorStr = "";
677             char *prefix, *temp;
678
679             invokeHandler = 0;
680             errorReturned = True;
681
682             switch (message->errorClass)
683             {
684             case IceNoVersion:
685
686                 temp =
687                     "None of the protocol versions specified are supported";
688                 errorStr = strdup(temp);
689                 break;
690
691             case IceNoAuth:
692
693                 temp =
694                     "None of the authentication protocols specified are supported";
695                 errorStr = strdup(temp);
696                 break;
697
698             case IceSetupFailed:
699
700                 prefix = "Protocol Setup Failed, reason : ";
701
702                 EXTRACT_STRING (pData, swap, temp);
703                 errorStr = (char *) malloc (
704                     strlen (prefix) + strlen (temp) + 1);
705                 sprintf (errorStr, "%s%s", prefix, temp);
706                 free (temp);
707                 break;
708
709             case IceAuthRejected:
710
711                 prefix = "Authentication Rejected, reason : ";
712                 EXTRACT_STRING (pData, swap, temp);
713                 errorStr = (char *) malloc (
714                     strlen (prefix) + strlen (temp) + 1);
715                 sprintf (errorStr, "%s%s", prefix, temp);
716                 free (temp);
717                 break;
718
719             case IceAuthFailed:
720
721                 prefix = "Authentication Failed, reason : ";
722                 EXTRACT_STRING (pData, swap, temp);
723                 errorStr = (char *) malloc (
724                     strlen (prefix) + strlen (temp) + 1);
725                 sprintf (errorStr, "%s%s", prefix, temp);
726                 free (temp);
727                 break;
728
729             case IceProtocolDuplicate:
730
731                 prefix = "Protocol was already registered : ";
732                 EXTRACT_STRING (pData, swap, temp);
733                 errorStr = (char *) malloc (
734                     strlen (prefix) + strlen (temp) + 1);
735                 sprintf (errorStr, "%s%s", prefix, temp);
736                 free (temp);
737                 break;
738
739             case IceMajorOpcodeDuplicate:
740
741                 prefix = "The major opcode was already used : ";
742                 errorStr = (char *) malloc (strlen (prefix) + 2);
743                 sprintf (errorStr, "%s%d", prefix, (int) *pData);
744                 break;
745
746             case IceUnknownProtocol:
747
748                 prefix = "Unknown Protocol : ";
749                 EXTRACT_STRING (pData, swap, temp);
750                 errorStr = (char *) malloc (
751                     strlen (prefix) + strlen (temp) + 1);
752                 sprintf (errorStr, "%s%s", prefix, temp);
753                 free (temp);
754                 break;
755
756             default:
757                 invokeHandler = 1;
758             }
759
760             errorReply->type = ICE_PROTOCOL_ERROR;
761             errorReply->error_message = errorStr;
762         }
763
764         if (errorReturned == True)
765         {
766             /*
767              * If we tried to authenticate, tell the authentication
768              * procedure to clean up.
769              */
770
771             IcePoAuthProc authProc;
772
773             if (iceConn->connect_to_you &&
774                 iceConn->connect_to_you->auth_active)
775             {
776                 authProc = _IcePoAuthProcs[(int)
777                     (iceConn->connect_to_you->my_auth_index)];
778
779                 (*authProc) (iceConn, &iceConn->connect_to_you->my_auth_state,
780                     True /* clean up */, False /* swap */,
781                     0, NULL, NULL, NULL, NULL);
782             }
783             else if (iceConn->protosetup_to_you &&
784                 iceConn->protosetup_to_you->auth_active)
785             {
786                 _IcePoProtocol *protocol = _IceProtocols[
787                     iceConn->protosetup_to_you->my_opcode - 1].orig_client;
788
789                 authProc = protocol->auth_procs[(int)(iceConn->
790                     protosetup_to_you->my_auth_index)];
791
792                 (*authProc) (iceConn,
793                     &iceConn->protosetup_to_you->my_auth_state,
794                     True /* clean up */, False /* swap */,
795                     0, NULL, NULL, NULL, NULL);
796             }
797         }
798     }
799
800     if (invokeHandler)
801     {
802         (*_IceErrorHandler) (iceConn, swap, message->offendingMinorOpcode,
803             message->offendingSequenceNum, message->errorClass,
804             message->severity, (IcePointer) pData);
805     }
806
807     IceDisposeCompleteMessage (iceConn, pStart);
808
809     return (errorReturned);
810 }
811
812
813 \f
814 static int
815 ProcessConnectionSetup (
816         IceConn         iceConn,
817         unsigned long   length,
818         Bool            swap
819 )
820 {
821     iceConnectionSetupMsg *message;
822     int  myVersionCount, hisVersionCount;
823     int  myVersionIndex, hisVersionIndex;
824     int  hisMajorVersion, hisMinorVersion;
825     int  myAuthCount, hisAuthCount;
826     int  found, i, j;
827     char *myAuthName, **hisAuthNames = NULL;
828     char *pData, *pStart, *pEnd;
829     char *vendor = NULL;
830     char *release = NULL;
831     int myAuthIndex = 0;
832     int hisAuthIndex = 0;
833     int accept_setup_now = 0;
834     char mustAuthenticate;
835     int authUsableCount;
836     int authUsableFlags[MAX_ICE_AUTH_NAMES];
837     int authIndices[MAX_ICE_AUTH_NAMES];
838
839     CHECK_AT_LEAST_SIZE (iceConn, ICE_ConnectionSetup,
840         length, SIZEOF (iceConnectionSetupMsg), IceFatalToConnection);
841
842     IceReadCompleteMessage (iceConn, SIZEOF (iceConnectionSetupMsg),
843         iceConnectionSetupMsg, message, pStart);
844
845     if (!IceValidIO (iceConn))
846     {
847         IceDisposeCompleteMessage (iceConn, pStart);
848         return (0);
849     }
850
851     pData = pStart;
852     pEnd = pStart + (length << 3);
853     
854     SKIP_STRING (pData, swap, pEnd, 
855                  BAIL_STRING(iceConn, ICE_ConnectionSetup,
856                              pStart));                         /* vendor */
857     SKIP_STRING (pData, swap, pEnd, 
858                  BAIL_STRING(iceConn, ICE_ConnectionSetup,
859                             pStart));                          /* release */
860     SKIP_LISTOF_STRING (pData, swap, (int) message->authCount, pEnd, 
861                         BAIL_STRING(iceConn, ICE_ConnectionSetup,
862                                    pStart));                   /* auth names */
863     
864     pData += (message->versionCount * 4);                      /* versions */
865
866     CHECK_COMPLETE_SIZE (iceConn, ICE_ConnectionSetup,
867         length, pData - pStart + SIZEOF (iceConnectionSetupMsg),
868         pStart, IceFatalToConnection);
869
870     mustAuthenticate = message->mustAuthenticate;
871     if (mustAuthenticate != 0 && mustAuthenticate != 1)
872     {
873         _IceErrorBadValue (iceConn, 0,
874             ICE_ConnectionSetup, 8, 1, &mustAuthenticate);
875         iceConn->connection_status = IceConnectRejected;
876         IceDisposeCompleteMessage (iceConn, pStart);
877         return (0);
878     }
879
880     pData = pStart;
881
882     EXTRACT_STRING (pData, swap, vendor);
883     EXTRACT_STRING (pData, swap, release);
884
885     if ((hisAuthCount = message->authCount) > 0)
886     {
887         hisAuthNames = (char **) malloc (hisAuthCount * sizeof (char *));
888         EXTRACT_LISTOF_STRING (pData, swap, hisAuthCount, hisAuthNames);
889     }
890
891     hisVersionCount = message->versionCount;
892     myVersionCount = _IceVersionCount;
893
894     hisVersionIndex = myVersionIndex = found = 0;
895
896     for (i = 0; i < hisVersionCount && !found; i++)
897     {
898         EXTRACT_CARD16 (pData, swap, hisMajorVersion);
899         EXTRACT_CARD16 (pData, swap, hisMinorVersion);
900
901         for (j = 0; j < myVersionCount && !found; j++)
902         {
903             if (_IceVersions[j].major_version == hisMajorVersion &&
904                 _IceVersions[j].minor_version == hisMinorVersion)
905             {
906                 hisVersionIndex = i;
907                 myVersionIndex = j;
908                 found = 1;
909             }
910         }
911     }
912
913     if (!found)
914     {
915         _IceErrorNoVersion (iceConn, ICE_ConnectionSetup);
916         iceConn->connection_status = IceConnectRejected;
917
918         free (vendor);
919         free (release);
920
921         if (hisAuthCount > 0)
922         {
923             for (i = 0; i < hisAuthCount; i++)
924                 free (hisAuthNames[i]);
925         
926             free ((char *) hisAuthNames);
927         }
928
929         IceDisposeCompleteMessage (iceConn, pStart);
930         return (0);
931     }
932
933     _IceGetPaValidAuthIndices ("ICE", iceConn->connection_string,
934         _IceAuthCount, _IceAuthNames, &authUsableCount, authIndices);
935
936     for (i = 0; i < _IceAuthCount; i++)
937     {
938         authUsableFlags[i] = 0;
939         for (j = 0; j < authUsableCount && !authUsableFlags[i]; j++)
940             authUsableFlags[i] = (authIndices[j] == i);
941     }
942
943     myAuthCount = _IceAuthCount;
944
945     for (i = found = 0; i < myAuthCount && !found; i++)
946     {
947         if (authUsableFlags[i])
948         {
949             myAuthName = _IceAuthNames[i];
950
951             for (j = 0; j < hisAuthCount && !found; j++)
952                 if (strcmp (myAuthName, hisAuthNames[j]) == 0)
953                 {
954                     myAuthIndex = i;
955                     hisAuthIndex = j;
956                     found = 1;
957                 }
958         }
959     }
960
961     if (!found)
962     {
963         /*
964          * None of the authentication methods specified by the
965          * other client is supported.  If the other client requires
966          * authentication, we must reject the connection now.
967          * Otherwise, we can invoke the host-based authentication callback
968          * to see if we can accept this connection.
969          */
970
971         if (mustAuthenticate || !iceConn->listen_obj->host_based_auth_proc)
972         {
973             _IceErrorNoAuthentication (iceConn, ICE_ConnectionSetup);
974             iceConn->connection_status = IceConnectRejected;
975         }
976         else
977         {
978             char *hostname = _IceGetPeerName (iceConn);
979
980             if ((*iceConn->listen_obj->host_based_auth_proc) (hostname))
981             {
982                 accept_setup_now = 1;
983             }
984             else 
985             {
986                 _IceErrorAuthenticationRejected (iceConn,
987                     ICE_ConnectionSetup, "None of the authentication protocols specified are supported and host-based authentication failed");
988
989                 iceConn->connection_status = IceConnectRejected;
990             }
991
992             if (hostname)
993                 free (hostname);
994         }
995
996         if (iceConn->connection_status == IceConnectRejected)
997         {
998             free (vendor);
999             free (release);
1000         }
1001     }
1002     else
1003     {
1004         IcePaAuthStatus status;
1005         int             authDataLen;
1006         IcePointer      authData = NULL;
1007         IcePointer      authState;
1008         char            *errorString = NULL;
1009         IcePaAuthProc   authProc = _IcePaAuthProcs[myAuthIndex];
1010
1011         authState = NULL;
1012
1013         status = (*authProc) (iceConn, &authState,
1014             swap, 0, NULL, &authDataLen, &authData, &errorString);
1015
1016         if (status == IcePaAuthContinue)
1017         {
1018             _IceConnectToMeInfo *setupInfo;
1019
1020             AuthRequired (iceConn, hisAuthIndex, authDataLen, authData);
1021
1022             iceConn->connect_to_me = setupInfo = (_IceConnectToMeInfo *)
1023                 malloc (sizeof (_IceConnectToMeInfo));
1024
1025             setupInfo->my_version_index = myVersionIndex;
1026             setupInfo->his_version_index = hisVersionIndex;
1027             setupInfo->his_vendor = vendor;
1028             setupInfo->his_release = release;
1029             setupInfo->my_auth_index = myAuthIndex;
1030             setupInfo->my_auth_state = authState;
1031             setupInfo->must_authenticate = mustAuthenticate;
1032         }
1033         else if (status == IcePaAuthAccepted)
1034         {
1035             accept_setup_now = 1;
1036         }
1037
1038         if (authData && authDataLen > 0)
1039             free ((char *) authData);
1040
1041         if (errorString)
1042             free (errorString);
1043     }
1044     
1045     if (accept_setup_now)
1046     {
1047         AcceptConnection (iceConn, hisVersionIndex);
1048
1049         iceConn->vendor = vendor;
1050         iceConn->release = release;
1051         iceConn->my_ice_version_index = myVersionIndex;
1052     }
1053
1054     if (hisAuthCount > 0)
1055     {
1056         for (i = 0; i < hisAuthCount; i++)
1057             free (hisAuthNames[i]);
1058         
1059         free ((char *) hisAuthNames);
1060     }
1061
1062     IceDisposeCompleteMessage (iceConn, pStart);
1063     return (0);
1064 }
1065
1066
1067 \f
1068 static Bool
1069 ProcessAuthRequired (
1070         IceConn                 iceConn,
1071         unsigned long           length,
1072         Bool                    swap,
1073         IceReplyWaitInfo        *replyWait
1074 )
1075 {
1076     iceAuthRequiredMsg  *message;
1077     int                 authDataLen;
1078     IcePointer          authData;
1079     int                 replyDataLen;
1080     IcePointer          replyData = NULL;
1081     char                *errorString = NULL;
1082     IcePoAuthProc       authProc;
1083     IcePoAuthStatus     status;
1084     IcePointer          authState;
1085     int                 realAuthIndex = 0;
1086
1087     CHECK_AT_LEAST_SIZE (iceConn, ICE_AuthRequired,
1088         length, SIZEOF (iceAuthRequiredMsg),
1089         iceConn->connect_to_you ? IceFatalToConnection : IceFatalToProtocol);
1090
1091     IceReadCompleteMessage (iceConn, SIZEOF (iceAuthRequiredMsg),
1092         iceAuthRequiredMsg, message, authData);
1093
1094     if (!IceValidIO (iceConn))
1095     {
1096         IceDisposeCompleteMessage (iceConn, authData);
1097         return (0);
1098     }
1099
1100     if (swap)
1101     {
1102         message->authDataLength = lswaps (message->authDataLength);
1103     }
1104
1105     CHECK_COMPLETE_SIZE (iceConn, ICE_AuthRequired, length,
1106         message->authDataLength + SIZEOF (iceAuthRequiredMsg), authData,
1107         iceConn->connect_to_you ? IceFatalToConnection : IceFatalToProtocol);
1108
1109     if (iceConn->connect_to_you)
1110     {
1111         if ((int) message->authIndex >= _IceAuthCount)
1112         {
1113             _IceConnectionError *errorReply =
1114                 &(((_IceReply *) (replyWait->reply))->connection_error);
1115
1116             const char *tempstr
1117                 = "Received bad authIndex in the AuthRequired message";
1118             char errIndex = (int) message->authIndex;
1119
1120             errorString = strdup(tempstr);
1121
1122             errorReply->type = ICE_CONNECTION_ERROR;
1123             errorReply->error_message = errorString;
1124
1125             _IceErrorBadValue (iceConn, 0,
1126                 ICE_AuthRequired, 2, 1, &errIndex);
1127
1128             IceDisposeCompleteMessage (iceConn, authData);
1129             return (1);
1130         }
1131         else
1132         {
1133             authProc = _IcePoAuthProcs[message->authIndex];
1134
1135             iceConn->connect_to_you->auth_active = 1;
1136         }
1137     }
1138     else if (iceConn->protosetup_to_you)
1139     {
1140         if ((int) message->authIndex >=
1141             iceConn->protosetup_to_you->my_auth_count)
1142         {
1143             _IceProtocolError *errorReply =
1144                 &(((_IceReply *) (replyWait->reply))->protocol_error);
1145
1146             const char *tempstr
1147                 = "Received bad authIndex in the AuthRequired message";
1148             char errIndex = (int) message->authIndex;
1149
1150             errorString = strdup(tempstr);
1151
1152             errorReply->type = ICE_PROTOCOL_ERROR;
1153             errorReply->error_message = errorString;
1154
1155             _IceErrorBadValue (iceConn, 0,
1156                 ICE_AuthRequired, 2, 1, &errIndex);
1157
1158             IceDisposeCompleteMessage (iceConn, authData);
1159             return (1);
1160         }
1161         else
1162         {
1163             _IcePoProtocol *myProtocol = _IceProtocols[
1164                 iceConn->protosetup_to_you->my_opcode - 1].orig_client;
1165
1166             realAuthIndex = iceConn->protosetup_to_you->
1167                 my_auth_indices[message->authIndex];
1168
1169             authProc = myProtocol->auth_procs[realAuthIndex];
1170
1171             iceConn->protosetup_to_you->auth_active = 1;
1172         }
1173     }
1174     else
1175     {
1176         /*
1177          * Unexpected message
1178          */
1179
1180         _IceErrorBadState (iceConn, 0, ICE_AuthRequired, IceCanContinue);
1181
1182         IceDisposeCompleteMessage (iceConn, authData);
1183         return (0);
1184     }
1185
1186     authState = NULL;
1187     authDataLen = message->authDataLength;
1188
1189     status = (*authProc) (iceConn, &authState, False /* don't clean up */,
1190         swap, authDataLen, authData, &replyDataLen, &replyData, &errorString);
1191
1192     if (status == IcePoAuthHaveReply)
1193     {
1194         AuthReply (iceConn, replyDataLen, replyData);
1195
1196         replyWait->sequence_of_request = iceConn->send_sequence;
1197         replyWait->minor_opcode_of_request = ICE_AuthReply;
1198
1199         if (iceConn->connect_to_you)
1200         {
1201             iceConn->connect_to_you->my_auth_state = authState;
1202             iceConn->connect_to_you->my_auth_index = message->authIndex;
1203         }
1204         else if (iceConn->protosetup_to_you)
1205         {
1206             iceConn->protosetup_to_you->my_auth_state = authState;
1207             iceConn->protosetup_to_you->my_auth_index = realAuthIndex;
1208         }
1209     }
1210     else if (status == IcePoAuthRejected || status == IcePoAuthFailed)
1211     {
1212         char *prefix, *returnErrorString;
1213
1214         if (status == IcePoAuthRejected)
1215         {
1216             _IceErrorAuthenticationRejected (iceConn,
1217                 ICE_AuthRequired, errorString);
1218
1219             prefix = "Authentication Rejected, reason : ";
1220         }
1221         else
1222         {
1223             _IceErrorAuthenticationFailed (iceConn,
1224                ICE_AuthRequired, errorString);
1225
1226             prefix = "Authentication Failed, reason : ";
1227         }
1228
1229         returnErrorString = (char *) malloc (strlen (prefix) +
1230             strlen (errorString) + 1);
1231         sprintf (returnErrorString, "%s%s", prefix, errorString);
1232         free (errorString);
1233         
1234         if (iceConn->connect_to_you)
1235         {
1236             _IceConnectionError *errorReply =
1237                 &(((_IceReply *) (replyWait->reply))->connection_error);
1238
1239             errorReply->type = ICE_CONNECTION_ERROR;
1240             errorReply->error_message = returnErrorString;
1241         }
1242         else
1243         {
1244             _IceProtocolError *errorReply =
1245                 &(((_IceReply *) (replyWait->reply))->protocol_error);
1246
1247             errorReply->type = ICE_PROTOCOL_ERROR;
1248             errorReply->error_message = returnErrorString;
1249         }
1250     }
1251
1252     if (replyData && replyDataLen > 0)
1253         free ((char *) replyData);
1254
1255     IceDisposeCompleteMessage (iceConn, authData);
1256
1257     return (status != IcePoAuthHaveReply);
1258 }
1259
1260
1261 \f
1262 static int
1263 ProcessAuthReply (
1264         IceConn         iceConn,
1265         unsigned long   length,
1266         Bool            swap
1267 )
1268 {
1269     iceAuthReplyMsg     *message;
1270     int                 replyDataLen;
1271     IcePointer          replyData;
1272     int                 authDataLen;
1273     IcePointer          authData = NULL;
1274     char                *errorString = NULL;
1275
1276     CHECK_AT_LEAST_SIZE (iceConn, ICE_AuthReply,
1277         length, SIZEOF (iceAuthReplyMsg),
1278         iceConn->connect_to_me ? IceFatalToConnection : IceFatalToProtocol);
1279
1280     IceReadCompleteMessage (iceConn, SIZEOF (iceAuthReplyMsg),
1281         iceAuthReplyMsg, message, replyData);
1282
1283     if (!IceValidIO (iceConn))
1284     {
1285         IceDisposeCompleteMessage (iceConn, replyData);
1286         return (0);
1287     }
1288
1289     if (swap)
1290     {
1291         message->authDataLength = lswaps (message->authDataLength);
1292     }
1293
1294     CHECK_COMPLETE_SIZE (iceConn, ICE_AuthReply, length,
1295         message->authDataLength + SIZEOF (iceAuthReplyMsg), replyData,
1296         iceConn->connect_to_me ? IceFatalToConnection : IceFatalToProtocol);
1297
1298     replyDataLen = message->authDataLength;
1299
1300     if (iceConn->connect_to_me)
1301     {
1302         IcePaAuthProc authProc = _IcePaAuthProcs[(int)
1303             (iceConn->connect_to_me->my_auth_index)];
1304         IcePaAuthStatus status =
1305             (*authProc) (iceConn, &iceConn->connect_to_me->my_auth_state, swap,
1306             replyDataLen, replyData, &authDataLen, &authData, &errorString);
1307
1308         if (status == IcePaAuthContinue)
1309         {
1310             AuthNextPhase (iceConn, authDataLen, authData);
1311         }
1312         else if (status == IcePaAuthRejected || status == IcePaAuthFailed)
1313         {
1314             /*
1315              * Before we reject, invoke host-based authentication callback
1316              * and give it a chance to accept the connection (only if the
1317              * other client doesn't require authentication).
1318              */
1319
1320             if (!iceConn->connect_to_me->must_authenticate &&
1321                 iceConn->listen_obj->host_based_auth_proc)
1322             {
1323                 char *hostname = _IceGetPeerName (iceConn);
1324
1325                 if ((*iceConn->listen_obj->host_based_auth_proc) (hostname))
1326                 {
1327                     status = IcePaAuthAccepted;
1328                 }
1329
1330                 if (hostname)
1331                     free (hostname);
1332             }
1333
1334             if (status != IcePaAuthAccepted)
1335             {
1336                 free (iceConn->connect_to_me->his_vendor);
1337                 free (iceConn->connect_to_me->his_release);
1338                 free ((char *) iceConn->connect_to_me);
1339                 iceConn->connect_to_me = NULL;
1340
1341                 iceConn->connection_status = IceConnectRejected;
1342
1343                 if (status == IcePaAuthRejected)
1344                 {
1345                     _IceErrorAuthenticationRejected (iceConn,
1346                         ICE_AuthReply, errorString);
1347                 }
1348                 else
1349                 {
1350                     _IceErrorAuthenticationFailed (iceConn,
1351                         ICE_AuthReply, errorString);
1352                 }
1353             }
1354         }
1355
1356         if (status == IcePaAuthAccepted)
1357         {
1358             AcceptConnection (iceConn,
1359                 iceConn->connect_to_me->his_version_index);
1360
1361             iceConn->vendor = iceConn->connect_to_me->his_vendor;
1362             iceConn->release = iceConn->connect_to_me->his_release;
1363             iceConn->my_ice_version_index =
1364                 iceConn->connect_to_me->my_version_index;
1365
1366             free ((char *) iceConn->connect_to_me);
1367             iceConn->connect_to_me = NULL;
1368         }
1369     }
1370     else if (iceConn->protosetup_to_me)
1371     {
1372         _IcePaProtocol *myProtocol = _IceProtocols[iceConn->protosetup_to_me->
1373             my_opcode - 1].accept_client;
1374         IcePaAuthProc authProc = myProtocol->auth_procs[(int)
1375             (iceConn->protosetup_to_me->my_auth_index)];
1376         IcePaAuthStatus status =
1377             (*authProc) (iceConn, &iceConn->protosetup_to_me->my_auth_state,
1378             swap, replyDataLen, replyData,
1379             &authDataLen, &authData, &errorString);
1380         int free_setup_info = 1;
1381
1382         if (status == IcePaAuthContinue)
1383         {
1384             AuthNextPhase (iceConn, authDataLen, authData);
1385             free_setup_info = 0;
1386         }
1387         else if (status == IcePaAuthRejected || status == IcePaAuthFailed)
1388         {
1389             /*
1390              * Before we reject, invoke host-based authentication callback
1391              * and give it a chance to accept the Protocol Setup (only if the
1392              * other client doesn't require authentication).
1393              */
1394
1395             if (!iceConn->protosetup_to_me->must_authenticate &&
1396                 myProtocol->host_based_auth_proc)
1397             {
1398                 char *hostname = _IceGetPeerName (iceConn);
1399
1400                 if ((*myProtocol->host_based_auth_proc) (hostname))
1401                 {
1402                     status = IcePaAuthAccepted;
1403                 }
1404
1405                 if (hostname)
1406                     free (hostname);
1407             }
1408
1409             if (status == IcePaAuthRejected)
1410             {
1411                 _IceErrorAuthenticationRejected (iceConn,
1412                     ICE_AuthReply, errorString);
1413             }
1414             else
1415             {
1416                 _IceErrorAuthenticationFailed (iceConn,
1417                     ICE_AuthReply, errorString);
1418             }
1419         }
1420
1421         if (status == IcePaAuthAccepted)
1422         {
1423             IcePaProcessMsgProc processMsgProc;
1424             IceProtocolSetupProc protocolSetupProc;
1425             IceProtocolActivateProc protocolActivateProc;
1426             _IceProcessMsgInfo *process_msg_info;
1427             IcePointer clientData = NULL;
1428             char *failureReason = NULL;
1429             Status status = 1;
1430
1431             protocolSetupProc = myProtocol->protocol_setup_proc;
1432             protocolActivateProc = myProtocol->protocol_activate_proc;
1433
1434             if (protocolSetupProc)
1435             {
1436                 /*
1437                  * Notify the client of the Protocol Setup.
1438                  */
1439
1440                 status = (*protocolSetupProc) (iceConn,
1441                     myProtocol->version_recs[iceConn->protosetup_to_me->
1442                         my_version_index].major_version,
1443                     myProtocol->version_recs[iceConn->protosetup_to_me->
1444                         my_version_index].minor_version,
1445                     iceConn->protosetup_to_me->his_vendor,
1446                     iceConn->protosetup_to_me->his_release,
1447                     &clientData, &failureReason);
1448
1449                 /*
1450                  * Set vendor and release pointers to NULL, so it won't
1451                  * get freed below.  The ProtocolSetupProc should
1452                  * free it.
1453                  */
1454
1455                 iceConn->protosetup_to_me->his_vendor = NULL;
1456                 iceConn->protosetup_to_me->his_release = NULL;
1457             }
1458
1459             if (status != 0)
1460             {
1461                 /*
1462                  * Send the Protocol Reply
1463                  */
1464
1465                 AcceptProtocol (iceConn,
1466                     iceConn->protosetup_to_me->his_opcode,
1467                     iceConn->protosetup_to_me->my_opcode,
1468                     iceConn->protosetup_to_me->his_version_index,
1469                     myProtocol->vendor, myProtocol->release);
1470
1471
1472                 /*
1473                  * Set info for this protocol.
1474                  */
1475
1476                 processMsgProc = myProtocol->version_recs[
1477                     iceConn->protosetup_to_me->
1478                     my_version_index].process_msg_proc;
1479
1480                 process_msg_info = &iceConn->process_msg_info[
1481                     iceConn->protosetup_to_me->
1482                     his_opcode -iceConn->his_min_opcode];
1483
1484                 process_msg_info->client_data = clientData;
1485                 process_msg_info->accept_flag = 1;
1486                 process_msg_info->process_msg_proc.
1487                     accept_client = processMsgProc;
1488
1489
1490                 /*
1491                  * Increase the reference count for the number
1492                  * of active protocols.
1493                  */
1494
1495                 iceConn->proto_ref_count++;
1496
1497
1498                 /*
1499                  * Notify the client that the protocol is active.  The reason
1500                  * we have this 2nd callback invoked is because the client
1501                  * may wish to immediately generate a message for this
1502                  * protocol, but it must wait until we send the Protocol Reply.
1503                  */
1504
1505                 if (protocolActivateProc)
1506                 {
1507                     (*protocolActivateProc) (iceConn,
1508                         process_msg_info->client_data);
1509                 }
1510             }
1511             else
1512             {
1513                 /*
1514                  * An error was encountered.
1515                  */
1516
1517                 _IceErrorSetupFailed (iceConn, ICE_ProtocolSetup,
1518                     failureReason);
1519
1520                 if (failureReason)
1521                     free (failureReason);
1522             }
1523         }
1524
1525
1526         if (free_setup_info)
1527         {
1528             if (iceConn->protosetup_to_me->his_vendor)
1529                 free (iceConn->protosetup_to_me->his_vendor);
1530             if (iceConn->protosetup_to_me->his_release)
1531                 free (iceConn->protosetup_to_me->his_release);
1532             free ((char *) iceConn->protosetup_to_me);
1533             iceConn->protosetup_to_me = NULL;
1534         }
1535     }
1536     else
1537     {
1538         /*
1539          * Unexpected message
1540          */
1541
1542         _IceErrorBadState (iceConn, 0, ICE_AuthReply, IceCanContinue);
1543     }
1544
1545     if (authData && authDataLen > 0)
1546         free ((char *) authData);
1547
1548     if (errorString)
1549         free (errorString);
1550
1551     IceDisposeCompleteMessage (iceConn, replyData);
1552     return (0);
1553 }
1554
1555
1556 \f
1557 static Bool
1558 ProcessAuthNextPhase (
1559         IceConn                 iceConn,
1560         unsigned long           length,
1561         Bool                    swap,
1562         IceReplyWaitInfo        *replyWait
1563 )
1564 {
1565     iceAuthNextPhaseMsg *message;
1566     int                 authDataLen;
1567     IcePointer          authData;
1568     int                 replyDataLen;
1569     IcePointer          replyData = NULL;
1570     char                *errorString = NULL;
1571     IcePoAuthProc       authProc;
1572     IcePoAuthStatus     status;
1573     IcePointer          *authState;
1574
1575     CHECK_AT_LEAST_SIZE (iceConn, ICE_AuthNextPhase,
1576         length, SIZEOF (iceAuthNextPhaseMsg),
1577         iceConn->connect_to_you ? IceFatalToConnection : IceFatalToProtocol);
1578
1579     IceReadCompleteMessage (iceConn, SIZEOF (iceAuthNextPhaseMsg),
1580         iceAuthNextPhaseMsg, message, authData);
1581
1582     if (!IceValidIO (iceConn))
1583     {
1584         IceDisposeCompleteMessage (iceConn, authData);
1585         return (0);
1586     }
1587
1588     if (swap)
1589     {
1590         message->authDataLength = lswaps (message->authDataLength);
1591     }
1592
1593     CHECK_COMPLETE_SIZE (iceConn, ICE_AuthNextPhase, length,
1594         message->authDataLength + SIZEOF (iceAuthNextPhaseMsg), authData,
1595         iceConn->connect_to_you ? IceFatalToConnection : IceFatalToProtocol);
1596
1597     if (iceConn->connect_to_you)
1598     {
1599         authProc = _IcePoAuthProcs[(int)
1600             (iceConn->connect_to_you->my_auth_index)];
1601
1602         authState = &iceConn->connect_to_you->my_auth_state;
1603     }
1604     else if (iceConn->protosetup_to_you)
1605     {
1606         _IcePoProtocol *myProtocol =
1607           _IceProtocols[iceConn->protosetup_to_you->my_opcode - 1].orig_client;
1608
1609         authProc = myProtocol->auth_procs[(int)
1610             (iceConn->protosetup_to_you->my_auth_index)];
1611
1612         authState = &iceConn->protosetup_to_you->my_auth_state;
1613     }
1614     else
1615     {
1616         /*
1617          * Unexpected message
1618          */
1619
1620         _IceErrorBadState (iceConn, 0, ICE_AuthNextPhase, IceCanContinue);
1621
1622         IceDisposeCompleteMessage (iceConn, authData);
1623         return (0);
1624     }
1625
1626     authDataLen = message->authDataLength;
1627
1628     status = (*authProc) (iceConn, authState, False /* don't clean up */,
1629         swap, authDataLen, authData, &replyDataLen, &replyData, &errorString);
1630
1631     if (status == IcePoAuthHaveReply)
1632     {
1633         AuthReply (iceConn, replyDataLen, replyData);
1634
1635         replyWait->sequence_of_request = iceConn->send_sequence;
1636     }
1637     else if (status == IcePoAuthRejected || status == IcePoAuthFailed)
1638     {
1639         char *prefix = NULL, *returnErrorString;
1640
1641         if (status == IcePoAuthRejected)
1642         {
1643             _IceErrorAuthenticationRejected (iceConn,
1644                ICE_AuthNextPhase, errorString);
1645
1646             prefix = "Authentication Rejected, reason : ";
1647         }
1648         else if (status == IcePoAuthFailed)
1649         {
1650             _IceErrorAuthenticationFailed (iceConn,
1651                ICE_AuthNextPhase, errorString);
1652
1653             prefix = "Authentication Failed, reason : ";
1654         }
1655
1656         returnErrorString = (char *) malloc (strlen (prefix) +
1657             strlen (errorString) + 1);
1658         sprintf (returnErrorString, "%s%s", prefix, errorString);
1659         free (errorString);
1660
1661         if (iceConn->connect_to_you)
1662         {
1663             _IceConnectionError *errorReply =
1664                 &(((_IceReply *) (replyWait->reply))->connection_error);
1665
1666             errorReply->type = ICE_CONNECTION_ERROR;
1667             errorReply->error_message = returnErrorString;
1668         }
1669         else
1670         {
1671             _IceProtocolError *errorReply =
1672                 &(((_IceReply *) (replyWait->reply))->protocol_error);
1673
1674             errorReply->type = ICE_PROTOCOL_ERROR;
1675             errorReply->error_message = returnErrorString;
1676         }
1677     }
1678
1679     if (replyData && replyDataLen > 0)
1680         free ((char *) replyData);
1681
1682     IceDisposeCompleteMessage (iceConn, authData);
1683
1684     return (status != IcePoAuthHaveReply);
1685 }
1686
1687
1688 \f
1689 static Bool
1690 ProcessConnectionReply (
1691         IceConn                 iceConn,
1692         unsigned long           length,
1693         Bool                    swap,
1694         IceReplyWaitInfo        *replyWait
1695 )
1696 {
1697     iceConnectionReplyMsg       *message;
1698     char                        *pData, *pStart, *pEnd;
1699     Bool                        replyReady;
1700
1701 #if 0 /* No-op */
1702     CHECK_AT_LEAST_SIZE (iceConn, ICE_ConnectionReply,
1703         length, SIZEOF (iceConnectionReplyMsg), IceFatalToConnection);
1704 #endif
1705
1706     IceReadCompleteMessage (iceConn, SIZEOF (iceConnectionReplyMsg),
1707         iceConnectionReplyMsg, message, pStart);
1708
1709     if (!IceValidIO (iceConn))
1710     {
1711         IceDisposeCompleteMessage (iceConn, pStart);
1712         return (0);
1713     }
1714
1715     pData = pStart;
1716     pEnd = pStart + (length << 3);
1717
1718     SKIP_STRING (pData, swap, pEnd,
1719                  BAIL_STRING (iceConn, ICE_ConnectionReply,
1720                               pStart));                      /* vendor */
1721     SKIP_STRING (pData, swap, pEnd,
1722                  BAIL_STRING (iceConn, ICE_ConnectionReply,
1723                               pStart));                      /* release */
1724
1725     CHECK_COMPLETE_SIZE (iceConn, ICE_ConnectionReply,
1726         length, pData - pStart + SIZEOF (iceConnectionReplyMsg),
1727         pStart, IceFatalToConnection);
1728
1729     pData = pStart;
1730
1731     if (iceConn->connect_to_you)
1732     {
1733         if (iceConn->connect_to_you->auth_active)
1734         {
1735             /*
1736              * Tell the authentication procedure to clean up.
1737              */
1738
1739             IcePoAuthProc authProc = _IcePoAuthProcs[(int)
1740                 (iceConn->connect_to_you->my_auth_index)];
1741
1742             (*authProc) (iceConn, &iceConn->connect_to_you->my_auth_state,
1743                 True /* clean up */, False /* swap */,
1744                 0, NULL, NULL, NULL, NULL);
1745         }
1746
1747         if ((int) message->versionIndex >= _IceVersionCount)
1748         {
1749             _IceConnectionError *errorReply =
1750                 &(((_IceReply *) (replyWait->reply))->connection_error);
1751             char errIndex = message->versionIndex;
1752
1753             _IceErrorBadValue (iceConn, 0,
1754                 ICE_ConnectionReply, 2, 1, &errIndex);
1755             
1756             errorReply->type = ICE_CONNECTION_ERROR;
1757             errorReply->error_message =
1758                 "Received bad version index in Connection Reply";
1759         }
1760         else
1761         {
1762             _IceReply *reply = (_IceReply *) (replyWait->reply);
1763
1764             reply->type = ICE_CONNECTION_REPLY;
1765             reply->connection_reply.version_index = message->versionIndex;
1766
1767             EXTRACT_STRING (pData, swap, reply->connection_reply.vendor);
1768             EXTRACT_STRING (pData, swap, reply->connection_reply.release);
1769         }
1770
1771         replyReady = True;
1772     }
1773     else
1774     {
1775         /*
1776          * Unexpected message
1777          */
1778
1779         _IceErrorBadState (iceConn, 0, ICE_ConnectionReply, IceCanContinue);
1780
1781         replyReady = False;
1782     }
1783
1784     IceDisposeCompleteMessage (iceConn, pStart);
1785
1786     return (replyReady);
1787 }
1788
1789
1790 \f
1791 static int
1792 ProcessProtocolSetup (
1793         IceConn         iceConn,
1794         unsigned long   length,
1795         Bool            swap
1796 )
1797 {
1798     iceProtocolSetupMsg *message;
1799     _IcePaProtocol      *myProtocol;
1800     int                 myVersionCount, hisVersionCount;
1801     int                 myVersionIndex, hisVersionIndex;
1802     int                 hisMajorVersion, hisMinorVersion;
1803     int                 myAuthCount, hisAuthCount;
1804     int                 myOpcode, hisOpcode;
1805     int                 found, i, j;
1806     char                *myAuthName, **hisAuthNames = NULL;
1807     char                *protocolName;
1808     char                *pData, *pStart, *pEnd;
1809     char                *vendor = NULL;
1810     char                *release = NULL;
1811     int                 accept_setup_now = 0;
1812     int                 myAuthIndex = 0;
1813     int                 hisAuthIndex = 0;
1814     char                mustAuthenticate;
1815     int                 authUsableCount;
1816     int                 authUsableFlags[MAX_ICE_AUTH_NAMES];
1817     int                 authIndices[MAX_ICE_AUTH_NAMES];
1818
1819     CHECK_AT_LEAST_SIZE (iceConn, ICE_ProtocolSetup,
1820         length, SIZEOF (iceProtocolSetupMsg), IceFatalToProtocol);
1821
1822     if (iceConn->want_to_close)
1823     {
1824         /*
1825          * If we sent a WantToClose message, but just got a ProtocolSetup,
1826          * we must cancel our WantToClose.  It is the responsiblity of the
1827          * other client to send a WantToClose later on.
1828          */
1829
1830         iceConn->want_to_close = 0;
1831     }
1832
1833     IceReadCompleteMessage (iceConn, SIZEOF (iceProtocolSetupMsg),
1834         iceProtocolSetupMsg, message, pStart);
1835
1836     if (!IceValidIO (iceConn))
1837     {
1838         IceDisposeCompleteMessage (iceConn, pStart);
1839         return (0);
1840     }
1841
1842     pData = pStart;
1843     pEnd = pStart + (length << 3);
1844
1845     SKIP_STRING (pData, swap, pEnd,
1846                  BAIL_STRING(iceConn, ICE_ProtocolSetup, 
1847                              pStart));                         /* proto name */
1848     SKIP_STRING (pData, swap, pEnd,
1849                  BAIL_STRING(iceConn, ICE_ProtocolSetup, 
1850                              pStart));                         /* vendor */
1851     SKIP_STRING (pData, swap, pEnd,
1852                  BAIL_STRING(iceConn, ICE_ProtocolSetup, 
1853                              pStart));                         /* release */
1854     SKIP_LISTOF_STRING (pData, swap, (int) message->authCount, pEnd,
1855                         BAIL_STRING(iceConn, ICE_ProtocolSetup, 
1856                                     pStart));                  /* auth names */
1857     pData += (message->versionCount * 4);                      /* versions */
1858
1859     CHECK_COMPLETE_SIZE (iceConn, ICE_ProtocolSetup,
1860         length, pData - pStart + SIZEOF (iceProtocolSetupMsg),
1861         pStart, IceFatalToProtocol);
1862
1863     mustAuthenticate = message->mustAuthenticate;
1864
1865     if (mustAuthenticate != 0 && mustAuthenticate != 1)
1866     {
1867         _IceErrorBadValue (iceConn, 0,
1868             ICE_ProtocolSetup, 4, 1, &mustAuthenticate);
1869         IceDisposeCompleteMessage (iceConn, pStart);
1870         return (0);
1871     }
1872
1873     pData = pStart;
1874
1875     if (iceConn->process_msg_info &&
1876         (int) message->protocolOpcode >= iceConn->his_min_opcode &&
1877         (int) message->protocolOpcode <= iceConn->his_max_opcode &&
1878         iceConn->process_msg_info[
1879         message->protocolOpcode - iceConn->his_min_opcode].in_use)
1880     {
1881         _IceErrorMajorOpcodeDuplicate (iceConn, message->protocolOpcode);
1882         IceDisposeCompleteMessage (iceConn, pStart);
1883         return (0);
1884     }
1885
1886     EXTRACT_STRING (pData, swap, protocolName);
1887
1888     if (iceConn->process_msg_info)
1889     {
1890         for (i = 0;
1891             i <= (iceConn->his_max_opcode - iceConn->his_min_opcode); i++)
1892         {
1893             if (iceConn->process_msg_info[i].in_use && strcmp (protocolName,
1894                 iceConn->process_msg_info[i].protocol->protocol_name) == 0)
1895             {
1896                 _IceErrorProtocolDuplicate (iceConn, protocolName);
1897                 free (protocolName);
1898                 IceDisposeCompleteMessage (iceConn, pStart);
1899                 return (0);
1900             }
1901         }
1902     }
1903
1904     for (i = 0; i < _IceLastMajorOpcode; i++)
1905         if (strcmp (protocolName, _IceProtocols[i].protocol_name) == 0)
1906             break;
1907
1908     if (i < _IceLastMajorOpcode &&
1909         (myProtocol = _IceProtocols[i].accept_client) != NULL)
1910     {
1911         hisOpcode = message->protocolOpcode;
1912         myOpcode = i + 1;
1913         free (protocolName);
1914     }
1915     else
1916     {
1917         _IceErrorUnknownProtocol (iceConn, protocolName);
1918         free (protocolName);
1919         IceDisposeCompleteMessage (iceConn, pStart);
1920         return (0);
1921     }
1922
1923     EXTRACT_STRING (pData, swap, vendor);
1924     EXTRACT_STRING (pData, swap, release);
1925
1926     if ((hisAuthCount = message->authCount) > 0)
1927     {
1928         hisAuthNames = (char **) malloc (hisAuthCount * sizeof (char *));
1929         EXTRACT_LISTOF_STRING (pData, swap, hisAuthCount, hisAuthNames);
1930     }
1931
1932     hisVersionCount = message->versionCount;
1933     myVersionCount = myProtocol->version_count;
1934
1935     hisVersionIndex = myVersionIndex = found = 0;
1936
1937     for (i = 0; i < hisVersionCount && !found; i++)
1938     {
1939         EXTRACT_CARD16 (pData, swap, hisMajorVersion);
1940         EXTRACT_CARD16 (pData, swap, hisMinorVersion);
1941
1942         for (j = 0; j < myVersionCount && !found; j++)
1943         {
1944             if (myProtocol->version_recs[j].major_version == hisMajorVersion &&
1945                 myProtocol->version_recs[j].minor_version == hisMinorVersion)
1946             {
1947                 hisVersionIndex = i;
1948                 myVersionIndex = j;
1949                 found = 1;
1950             }
1951         }
1952     }
1953
1954     if (!found)
1955     {
1956         _IceErrorNoVersion (iceConn, ICE_ProtocolSetup);
1957
1958         free (vendor);
1959         free (release);
1960
1961         if (hisAuthCount > 0)
1962         {
1963             for (i = 0; i < hisAuthCount; i++)
1964                 free (hisAuthNames[i]);
1965         
1966             free ((char *) hisAuthNames);
1967         }
1968
1969         IceDisposeCompleteMessage (iceConn, pStart);
1970         return (0);
1971     }
1972
1973     myAuthCount = myProtocol->auth_count;
1974
1975     _IceGetPaValidAuthIndices (
1976         _IceProtocols[myOpcode - 1].protocol_name,
1977         iceConn->connection_string, myAuthCount, myProtocol->auth_names,
1978         &authUsableCount, authIndices);
1979
1980     for (i = 0; i < myAuthCount; i++)
1981     {
1982         authUsableFlags[i] = 0;
1983         for (j = 0; j < authUsableCount && !authUsableFlags[i]; j++)
1984             authUsableFlags[i] = (authIndices[j] == i);
1985     }
1986
1987     for (i = found = 0; i < myAuthCount && !found; i++)
1988     {
1989         if (authUsableFlags[i])
1990         {
1991             myAuthName = myProtocol->auth_names[i];
1992
1993             for (j = 0; j < hisAuthCount && !found; j++)
1994                 if (strcmp (myAuthName, hisAuthNames[j]) == 0)
1995                 {
1996                     myAuthIndex = i;
1997                     hisAuthIndex = j;
1998                     found = 1;
1999                 }
2000         }
2001     }
2002
2003     if (!found)
2004     {
2005         /*
2006          * None of the authentication methods specified by the
2007          * other client is supported.  If the other client requires
2008          * authentication, we must reject the Protocol Setup now.
2009          * Otherwise, we can invoke the host-based authentication callback
2010          * to see if we can accept this Protocol Setup.
2011          */
2012
2013         if (mustAuthenticate || !myProtocol->host_based_auth_proc)
2014         {
2015             _IceErrorNoAuthentication (iceConn, ICE_ProtocolSetup);
2016         }
2017         else
2018         {
2019             char *hostname = _IceGetPeerName (iceConn);
2020
2021             if ((*myProtocol->host_based_auth_proc) (hostname))
2022             {
2023                 accept_setup_now = 1;
2024             }
2025             else 
2026             {
2027                 _IceErrorAuthenticationRejected (iceConn,
2028                     ICE_ProtocolSetup, "None of the authentication protocols specified are supported and host-based authentication failed");
2029             }
2030
2031             if (hostname)
2032                 free (hostname);
2033         }
2034     }
2035     else
2036     {
2037         IcePaAuthStatus status;
2038         int             authDataLen;
2039         IcePointer      authData = NULL;
2040         IcePointer      authState;
2041         char            *errorString = NULL;
2042         IcePaAuthProc   authProc =
2043                 myProtocol->auth_procs[myAuthIndex];
2044
2045         authState = NULL;
2046
2047         status = (*authProc) (iceConn, &authState, swap, 0, NULL,
2048             &authDataLen, &authData, &errorString);
2049
2050         if (status == IcePaAuthContinue)
2051         {
2052             _IceProtoSetupToMeInfo *setupInfo;
2053
2054             AuthRequired (iceConn, hisAuthIndex, authDataLen, authData);
2055          
2056             iceConn->protosetup_to_me = setupInfo =
2057                 (_IceProtoSetupToMeInfo *) malloc (
2058                 sizeof (_IceProtoSetupToMeInfo));
2059
2060             setupInfo->his_opcode = hisOpcode;
2061             setupInfo->my_opcode = myOpcode;
2062             setupInfo->my_version_index = myVersionIndex;
2063             setupInfo->his_version_index = hisVersionIndex;
2064             setupInfo->his_vendor = vendor;
2065             setupInfo->his_release = release;
2066             vendor = release = NULL;   /* so we don't free it */
2067             setupInfo->my_auth_index = myAuthIndex;
2068             setupInfo->my_auth_state = authState;
2069             setupInfo->must_authenticate = mustAuthenticate;
2070         }
2071         else if (status == IcePaAuthAccepted)
2072         {
2073             accept_setup_now = 1;
2074         }
2075
2076         if (authData && authDataLen > 0)
2077             free ((char *) authData);
2078
2079         if (errorString)
2080             free (errorString);
2081     }
2082
2083     if (accept_setup_now)
2084     {
2085         IcePaProcessMsgProc             processMsgProc;
2086         IceProtocolSetupProc            protocolSetupProc;
2087         IceProtocolActivateProc         protocolActivateProc;
2088         _IceProcessMsgInfo              *process_msg_info;
2089         IcePointer                      clientData = NULL;
2090         char                            *failureReason = NULL;
2091         Status                          status = 1;
2092
2093         protocolSetupProc = myProtocol->protocol_setup_proc;
2094         protocolActivateProc = myProtocol->protocol_activate_proc;
2095
2096         if (protocolSetupProc)
2097         {
2098             /*
2099              * Notify the client of the Protocol Setup.
2100              */
2101
2102             status = (*protocolSetupProc) (iceConn,
2103                 myProtocol->version_recs[myVersionIndex].major_version,
2104                 myProtocol->version_recs[myVersionIndex].minor_version,
2105                 vendor, release, &clientData, &failureReason);
2106
2107             vendor = release = NULL;   /* so we don't free it */
2108         }
2109
2110         if (status != 0)
2111         {
2112             /*
2113              * Send the Protocol Reply
2114              */
2115
2116             AcceptProtocol (iceConn, hisOpcode, myOpcode, hisVersionIndex,
2117                 myProtocol->vendor, myProtocol->release);
2118
2119
2120             /*
2121              * Set info for this protocol.
2122              */
2123
2124             processMsgProc = myProtocol->version_recs[
2125                 myVersionIndex].process_msg_proc;
2126
2127             process_msg_info = &iceConn->process_msg_info[hisOpcode -
2128                 iceConn->his_min_opcode];
2129
2130             process_msg_info->client_data = clientData;
2131             process_msg_info->accept_flag = 1;
2132             process_msg_info->process_msg_proc.accept_client = processMsgProc;
2133
2134
2135             /*
2136              * Increase the reference count for the number of active protocols.
2137              */
2138
2139             iceConn->proto_ref_count++;
2140
2141
2142             /*
2143              * Notify the client that the protocol is active.  The reason
2144              * we have this 2nd callback invoked is because the client
2145              * may wish to immediately generate a message for this
2146              * protocol, but it must wait until we send the Protocol Reply.
2147              */
2148
2149             if (protocolActivateProc)
2150             {
2151                 (*protocolActivateProc) (iceConn,
2152                     process_msg_info->client_data);
2153             }
2154         }
2155         else
2156         {
2157             /*
2158              * An error was encountered.
2159              */
2160
2161             _IceErrorSetupFailed (iceConn, ICE_ProtocolSetup, failureReason);
2162
2163             if (failureReason)
2164                 free (failureReason);
2165         }
2166     }
2167
2168     if (vendor)
2169         free (vendor);
2170
2171     if (release)
2172         free (release);
2173
2174     if (hisAuthCount > 0)
2175     {
2176         for (i = 0; i < hisAuthCount; i++)
2177             free (hisAuthNames[i]);
2178
2179         free ((char *) hisAuthNames);
2180     }
2181
2182     IceDisposeCompleteMessage (iceConn, pStart);
2183     return (0);
2184 }
2185
2186
2187 \f
2188 static Bool
2189 ProcessProtocolReply (
2190         IceConn                 iceConn,
2191         unsigned long           length,
2192         Bool                    swap,
2193         IceReplyWaitInfo        *replyWait
2194 )
2195 {
2196     iceProtocolReplyMsg *message;
2197     char                *pData, *pStart, *pEnd;
2198     Bool                replyReady;
2199
2200 #if 0 /* No-op */
2201     CHECK_AT_LEAST_SIZE (iceConn, ICE_ProtocolReply,
2202         length, SIZEOF (iceProtocolReplyMsg), IceFatalToProtocol);
2203 #endif
2204
2205     IceReadCompleteMessage (iceConn, SIZEOF (iceProtocolReplyMsg),
2206         iceProtocolReplyMsg, message, pStart);
2207
2208     if (!IceValidIO (iceConn))
2209     {
2210         IceDisposeCompleteMessage (iceConn, pStart);
2211         return (0);
2212     }
2213
2214     pData = pStart;
2215     pEnd = pStart + (length << 3);
2216
2217     SKIP_STRING (pData, swap, pEnd,
2218                  BAIL_STRING(iceConn, ICE_ProtocolReply,
2219                              pStart));                       /* vendor */
2220     SKIP_STRING (pData, swap, pEnd,
2221                  BAIL_STRING(iceConn, ICE_ProtocolReply,
2222                              pStart));                       /* release */
2223
2224     CHECK_COMPLETE_SIZE (iceConn, ICE_ProtocolReply,
2225         length, pData - pStart + SIZEOF (iceProtocolReplyMsg),
2226         pStart, IceFatalToProtocol);
2227
2228     pData = pStart;
2229
2230     if (iceConn->protosetup_to_you)
2231     {
2232         if (iceConn->protosetup_to_you->auth_active)
2233         {
2234             /*
2235              * Tell the authentication procedure to clean up.
2236              */
2237
2238             _IcePoProtocol *myProtocol = _IceProtocols[
2239                 iceConn->protosetup_to_you->my_opcode - 1].orig_client;
2240
2241             IcePoAuthProc authProc = myProtocol->auth_procs[(int)
2242                 (iceConn->protosetup_to_you->my_auth_index)];
2243
2244 #ifdef SVR4
2245
2246 /*
2247  * authProc is never NULL, but the cc compiler on UNIX System V/386
2248  * Release 4.2 Version 1 screws up an optimization.  Unless there is
2249  * some sort of reference to authProc before the function call, the
2250  * function call will seg fault.
2251  */
2252             if (authProc)
2253 #endif
2254                 (*authProc) (iceConn,
2255                 &iceConn->protosetup_to_you->my_auth_state,
2256                 True /* clean up */, False /* swap */,
2257                 0, NULL, NULL, NULL, NULL);
2258         }
2259
2260         if ((int) message->versionIndex >= _IceVersionCount)
2261         {
2262             _IceProtocolError *errorReply =
2263                 &(((_IceReply *) (replyWait->reply))->protocol_error);
2264             char errIndex = message->versionIndex;
2265
2266             _IceErrorBadValue (iceConn, 0,
2267                 ICE_ProtocolReply, 2, 1, &errIndex);
2268             
2269             errorReply->type = ICE_PROTOCOL_ERROR;
2270             errorReply->error_message =
2271                 "Received bad version index in Protocol Reply";
2272         }
2273         else
2274         {
2275             _IceProtocolReply *reply = 
2276                 &(((_IceReply *) (replyWait->reply))->protocol_reply);
2277
2278             reply->type = ICE_PROTOCOL_REPLY;
2279             reply->major_opcode = message->protocolOpcode;
2280             reply->version_index = message->versionIndex;
2281
2282             EXTRACT_STRING (pData, swap, reply->vendor);
2283             EXTRACT_STRING (pData, swap, reply->release);
2284         }
2285
2286         replyReady = True;
2287     }
2288     else
2289     {
2290         _IceErrorBadState (iceConn, 0, ICE_ProtocolReply, IceCanContinue);
2291
2292         replyReady = False;
2293     }
2294
2295     IceDisposeCompleteMessage (iceConn, pStart);
2296
2297     return (replyReady);
2298 }
2299
2300
2301 \f
2302 static int
2303 ProcessPing (
2304         IceConn         iceConn,
2305         unsigned long   length
2306 )
2307 {
2308     CHECK_SIZE_MATCH (iceConn, ICE_Ping,
2309         length, SIZEOF (icePingMsg), IceFatalToConnection, 0);
2310
2311     PingReply (iceConn);
2312
2313     return (0);
2314 }
2315
2316
2317 \f
2318 static int
2319 ProcessPingReply (
2320         IceConn         iceConn,
2321         unsigned long   length
2322 )
2323 {
2324     CHECK_SIZE_MATCH (iceConn, ICE_PingReply,
2325         length, SIZEOF (icePingReplyMsg), IceFatalToConnection, 0);
2326
2327     if (iceConn->ping_waits)
2328     {
2329         _IcePingWait *next = iceConn->ping_waits->next;
2330         
2331         (*iceConn->ping_waits->ping_reply_proc) (iceConn,
2332             iceConn->ping_waits->client_data);
2333
2334         free ((char *) iceConn->ping_waits);
2335         iceConn->ping_waits = next;
2336     }
2337     else
2338     {
2339         _IceErrorBadState (iceConn, 0, ICE_PingReply, IceCanContinue);
2340     }
2341
2342     return (0);
2343 }
2344
2345
2346 \f
2347 static int
2348 ProcessWantToClose (
2349         IceConn         iceConn,
2350         unsigned long   length,
2351         Bool            *connectionClosedRet
2352 )
2353 {
2354     *connectionClosedRet = False;
2355
2356     CHECK_SIZE_MATCH (iceConn, ICE_WantToClose,
2357         length, SIZEOF (iceWantToCloseMsg), IceFatalToConnection, 0);
2358
2359     if (iceConn->want_to_close || iceConn->open_ref_count == 0)
2360     {
2361         /*
2362          * We just received a WantToClose.  Either we also sent a
2363          * WantToClose, so we close the connection, or the iceConn
2364          * is not being used, so we close the connection.  This
2365          * second case is possible if we sent a WantToClose because
2366          * the iceConn->open_ref_count reached zero, but then we
2367          * received a NoClose.
2368          */
2369
2370         _IceConnectionClosed (iceConn);         /* invoke watch procs */
2371         _IceFreeConnection (iceConn);
2372         *connectionClosedRet = True;
2373     }
2374     else if (iceConn->proto_ref_count > 0)
2375     {
2376         /*
2377          * We haven't shut down all of our protocols yet.  We send a NoClose,
2378          * and it's up to us to generate a WantToClose later on.
2379          */
2380
2381         IceSimpleMessage (iceConn, 0, ICE_NoClose);
2382         IceFlush (iceConn);
2383     }
2384     else
2385     {
2386         /*
2387          * The reference count on this iceConn is zero.  This means that
2388          * there are no active protocols, but the client didn't explicitly
2389          * close the connection yet.  If we didn't just send a Protocol Setup,
2390          * we send a NoClose, and it's up to us to generate a WantToClose
2391          * later on.
2392          */
2393
2394         if (!iceConn->protosetup_to_you)
2395         {
2396             IceSimpleMessage (iceConn, 0, ICE_NoClose);
2397             IceFlush (iceConn);
2398         }
2399     }
2400
2401     return (0);
2402 }
2403
2404
2405 \f
2406 static int
2407 ProcessNoClose (
2408         IceConn         iceConn,
2409         unsigned long   length
2410 )
2411 {
2412     CHECK_SIZE_MATCH (iceConn, ICE_NoClose,
2413         length, SIZEOF (iceNoCloseMsg), IceFatalToConnection, 0);
2414
2415     if (iceConn->want_to_close)
2416     {
2417         /*
2418          * The other side can't close now.  We cancel our WantToClose,
2419          * and we can expect a WantToClose from the other side.
2420          */
2421
2422         iceConn->want_to_close = 0;
2423     }
2424     else
2425     {
2426         _IceErrorBadState (iceConn, 0, ICE_NoClose, IceCanContinue);
2427     }
2428
2429     return (0);
2430 }
2431
2432
2433 \f
2434 static void
2435 _IceProcessCoreMessage (
2436         IceConn          iceConn,
2437         int              opcode,
2438         unsigned long    length,
2439         Bool             swap,
2440         IceReplyWaitInfo *replyWait,
2441         Bool             *replyReadyRet,
2442         Bool             *connectionClosedRet
2443 )
2444 {
2445     Bool replyReady = False;
2446
2447     *connectionClosedRet = False;
2448
2449     switch (opcode)
2450     {
2451     case ICE_Error:
2452
2453         replyReady = ProcessError (iceConn, length, swap, replyWait);
2454         break;
2455
2456     case ICE_ConnectionSetup:
2457
2458         ProcessConnectionSetup (iceConn, length, swap);
2459         break;
2460
2461     case ICE_AuthRequired:
2462
2463         replyReady = ProcessAuthRequired (iceConn, length, swap, replyWait);
2464         break;
2465
2466     case ICE_AuthReply:
2467
2468         ProcessAuthReply (iceConn, length, swap);
2469         break;
2470
2471     case ICE_AuthNextPhase:
2472
2473         replyReady = ProcessAuthNextPhase (iceConn, length, swap, replyWait);
2474         break;
2475
2476     case ICE_ConnectionReply:
2477
2478         replyReady = ProcessConnectionReply (iceConn, length, swap, replyWait);
2479         break;
2480
2481     case ICE_ProtocolSetup:
2482
2483         ProcessProtocolSetup (iceConn, length, swap);
2484         break;
2485
2486     case ICE_ProtocolReply:
2487
2488         replyReady = ProcessProtocolReply (iceConn, length, swap, replyWait);
2489         break;
2490
2491     case ICE_Ping:
2492
2493         ProcessPing (iceConn, length);
2494         break;
2495
2496     case ICE_PingReply:
2497
2498         ProcessPingReply (iceConn, length);
2499         break;
2500
2501     case ICE_WantToClose:
2502
2503         ProcessWantToClose (iceConn, length, connectionClosedRet);
2504         break;
2505
2506     case ICE_NoClose:
2507
2508         ProcessNoClose (iceConn, length);
2509         break;
2510
2511     default:
2512
2513         _IceErrorBadMinor (iceConn, 0, opcode, IceCanContinue);
2514         _IceReadSkip (iceConn, length << 3);
2515         break;
2516     }
2517
2518     if (replyWait)
2519         *replyReadyRet = replyReady;
2520 }
2521
2522 int             _IceVersionCount = 1;
2523 _IceVersion     _IceVersions[] = {
2524                     {IceProtoMajor, IceProtoMinor, _IceProcessCoreMessage}};
2525