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