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 
36 IceProtocolSetupStatus
IceProtocolSetup(IceConn iceConn,int myOpcode,IcePointer clientData,Bool mustAuthenticate,int * majorVersionRet,int * minorVersionRet,char ** vendorRet,char ** releaseRet,int errorLength,char * errorStringRet)37 IceProtocolSetup (
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 	if (errorStringRet && errorLength > 0) {
75 	    strncpy (errorStringRet, "myOpcode out of range", errorLength);
76 	    errorStringRet[errorLength - 1] = '\0';
77 	}
78 	return (IceProtocolSetupFailure);
79     }
80 
81     myProtocol = &_IceProtocols[myOpcode - 1];
82 
83     if (myProtocol->orig_client == NULL)
84     {
85 	if (errorStringRet && errorLength > 0) {
86 	    strncpy (errorStringRet,
87 		"IceRegisterForProtocolSetup was not called", errorLength);
88 	    errorStringRet[errorLength - 1] = '\0';
89 	}
90 	return (IceProtocolSetupFailure);
91     }
92 
93 
94     /*
95      * Make sure this protocol hasn't been activated already.
96      */
97 
98     if (iceConn->process_msg_info)
99     {
100 	for (i = iceConn->his_min_opcode; i <= iceConn->his_max_opcode; i++)
101 	{
102 	    if (iceConn->process_msg_info[
103 		i - iceConn->his_min_opcode].in_use &&
104                 iceConn->process_msg_info[
105 		i - iceConn->his_min_opcode ].my_opcode == myOpcode)
106 		break;
107 	}
108 
109 	if (i <= iceConn->his_max_opcode)
110 	{
111 	    return (IceProtocolAlreadyActive);
112 	}
113     }
114 
115     /*
116      * Generate the message.
117      */
118 
119     if (myProtocol->orig_client->auth_count > 0)
120     {
121 	authIndices = malloc (
122 	    myProtocol->orig_client->auth_count * sizeof (int));
123 
124 	_IceGetPoValidAuthIndices (myProtocol->protocol_name,
125 	    iceConn->connection_string,
126 	    myProtocol->orig_client->auth_count,
127 	    (const char **) myProtocol->orig_client->auth_names,
128             &authCount, authIndices);
129 
130     }
131     else
132     {
133 	authCount = 0;
134 	authIndices = NULL;
135     }
136 
137     extra = STRING_BYTES (myProtocol->protocol_name) +
138             STRING_BYTES (myProtocol->orig_client->vendor) +
139             STRING_BYTES (myProtocol->orig_client->release);
140 
141     for (i = 0; i < authCount; i++)
142     {
143 	extra += STRING_BYTES (myProtocol->orig_client->auth_names[
144 	    authIndices[i]]);
145     }
146 
147     extra += (myProtocol->orig_client->version_count * 4);
148 
149     IceGetHeaderExtra (iceConn, 0, ICE_ProtocolSetup,
150 	SIZEOF (iceProtocolSetupMsg), WORD64COUNT (extra),
151 	iceProtocolSetupMsg, pMsg, pData);
152 
153     setup_sequence = iceConn->send_sequence;
154 
155     pMsg->protocolOpcode = myOpcode;
156     pMsg->versionCount = myProtocol->orig_client->version_count;
157     pMsg->authCount = authCount;
158     pMsg->mustAuthenticate = mustAuthenticate;
159 
160     STORE_STRING (pData, myProtocol->protocol_name);
161     STORE_STRING (pData, myProtocol->orig_client->vendor);
162     STORE_STRING (pData, myProtocol->orig_client->release);
163 
164     for (i = 0; i < authCount; i++)
165     {
166 	STORE_STRING (pData, myProtocol->orig_client->auth_names[
167 	    authIndices[i]]);
168     }
169 
170     for (i = 0; i < myProtocol->orig_client->version_count; i++)
171     {
172 	STORE_CARD16 (pData,
173 	    myProtocol->orig_client->version_recs[i].major_version);
174 	STORE_CARD16 (pData,
175 	    myProtocol->orig_client->version_recs[i].minor_version);
176     }
177 
178     IceFlush (iceConn);
179 
180 
181     /*
182      * Process messages until we get a Protocol Reply.
183      */
184 
185     replyWait.sequence_of_request = setup_sequence;
186     replyWait.major_opcode_of_request = 0;
187     replyWait.minor_opcode_of_request = ICE_ProtocolSetup;
188     replyWait.reply = (IcePointer) &reply;
189 
190     iceConn->protosetup_to_you = malloc (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 	    if (errorStringRet && errorLength > 0) {
208 		strncpy (errorStringRet,
209 		    "IO error occured doing Protocol Setup on connection",
210 		    errorLength);
211 		errorStringRet[errorLength - 1] = '\0';
212 	    }
213 	    return (IceProtocolSetupIOError);
214 	}
215 	else if (gotReply)
216 	{
217 	    if (reply.type == ICE_PROTOCOL_REPLY)
218 	    {
219 		if (reply.protocol_reply.version_index >=
220 		    myProtocol->orig_client->version_count)
221 		{
222 		    if (errorStringRet && errorLength > 0) {
223 			strncpy (errorStringRet,
224 	                    "Got a bad version index in the Protocol Reply",
225 		            errorLength);
226 			errorStringRet[errorLength - 1] = '\0';
227 		    }
228 
229 		    free (reply.protocol_reply.vendor);
230 		    free (reply.protocol_reply.release);
231 		}
232 		else
233 		{
234 		    versionRec = &(myProtocol->orig_client->version_recs[
235 		        reply.protocol_reply.version_index]);
236 
237 		    accepted = 1;
238 		}
239 	    }
240 	    else /* reply.type == ICE_PROTOCOL_ERROR */
241 	    {
242 		/* Protocol Setup failed */
243 
244 		if (errorStringRet && errorLength > 0) {
245 		    strncpy (errorStringRet, reply.protocol_error.error_message,
246 			errorLength);
247 		    errorStringRet[errorLength - 1] = '\0';
248 		}
249 
250 		free (reply.protocol_error.error_message);
251 	    }
252 
253 	    if (iceConn->protosetup_to_you->my_auth_indices)
254 		free (iceConn->protosetup_to_you->my_auth_indices);
255 	    free (iceConn->protosetup_to_you);
256 	    iceConn->protosetup_to_you = NULL;
257 	}
258     }
259 
260     if (accepted)
261     {
262 	_IceProcessMsgInfo *process_msg_info;
263 
264 	*majorVersionRet = versionRec->major_version;
265 	*minorVersionRet = versionRec->minor_version;
266 	*vendorRet = reply.protocol_reply.vendor;
267 	*releaseRet = reply.protocol_reply.release;
268 
269 
270 	/*
271 	 * Increase the reference count for the number of active protocols.
272 	 */
273 
274 	iceConn->proto_ref_count++;
275 
276 
277 	/*
278 	 * We may be using a different major opcode for this protocol
279 	 * than the other client.  Whenever we get a message, we must
280 	 * map to our own major opcode.
281 	 */
282 
283 	hisOpcode = reply.protocol_reply.major_opcode;
284 
285 	_IceAddOpcodeMapping (iceConn, hisOpcode, myOpcode);
286 
287 	process_msg_info = &iceConn->process_msg_info[hisOpcode -
288 	    iceConn->his_min_opcode];
289 
290 	process_msg_info->client_data = clientData;
291 	process_msg_info->accept_flag = 0;
292 
293 	process_msg_info->process_msg_proc.orig_client =
294 		versionRec->process_msg_proc;
295 
296 	return (IceProtocolSetupSuccess);
297     }
298     else
299     {
300 	return (IceProtocolSetupFailure);
301     }
302 }
303