1266e564dSmrg/******************************************************************************
2266e564dSmrg
3266e564dSmrg
4266e564dSmrgCopyright 1993, 1998  The Open Group
5266e564dSmrg
6266e564dSmrgPermission to use, copy, modify, distribute, and sell this software and its
7266e564dSmrgdocumentation for any purpose is hereby granted without fee, provided that
8266e564dSmrgthe above copyright notice appear in all copies and that both that
9266e564dSmrgcopyright notice and this permission notice appear in supporting
10266e564dSmrgdocumentation.
11266e564dSmrg
12266e564dSmrgThe above copyright notice and this permission notice shall be included in
13266e564dSmrgall copies or substantial portions of the Software.
14266e564dSmrg
15266e564dSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16266e564dSmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17266e564dSmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
18266e564dSmrgOPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
19266e564dSmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20266e564dSmrgCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21266e564dSmrg
22266e564dSmrgExcept as contained in this notice, the name of The Open Group shall not be
23266e564dSmrgused in advertising or otherwise to promote the sale, use or other dealings
24266e564dSmrgin this Software without prior written authorization from The Open Group.
25266e564dSmrg
26266e564dSmrgAuthor: Ralph Mor, X Consortium
27266e564dSmrg******************************************************************************/
28266e564dSmrg
29266e564dSmrg#ifdef HAVE_CONFIG_H
30266e564dSmrg#include <config.h>
31266e564dSmrg#endif
32266e564dSmrg#include <X11/ICE/ICElib.h>
33266e564dSmrg#include "ICElibint.h"
34266e564dSmrg#include <X11/Xtrans/Xtrans.h>
35266e564dSmrg#include "globals.h"
36266e564dSmrg
37266e564dSmrgstatic XtransConnInfo ConnectToPeer(char *networkIdsList,
38266e564dSmrg				    char **actualConnectionRet);
39266e564dSmrg
40266e564dSmrgIceConn
41c5629e66SmrgIceOpenConnection (
42c5629e66Smrg	char 	   *networkIdsList,
43c5629e66Smrg	IcePointer context,
44c5629e66Smrg	Bool 	   mustAuthenticate,
45c5629e66Smrg	int  	   majorOpcodeCheck,
46c5629e66Smrg	int  	   errorLength,
47c5629e66Smrg	char 	   *errorStringRet
48c5629e66Smrg)
49266e564dSmrg{
50266e564dSmrg    IceConn			iceConn;
51266e564dSmrg    int				extra, i, j;
52266e564dSmrg    int		       		endian;
53266e564dSmrg    Bool			gotReply, ioErrorOccured;
54266e564dSmrg    unsigned long		setup_sequence;
55266e564dSmrg    iceByteOrderMsg		*pByteOrderMsg;
56266e564dSmrg    iceConnectionSetupMsg	*pSetupMsg;
57266e564dSmrg    char			*pData;
58266e564dSmrg    IceReplyWaitInfo 		replyWait;
59266e564dSmrg    _IceReply		 	reply;
60266e564dSmrg    int				authUsableCount;
61266e564dSmrg    int				authUsableFlags[MAX_ICE_AUTH_NAMES];
62266e564dSmrg    int				authIndices[MAX_ICE_AUTH_NAMES];
63266e564dSmrg
64266e564dSmrg    if (errorStringRet && errorLength > 0)
65266e564dSmrg	*errorStringRet = '\0';
66266e564dSmrg
67266e564dSmrg    if (networkIdsList == NULL || *networkIdsList == '\0')
68266e564dSmrg    {
69a3129944Smrg	if (errorStringRet && errorLength > 0) {
70a3129944Smrg	    strncpy (errorStringRet,
71a3129944Smrg		"networkIdsList argument is NULL", errorLength);
72a3129944Smrg	    errorStringRet[errorLength - 1] = '\0';
73a3129944Smrg	}
74266e564dSmrg	return (NULL);
75266e564dSmrg    }
76266e564dSmrg
77266e564dSmrg    /*
78266e564dSmrg     * Check to see if we can use a previously created ICE connection.
79266e564dSmrg     *
80266e564dSmrg     * If iceConn->want_to_close is True, or iceConn->free_asap is True,
81266e564dSmrg     * we can not use the iceConn.
82266e564dSmrg     *
83266e564dSmrg     * If 'context' is non-NULL, we will only use a previously opened ICE
84266e564dSmrg     * connection if the specified 'context' is equal to the context
85266e564dSmrg     * associated with the ICE connection, or if the context associated
86266e564dSmrg     * with the ICE connection is NULL.
879ef0b394Smrg     *
88266e564dSmrg     * If 'majorOpcodeCheck' is non-zero, it will contain a protocol major
89266e564dSmrg     * opcode that we should make sure is not already active on the ICE
901009a292Smrg     * connection.  Some clients will want two separate connections for the
91266e564dSmrg     * same protocol to the same destination client.
92266e564dSmrg     */
93266e564dSmrg
94266e564dSmrg    for (i = 0; i < _IceConnectionCount; i++)
95266e564dSmrg    {
96266e564dSmrg	char *strptr;
973bf3b463Smrg	if ((strptr = strstr (
98266e564dSmrg	    networkIdsList, _IceConnectionStrings[i])) != NULL)
99266e564dSmrg	{
100266e564dSmrg	    char ch = *(strptr + strlen (_IceConnectionStrings[i]));
101266e564dSmrg	    if (ch == ',' || ch == '\0')
102266e564dSmrg	    {
103266e564dSmrg		/*
104266e564dSmrg		 * OK, we found a connection.  Make sure we can reuse it.
105266e564dSmrg		 */
106266e564dSmrg
1071009a292Smrg		IceConn iConn = _IceConnectionObjs[i];
108266e564dSmrg
1091009a292Smrg		if (iConn->want_to_close || iConn->free_asap ||
1101009a292Smrg		    (context && iConn->context &&
1111009a292Smrg		     iConn->context != context))
112266e564dSmrg		{
113266e564dSmrg		    /* force a new connection to be created */
114266e564dSmrg		    break;
115266e564dSmrg		}
116266e564dSmrg
117266e564dSmrg		if (majorOpcodeCheck)
118266e564dSmrg		{
1191009a292Smrg		    for (j = iConn->his_min_opcode;
1201009a292Smrg		        j <= iConn->his_max_opcode; j++)
121266e564dSmrg		    {
1221009a292Smrg			if (iConn->process_msg_info[
1231009a292Smrg			    j - iConn->his_min_opcode].in_use &&
1241009a292Smrg			    iConn->process_msg_info[
1251009a292Smrg			    j - iConn->his_min_opcode].my_opcode ==
126266e564dSmrg			    majorOpcodeCheck)
127266e564dSmrg			    break;
128266e564dSmrg		    }
129266e564dSmrg
1301009a292Smrg		    if (j <= iConn->his_max_opcode ||
1311009a292Smrg			(iConn->protosetup_to_you &&
1321009a292Smrg			iConn->protosetup_to_you->my_opcode ==
133266e564dSmrg			majorOpcodeCheck))
134266e564dSmrg		    {
135266e564dSmrg			/* force a new connection to be created */
136266e564dSmrg			break;
137266e564dSmrg		    }
138266e564dSmrg		}
139266e564dSmrg
1401009a292Smrg		iConn->open_ref_count++;
1411009a292Smrg		if (context && !iConn->context)
1421009a292Smrg		    iConn->context = context;
1431009a292Smrg		return (iConn);
144266e564dSmrg	    }
145266e564dSmrg	}
146266e564dSmrg    }
147266e564dSmrg
148fb5e8d76Smrg    if ((iceConn = malloc (sizeof (struct _IceConn))) == NULL)
149266e564dSmrg    {
150a3129944Smrg	if (errorStringRet && errorLength > 0) {
151a3129944Smrg	    strncpy (errorStringRet, "Can't malloc", errorLength);
152a3129944Smrg	    errorStringRet[errorLength - 1] = '\0';
153a3129944Smrg	}
154266e564dSmrg	return (NULL);
155266e564dSmrg    }
156266e564dSmrg
157266e564dSmrg
158266e564dSmrg    /*
159266e564dSmrg     * Open a network connection with the peer client.
160266e564dSmrg     */
161266e564dSmrg
162266e564dSmrg    if ((iceConn->trans_conn = ConnectToPeer (networkIdsList,
163266e564dSmrg	&iceConn->connection_string)) == NULL)
164266e564dSmrg    {
165fb5e8d76Smrg	free (iceConn);
166a3129944Smrg	if (errorStringRet && errorLength > 0) {
167a3129944Smrg	    strncpy (errorStringRet, "Could not open network socket", errorLength);
168a3129944Smrg	    errorStringRet[errorLength - 1] = '\0';
169a3129944Smrg	}
170266e564dSmrg	return (NULL);
171266e564dSmrg    }
172266e564dSmrg
173266e564dSmrg    /*
174266e564dSmrg     * Set close-on-exec so that programs that fork() don't get confused.
175266e564dSmrg     */
176266e564dSmrg
177266e564dSmrg    _IceTransSetOption (iceConn->trans_conn, TRANS_CLOSEONEXEC, 1);
178266e564dSmrg
179266e564dSmrg    iceConn->listen_obj = NULL;
180266e564dSmrg
181266e564dSmrg    iceConn->connection_status = IceConnectPending;
182266e564dSmrg    iceConn->io_ok = True;
183266e564dSmrg    iceConn->dispatch_level = 0;
184266e564dSmrg    iceConn->context = context;
185266e564dSmrg    iceConn->my_ice_version_index = 0;
186266e564dSmrg    iceConn->send_sequence = 0;
187266e564dSmrg    iceConn->receive_sequence = 0;
188266e564dSmrg
189266e564dSmrg    iceConn->vendor = NULL;
190266e564dSmrg    iceConn->release = NULL;
191266e564dSmrg    iceConn->outbuf = NULL;
192266e564dSmrg
193266e564dSmrg    iceConn->scratch = NULL;
194266e564dSmrg    iceConn->scratch_size = 0;
195266e564dSmrg
196266e564dSmrg    iceConn->process_msg_info = NULL;
197266e564dSmrg
198266e564dSmrg    iceConn->connect_to_you = NULL;
199266e564dSmrg    iceConn->protosetup_to_you = NULL;
200266e564dSmrg
201266e564dSmrg    iceConn->connect_to_me = NULL;
202266e564dSmrg    iceConn->protosetup_to_me = NULL;
203266e564dSmrg
204fb5e8d76Smrg    if ((iceConn->inbuf = iceConn->inbufptr = malloc (ICE_INBUFSIZE)) == NULL)
205266e564dSmrg    {
206266e564dSmrg	_IceFreeConnection (iceConn);
207a3129944Smrg	if (errorStringRet && errorLength > 0) {
208a3129944Smrg	    strncpy (errorStringRet, "Can't malloc", errorLength);
209a3129944Smrg	    errorStringRet[errorLength - 1] = '\0';
210a3129944Smrg	}
211266e564dSmrg	return (NULL);
212266e564dSmrg    }
213266e564dSmrg
214266e564dSmrg    iceConn->inbufmax = iceConn->inbuf + ICE_INBUFSIZE;
215266e564dSmrg
216fb5e8d76Smrg    if ((iceConn->outbuf = iceConn->outbufptr = calloc (1, ICE_OUTBUFSIZE)) == NULL)
217266e564dSmrg    {
218266e564dSmrg	_IceFreeConnection (iceConn);
219a3129944Smrg	if (errorStringRet && errorLength > 0) {
220a3129944Smrg	    strncpy (errorStringRet, "Can't malloc", errorLength);
221a3129944Smrg	    errorStringRet[errorLength - 1] = '\0';
222a3129944Smrg	}
223266e564dSmrg	return (NULL);
224266e564dSmrg    }
225266e564dSmrg
226266e564dSmrg    iceConn->outbufmax = iceConn->outbuf + ICE_OUTBUFSIZE;
227266e564dSmrg
228266e564dSmrg    iceConn->open_ref_count = 1;
229266e564dSmrg    iceConn->proto_ref_count = 0;
230266e564dSmrg
231266e564dSmrg    iceConn->skip_want_to_close = False;
232266e564dSmrg    iceConn->want_to_close = False;
233266e564dSmrg    iceConn->free_asap = False;
234266e564dSmrg
235266e564dSmrg    iceConn->saved_reply_waits = NULL;
236266e564dSmrg    iceConn->ping_waits = NULL;
237266e564dSmrg
238fb5e8d76Smrg    iceConn->connect_to_you = malloc (sizeof (_IceConnectToYouInfo));
239a3129944Smrg    if (iceConn->connect_to_you == NULL)
240a3129944Smrg    {
241a3129944Smrg	_IceFreeConnection (iceConn);
242a3129944Smrg	if (errorStringRet && errorLength > 0) {
243a3129944Smrg	    strncpy (errorStringRet, "Can't malloc", errorLength);
244a3129944Smrg	    errorStringRet[errorLength - 1] = '\0';
245a3129944Smrg	}
246a3129944Smrg	return (NULL);
247a3129944Smrg    }
248266e564dSmrg    iceConn->connect_to_you->auth_active = 0;
249266e564dSmrg
250266e564dSmrg    /*
251266e564dSmrg     * Send our byte order.
252266e564dSmrg     */
253266e564dSmrg
254266e564dSmrg    IceGetHeader (iceConn, 0, ICE_ByteOrder,
255266e564dSmrg	SIZEOF (iceByteOrderMsg), iceByteOrderMsg, pByteOrderMsg);
256266e564dSmrg
257266e564dSmrg    endian = 1;
258266e564dSmrg    if (*(char *) &endian)
259266e564dSmrg	pByteOrderMsg->byteOrder = IceLSBfirst;
260266e564dSmrg    else
261266e564dSmrg	pByteOrderMsg->byteOrder = IceMSBfirst;
262266e564dSmrg
263266e564dSmrg    IceFlush (iceConn);
264266e564dSmrg
265266e564dSmrg
266266e564dSmrg    /*
267266e564dSmrg     * Now read the ByteOrder message from the other client.
268266e564dSmrg     * iceConn->swap should be set to the appropriate boolean
269266e564dSmrg     * value after the call to IceProcessMessages.
270266e564dSmrg     */
271266e564dSmrg
272266e564dSmrg    iceConn->waiting_for_byteorder = True;
273266e564dSmrg
274266e564dSmrg    ioErrorOccured = False;
275266e564dSmrg    while (iceConn->waiting_for_byteorder == True && !ioErrorOccured)
276266e564dSmrg    {
277266e564dSmrg	ioErrorOccured = (IceProcessMessages (
278266e564dSmrg	    iceConn, NULL, NULL) == IceProcessMessagesIOError);
279266e564dSmrg    }
280266e564dSmrg
281266e564dSmrg    if (ioErrorOccured)
282266e564dSmrg    {
283266e564dSmrg	_IceFreeConnection (iceConn);
284a3129944Smrg	if (errorStringRet && errorLength > 0) {
2851009a292Smrg	    strncpy (errorStringRet, "IO error occurred opening connection",
286a3129944Smrg		 errorLength);
287a3129944Smrg	    errorStringRet[errorLength - 1] = '\0';
288a3129944Smrg	}
289266e564dSmrg	return (NULL);
290266e564dSmrg    }
291266e564dSmrg
292266e564dSmrg    if (iceConn->connection_status == IceConnectRejected)
293266e564dSmrg    {
294266e564dSmrg	/*
295266e564dSmrg	 * We failed to get the required ByteOrder message.
296266e564dSmrg	 */
297266e564dSmrg
298266e564dSmrg	_IceFreeConnection (iceConn);
299a3129944Smrg	if (errorStringRet && errorLength > 0) {
300a3129944Smrg	    strncpy (errorStringRet,
301a3129944Smrg		"Internal error - did not receive the expected ByteOrder "
302a3129944Smrg		"message", errorLength);
303a3129944Smrg	    errorStringRet[errorLength - 1] = '\0';
304a3129944Smrg	}
305266e564dSmrg	return (NULL);
306266e564dSmrg    }
307266e564dSmrg
308266e564dSmrg
309266e564dSmrg    /*
310266e564dSmrg     * Determine which authentication methods are available for
311266e564dSmrg     * the Connection Setup authentication.
312266e564dSmrg     */
313266e564dSmrg
314266e564dSmrg    _IceGetPoValidAuthIndices (
315266e564dSmrg	"ICE", iceConn->connection_string,
316266e564dSmrg	_IceAuthCount, _IceAuthNames, &authUsableCount, authIndices);
317266e564dSmrg
318266e564dSmrg    for (i = 0; i < _IceAuthCount; i++)
319266e564dSmrg    {
320266e564dSmrg	authUsableFlags[i] = 0;
321266e564dSmrg	for (j = 0; j < authUsableCount && !authUsableFlags[i]; j++)
322266e564dSmrg	    authUsableFlags[i] = (authIndices[j] == i);
323266e564dSmrg    }
324266e564dSmrg
325266e564dSmrg
326266e564dSmrg    /*
327266e564dSmrg     * Now send a Connection Setup message.
328266e564dSmrg     */
329266e564dSmrg
330266e564dSmrg    extra = STRING_BYTES (IceVendorString) + STRING_BYTES (IceReleaseString);
331266e564dSmrg
332266e564dSmrg    for (i = 0; i < _IceAuthCount; i++)
333266e564dSmrg	if (authUsableFlags[i])
334266e564dSmrg	{
335266e564dSmrg	    extra += STRING_BYTES (_IceAuthNames[i]);
336266e564dSmrg	}
337266e564dSmrg
338266e564dSmrg    extra += (_IceVersionCount * 4);
339266e564dSmrg
340266e564dSmrg    IceGetHeaderExtra (iceConn, 0, ICE_ConnectionSetup,
341266e564dSmrg	SIZEOF (iceConnectionSetupMsg), WORD64COUNT (extra),
342266e564dSmrg	iceConnectionSetupMsg, pSetupMsg, pData);
343266e564dSmrg
344266e564dSmrg    setup_sequence = iceConn->send_sequence;
345266e564dSmrg
346266e564dSmrg    pSetupMsg->versionCount = _IceVersionCount;
347266e564dSmrg    pSetupMsg->authCount = authUsableCount;
348266e564dSmrg    pSetupMsg->mustAuthenticate = mustAuthenticate;
349266e564dSmrg
3501009a292Smrg    if (_X_LIKELY(pData != NULL)) {
3511009a292Smrg	STORE_STRING (pData, IceVendorString);
3521009a292Smrg	STORE_STRING (pData, IceReleaseString);
353266e564dSmrg
3541009a292Smrg	for (i = 0; i < _IceAuthCount; i++)
355266e564dSmrg	{
3561009a292Smrg	    if (authUsableFlags[i])
3571009a292Smrg	    {
3581009a292Smrg		STORE_STRING (pData, _IceAuthNames[i]);
3591009a292Smrg	    }
360266e564dSmrg	}
361266e564dSmrg
3621009a292Smrg	for (i = 0; i < _IceVersionCount; i++)
3631009a292Smrg	{
3641009a292Smrg	    STORE_CARD16 (pData, _IceVersions[i].major_version);
3651009a292Smrg	    STORE_CARD16 (pData, _IceVersions[i].minor_version);
3661009a292Smrg	}
367266e564dSmrg    }
3681009a292Smrg    else {
3691009a292Smrg	SEND_STRING (iceConn, IceVendorString);
3701009a292Smrg	SEND_STRING (iceConn, IceReleaseString);
371266e564dSmrg
3721009a292Smrg	for (i = 0; i < _IceAuthCount; i++)
3731009a292Smrg	{
3741009a292Smrg	    if (authUsableFlags[i])
3751009a292Smrg	    {
3761009a292Smrg		SEND_STRING (iceConn, _IceAuthNames[i]);
3771009a292Smrg	    }
3781009a292Smrg	}
379266e564dSmrg
3801009a292Smrg	for (i = 0; i < _IceVersionCount; i++)
3811009a292Smrg	{
3821009a292Smrg	    CARD16 v;
3831009a292Smrg	    v = _IceVersions[i].major_version;
3841009a292Smrg	    IceWriteData16 (iceConn, 2, &v);
3851009a292Smrg	    v = _IceVersions[i].minor_version;
3861009a292Smrg	    IceWriteData16 (iceConn, 2, &v);
3871009a292Smrg	}
3881009a292Smrg    }
3891009a292Smrg    IceFlush (iceConn);
390266e564dSmrg
391266e564dSmrg    /*
392266e564dSmrg     * Process messages until we get a Connection Reply or an Error Message.
393266e564dSmrg     * Authentication will take place behind the scenes.
394266e564dSmrg     */
395266e564dSmrg
396266e564dSmrg    replyWait.sequence_of_request = setup_sequence;
397266e564dSmrg    replyWait.major_opcode_of_request = 0;
398266e564dSmrg    replyWait.minor_opcode_of_request = ICE_ConnectionSetup;
399266e564dSmrg    replyWait.reply = (IcePointer) &reply;
400266e564dSmrg
401266e564dSmrg    gotReply = False;
402266e564dSmrg    ioErrorOccured = False;
403266e564dSmrg
4043bf3b463Smrg    while (!gotReply && !ioErrorOccured && iceConn)
405266e564dSmrg    {
406266e564dSmrg	ioErrorOccured = (IceProcessMessages (
407266e564dSmrg	    iceConn, &replyWait, &gotReply) == IceProcessMessagesIOError);
408266e564dSmrg
409266e564dSmrg	if (ioErrorOccured)
410266e564dSmrg	{
411a3129944Smrg	    if (errorStringRet && errorLength > 0) {
4121009a292Smrg		strncpy (errorStringRet, "IO error occurred opening connection",
413a3129944Smrg		    errorLength);
414a3129944Smrg		errorStringRet[errorLength - 1] = '\0';
415a3129944Smrg	    }
416266e564dSmrg	    _IceFreeConnection (iceConn);
417266e564dSmrg	    iceConn = NULL;
418266e564dSmrg	}
419266e564dSmrg	else if (gotReply)
420266e564dSmrg	{
421266e564dSmrg	    if (reply.type == ICE_CONNECTION_REPLY)
422266e564dSmrg	    {
423266e564dSmrg		if (reply.connection_reply.version_index >= _IceVersionCount)
424266e564dSmrg		{
425a3129944Smrg		    if (errorStringRet && errorLength > 0) {
426a3129944Smrg			strncpy (errorStringRet,
427a3129944Smrg			    "Got a bad version index in the Connection Reply",
428a3129944Smrg			    errorLength);
429a3129944Smrg			errorStringRet[errorLength - 1] = '\0';
430a3129944Smrg		    }
431266e564dSmrg
432266e564dSmrg		    free (reply.connection_reply.vendor);
433266e564dSmrg		    free (reply.connection_reply.release);
434266e564dSmrg		    _IceFreeConnection (iceConn);
435266e564dSmrg		    iceConn = NULL;
436266e564dSmrg		}
437266e564dSmrg		else
438266e564dSmrg		{
439266e564dSmrg		    iceConn->my_ice_version_index =
440266e564dSmrg			reply.connection_reply.version_index;
441266e564dSmrg		    iceConn->vendor = reply.connection_reply.vendor;
442266e564dSmrg		    iceConn->release = reply.connection_reply.release;
443266e564dSmrg
444266e564dSmrg		    _IceConnectionObjs[_IceConnectionCount] = iceConn;
445266e564dSmrg		    _IceConnectionStrings[_IceConnectionCount] =
446266e564dSmrg			iceConn->connection_string;
447266e564dSmrg		    _IceConnectionCount++;
448266e564dSmrg
449fb5e8d76Smrg		    free (iceConn->connect_to_you);
450266e564dSmrg		    iceConn->connect_to_you = NULL;
451266e564dSmrg
452266e564dSmrg		    iceConn->connection_status = IceConnectAccepted;
453266e564dSmrg		}
454266e564dSmrg	    }
455266e564dSmrg	    else /* reply.type == ICE_CONNECTION_ERROR */
456266e564dSmrg	    {
457266e564dSmrg		/* Connection failed */
458266e564dSmrg
459a3129944Smrg		if (errorStringRet && errorLength > 0) {
460a3129944Smrg		    strncpy (errorStringRet,
461a3129944Smrg			reply.connection_error.error_message, errorLength);
462a3129944Smrg		    errorStringRet[errorLength - 1] = '\0';
463a3129944Smrg		}
464266e564dSmrg
465266e564dSmrg		free (reply.connection_error.error_message);
466266e564dSmrg
467266e564dSmrg		_IceFreeConnection (iceConn);
468266e564dSmrg		iceConn = NULL;
469266e564dSmrg	    }
470266e564dSmrg	}
471266e564dSmrg    }
472266e564dSmrg
473266e564dSmrg    if (iceConn && _IceWatchProcs)
474266e564dSmrg    {
475266e564dSmrg	/*
476266e564dSmrg	 * Notify the watch procedures that an iceConn was opened.
477266e564dSmrg	 */
478266e564dSmrg
479266e564dSmrg	_IceConnectionOpened (iceConn);
480266e564dSmrg    }
481266e564dSmrg
482266e564dSmrg    return (iceConn);
483266e564dSmrg}
484266e564dSmrg
485266e564dSmrg
486a3129944Smrg
487266e564dSmrgIcePointer
488c5629e66SmrgIceGetConnectionContext (
489c5629e66Smrg	IceConn    iceConn
490c5629e66Smrg)
491266e564dSmrg{
492266e564dSmrg    return (iceConn->context);
493266e564dSmrg}
494266e564dSmrg
495266e564dSmrg
496a3129944Smrg
497266e564dSmrg/* ------------------------------------------------------------------------- *
498266e564dSmrg *                            local routines                                 *
499266e564dSmrg * ------------------------------------------------------------------------- */
500266e564dSmrg
501266e564dSmrg#define ICE_CONNECTION_RETRIES 5
502266e564dSmrg
503266e564dSmrg
504266e564dSmrgstatic XtransConnInfo
505266e564dSmrgConnectToPeer (char *networkIdsList, char **actualConnectionRet)
506266e564dSmrg{
507266e564dSmrg    char addrbuf[256];
508266e564dSmrg    char* address;
509266e564dSmrg    char *ptr, *endptr, *delim;
510266e564dSmrg    int  madeConnection = 0;
511fb5e8d76Smrg    size_t  len;
512fb5e8d76Smrg    int  retry, connect_stat;
513fb5e8d76Smrg    size_t  address_size;
514266e564dSmrg    XtransConnInfo trans_conn = NULL;
515266e564dSmrg
516266e564dSmrg    *actualConnectionRet = NULL;
517266e564dSmrg
518266e564dSmrg    ptr = networkIdsList;
519266e564dSmrg    len = strlen (networkIdsList);
520266e564dSmrg    endptr = networkIdsList + len;
521266e564dSmrg
522266e564dSmrg    if (len < sizeof addrbuf)
523266e564dSmrg    {
524266e564dSmrg       address = addrbuf;
525266e564dSmrg       address_size = 256;
526266e564dSmrg    }
527266e564dSmrg    else
528266e564dSmrg    {
529266e564dSmrg       address = malloc (len + 1);
5303bf3b463Smrg       if (address == NULL)
5313bf3b463Smrg           return NULL;
532266e564dSmrg       address_size = len;
5339ef0b394Smrg    }
534266e564dSmrg
535266e564dSmrg    while (ptr < endptr && !madeConnection)
536266e564dSmrg    {
5373bf3b463Smrg	if ((delim = strchr (ptr, ',')) == NULL)
538266e564dSmrg	    delim = endptr;
539266e564dSmrg
540266e564dSmrg	len = delim - ptr;
541266e564dSmrg	if (len > address_size - 1)
542266e564dSmrg	    len = address_size - 1;
543266e564dSmrg	strncpy (address, ptr, len);
544266e564dSmrg	address[len] = '\0';
545266e564dSmrg
546266e564dSmrg	ptr = delim + 1;
547266e564dSmrg
548266e564dSmrg	for (retry = ICE_CONNECTION_RETRIES; retry >= 0; retry--)
549266e564dSmrg	{
550266e564dSmrg	    if ((trans_conn = _IceTransOpenCOTSClient (address)) == NULL)
551266e564dSmrg	    {
552266e564dSmrg		break;
553266e564dSmrg	    }
554266e564dSmrg
555266e564dSmrg	    if ((connect_stat = _IceTransConnect (trans_conn, address)) < 0)
556266e564dSmrg	    {
557266e564dSmrg		_IceTransClose (trans_conn);
5581009a292Smrg		trans_conn = NULL;
559266e564dSmrg
560266e564dSmrg		if (connect_stat == TRANS_TRY_CONNECT_AGAIN)
561266e564dSmrg		{
562266e564dSmrg		    sleep(1);
563266e564dSmrg		    continue;
564266e564dSmrg		}
565266e564dSmrg		else
566266e564dSmrg		    break;
567266e564dSmrg	    }
568266e564dSmrg	    else
569266e564dSmrg	    {
570266e564dSmrg		madeConnection = 1;
571266e564dSmrg		break;
572266e564dSmrg	    }
573266e564dSmrg	}
574266e564dSmrg    }
575266e564dSmrg
5769ef0b394Smrg    if (madeConnection)
577266e564dSmrg    {
578266e564dSmrg	/*
579266e564dSmrg	 * We need to return the actual network connection string
580266e564dSmrg	 */
581266e564dSmrg
582266e564dSmrg	*actualConnectionRet = strdup(address);
5839ef0b394Smrg
584266e564dSmrg	/*
585266e564dSmrg	 * Return the file descriptor
586266e564dSmrg	 */
5879ef0b394Smrg    }
588266e564dSmrg    else trans_conn = NULL;
589266e564dSmrg
590266e564dSmrg    if (address != addrbuf) free (address);
591266e564dSmrg
592266e564dSmrg    return trans_conn;
593266e564dSmrg}
594