Home | History | Annotate | Line # | Download | only in src
      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
     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 separate 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 = 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 iConn = _IceConnectionObjs[i];
    108 
    109 		if (iConn->want_to_close || iConn->free_asap ||
    110 		    (context && iConn->context &&
    111 		     iConn->context != context))
    112 		{
    113 		    /* force a new connection to be created */
    114 		    break;
    115 		}
    116 
    117 		if (majorOpcodeCheck)
    118 		{
    119 		    for (j = iConn->his_min_opcode;
    120 		        j <= iConn->his_max_opcode; j++)
    121 		    {
    122 			if (iConn->process_msg_info[
    123 			    j - iConn->his_min_opcode].in_use &&
    124 			    iConn->process_msg_info[
    125 			    j - iConn->his_min_opcode].my_opcode ==
    126 			    majorOpcodeCheck)
    127 			    break;
    128 		    }
    129 
    130 		    if (j <= iConn->his_max_opcode ||
    131 			(iConn->protosetup_to_you &&
    132 			iConn->protosetup_to_you->my_opcode ==
    133 			majorOpcodeCheck))
    134 		    {
    135 			/* force a new connection to be created */
    136 			break;
    137 		    }
    138 		}
    139 
    140 		iConn->open_ref_count++;
    141 		if (context && !iConn->context)
    142 		    iConn->context = context;
    143 		return (iConn);
    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 occurred 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     if (_X_LIKELY(pData != NULL)) {
    351 	STORE_STRING (pData, IceVendorString);
    352 	STORE_STRING (pData, IceReleaseString);
    353 
    354 	for (i = 0; i < _IceAuthCount; i++)
    355 	{
    356 	    if (authUsableFlags[i])
    357 	    {
    358 		STORE_STRING (pData, _IceAuthNames[i]);
    359 	    }
    360 	}
    361 
    362 	for (i = 0; i < _IceVersionCount; i++)
    363 	{
    364 	    STORE_CARD16 (pData, _IceVersions[i].major_version);
    365 	    STORE_CARD16 (pData, _IceVersions[i].minor_version);
    366 	}
    367     }
    368     else {
    369 	SEND_STRING (iceConn, IceVendorString);
    370 	SEND_STRING (iceConn, IceReleaseString);
    371 
    372 	for (i = 0; i < _IceAuthCount; i++)
    373 	{
    374 	    if (authUsableFlags[i])
    375 	    {
    376 		SEND_STRING (iceConn, _IceAuthNames[i]);
    377 	    }
    378 	}
    379 
    380 	for (i = 0; i < _IceVersionCount; i++)
    381 	{
    382 	    CARD16 v;
    383 	    v = _IceVersions[i].major_version;
    384 	    IceWriteData16 (iceConn, 2, &v);
    385 	    v = _IceVersions[i].minor_version;
    386 	    IceWriteData16 (iceConn, 2, &v);
    387 	}
    388     }
    389     IceFlush (iceConn);
    390 
    391     /*
    392      * Process messages until we get a Connection Reply or an Error Message.
    393      * Authentication will take place behind the scenes.
    394      */
    395 
    396     replyWait.sequence_of_request = setup_sequence;
    397     replyWait.major_opcode_of_request = 0;
    398     replyWait.minor_opcode_of_request = ICE_ConnectionSetup;
    399     replyWait.reply = (IcePointer) &reply;
    400 
    401     gotReply = False;
    402     ioErrorOccured = False;
    403 
    404     while (!gotReply && !ioErrorOccured && iceConn)
    405     {
    406 	ioErrorOccured = (IceProcessMessages (
    407 	    iceConn, &replyWait, &gotReply) == IceProcessMessagesIOError);
    408 
    409 	if (ioErrorOccured)
    410 	{
    411 	    if (errorStringRet && errorLength > 0) {
    412 		strncpy (errorStringRet, "IO error occurred opening connection",
    413 		    errorLength);
    414 		errorStringRet[errorLength - 1] = '\0';
    415 	    }
    416 	    _IceFreeConnection (iceConn);
    417 	    iceConn = NULL;
    418 	}
    419 	else if (gotReply)
    420 	{
    421 	    if (reply.type == ICE_CONNECTION_REPLY)
    422 	    {
    423 		if (reply.connection_reply.version_index >= _IceVersionCount)
    424 		{
    425 		    if (errorStringRet && errorLength > 0) {
    426 			strncpy (errorStringRet,
    427 			    "Got a bad version index in the Connection Reply",
    428 			    errorLength);
    429 			errorStringRet[errorLength - 1] = '\0';
    430 		    }
    431 
    432 		    free (reply.connection_reply.vendor);
    433 		    free (reply.connection_reply.release);
    434 		    _IceFreeConnection (iceConn);
    435 		    iceConn = NULL;
    436 		}
    437 		else
    438 		{
    439 		    iceConn->my_ice_version_index =
    440 			reply.connection_reply.version_index;
    441 		    iceConn->vendor = reply.connection_reply.vendor;
    442 		    iceConn->release = reply.connection_reply.release;
    443 
    444 		    _IceConnectionObjs[_IceConnectionCount] = iceConn;
    445 		    _IceConnectionStrings[_IceConnectionCount] =
    446 			iceConn->connection_string;
    447 		    _IceConnectionCount++;
    448 
    449 		    free (iceConn->connect_to_you);
    450 		    iceConn->connect_to_you = NULL;
    451 
    452 		    iceConn->connection_status = IceConnectAccepted;
    453 		}
    454 	    }
    455 	    else /* reply.type == ICE_CONNECTION_ERROR */
    456 	    {
    457 		/* Connection failed */
    458 
    459 		if (errorStringRet && errorLength > 0) {
    460 		    strncpy (errorStringRet,
    461 			reply.connection_error.error_message, errorLength);
    462 		    errorStringRet[errorLength - 1] = '\0';
    463 		}
    464 
    465 		free (reply.connection_error.error_message);
    466 
    467 		_IceFreeConnection (iceConn);
    468 		iceConn = NULL;
    469 	    }
    470 	}
    471     }
    472 
    473     if (iceConn && _IceWatchProcs)
    474     {
    475 	/*
    476 	 * Notify the watch procedures that an iceConn was opened.
    477 	 */
    478 
    479 	_IceConnectionOpened (iceConn);
    480     }
    481 
    482     return (iceConn);
    483 }
    484 
    485 
    486 
    487 IcePointer
    488 IceGetConnectionContext (
    489 	IceConn    iceConn
    490 )
    491 {
    492     return (iceConn->context);
    493 }
    494 
    495 
    496 
    497 /* ------------------------------------------------------------------------- *
    498  *                            local routines                                 *
    499  * ------------------------------------------------------------------------- */
    500 
    501 #define ICE_CONNECTION_RETRIES 5
    502 
    503 
    504 static XtransConnInfo
    505 ConnectToPeer (char *networkIdsList, char **actualConnectionRet)
    506 {
    507     char addrbuf[256];
    508     char* address;
    509     char *ptr, *endptr, *delim;
    510     int  madeConnection = 0;
    511     size_t  len;
    512     int  retry, connect_stat;
    513     size_t  address_size;
    514     XtransConnInfo trans_conn = NULL;
    515 
    516     *actualConnectionRet = NULL;
    517 
    518     ptr = networkIdsList;
    519     len = strlen (networkIdsList);
    520     endptr = networkIdsList + len;
    521 
    522     if (len < sizeof addrbuf)
    523     {
    524        address = addrbuf;
    525        address_size = 256;
    526     }
    527     else
    528     {
    529        address = malloc (len + 1);
    530        if (address == NULL)
    531            return NULL;
    532        address_size = len;
    533     }
    534 
    535     while (ptr < endptr && !madeConnection)
    536     {
    537 	if ((delim = strchr (ptr, ',')) == NULL)
    538 	    delim = endptr;
    539 
    540 	len = delim - ptr;
    541 	if (len > address_size - 1)
    542 	    len = address_size - 1;
    543 	strncpy (address, ptr, len);
    544 	address[len] = '\0';
    545 
    546 	ptr = delim + 1;
    547 
    548 	for (retry = ICE_CONNECTION_RETRIES; retry >= 0; retry--)
    549 	{
    550 	    if ((trans_conn = _IceTransOpenCOTSClient (address)) == NULL)
    551 	    {
    552 		break;
    553 	    }
    554 
    555 	    if ((connect_stat = _IceTransConnect (trans_conn, address)) < 0)
    556 	    {
    557 		_IceTransClose (trans_conn);
    558 		trans_conn = NULL;
    559 
    560 		if (connect_stat == TRANS_TRY_CONNECT_AGAIN)
    561 		{
    562 		    sleep(1);
    563 		    continue;
    564 		}
    565 		else
    566 		    break;
    567 	    }
    568 	    else
    569 	    {
    570 		madeConnection = 1;
    571 		break;
    572 	    }
    573 	}
    574     }
    575 
    576     if (madeConnection)
    577     {
    578 	/*
    579 	 * We need to return the actual network connection string
    580 	 */
    581 
    582 	*actualConnectionRet = strdup(address);
    583 
    584 	/*
    585 	 * Return the file descriptor
    586 	 */
    587     }
    588     else trans_conn = NULL;
    589 
    590     if (address != addrbuf) free (address);
    591 
    592     return trans_conn;
    593 }
    594