protosetup.c revision 266e564d
1/* $Xorg: protosetup.c,v 1.4 2001/02/09 02:03:26 xorgcvs Exp $ */
2/******************************************************************************
3
4
5Copyright 1993, 1998  The Open Group
6
7Permission to use, copy, modify, distribute, and sell this software and its
8documentation for any purpose is hereby granted without fee, provided that
9the above copyright notice appear in all copies and that both that
10copyright notice and this permission notice appear in supporting
11documentation.
12
13The above copyright notice and this permission notice shall be included in
14all copies or substantial portions of the Software.
15
16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
19OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
20AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
23Except as contained in this notice, the name of The Open Group shall not be
24used in advertising or otherwise to promote the sale, use or other dealings
25in this Software without prior written authorization from The Open Group.
26
27Author: Ralph Mor, X Consortium
28******************************************************************************/
29/* $XFree86: xc/lib/ICE/protosetup.c,v 1.2 2001/10/28 03:32:28 tsi Exp $ */
30
31#ifdef HAVE_CONFIG_H
32#include <config.h>
33#endif
34#include <X11/ICE/ICElib.h>
35#include "ICElibint.h"
36
37
38IceProtocolSetupStatus
39IceProtocolSetup (iceConn, myOpcode, clientData, mustAuthenticate,
40    majorVersionRet, minorVersionRet, vendorRet, releaseRet,
41    errorLength, errorStringRet)
42
43IceConn	   iceConn;
44int 	   myOpcode;
45IcePointer clientData;
46Bool       mustAuthenticate;
47int	   *majorVersionRet;
48int	   *minorVersionRet;
49char	   **vendorRet;
50char	   **releaseRet;
51int  	   errorLength;
52char 	   *errorStringRet;
53
54{
55    iceProtocolSetupMsg	*pMsg;
56    char		*pData;
57    _IceProtocol	*myProtocol;
58    int			extra;
59    Bool		gotReply, ioErrorOccured;
60    int			accepted, i;
61    int			hisOpcode;
62    unsigned long	setup_sequence;
63    IceReplyWaitInfo 	replyWait;
64    _IceReply		reply;
65    IcePoVersionRec	*versionRec = NULL;
66    int			authCount;
67    int			*authIndices;
68
69    if (errorStringRet && errorLength > 0)
70	*errorStringRet = '\0';
71
72    *majorVersionRet = 0;
73    *minorVersionRet = 0;
74    *vendorRet = NULL;
75    *releaseRet = NULL;
76
77    if (myOpcode < 1 || myOpcode > _IceLastMajorOpcode)
78    {
79	strncpy (errorStringRet, "myOpcode out of range", errorLength);
80	return (IceProtocolSetupFailure);
81    }
82
83    myProtocol = &_IceProtocols[myOpcode - 1];
84
85    if (myProtocol->orig_client == NULL)
86    {
87	strncpy (errorStringRet,
88	    "IceRegisterForProtocolSetup was not called", errorLength);
89	return (IceProtocolSetupFailure);
90    }
91
92
93    /*
94     * Make sure this protocol hasn't been activated already.
95     */
96
97    if (iceConn->process_msg_info)
98    {
99	for (i = iceConn->his_min_opcode; i <= iceConn->his_max_opcode; i++)
100	{
101	    if (iceConn->process_msg_info[
102		i - iceConn->his_min_opcode].in_use &&
103                iceConn->process_msg_info[
104		i - iceConn->his_min_opcode ].my_opcode == myOpcode)
105		break;
106	}
107
108	if (i <= iceConn->his_max_opcode)
109	{
110	    return (IceProtocolAlreadyActive);
111	}
112    }
113
114    /*
115     * Generate the message.
116     */
117
118    if (myProtocol->orig_client->auth_count > 0)
119    {
120	authIndices = (int *) malloc (
121	    myProtocol->orig_client->auth_count * sizeof (int));
122
123	_IceGetPoValidAuthIndices (myProtocol->protocol_name,
124	    iceConn->connection_string,
125	    myProtocol->orig_client->auth_count,
126	    myProtocol->orig_client->auth_names,
127            &authCount, authIndices);
128
129    }
130    else
131    {
132	authCount = 0;
133	authIndices = NULL;
134    }
135
136    extra = STRING_BYTES (myProtocol->protocol_name) +
137            STRING_BYTES (myProtocol->orig_client->vendor) +
138            STRING_BYTES (myProtocol->orig_client->release);
139
140    for (i = 0; i < authCount; i++)
141    {
142	extra += STRING_BYTES (myProtocol->orig_client->auth_names[
143	    authIndices[i]]);
144    }
145
146    extra += (myProtocol->orig_client->version_count * 4);
147
148    IceGetHeaderExtra (iceConn, 0, ICE_ProtocolSetup,
149	SIZEOF (iceProtocolSetupMsg), WORD64COUNT (extra),
150	iceProtocolSetupMsg, pMsg, pData);
151
152    setup_sequence = iceConn->send_sequence;
153
154    pMsg->protocolOpcode = myOpcode;
155    pMsg->versionCount = myProtocol->orig_client->version_count;
156    pMsg->authCount = authCount;
157    pMsg->mustAuthenticate = mustAuthenticate;
158
159    STORE_STRING (pData, myProtocol->protocol_name);
160    STORE_STRING (pData, myProtocol->orig_client->vendor);
161    STORE_STRING (pData, myProtocol->orig_client->release);
162
163    for (i = 0; i < authCount; i++)
164    {
165	STORE_STRING (pData, myProtocol->orig_client->auth_names[
166	    authIndices[i]]);
167    }
168
169    for (i = 0; i < myProtocol->orig_client->version_count; i++)
170    {
171	STORE_CARD16 (pData,
172	    myProtocol->orig_client->version_recs[i].major_version);
173	STORE_CARD16 (pData,
174	    myProtocol->orig_client->version_recs[i].minor_version);
175    }
176
177    IceFlush (iceConn);
178
179
180    /*
181     * Process messages until we get a Protocol Reply.
182     */
183
184    replyWait.sequence_of_request = setup_sequence;
185    replyWait.major_opcode_of_request = 0;
186    replyWait.minor_opcode_of_request = ICE_ProtocolSetup;
187    replyWait.reply = (IcePointer) &reply;
188
189    iceConn->protosetup_to_you = (_IceProtoSetupToYouInfo *) malloc (
190	sizeof (_IceProtoSetupToYouInfo));
191    iceConn->protosetup_to_you->my_opcode = myOpcode;
192    iceConn->protosetup_to_you->my_auth_count = authCount;
193    iceConn->protosetup_to_you->auth_active = 0;
194    iceConn->protosetup_to_you->my_auth_indices = authIndices;
195
196    gotReply = False;
197    ioErrorOccured = False;
198    accepted = 0;
199
200    while (!gotReply && !ioErrorOccured)
201    {
202	ioErrorOccured = (IceProcessMessages (
203	    iceConn, &replyWait, &gotReply) == IceProcessMessagesIOError);
204
205	if (ioErrorOccured)
206	{
207	    strncpy (errorStringRet,
208		"IO error occured doing Protocol Setup on connection",
209		errorLength);
210	    return (IceProtocolSetupIOError);
211	}
212	else if (gotReply)
213	{
214	    if (reply.type == ICE_PROTOCOL_REPLY)
215	    {
216		if (reply.protocol_reply.version_index >=
217		    myProtocol->orig_client->version_count)
218		{
219		    strncpy (errorStringRet,
220	                "Got a bad version index in the Protocol Reply",
221		        errorLength);
222
223		    free (reply.protocol_reply.vendor);
224		    free (reply.protocol_reply.release);
225		}
226		else
227		{
228		    versionRec = &(myProtocol->orig_client->version_recs[
229		        reply.protocol_reply.version_index]);
230
231		    accepted = 1;
232		}
233	    }
234	    else /* reply.type == ICE_PROTOCOL_ERROR */
235	    {
236		/* Protocol Setup failed */
237
238		strncpy (errorStringRet, reply.protocol_error.error_message,
239		    errorLength);
240
241		free (reply.protocol_error.error_message);
242	    }
243
244	    if (iceConn->protosetup_to_you->my_auth_indices)
245		free ((char *) iceConn->protosetup_to_you->my_auth_indices);
246	    free ((char *) iceConn->protosetup_to_you);
247	    iceConn->protosetup_to_you = NULL;
248	}
249    }
250
251    if (accepted)
252    {
253	_IceProcessMsgInfo *process_msg_info;
254
255	*majorVersionRet = versionRec->major_version;
256	*minorVersionRet = versionRec->minor_version;
257	*vendorRet = reply.protocol_reply.vendor;
258	*releaseRet = reply.protocol_reply.release;
259
260
261	/*
262	 * Increase the reference count for the number of active protocols.
263	 */
264
265	iceConn->proto_ref_count++;
266
267
268	/*
269	 * We may be using a different major opcode for this protocol
270	 * than the other client.  Whenever we get a message, we must
271	 * map to our own major opcode.
272	 */
273
274	hisOpcode = reply.protocol_reply.major_opcode;
275
276	_IceAddOpcodeMapping (iceConn, hisOpcode, myOpcode);
277
278	process_msg_info = &iceConn->process_msg_info[hisOpcode -
279	    iceConn->his_min_opcode];
280
281	process_msg_info->client_data = clientData;
282	process_msg_info->accept_flag = 0;
283
284	process_msg_info->process_msg_proc.orig_client =
285		versionRec->process_msg_proc;
286
287	return (IceProtocolSetupSuccess);
288    }
289    else
290    {
291	return (IceProtocolSetupFailure);
292    }
293}
294