mirror of
https://github.com/Stichting-MINIX-Research-Foundation/xsrc.git
synced 2025-09-09 20:59:43 -04:00
541 lines
13 KiB
C
541 lines
13 KiB
C
/* $Xorg: connect.c,v 1.4 2001/02/09 02:03:26 xorgcvs Exp $ */
|
||
/******************************************************************************
|
||
|
||
|
||
Copyright 1993, 1998 The Open Group
|
||
|
||
Permission to use, copy, modify, distribute, and sell this software and its
|
||
documentation for any purpose is hereby granted without fee, provided that
|
||
the above copyright notice appear in all copies and that both that
|
||
copyright notice and this permission notice appear in supporting
|
||
documentation.
|
||
|
||
The above copyright notice and this permission notice shall be included in
|
||
all copies or substantial portions of the Software.
|
||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||
OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||
|
||
Except as contained in this notice, the name of The Open Group shall not be
|
||
used in advertising or otherwise to promote the sale, use or other dealings
|
||
in this Software without prior written authorization from The Open Group.
|
||
|
||
Author: Ralph Mor, X Consortium
|
||
******************************************************************************/
|
||
/* $XFree86: xc/lib/ICE/connect.c,v 3.10 2002/12/02 21:50:29 tsi Exp $ */
|
||
|
||
#include <X11/ICE/ICElib.h>
|
||
#include "ICElibint.h"
|
||
#include <X11/Xtrans.h>
|
||
#include "globals.h"
|
||
|
||
static XtransConnInfo ConnectToPeer();
|
||
|
||
#define Strstr strstr
|
||
|
||
IceConn
|
||
IceOpenConnection (networkIdsList, context, mustAuthenticate, majorOpcodeCheck,
|
||
errorLength, errorStringRet)
|
||
|
||
char *networkIdsList;
|
||
IcePointer context;
|
||
Bool mustAuthenticate;
|
||
int majorOpcodeCheck;
|
||
int errorLength;
|
||
char *errorStringRet;
|
||
|
||
{
|
||
IceConn iceConn;
|
||
int extra, i, j;
|
||
int endian;
|
||
Bool gotReply, ioErrorOccured;
|
||
unsigned long setup_sequence;
|
||
iceByteOrderMsg *pByteOrderMsg;
|
||
iceConnectionSetupMsg *pSetupMsg;
|
||
char *pData;
|
||
IceReplyWaitInfo replyWait;
|
||
_IceReply reply;
|
||
int authUsableCount;
|
||
int authUsableFlags[MAX_ICE_AUTH_NAMES];
|
||
int authIndices[MAX_ICE_AUTH_NAMES];
|
||
|
||
if (errorStringRet && errorLength > 0)
|
||
*errorStringRet = '\0';
|
||
|
||
if (networkIdsList == NULL || *networkIdsList == '\0')
|
||
{
|
||
strncpy (errorStringRet,
|
||
"networkIdsList argument is NULL", errorLength);
|
||
return (NULL);
|
||
}
|
||
|
||
/*
|
||
* Check to see if we can use a previously created ICE connection.
|
||
*
|
||
* If iceConn->want_to_close is True, or iceConn->free_asap is True,
|
||
* we can not use the iceConn.
|
||
*
|
||
* If 'context' is non-NULL, we will only use a previously opened ICE
|
||
* connection if the specified 'context' is equal to the context
|
||
* associated with the ICE connection, or if the context associated
|
||
* with the ICE connection is NULL.
|
||
*
|
||
* If 'majorOpcodeCheck' is non-zero, it will contain a protocol major
|
||
* opcode that we should make sure is not already active on the ICE
|
||
* connection. Some clients will want two seperate connections for the
|
||
* same protocol to the same destination client.
|
||
*/
|
||
|
||
for (i = 0; i < _IceConnectionCount; i++)
|
||
{
|
||
char *strptr;
|
||
if ((strptr = (char *) Strstr (
|
||
networkIdsList, _IceConnectionStrings[i])) != NULL)
|
||
{
|
||
char ch = *(strptr + strlen (_IceConnectionStrings[i]));
|
||
if (ch == ',' || ch == '\0')
|
||
{
|
||
/*
|
||
* OK, we found a connection. Make sure we can reuse it.
|
||
*/
|
||
|
||
IceConn iceConn = _IceConnectionObjs[i];
|
||
|
||
if (iceConn->want_to_close || iceConn->free_asap ||
|
||
(context && iceConn->context &&
|
||
iceConn->context != context))
|
||
{
|
||
/* force a new connection to be created */
|
||
break;
|
||
}
|
||
|
||
if (majorOpcodeCheck)
|
||
{
|
||
for (j = iceConn->his_min_opcode;
|
||
j <= iceConn->his_max_opcode; j++)
|
||
{
|
||
if (iceConn->process_msg_info[
|
||
j - iceConn->his_min_opcode].in_use &&
|
||
iceConn->process_msg_info[
|
||
j - iceConn->his_min_opcode].my_opcode ==
|
||
majorOpcodeCheck)
|
||
break;
|
||
}
|
||
|
||
if (j <= iceConn->his_max_opcode ||
|
||
(iceConn->protosetup_to_you &&
|
||
iceConn->protosetup_to_you->my_opcode ==
|
||
majorOpcodeCheck))
|
||
{
|
||
/* force a new connection to be created */
|
||
break;
|
||
}
|
||
}
|
||
|
||
iceConn->open_ref_count++;
|
||
if (context && !iceConn->context)
|
||
iceConn->context = context;
|
||
return (iceConn);
|
||
}
|
||
}
|
||
}
|
||
|
||
if ((iceConn = (IceConn) malloc (sizeof (struct _IceConn))) == NULL)
|
||
{
|
||
strncpy (errorStringRet, "Can't malloc", errorLength);
|
||
return (NULL);
|
||
}
|
||
|
||
|
||
/*
|
||
* Open a network connection with the peer client.
|
||
*/
|
||
|
||
if ((iceConn->trans_conn = ConnectToPeer (networkIdsList,
|
||
&iceConn->connection_string)) == NULL)
|
||
{
|
||
free ((char *) iceConn);
|
||
strncpy (errorStringRet, "Could not open network socket", errorLength);
|
||
return (NULL);
|
||
}
|
||
|
||
/*
|
||
* Set close-on-exec so that programs that fork() don't get confused.
|
||
*/
|
||
|
||
_IceTransSetOption (iceConn->trans_conn, TRANS_CLOSEONEXEC, 1);
|
||
|
||
iceConn->listen_obj = NULL;
|
||
|
||
iceConn->connection_status = IceConnectPending;
|
||
iceConn->io_ok = True;
|
||
iceConn->dispatch_level = 0;
|
||
iceConn->context = context;
|
||
iceConn->my_ice_version_index = 0;
|
||
iceConn->send_sequence = 0;
|
||
iceConn->receive_sequence = 0;
|
||
|
||
iceConn->vendor = NULL;
|
||
iceConn->release = NULL;
|
||
iceConn->outbuf = NULL;
|
||
|
||
iceConn->scratch = NULL;
|
||
iceConn->scratch_size = 0;
|
||
|
||
iceConn->process_msg_info = NULL;
|
||
|
||
iceConn->connect_to_you = NULL;
|
||
iceConn->protosetup_to_you = NULL;
|
||
|
||
iceConn->connect_to_me = NULL;
|
||
iceConn->protosetup_to_me = NULL;
|
||
|
||
if ((iceConn->inbuf = iceConn->inbufptr =
|
||
(char *) malloc (ICE_INBUFSIZE)) == NULL)
|
||
{
|
||
_IceFreeConnection (iceConn);
|
||
strncpy (errorStringRet, "Can't malloc", errorLength);
|
||
return (NULL);
|
||
}
|
||
|
||
iceConn->inbufmax = iceConn->inbuf + ICE_INBUFSIZE;
|
||
|
||
if ((iceConn->outbuf = iceConn->outbufptr =
|
||
(char *) calloc (1, ICE_OUTBUFSIZE)) == NULL)
|
||
{
|
||
_IceFreeConnection (iceConn);
|
||
strncpy (errorStringRet, "Can't malloc", errorLength);
|
||
return (NULL);
|
||
}
|
||
|
||
iceConn->outbufmax = iceConn->outbuf + ICE_OUTBUFSIZE;
|
||
|
||
iceConn->open_ref_count = 1;
|
||
iceConn->proto_ref_count = 0;
|
||
|
||
iceConn->skip_want_to_close = False;
|
||
iceConn->want_to_close = False;
|
||
iceConn->free_asap = False;
|
||
|
||
iceConn->saved_reply_waits = NULL;
|
||
iceConn->ping_waits = NULL;
|
||
|
||
iceConn->connect_to_you = (_IceConnectToYouInfo *) malloc (
|
||
sizeof (_IceConnectToYouInfo));
|
||
iceConn->connect_to_you->auth_active = 0;
|
||
|
||
/*
|
||
* Send our byte order.
|
||
*/
|
||
|
||
IceGetHeader (iceConn, 0, ICE_ByteOrder,
|
||
SIZEOF (iceByteOrderMsg), iceByteOrderMsg, pByteOrderMsg);
|
||
|
||
endian = 1;
|
||
if (*(char *) &endian)
|
||
pByteOrderMsg->byteOrder = IceLSBfirst;
|
||
else
|
||
pByteOrderMsg->byteOrder = IceMSBfirst;
|
||
|
||
IceFlush (iceConn);
|
||
|
||
|
||
/*
|
||
* Now read the ByteOrder message from the other client.
|
||
* iceConn->swap should be set to the appropriate boolean
|
||
* value after the call to IceProcessMessages.
|
||
*/
|
||
|
||
iceConn->waiting_for_byteorder = True;
|
||
|
||
ioErrorOccured = False;
|
||
while (iceConn->waiting_for_byteorder == True && !ioErrorOccured)
|
||
{
|
||
ioErrorOccured = (IceProcessMessages (
|
||
iceConn, NULL, NULL) == IceProcessMessagesIOError);
|
||
}
|
||
|
||
if (ioErrorOccured)
|
||
{
|
||
_IceFreeConnection (iceConn);
|
||
strncpy (errorStringRet, "IO error occured opening connection",
|
||
errorLength);
|
||
return (NULL);
|
||
}
|
||
|
||
if (iceConn->connection_status == IceConnectRejected)
|
||
{
|
||
/*
|
||
* We failed to get the required ByteOrder message.
|
||
*/
|
||
|
||
_IceFreeConnection (iceConn);
|
||
strncpy (errorStringRet,
|
||
"Internal error - did not receive the expected ByteOrder message",
|
||
errorLength);
|
||
return (NULL);
|
||
}
|
||
|
||
|
||
/*
|
||
* Determine which authentication methods are available for
|
||
* the Connection Setup authentication.
|
||
*/
|
||
|
||
_IceGetPoValidAuthIndices (
|
||
"ICE", iceConn->connection_string,
|
||
_IceAuthCount, _IceAuthNames, &authUsableCount, authIndices);
|
||
|
||
for (i = 0; i < _IceAuthCount; i++)
|
||
{
|
||
authUsableFlags[i] = 0;
|
||
for (j = 0; j < authUsableCount && !authUsableFlags[i]; j++)
|
||
authUsableFlags[i] = (authIndices[j] == i);
|
||
}
|
||
|
||
|
||
/*
|
||
* Now send a Connection Setup message.
|
||
*/
|
||
|
||
extra = STRING_BYTES (IceVendorString) + STRING_BYTES (IceReleaseString);
|
||
|
||
for (i = 0; i < _IceAuthCount; i++)
|
||
if (authUsableFlags[i])
|
||
{
|
||
extra += STRING_BYTES (_IceAuthNames[i]);
|
||
}
|
||
|
||
extra += (_IceVersionCount * 4);
|
||
|
||
IceGetHeaderExtra (iceConn, 0, ICE_ConnectionSetup,
|
||
SIZEOF (iceConnectionSetupMsg), WORD64COUNT (extra),
|
||
iceConnectionSetupMsg, pSetupMsg, pData);
|
||
|
||
setup_sequence = iceConn->send_sequence;
|
||
|
||
pSetupMsg->versionCount = _IceVersionCount;
|
||
pSetupMsg->authCount = authUsableCount;
|
||
pSetupMsg->mustAuthenticate = mustAuthenticate;
|
||
|
||
STORE_STRING (pData, IceVendorString);
|
||
STORE_STRING (pData, IceReleaseString);
|
||
|
||
for (i = 0; i < _IceAuthCount; i++)
|
||
if (authUsableFlags[i])
|
||
{
|
||
STORE_STRING (pData, _IceAuthNames[i]);
|
||
}
|
||
|
||
for (i = 0; i < _IceVersionCount; i++)
|
||
{
|
||
STORE_CARD16 (pData, _IceVersions[i].major_version);
|
||
STORE_CARD16 (pData, _IceVersions[i].minor_version);
|
||
}
|
||
|
||
IceFlush (iceConn);
|
||
|
||
|
||
/*
|
||
* Process messages until we get a Connection Reply or an Error Message.
|
||
* Authentication will take place behind the scenes.
|
||
*/
|
||
|
||
replyWait.sequence_of_request = setup_sequence;
|
||
replyWait.major_opcode_of_request = 0;
|
||
replyWait.minor_opcode_of_request = ICE_ConnectionSetup;
|
||
replyWait.reply = (IcePointer) &reply;
|
||
|
||
gotReply = False;
|
||
ioErrorOccured = False;
|
||
|
||
while (!gotReply && !ioErrorOccured)
|
||
{
|
||
ioErrorOccured = (IceProcessMessages (
|
||
iceConn, &replyWait, &gotReply) == IceProcessMessagesIOError);
|
||
|
||
if (ioErrorOccured)
|
||
{
|
||
strncpy (errorStringRet, "IO error occured opening connection",
|
||
errorLength);
|
||
_IceFreeConnection (iceConn);
|
||
iceConn = NULL;
|
||
}
|
||
else if (gotReply)
|
||
{
|
||
if (reply.type == ICE_CONNECTION_REPLY)
|
||
{
|
||
if (reply.connection_reply.version_index >= _IceVersionCount)
|
||
{
|
||
strncpy (errorStringRet,
|
||
"Got a bad version index in the Connection Reply",
|
||
errorLength);
|
||
|
||
free (reply.connection_reply.vendor);
|
||
free (reply.connection_reply.release);
|
||
_IceFreeConnection (iceConn);
|
||
iceConn = NULL;
|
||
}
|
||
else
|
||
{
|
||
iceConn->my_ice_version_index =
|
||
reply.connection_reply.version_index;
|
||
iceConn->vendor = reply.connection_reply.vendor;
|
||
iceConn->release = reply.connection_reply.release;
|
||
|
||
_IceConnectionObjs[_IceConnectionCount] = iceConn;
|
||
_IceConnectionStrings[_IceConnectionCount] =
|
||
iceConn->connection_string;
|
||
_IceConnectionCount++;
|
||
|
||
free ((char *) iceConn->connect_to_you);
|
||
iceConn->connect_to_you = NULL;
|
||
|
||
iceConn->connection_status = IceConnectAccepted;
|
||
}
|
||
}
|
||
else /* reply.type == ICE_CONNECTION_ERROR */
|
||
{
|
||
/* Connection failed */
|
||
|
||
strncpy (errorStringRet, reply.connection_error.error_message,
|
||
errorLength);
|
||
|
||
free (reply.connection_error.error_message);
|
||
|
||
_IceFreeConnection (iceConn);
|
||
iceConn = NULL;
|
||
}
|
||
}
|
||
}
|
||
|
||
if (iceConn && _IceWatchProcs)
|
||
{
|
||
/*
|
||
* Notify the watch procedures that an iceConn was opened.
|
||
*/
|
||
|
||
_IceConnectionOpened (iceConn);
|
||
}
|
||
|
||
return (iceConn);
|
||
}
|
||
|
||
|
||
|
||
IcePointer
|
||
IceGetConnectionContext (iceConn)
|
||
|
||
IceConn iceConn;
|
||
|
||
{
|
||
return (iceConn->context);
|
||
}
|
||
|
||
|
||
|
||
/* ------------------------------------------------------------------------- *
|
||
* local routines *
|
||
* ------------------------------------------------------------------------- */
|
||
|
||
#define ICE_CONNECTION_RETRIES 5
|
||
|
||
|
||
static XtransConnInfo
|
||
ConnectToPeer (networkIdsList, actualConnectionRet)
|
||
|
||
char *networkIdsList;
|
||
char **actualConnectionRet;
|
||
|
||
{
|
||
char addrbuf[256];
|
||
char* address;
|
||
char *ptr, *endptr, *delim;
|
||
int madeConnection = 0;
|
||
int len, retry;
|
||
int connect_stat;
|
||
int address_size;
|
||
XtransConnInfo trans_conn = NULL;
|
||
|
||
*actualConnectionRet = NULL;
|
||
|
||
ptr = networkIdsList;
|
||
len = strlen (networkIdsList);
|
||
endptr = networkIdsList + len;
|
||
|
||
if (len < sizeof addrbuf)
|
||
{
|
||
address = addrbuf;
|
||
address_size = 256;
|
||
}
|
||
else
|
||
{
|
||
address = malloc (len + 1);
|
||
address_size = len;
|
||
}
|
||
|
||
while (ptr < endptr && !madeConnection)
|
||
{
|
||
if ((delim = (char *) strchr (ptr, ',')) == NULL)
|
||
delim = endptr;
|
||
|
||
len = delim - ptr;
|
||
if (len > address_size - 1)
|
||
len = address_size - 1;
|
||
strncpy (address, ptr, len);
|
||
address[len] = '\0';
|
||
|
||
ptr = delim + 1;
|
||
|
||
for (retry = ICE_CONNECTION_RETRIES; retry >= 0; retry--)
|
||
{
|
||
if ((trans_conn = _IceTransOpenCOTSClient (address)) == NULL)
|
||
{
|
||
break;
|
||
}
|
||
|
||
if ((connect_stat = _IceTransConnect (trans_conn, address)) < 0)
|
||
{
|
||
_IceTransClose (trans_conn);
|
||
|
||
if (connect_stat == TRANS_TRY_CONNECT_AGAIN)
|
||
{
|
||
sleep(1);
|
||
continue;
|
||
}
|
||
else
|
||
break;
|
||
}
|
||
else
|
||
{
|
||
madeConnection = 1;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
if (madeConnection)
|
||
{
|
||
/*
|
||
* We need to return the actual network connection string
|
||
*/
|
||
|
||
*actualConnectionRet = (char *) malloc (strlen (address) + 1);
|
||
strcpy (*actualConnectionRet, address);
|
||
|
||
|
||
/*
|
||
* Return the file descriptor
|
||
*/
|
||
}
|
||
else trans_conn = NULL;
|
||
|
||
if (address != addrbuf) free (address);
|
||
|
||
return trans_conn;
|
||
}
|