connect.c revision 266e564d
1266e564dSmrg/* $Xorg: connect.c,v 1.4 2001/02/09 02:03:26 xorgcvs Exp $ */
2266e564dSmrg/******************************************************************************
3266e564dSmrg
4266e564dSmrg
5266e564dSmrgCopyright 1993, 1998  The Open Group
6266e564dSmrg
7266e564dSmrgPermission to use, copy, modify, distribute, and sell this software and its
8266e564dSmrgdocumentation for any purpose is hereby granted without fee, provided that
9266e564dSmrgthe above copyright notice appear in all copies and that both that
10266e564dSmrgcopyright notice and this permission notice appear in supporting
11266e564dSmrgdocumentation.
12266e564dSmrg
13266e564dSmrgThe above copyright notice and this permission notice shall be included in
14266e564dSmrgall copies or substantial portions of the Software.
15266e564dSmrg
16266e564dSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17266e564dSmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18266e564dSmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
19266e564dSmrgOPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
20266e564dSmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21266e564dSmrgCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22266e564dSmrg
23266e564dSmrgExcept as contained in this notice, the name of The Open Group shall not be
24266e564dSmrgused in advertising or otherwise to promote the sale, use or other dealings
25266e564dSmrgin this Software without prior written authorization from The Open Group.
26266e564dSmrg
27266e564dSmrgAuthor: Ralph Mor, X Consortium
28266e564dSmrg******************************************************************************/
29266e564dSmrg/* $XFree86: xc/lib/ICE/connect.c,v 3.9 2001/12/14 19:53:35 dawes Exp $ */
30266e564dSmrg
31266e564dSmrg#ifdef HAVE_CONFIG_H
32266e564dSmrg#include <config.h>
33266e564dSmrg#endif
34266e564dSmrg#include <X11/ICE/ICElib.h>
35266e564dSmrg#include "ICElibint.h"
36266e564dSmrg#include <X11/Xtrans/Xtrans.h>
37266e564dSmrg#include "globals.h"
38266e564dSmrg
39266e564dSmrgstatic XtransConnInfo ConnectToPeer(char *networkIdsList,
40266e564dSmrg				    char **actualConnectionRet);
41266e564dSmrg
42266e564dSmrg#define Strstr strstr
43266e564dSmrg
44266e564dSmrgIceConn
45266e564dSmrgIceOpenConnection (networkIdsList, context, mustAuthenticate, majorOpcodeCheck,
46266e564dSmrg    errorLength, errorStringRet)
47266e564dSmrg
48266e564dSmrgchar 	   *networkIdsList;
49266e564dSmrgIcePointer context;
50266e564dSmrgBool 	   mustAuthenticate;
51266e564dSmrgint  	   majorOpcodeCheck;
52266e564dSmrgint  	   errorLength;
53266e564dSmrgchar 	   *errorStringRet;
54266e564dSmrg
55266e564dSmrg{
56266e564dSmrg    IceConn			iceConn;
57266e564dSmrg    int				extra, i, j;
58266e564dSmrg    int		       		endian;
59266e564dSmrg    Bool			gotReply, ioErrorOccured;
60266e564dSmrg    unsigned long		setup_sequence;
61266e564dSmrg    iceByteOrderMsg		*pByteOrderMsg;
62266e564dSmrg    iceConnectionSetupMsg	*pSetupMsg;
63266e564dSmrg    char			*pData;
64266e564dSmrg    IceReplyWaitInfo 		replyWait;
65266e564dSmrg    _IceReply		 	reply;
66266e564dSmrg    int				authUsableCount;
67266e564dSmrg    int				authUsableFlags[MAX_ICE_AUTH_NAMES];
68266e564dSmrg    int				authIndices[MAX_ICE_AUTH_NAMES];
69266e564dSmrg
70266e564dSmrg    if (errorStringRet && errorLength > 0)
71266e564dSmrg	*errorStringRet = '\0';
72266e564dSmrg
73266e564dSmrg    if (networkIdsList == NULL || *networkIdsList == '\0')
74266e564dSmrg    {
75266e564dSmrg	strncpy (errorStringRet,
76266e564dSmrg	    "networkIdsList argument is NULL", errorLength);
77266e564dSmrg	return (NULL);
78266e564dSmrg    }
79266e564dSmrg
80266e564dSmrg    /*
81266e564dSmrg     * Check to see if we can use a previously created ICE connection.
82266e564dSmrg     *
83266e564dSmrg     * If iceConn->want_to_close is True, or iceConn->free_asap is True,
84266e564dSmrg     * we can not use the iceConn.
85266e564dSmrg     *
86266e564dSmrg     * If 'context' is non-NULL, we will only use a previously opened ICE
87266e564dSmrg     * connection if the specified 'context' is equal to the context
88266e564dSmrg     * associated with the ICE connection, or if the context associated
89266e564dSmrg     * with the ICE connection is NULL.
90266e564dSmrg     *
91266e564dSmrg     * If 'majorOpcodeCheck' is non-zero, it will contain a protocol major
92266e564dSmrg     * opcode that we should make sure is not already active on the ICE
93266e564dSmrg     * connection.  Some clients will want two seperate connections for the
94266e564dSmrg     * same protocol to the same destination client.
95266e564dSmrg     */
96266e564dSmrg
97266e564dSmrg    for (i = 0; i < _IceConnectionCount; i++)
98266e564dSmrg    {
99266e564dSmrg	char *strptr;
100266e564dSmrg	if ((strptr = (char *) Strstr (
101266e564dSmrg	    networkIdsList, _IceConnectionStrings[i])) != NULL)
102266e564dSmrg	{
103266e564dSmrg	    char ch = *(strptr + strlen (_IceConnectionStrings[i]));
104266e564dSmrg	    if (ch == ',' || ch == '\0')
105266e564dSmrg	    {
106266e564dSmrg		/*
107266e564dSmrg		 * OK, we found a connection.  Make sure we can reuse it.
108266e564dSmrg		 */
109266e564dSmrg
110266e564dSmrg		IceConn iceConn = _IceConnectionObjs[i];
111266e564dSmrg
112266e564dSmrg		if (iceConn->want_to_close || iceConn->free_asap ||
113266e564dSmrg		    (context && iceConn->context &&
114266e564dSmrg		     iceConn->context != context))
115266e564dSmrg		{
116266e564dSmrg		    /* force a new connection to be created */
117266e564dSmrg		    break;
118266e564dSmrg		}
119266e564dSmrg
120266e564dSmrg		if (majorOpcodeCheck)
121266e564dSmrg		{
122266e564dSmrg		    for (j = iceConn->his_min_opcode;
123266e564dSmrg		        j <= iceConn->his_max_opcode; j++)
124266e564dSmrg		    {
125266e564dSmrg			if (iceConn->process_msg_info[
126266e564dSmrg			    j - iceConn->his_min_opcode].in_use &&
127266e564dSmrg			    iceConn->process_msg_info[
128266e564dSmrg			    j - iceConn->his_min_opcode].my_opcode ==
129266e564dSmrg			    majorOpcodeCheck)
130266e564dSmrg			    break;
131266e564dSmrg		    }
132266e564dSmrg
133266e564dSmrg		    if (j <= iceConn->his_max_opcode ||
134266e564dSmrg			(iceConn->protosetup_to_you &&
135266e564dSmrg			iceConn->protosetup_to_you->my_opcode ==
136266e564dSmrg			majorOpcodeCheck))
137266e564dSmrg		    {
138266e564dSmrg			/* force a new connection to be created */
139266e564dSmrg			break;
140266e564dSmrg		    }
141266e564dSmrg		}
142266e564dSmrg
143266e564dSmrg		iceConn->open_ref_count++;
144266e564dSmrg		if (context && !iceConn->context)
145266e564dSmrg		    iceConn->context = context;
146266e564dSmrg		return (iceConn);
147266e564dSmrg	    }
148266e564dSmrg	}
149266e564dSmrg    }
150266e564dSmrg
151266e564dSmrg    if ((iceConn = (IceConn) malloc (sizeof (struct _IceConn))) == NULL)
152266e564dSmrg    {
153266e564dSmrg	strncpy (errorStringRet, "Can't malloc", errorLength);
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    {
165266e564dSmrg	free ((char *) iceConn);
166266e564dSmrg	strncpy (errorStringRet, "Could not open network socket", errorLength);
167266e564dSmrg	return (NULL);
168266e564dSmrg    }
169266e564dSmrg
170266e564dSmrg    /*
171266e564dSmrg     * Set close-on-exec so that programs that fork() don't get confused.
172266e564dSmrg     */
173266e564dSmrg
174266e564dSmrg    _IceTransSetOption (iceConn->trans_conn, TRANS_CLOSEONEXEC, 1);
175266e564dSmrg
176266e564dSmrg    iceConn->listen_obj = NULL;
177266e564dSmrg
178266e564dSmrg    iceConn->connection_status = IceConnectPending;
179266e564dSmrg    iceConn->io_ok = True;
180266e564dSmrg    iceConn->dispatch_level = 0;
181266e564dSmrg    iceConn->context = context;
182266e564dSmrg    iceConn->my_ice_version_index = 0;
183266e564dSmrg    iceConn->send_sequence = 0;
184266e564dSmrg    iceConn->receive_sequence = 0;
185266e564dSmrg
186266e564dSmrg    iceConn->vendor = NULL;
187266e564dSmrg    iceConn->release = NULL;
188266e564dSmrg    iceConn->outbuf = NULL;
189266e564dSmrg
190266e564dSmrg    iceConn->scratch = NULL;
191266e564dSmrg    iceConn->scratch_size = 0;
192266e564dSmrg
193266e564dSmrg    iceConn->process_msg_info = NULL;
194266e564dSmrg
195266e564dSmrg    iceConn->connect_to_you = NULL;
196266e564dSmrg    iceConn->protosetup_to_you = NULL;
197266e564dSmrg
198266e564dSmrg    iceConn->connect_to_me = NULL;
199266e564dSmrg    iceConn->protosetup_to_me = NULL;
200266e564dSmrg
201266e564dSmrg    if ((iceConn->inbuf = iceConn->inbufptr =
202266e564dSmrg	(char *) malloc (ICE_INBUFSIZE)) == NULL)
203266e564dSmrg    {
204266e564dSmrg	_IceFreeConnection (iceConn);
205266e564dSmrg	strncpy (errorStringRet, "Can't malloc", errorLength);
206266e564dSmrg	return (NULL);
207266e564dSmrg    }
208266e564dSmrg
209266e564dSmrg    iceConn->inbufmax = iceConn->inbuf + ICE_INBUFSIZE;
210266e564dSmrg
211266e564dSmrg    if ((iceConn->outbuf = iceConn->outbufptr =
212266e564dSmrg	(char *) calloc (1, ICE_OUTBUFSIZE)) == NULL)
213266e564dSmrg    {
214266e564dSmrg	_IceFreeConnection (iceConn);
215266e564dSmrg	strncpy (errorStringRet, "Can't malloc", errorLength);
216266e564dSmrg	return (NULL);
217266e564dSmrg    }
218266e564dSmrg
219266e564dSmrg    iceConn->outbufmax = iceConn->outbuf + ICE_OUTBUFSIZE;
220266e564dSmrg
221266e564dSmrg    iceConn->open_ref_count = 1;
222266e564dSmrg    iceConn->proto_ref_count = 0;
223266e564dSmrg
224266e564dSmrg    iceConn->skip_want_to_close = False;
225266e564dSmrg    iceConn->want_to_close = False;
226266e564dSmrg    iceConn->free_asap = False;
227266e564dSmrg
228266e564dSmrg    iceConn->saved_reply_waits = NULL;
229266e564dSmrg    iceConn->ping_waits = NULL;
230266e564dSmrg
231266e564dSmrg    iceConn->connect_to_you = (_IceConnectToYouInfo *) malloc (
232266e564dSmrg	sizeof (_IceConnectToYouInfo));
233266e564dSmrg    iceConn->connect_to_you->auth_active = 0;
234266e564dSmrg
235266e564dSmrg    /*
236266e564dSmrg     * Send our byte order.
237266e564dSmrg     */
238266e564dSmrg
239266e564dSmrg    IceGetHeader (iceConn, 0, ICE_ByteOrder,
240266e564dSmrg	SIZEOF (iceByteOrderMsg), iceByteOrderMsg, pByteOrderMsg);
241266e564dSmrg
242266e564dSmrg    endian = 1;
243266e564dSmrg    if (*(char *) &endian)
244266e564dSmrg	pByteOrderMsg->byteOrder = IceLSBfirst;
245266e564dSmrg    else
246266e564dSmrg	pByteOrderMsg->byteOrder = IceMSBfirst;
247266e564dSmrg
248266e564dSmrg    IceFlush (iceConn);
249266e564dSmrg
250266e564dSmrg
251266e564dSmrg    /*
252266e564dSmrg     * Now read the ByteOrder message from the other client.
253266e564dSmrg     * iceConn->swap should be set to the appropriate boolean
254266e564dSmrg     * value after the call to IceProcessMessages.
255266e564dSmrg     */
256266e564dSmrg
257266e564dSmrg    iceConn->waiting_for_byteorder = True;
258266e564dSmrg
259266e564dSmrg    ioErrorOccured = False;
260266e564dSmrg    while (iceConn->waiting_for_byteorder == True && !ioErrorOccured)
261266e564dSmrg    {
262266e564dSmrg	ioErrorOccured = (IceProcessMessages (
263266e564dSmrg	    iceConn, NULL, NULL) == IceProcessMessagesIOError);
264266e564dSmrg    }
265266e564dSmrg
266266e564dSmrg    if (ioErrorOccured)
267266e564dSmrg    {
268266e564dSmrg	_IceFreeConnection (iceConn);
269266e564dSmrg	strncpy (errorStringRet, "IO error occured opening connection",
270266e564dSmrg	     errorLength);
271266e564dSmrg	return (NULL);
272266e564dSmrg    }
273266e564dSmrg
274266e564dSmrg    if (iceConn->connection_status == IceConnectRejected)
275266e564dSmrg    {
276266e564dSmrg	/*
277266e564dSmrg	 * We failed to get the required ByteOrder message.
278266e564dSmrg	 */
279266e564dSmrg
280266e564dSmrg	_IceFreeConnection (iceConn);
281266e564dSmrg	strncpy (errorStringRet,
282266e564dSmrg	    "Internal error - did not receive the expected ByteOrder message",
283266e564dSmrg	     errorLength);
284266e564dSmrg	return (NULL);
285266e564dSmrg    }
286266e564dSmrg
287266e564dSmrg
288266e564dSmrg    /*
289266e564dSmrg     * Determine which authentication methods are available for
290266e564dSmrg     * the Connection Setup authentication.
291266e564dSmrg     */
292266e564dSmrg
293266e564dSmrg    _IceGetPoValidAuthIndices (
294266e564dSmrg	"ICE", iceConn->connection_string,
295266e564dSmrg	_IceAuthCount, _IceAuthNames, &authUsableCount, authIndices);
296266e564dSmrg
297266e564dSmrg    for (i = 0; i < _IceAuthCount; i++)
298266e564dSmrg    {
299266e564dSmrg	authUsableFlags[i] = 0;
300266e564dSmrg	for (j = 0; j < authUsableCount && !authUsableFlags[i]; j++)
301266e564dSmrg	    authUsableFlags[i] = (authIndices[j] == i);
302266e564dSmrg    }
303266e564dSmrg
304266e564dSmrg
305266e564dSmrg    /*
306266e564dSmrg     * Now send a Connection Setup message.
307266e564dSmrg     */
308266e564dSmrg
309266e564dSmrg    extra = STRING_BYTES (IceVendorString) + STRING_BYTES (IceReleaseString);
310266e564dSmrg
311266e564dSmrg    for (i = 0; i < _IceAuthCount; i++)
312266e564dSmrg	if (authUsableFlags[i])
313266e564dSmrg	{
314266e564dSmrg	    extra += STRING_BYTES (_IceAuthNames[i]);
315266e564dSmrg	}
316266e564dSmrg
317266e564dSmrg    extra += (_IceVersionCount * 4);
318266e564dSmrg
319266e564dSmrg    IceGetHeaderExtra (iceConn, 0, ICE_ConnectionSetup,
320266e564dSmrg	SIZEOF (iceConnectionSetupMsg), WORD64COUNT (extra),
321266e564dSmrg	iceConnectionSetupMsg, pSetupMsg, pData);
322266e564dSmrg
323266e564dSmrg    setup_sequence = iceConn->send_sequence;
324266e564dSmrg
325266e564dSmrg    pSetupMsg->versionCount = _IceVersionCount;
326266e564dSmrg    pSetupMsg->authCount = authUsableCount;
327266e564dSmrg    pSetupMsg->mustAuthenticate = mustAuthenticate;
328266e564dSmrg
329266e564dSmrg    STORE_STRING (pData, IceVendorString);
330266e564dSmrg    STORE_STRING (pData, IceReleaseString);
331266e564dSmrg
332266e564dSmrg    for (i = 0; i < _IceAuthCount; i++)
333266e564dSmrg	if (authUsableFlags[i])
334266e564dSmrg	{
335266e564dSmrg	    STORE_STRING (pData, _IceAuthNames[i]);
336266e564dSmrg	}
337266e564dSmrg
338266e564dSmrg    for (i = 0; i < _IceVersionCount; i++)
339266e564dSmrg    {
340266e564dSmrg	STORE_CARD16 (pData, _IceVersions[i].major_version);
341266e564dSmrg	STORE_CARD16 (pData, _IceVersions[i].minor_version);
342266e564dSmrg    }
343266e564dSmrg
344266e564dSmrg    IceFlush (iceConn);
345266e564dSmrg
346266e564dSmrg
347266e564dSmrg    /*
348266e564dSmrg     * Process messages until we get a Connection Reply or an Error Message.
349266e564dSmrg     * Authentication will take place behind the scenes.
350266e564dSmrg     */
351266e564dSmrg
352266e564dSmrg    replyWait.sequence_of_request = setup_sequence;
353266e564dSmrg    replyWait.major_opcode_of_request = 0;
354266e564dSmrg    replyWait.minor_opcode_of_request = ICE_ConnectionSetup;
355266e564dSmrg    replyWait.reply = (IcePointer) &reply;
356266e564dSmrg
357266e564dSmrg    gotReply = False;
358266e564dSmrg    ioErrorOccured = False;
359266e564dSmrg
360266e564dSmrg    while (!gotReply && !ioErrorOccured)
361266e564dSmrg    {
362266e564dSmrg	ioErrorOccured = (IceProcessMessages (
363266e564dSmrg	    iceConn, &replyWait, &gotReply) == IceProcessMessagesIOError);
364266e564dSmrg
365266e564dSmrg	if (ioErrorOccured)
366266e564dSmrg	{
367266e564dSmrg	    strncpy (errorStringRet, "IO error occured opening connection",
368266e564dSmrg		errorLength);
369266e564dSmrg	    _IceFreeConnection (iceConn);
370266e564dSmrg	    iceConn = NULL;
371266e564dSmrg	}
372266e564dSmrg	else if (gotReply)
373266e564dSmrg	{
374266e564dSmrg	    if (reply.type == ICE_CONNECTION_REPLY)
375266e564dSmrg	    {
376266e564dSmrg		if (reply.connection_reply.version_index >= _IceVersionCount)
377266e564dSmrg		{
378266e564dSmrg		    strncpy (errorStringRet,
379266e564dSmrg	    		"Got a bad version index in the Connection Reply",
380266e564dSmrg			errorLength);
381266e564dSmrg
382266e564dSmrg		    free (reply.connection_reply.vendor);
383266e564dSmrg		    free (reply.connection_reply.release);
384266e564dSmrg		    _IceFreeConnection (iceConn);
385266e564dSmrg		    iceConn = NULL;
386266e564dSmrg		}
387266e564dSmrg		else
388266e564dSmrg		{
389266e564dSmrg		    iceConn->my_ice_version_index =
390266e564dSmrg			reply.connection_reply.version_index;
391266e564dSmrg		    iceConn->vendor = reply.connection_reply.vendor;
392266e564dSmrg		    iceConn->release = reply.connection_reply.release;
393266e564dSmrg
394266e564dSmrg		    _IceConnectionObjs[_IceConnectionCount] = iceConn;
395266e564dSmrg		    _IceConnectionStrings[_IceConnectionCount] =
396266e564dSmrg			iceConn->connection_string;
397266e564dSmrg		    _IceConnectionCount++;
398266e564dSmrg
399266e564dSmrg		    free ((char *) iceConn->connect_to_you);
400266e564dSmrg		    iceConn->connect_to_you = NULL;
401266e564dSmrg
402266e564dSmrg		    iceConn->connection_status = IceConnectAccepted;
403266e564dSmrg		}
404266e564dSmrg	    }
405266e564dSmrg	    else /* reply.type == ICE_CONNECTION_ERROR */
406266e564dSmrg	    {
407266e564dSmrg		/* Connection failed */
408266e564dSmrg
409266e564dSmrg		strncpy (errorStringRet, reply.connection_error.error_message,
410266e564dSmrg		    errorLength);
411266e564dSmrg
412266e564dSmrg		free (reply.connection_error.error_message);
413266e564dSmrg
414266e564dSmrg		_IceFreeConnection (iceConn);
415266e564dSmrg		iceConn = NULL;
416266e564dSmrg	    }
417266e564dSmrg	}
418266e564dSmrg    }
419266e564dSmrg
420266e564dSmrg    if (iceConn && _IceWatchProcs)
421266e564dSmrg    {
422266e564dSmrg	/*
423266e564dSmrg	 * Notify the watch procedures that an iceConn was opened.
424266e564dSmrg	 */
425266e564dSmrg
426266e564dSmrg	_IceConnectionOpened (iceConn);
427266e564dSmrg    }
428266e564dSmrg
429266e564dSmrg    return (iceConn);
430266e564dSmrg}
431266e564dSmrg
432266e564dSmrg
433266e564dSmrg
434266e564dSmrgIcePointer
435266e564dSmrgIceGetConnectionContext (iceConn)
436266e564dSmrg
437266e564dSmrgIceConn    iceConn;
438266e564dSmrg
439266e564dSmrg{
440266e564dSmrg    return (iceConn->context);
441266e564dSmrg}
442266e564dSmrg
443266e564dSmrg
444266e564dSmrg
445266e564dSmrg/* ------------------------------------------------------------------------- *
446266e564dSmrg *                            local routines                                 *
447266e564dSmrg * ------------------------------------------------------------------------- */
448266e564dSmrg
449266e564dSmrg#define ICE_CONNECTION_RETRIES 5
450266e564dSmrg
451266e564dSmrg
452266e564dSmrgstatic XtransConnInfo
453266e564dSmrgConnectToPeer (char *networkIdsList, char **actualConnectionRet)
454266e564dSmrg{
455266e564dSmrg    char addrbuf[256];
456266e564dSmrg    char* address;
457266e564dSmrg    char *ptr, *endptr, *delim;
458266e564dSmrg    int  madeConnection = 0;
459266e564dSmrg    int  len, retry;
460266e564dSmrg    int  connect_stat;
461266e564dSmrg    int  address_size;
462266e564dSmrg    XtransConnInfo trans_conn = NULL;
463266e564dSmrg
464266e564dSmrg    *actualConnectionRet = NULL;
465266e564dSmrg
466266e564dSmrg    ptr = networkIdsList;
467266e564dSmrg    len = strlen (networkIdsList);
468266e564dSmrg    endptr = networkIdsList + len;
469266e564dSmrg
470266e564dSmrg    if (len < sizeof addrbuf)
471266e564dSmrg    {
472266e564dSmrg       address = addrbuf;
473266e564dSmrg       address_size = 256;
474266e564dSmrg    }
475266e564dSmrg    else
476266e564dSmrg    {
477266e564dSmrg       address = malloc (len + 1);
478266e564dSmrg       address_size = len;
479266e564dSmrg    }
480266e564dSmrg
481266e564dSmrg    while (ptr < endptr && !madeConnection)
482266e564dSmrg    {
483266e564dSmrg	if ((delim = (char *) strchr (ptr, ',')) == NULL)
484266e564dSmrg	    delim = endptr;
485266e564dSmrg
486266e564dSmrg	len = delim - ptr;
487266e564dSmrg	if (len > address_size - 1)
488266e564dSmrg	    len = address_size - 1;
489266e564dSmrg	strncpy (address, ptr, len);
490266e564dSmrg	address[len] = '\0';
491266e564dSmrg
492266e564dSmrg	ptr = delim + 1;
493266e564dSmrg
494266e564dSmrg	for (retry = ICE_CONNECTION_RETRIES; retry >= 0; retry--)
495266e564dSmrg	{
496266e564dSmrg	    if ((trans_conn = _IceTransOpenCOTSClient (address)) == NULL)
497266e564dSmrg	    {
498266e564dSmrg		break;
499266e564dSmrg	    }
500266e564dSmrg
501266e564dSmrg	    if ((connect_stat = _IceTransConnect (trans_conn, address)) < 0)
502266e564dSmrg	    {
503266e564dSmrg		_IceTransClose (trans_conn);
504266e564dSmrg
505266e564dSmrg		if (connect_stat == TRANS_TRY_CONNECT_AGAIN)
506266e564dSmrg		{
507266e564dSmrg		    sleep(1);
508266e564dSmrg		    continue;
509266e564dSmrg		}
510266e564dSmrg		else
511266e564dSmrg		    break;
512266e564dSmrg	    }
513266e564dSmrg	    else
514266e564dSmrg	    {
515266e564dSmrg		madeConnection = 1;
516266e564dSmrg		break;
517266e564dSmrg	    }
518266e564dSmrg	}
519266e564dSmrg    }
520266e564dSmrg
521266e564dSmrg    if (madeConnection)
522266e564dSmrg    {
523266e564dSmrg	/*
524266e564dSmrg	 * We need to return the actual network connection string
525266e564dSmrg	 */
526266e564dSmrg
527266e564dSmrg	*actualConnectionRet = strdup(address);
528266e564dSmrg
529266e564dSmrg	/*
530266e564dSmrg	 * Return the file descriptor
531266e564dSmrg	 */
532266e564dSmrg    }
533266e564dSmrg    else trans_conn = NULL;
534266e564dSmrg
535266e564dSmrg    if (address != addrbuf) free (address);
536266e564dSmrg
537266e564dSmrg    return trans_conn;
538266e564dSmrg}
539