#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <X11/ICE/ICElib.h>
#include "ICElibint.h"
#include <X11/Xtrans/Xtrans.h>
#include "globals.h"
static XtransConnInfo ConnectToPeer(char *networkIdsList,
char **actualConnectionRet);
#define Strstr strstr
IceConn
IceOpenConnection (
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);
}
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')
{
IceConn iceConn = _IceConnectionObjs[i];
if (iceConn->want_to_close || iceConn->free_asap ||
(context && iceConn->context &&
iceConn->context != context))
{
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))
{
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);
}
if ((iceConn->trans_conn = ConnectToPeer (networkIdsList,
&iceConn->connection_string)) == NULL)
{
free ((char *) iceConn);
strncpy (errorStringRet, "Could not open network socket", errorLength);
return (NULL);
}
_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;
IceGetHeader (iceConn, 0, ICE_ByteOrder,
SIZEOF (iceByteOrderMsg), iceByteOrderMsg, pByteOrderMsg);
endian = 1;
if (*(char *) &endian)
pByteOrderMsg->byteOrder = IceLSBfirst;
else
pByteOrderMsg->byteOrder = IceMSBfirst;
IceFlush (iceConn);
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)
{
_IceFreeConnection (iceConn);
strncpy (errorStringRet,
"Internal error - did not receive the expected ByteOrder message",
errorLength);
return (NULL);
}
_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);
}
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);
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
{
strncpy (errorStringRet, reply.connection_error.error_message,
errorLength);
free (reply.connection_error.error_message);
_IceFreeConnection (iceConn);
iceConn = NULL;
}
}
}
if (iceConn && _IceWatchProcs)
{
_IceConnectionOpened (iceConn);
}
return (iceConn);
}
IcePointer
IceGetConnectionContext (
IceConn iceConn
)
{
return (iceConn->context);
}
#define ICE_CONNECTION_RETRIES 5
static XtransConnInfo
ConnectToPeer (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)
{
*actualConnectionRet = strdup(address);
}
else trans_conn = NULL;
if (address != addrbuf) free (address);
return trans_conn;
}