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 #include <X11/Xtrans/Xtrans.h>
35 #include "globals.h"
36 
37 static XtransConnInfo ConnectToPeer(char *networkIdsList,
38 				    char **actualConnectionRet);
39 
40 IceConn
IceOpenConnection(char * networkIdsList,IcePointer context,Bool mustAuthenticate,int majorOpcodeCheck,int errorLength,char * errorStringRet)41 IceOpenConnection (
42 	char 	   *networkIdsList,
43 	IcePointer context,
44 	Bool 	   mustAuthenticate,
45 	int  	   majorOpcodeCheck,
46 	int  	   errorLength,
47 	char 	   *errorStringRet
48 )
49 {
50     IceConn			iceConn;
51     int				extra, i, j;
52     int		       		endian;
53     Bool			gotReply, ioErrorOccured;
54     unsigned long		setup_sequence;
55     iceByteOrderMsg		*pByteOrderMsg;
56     iceConnectionSetupMsg	*pSetupMsg;
57     char			*pData;
58     IceReplyWaitInfo 		replyWait;
59     _IceReply		 	reply;
60     int				authUsableCount;
61     int				authUsableFlags[MAX_ICE_AUTH_NAMES];
62     int				authIndices[MAX_ICE_AUTH_NAMES];
63 
64     if (errorStringRet && errorLength > 0)
65 	*errorStringRet = '\0';
66 
67     if (networkIdsList == NULL || *networkIdsList == '\0')
68     {
69 	if (errorStringRet && errorLength > 0) {
70 	    strncpy (errorStringRet,
71 		"networkIdsList argument is NULL", errorLength);
72 	    errorStringRet[errorLength - 1] = '\0';
73 	}
74 	return (NULL);
75     }
76 
77     /*
78      * Check to see if we can use a previously created ICE connection.
79      *
80      * If iceConn->want_to_close is True, or iceConn->free_asap is True,
81      * we can not use the iceConn.
82      *
83      * If 'context' is non-NULL, we will only use a previously opened ICE
84      * connection if the specified 'context' is equal to the context
85      * associated with the ICE connection, or if the context associated
86      * with the ICE connection is NULL.
87      *
88      * If 'majorOpcodeCheck' is non-zero, it will contain a protocol major
89      * opcode that we should make sure is not already active on the ICE
90      * connection.  Some clients will want two seperate connections for the
91      * same protocol to the same destination client.
92      */
93 
94     for (i = 0; i < _IceConnectionCount; i++)
95     {
96 	char *strptr;
97 	if ((strptr = (char *) strstr (
98 	    networkIdsList, _IceConnectionStrings[i])) != NULL)
99 	{
100 	    char ch = *(strptr + strlen (_IceConnectionStrings[i]));
101 	    if (ch == ',' || ch == '\0')
102 	    {
103 		/*
104 		 * OK, we found a connection.  Make sure we can reuse it.
105 		 */
106 
107 		IceConn iceConn = _IceConnectionObjs[i];
108 
109 		if (iceConn->want_to_close || iceConn->free_asap ||
110 		    (context && iceConn->context &&
111 		     iceConn->context != context))
112 		{
113 		    /* force a new connection to be created */
114 		    break;
115 		}
116 
117 		if (majorOpcodeCheck)
118 		{
119 		    for (j = iceConn->his_min_opcode;
120 		        j <= iceConn->his_max_opcode; j++)
121 		    {
122 			if (iceConn->process_msg_info[
123 			    j - iceConn->his_min_opcode].in_use &&
124 			    iceConn->process_msg_info[
125 			    j - iceConn->his_min_opcode].my_opcode ==
126 			    majorOpcodeCheck)
127 			    break;
128 		    }
129 
130 		    if (j <= iceConn->his_max_opcode ||
131 			(iceConn->protosetup_to_you &&
132 			iceConn->protosetup_to_you->my_opcode ==
133 			majorOpcodeCheck))
134 		    {
135 			/* force a new connection to be created */
136 			break;
137 		    }
138 		}
139 
140 		iceConn->open_ref_count++;
141 		if (context && !iceConn->context)
142 		    iceConn->context = context;
143 		return (iceConn);
144 	    }
145 	}
146     }
147 
148     if ((iceConn = malloc (sizeof (struct _IceConn))) == NULL)
149     {
150 	if (errorStringRet && errorLength > 0) {
151 	    strncpy (errorStringRet, "Can't malloc", errorLength);
152 	    errorStringRet[errorLength - 1] = '\0';
153 	}
154 	return (NULL);
155     }
156 
157 
158     /*
159      * Open a network connection with the peer client.
160      */
161 
162     if ((iceConn->trans_conn = ConnectToPeer (networkIdsList,
163 	&iceConn->connection_string)) == NULL)
164     {
165 	free (iceConn);
166 	if (errorStringRet && errorLength > 0) {
167 	    strncpy (errorStringRet, "Could not open network socket", errorLength);
168 	    errorStringRet[errorLength - 1] = '\0';
169 	}
170 	return (NULL);
171     }
172 
173     /*
174      * Set close-on-exec so that programs that fork() don't get confused.
175      */
176 
177     _IceTransSetOption (iceConn->trans_conn, TRANS_CLOSEONEXEC, 1);
178 
179     iceConn->listen_obj = NULL;
180 
181     iceConn->connection_status = IceConnectPending;
182     iceConn->io_ok = True;
183     iceConn->dispatch_level = 0;
184     iceConn->context = context;
185     iceConn->my_ice_version_index = 0;
186     iceConn->send_sequence = 0;
187     iceConn->receive_sequence = 0;
188 
189     iceConn->vendor = NULL;
190     iceConn->release = NULL;
191     iceConn->outbuf = NULL;
192 
193     iceConn->scratch = NULL;
194     iceConn->scratch_size = 0;
195 
196     iceConn->process_msg_info = NULL;
197 
198     iceConn->connect_to_you = NULL;
199     iceConn->protosetup_to_you = NULL;
200 
201     iceConn->connect_to_me = NULL;
202     iceConn->protosetup_to_me = NULL;
203 
204     if ((iceConn->inbuf = iceConn->inbufptr = malloc (ICE_INBUFSIZE)) == NULL)
205     {
206 	_IceFreeConnection (iceConn);
207 	if (errorStringRet && errorLength > 0) {
208 	    strncpy (errorStringRet, "Can't malloc", errorLength);
209 	    errorStringRet[errorLength - 1] = '\0';
210 	}
211 	return (NULL);
212     }
213 
214     iceConn->inbufmax = iceConn->inbuf + ICE_INBUFSIZE;
215 
216     if ((iceConn->outbuf = iceConn->outbufptr = calloc (1, ICE_OUTBUFSIZE)) == NULL)
217     {
218 	_IceFreeConnection (iceConn);
219 	if (errorStringRet && errorLength > 0) {
220 	    strncpy (errorStringRet, "Can't malloc", errorLength);
221 	    errorStringRet[errorLength - 1] = '\0';
222 	}
223 	return (NULL);
224     }
225 
226     iceConn->outbufmax = iceConn->outbuf + ICE_OUTBUFSIZE;
227 
228     iceConn->open_ref_count = 1;
229     iceConn->proto_ref_count = 0;
230 
231     iceConn->skip_want_to_close = False;
232     iceConn->want_to_close = False;
233     iceConn->free_asap = False;
234 
235     iceConn->saved_reply_waits = NULL;
236     iceConn->ping_waits = NULL;
237 
238     iceConn->connect_to_you = malloc (sizeof (_IceConnectToYouInfo));
239     if (iceConn->connect_to_you == NULL)
240     {
241 	_IceFreeConnection (iceConn);
242 	if (errorStringRet && errorLength > 0) {
243 	    strncpy (errorStringRet, "Can't malloc", errorLength);
244 	    errorStringRet[errorLength - 1] = '\0';
245 	}
246 	return (NULL);
247     }
248     iceConn->connect_to_you->auth_active = 0;
249 
250     /*
251      * Send our byte order.
252      */
253 
254     IceGetHeader (iceConn, 0, ICE_ByteOrder,
255 	SIZEOF (iceByteOrderMsg), iceByteOrderMsg, pByteOrderMsg);
256 
257     endian = 1;
258     if (*(char *) &endian)
259 	pByteOrderMsg->byteOrder = IceLSBfirst;
260     else
261 	pByteOrderMsg->byteOrder = IceMSBfirst;
262 
263     IceFlush (iceConn);
264 
265 
266     /*
267      * Now read the ByteOrder message from the other client.
268      * iceConn->swap should be set to the appropriate boolean
269      * value after the call to IceProcessMessages.
270      */
271 
272     iceConn->waiting_for_byteorder = True;
273 
274     ioErrorOccured = False;
275     while (iceConn->waiting_for_byteorder == True && !ioErrorOccured)
276     {
277 	ioErrorOccured = (IceProcessMessages (
278 	    iceConn, NULL, NULL) == IceProcessMessagesIOError);
279     }
280 
281     if (ioErrorOccured)
282     {
283 	_IceFreeConnection (iceConn);
284 	if (errorStringRet && errorLength > 0) {
285 	    strncpy (errorStringRet, "IO error occured opening connection",
286 		 errorLength);
287 	    errorStringRet[errorLength - 1] = '\0';
288 	}
289 	return (NULL);
290     }
291 
292     if (iceConn->connection_status == IceConnectRejected)
293     {
294 	/*
295 	 * We failed to get the required ByteOrder message.
296 	 */
297 
298 	_IceFreeConnection (iceConn);
299 	if (errorStringRet && errorLength > 0) {
300 	    strncpy (errorStringRet,
301 		"Internal error - did not receive the expected ByteOrder "
302 		"message", errorLength);
303 	    errorStringRet[errorLength - 1] = '\0';
304 	}
305 	return (NULL);
306     }
307 
308 
309     /*
310      * Determine which authentication methods are available for
311      * the Connection Setup authentication.
312      */
313 
314     _IceGetPoValidAuthIndices (
315 	"ICE", iceConn->connection_string,
316 	_IceAuthCount, _IceAuthNames, &authUsableCount, authIndices);
317 
318     for (i = 0; i < _IceAuthCount; i++)
319     {
320 	authUsableFlags[i] = 0;
321 	for (j = 0; j < authUsableCount && !authUsableFlags[i]; j++)
322 	    authUsableFlags[i] = (authIndices[j] == i);
323     }
324 
325 
326     /*
327      * Now send a Connection Setup message.
328      */
329 
330     extra = STRING_BYTES (IceVendorString) + STRING_BYTES (IceReleaseString);
331 
332     for (i = 0; i < _IceAuthCount; i++)
333 	if (authUsableFlags[i])
334 	{
335 	    extra += STRING_BYTES (_IceAuthNames[i]);
336 	}
337 
338     extra += (_IceVersionCount * 4);
339 
340     IceGetHeaderExtra (iceConn, 0, ICE_ConnectionSetup,
341 	SIZEOF (iceConnectionSetupMsg), WORD64COUNT (extra),
342 	iceConnectionSetupMsg, pSetupMsg, pData);
343 
344     setup_sequence = iceConn->send_sequence;
345 
346     pSetupMsg->versionCount = _IceVersionCount;
347     pSetupMsg->authCount = authUsableCount;
348     pSetupMsg->mustAuthenticate = mustAuthenticate;
349 
350     STORE_STRING (pData, IceVendorString);
351     STORE_STRING (pData, IceReleaseString);
352 
353     for (i = 0; i < _IceAuthCount; i++)
354 	if (authUsableFlags[i])
355 	{
356 	    STORE_STRING (pData, _IceAuthNames[i]);
357 	}
358 
359     for (i = 0; i < _IceVersionCount; i++)
360     {
361 	STORE_CARD16 (pData, _IceVersions[i].major_version);
362 	STORE_CARD16 (pData, _IceVersions[i].minor_version);
363     }
364 
365     IceFlush (iceConn);
366 
367 
368     /*
369      * Process messages until we get a Connection Reply or an Error Message.
370      * Authentication will take place behind the scenes.
371      */
372 
373     replyWait.sequence_of_request = setup_sequence;
374     replyWait.major_opcode_of_request = 0;
375     replyWait.minor_opcode_of_request = ICE_ConnectionSetup;
376     replyWait.reply = (IcePointer) &reply;
377 
378     gotReply = False;
379     ioErrorOccured = False;
380 
381     while (!gotReply && !ioErrorOccured)
382     {
383 	ioErrorOccured = (IceProcessMessages (
384 	    iceConn, &replyWait, &gotReply) == IceProcessMessagesIOError);
385 
386 	if (ioErrorOccured)
387 	{
388 	    if (errorStringRet && errorLength > 0) {
389 		strncpy (errorStringRet, "IO error occured opening connection",
390 		    errorLength);
391 		errorStringRet[errorLength - 1] = '\0';
392 	    }
393 	    _IceFreeConnection (iceConn);
394 	    iceConn = NULL;
395 	}
396 	else if (gotReply)
397 	{
398 	    if (reply.type == ICE_CONNECTION_REPLY)
399 	    {
400 		if (reply.connection_reply.version_index >= _IceVersionCount)
401 		{
402 		    if (errorStringRet && errorLength > 0) {
403 			strncpy (errorStringRet,
404 			    "Got a bad version index in the Connection Reply",
405 			    errorLength);
406 			errorStringRet[errorLength - 1] = '\0';
407 		    }
408 
409 		    free (reply.connection_reply.vendor);
410 		    free (reply.connection_reply.release);
411 		    _IceFreeConnection (iceConn);
412 		    iceConn = NULL;
413 		}
414 		else
415 		{
416 		    iceConn->my_ice_version_index =
417 			reply.connection_reply.version_index;
418 		    iceConn->vendor = reply.connection_reply.vendor;
419 		    iceConn->release = reply.connection_reply.release;
420 
421 		    _IceConnectionObjs[_IceConnectionCount] = iceConn;
422 		    _IceConnectionStrings[_IceConnectionCount] =
423 			iceConn->connection_string;
424 		    _IceConnectionCount++;
425 
426 		    free (iceConn->connect_to_you);
427 		    iceConn->connect_to_you = NULL;
428 
429 		    iceConn->connection_status = IceConnectAccepted;
430 		}
431 	    }
432 	    else /* reply.type == ICE_CONNECTION_ERROR */
433 	    {
434 		/* Connection failed */
435 
436 		if (errorStringRet && errorLength > 0) {
437 		    strncpy (errorStringRet,
438 			reply.connection_error.error_message, errorLength);
439 		    errorStringRet[errorLength - 1] = '\0';
440 		}
441 
442 		free (reply.connection_error.error_message);
443 
444 		_IceFreeConnection (iceConn);
445 		iceConn = NULL;
446 	    }
447 	}
448     }
449 
450     if (iceConn && _IceWatchProcs)
451     {
452 	/*
453 	 * Notify the watch procedures that an iceConn was opened.
454 	 */
455 
456 	_IceConnectionOpened (iceConn);
457     }
458 
459     return (iceConn);
460 }
461 
462 
463 
464 IcePointer
IceGetConnectionContext(IceConn iceConn)465 IceGetConnectionContext (
466 	IceConn    iceConn
467 )
468 {
469     return (iceConn->context);
470 }
471 
472 
473 
474 /* ------------------------------------------------------------------------- *
475  *                            local routines                                 *
476  * ------------------------------------------------------------------------- */
477 
478 #define ICE_CONNECTION_RETRIES 5
479 
480 
481 static XtransConnInfo
ConnectToPeer(char * networkIdsList,char ** actualConnectionRet)482 ConnectToPeer (char *networkIdsList, char **actualConnectionRet)
483 {
484     char addrbuf[256];
485     char* address;
486     char *ptr, *endptr, *delim;
487     int  madeConnection = 0;
488     size_t  len;
489     int  retry, connect_stat;
490     size_t  address_size;
491     XtransConnInfo trans_conn = NULL;
492 
493     *actualConnectionRet = NULL;
494 
495     ptr = networkIdsList;
496     len = strlen (networkIdsList);
497     endptr = networkIdsList + len;
498 
499     if (len < sizeof addrbuf)
500     {
501        address = addrbuf;
502        address_size = 256;
503     }
504     else
505     {
506        address = malloc (len + 1);
507        address_size = len;
508     }
509 
510     while (ptr < endptr && !madeConnection)
511     {
512 	if ((delim = (char *) strchr (ptr, ',')) == NULL)
513 	    delim = endptr;
514 
515 	len = delim - ptr;
516 	if (len > address_size - 1)
517 	    len = address_size - 1;
518 	strncpy (address, ptr, len);
519 	address[len] = '\0';
520 
521 	ptr = delim + 1;
522 
523 	for (retry = ICE_CONNECTION_RETRIES; retry >= 0; retry--)
524 	{
525 	    if ((trans_conn = _IceTransOpenCOTSClient (address)) == NULL)
526 	    {
527 		break;
528 	    }
529 
530 	    if ((connect_stat = _IceTransConnect (trans_conn, address)) < 0)
531 	    {
532 		_IceTransClose (trans_conn);
533 
534 		if (connect_stat == TRANS_TRY_CONNECT_AGAIN)
535 		{
536 		    sleep(1);
537 		    continue;
538 		}
539 		else
540 		    break;
541 	    }
542 	    else
543 	    {
544 		madeConnection = 1;
545 		break;
546 	    }
547 	}
548     }
549 
550     if (madeConnection)
551     {
552 	/*
553 	 * We need to return the actual network connection string
554 	 */
555 
556 	*actualConnectionRet = strdup(address);
557 
558 	/*
559 	 * Return the file descriptor
560 	 */
561     }
562     else trans_conn = NULL;
563 
564     if (address != addrbuf) free (address);
565 
566     return trans_conn;
567 }
568