protosetup.c revision d17cd367
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 = (int *) 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	    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 = (_IceProtoSetupToYouInfo *) malloc (
185	sizeof (_IceProtoSetupToYouInfo));
186    iceConn->protosetup_to_you->my_opcode = myOpcode;
187    iceConn->protosetup_to_you->my_auth_count = authCount;
188    iceConn->protosetup_to_you->auth_active = 0;
189    iceConn->protosetup_to_you->my_auth_indices = authIndices;
190
191    gotReply = False;
192    ioErrorOccured = False;
193    accepted = 0;
194
195    while (!gotReply && !ioErrorOccured)
196    {
197	ioErrorOccured = (IceProcessMessages (
198	    iceConn, &replyWait, &gotReply) == IceProcessMessagesIOError);
199
200	if (ioErrorOccured)
201	{
202	    strncpy (errorStringRet,
203		"IO error occured doing Protocol Setup on connection",
204		errorLength);
205	    return (IceProtocolSetupIOError);
206	}
207	else if (gotReply)
208	{
209	    if (reply.type == ICE_PROTOCOL_REPLY)
210	    {
211		if (reply.protocol_reply.version_index >=
212		    myProtocol->orig_client->version_count)
213		{
214		    strncpy (errorStringRet,
215	                "Got a bad version index in the Protocol Reply",
216		        errorLength);
217
218		    free (reply.protocol_reply.vendor);
219		    free (reply.protocol_reply.release);
220		}
221		else
222		{
223		    versionRec = &(myProtocol->orig_client->version_recs[
224		        reply.protocol_reply.version_index]);
225
226		    accepted = 1;
227		}
228	    }
229	    else /* reply.type == ICE_PROTOCOL_ERROR */
230	    {
231		/* Protocol Setup failed */
232
233		strncpy (errorStringRet, reply.protocol_error.error_message,
234		    errorLength);
235
236		free (reply.protocol_error.error_message);
237	    }
238
239	    if (iceConn->protosetup_to_you->my_auth_indices)
240		free ((char *) iceConn->protosetup_to_you->my_auth_indices);
241	    free ((char *) iceConn->protosetup_to_you);
242	    iceConn->protosetup_to_you = NULL;
243	}
244    }
245
246    if (accepted)
247    {
248	_IceProcessMsgInfo *process_msg_info;
249
250	*majorVersionRet = versionRec->major_version;
251	*minorVersionRet = versionRec->minor_version;
252	*vendorRet = reply.protocol_reply.vendor;
253	*releaseRet = reply.protocol_reply.release;
254
255
256	/*
257	 * Increase the reference count for the number of active protocols.
258	 */
259
260	iceConn->proto_ref_count++;
261
262
263	/*
264	 * We may be using a different major opcode for this protocol
265	 * than the other client.  Whenever we get a message, we must
266	 * map to our own major opcode.
267	 */
268
269	hisOpcode = reply.protocol_reply.major_opcode;
270
271	_IceAddOpcodeMapping (iceConn, hisOpcode, myOpcode);
272
273	process_msg_info = &iceConn->process_msg_info[hisOpcode -
274	    iceConn->his_min_opcode];
275
276	process_msg_info->client_data = clientData;
277	process_msg_info->accept_flag = 0;
278
279	process_msg_info->process_msg_proc.orig_client =
280		versionRec->process_msg_proc;
281
282	return (IceProtocolSetupSuccess);
283    }
284    else
285    {
286	return (IceProtocolSetupFailure);
287    }
288}
289