connect.c revision c5629e66
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
45c5629e66SmrgIceOpenConnection (
46c5629e66Smrg	char 	   *networkIdsList,
47c5629e66Smrg	IcePointer context,
48c5629e66Smrg	Bool 	   mustAuthenticate,
49c5629e66Smrg	int  	   majorOpcodeCheck,
50c5629e66Smrg	int  	   errorLength,
51c5629e66Smrg	char 	   *errorStringRet
52c5629e66Smrg)
53266e564dSmrg{
54266e564dSmrg    IceConn			iceConn;
55266e564dSmrg    int				extra, i, j;
56266e564dSmrg    int		       		endian;
57266e564dSmrg    Bool			gotReply, ioErrorOccured;
58266e564dSmrg    unsigned long		setup_sequence;
59266e564dSmrg    iceByteOrderMsg		*pByteOrderMsg;
60266e564dSmrg    iceConnectionSetupMsg	*pSetupMsg;
61266e564dSmrg    char			*pData;
62266e564dSmrg    IceReplyWaitInfo 		replyWait;
63266e564dSmrg    _IceReply		 	reply;
64266e564dSmrg    int				authUsableCount;
65266e564dSmrg    int				authUsableFlags[MAX_ICE_AUTH_NAMES];
66266e564dSmrg    int				authIndices[MAX_ICE_AUTH_NAMES];
67266e564dSmrg
68266e564dSmrg    if (errorStringRet && errorLength > 0)
69266e564dSmrg	*errorStringRet = '\0';
70266e564dSmrg
71266e564dSmrg    if (networkIdsList == NULL || *networkIdsList == '\0')
72266e564dSmrg    {
73266e564dSmrg	strncpy (errorStringRet,
74266e564dSmrg	    "networkIdsList argument is NULL", errorLength);
75266e564dSmrg	return (NULL);
76266e564dSmrg    }
77266e564dSmrg
78266e564dSmrg    /*
79266e564dSmrg     * Check to see if we can use a previously created ICE connection.
80266e564dSmrg     *
81266e564dSmrg     * If iceConn->want_to_close is True, or iceConn->free_asap is True,
82266e564dSmrg     * we can not use the iceConn.
83266e564dSmrg     *
84266e564dSmrg     * If 'context' is non-NULL, we will only use a previously opened ICE
85266e564dSmrg     * connection if the specified 'context' is equal to the context
86266e564dSmrg     * associated with the ICE connection, or if the context associated
87266e564dSmrg     * with the ICE connection is NULL.
88266e564dSmrg     *
89266e564dSmrg     * If 'majorOpcodeCheck' is non-zero, it will contain a protocol major
90266e564dSmrg     * opcode that we should make sure is not already active on the ICE
91266e564dSmrg     * connection.  Some clients will want two seperate connections for the
92266e564dSmrg     * same protocol to the same destination client.
93266e564dSmrg     */
94266e564dSmrg
95266e564dSmrg    for (i = 0; i < _IceConnectionCount; i++)
96266e564dSmrg    {
97266e564dSmrg	char *strptr;
98266e564dSmrg	if ((strptr = (char *) Strstr (
99266e564dSmrg	    networkIdsList, _IceConnectionStrings[i])) != NULL)
100266e564dSmrg	{
101266e564dSmrg	    char ch = *(strptr + strlen (_IceConnectionStrings[i]));
102266e564dSmrg	    if (ch == ',' || ch == '\0')
103266e564dSmrg	    {
104266e564dSmrg		/*
105266e564dSmrg		 * OK, we found a connection.  Make sure we can reuse it.
106266e564dSmrg		 */
107266e564dSmrg
108266e564dSmrg		IceConn iceConn = _IceConnectionObjs[i];
109266e564dSmrg
110266e564dSmrg		if (iceConn->want_to_close || iceConn->free_asap ||
111266e564dSmrg		    (context && iceConn->context &&
112266e564dSmrg		     iceConn->context != context))
113266e564dSmrg		{
114266e564dSmrg		    /* force a new connection to be created */
115266e564dSmrg		    break;
116266e564dSmrg		}
117266e564dSmrg
118266e564dSmrg		if (majorOpcodeCheck)
119266e564dSmrg		{
120266e564dSmrg		    for (j = iceConn->his_min_opcode;
121266e564dSmrg		        j <= iceConn->his_max_opcode; j++)
122266e564dSmrg		    {
123266e564dSmrg			if (iceConn->process_msg_info[
124266e564dSmrg			    j - iceConn->his_min_opcode].in_use &&
125266e564dSmrg			    iceConn->process_msg_info[
126266e564dSmrg			    j - iceConn->his_min_opcode].my_opcode ==
127266e564dSmrg			    majorOpcodeCheck)
128266e564dSmrg			    break;
129266e564dSmrg		    }
130266e564dSmrg
131266e564dSmrg		    if (j <= iceConn->his_max_opcode ||
132266e564dSmrg			(iceConn->protosetup_to_you &&
133266e564dSmrg			iceConn->protosetup_to_you->my_opcode ==
134266e564dSmrg			majorOpcodeCheck))
135266e564dSmrg		    {
136266e564dSmrg			/* force a new connection to be created */
137266e564dSmrg			break;
138266e564dSmrg		    }
139266e564dSmrg		}
140266e564dSmrg
141266e564dSmrg		iceConn->open_ref_count++;
142266e564dSmrg		if (context && !iceConn->context)
143266e564dSmrg		    iceConn->context = context;
144266e564dSmrg		return (iceConn);
145266e564dSmrg	    }
146266e564dSmrg	}
147266e564dSmrg    }
148266e564dSmrg
149266e564dSmrg    if ((iceConn = (IceConn) malloc (sizeof (struct _IceConn))) == NULL)
150266e564dSmrg    {
151266e564dSmrg	strncpy (errorStringRet, "Can't malloc", errorLength);
152266e564dSmrg	return (NULL);
153266e564dSmrg    }
154266e564dSmrg
155266e564dSmrg
156266e564dSmrg    /*
157266e564dSmrg     * Open a network connection with the peer client.
158266e564dSmrg     */
159266e564dSmrg
160266e564dSmrg    if ((iceConn->trans_conn = ConnectToPeer (networkIdsList,
161266e564dSmrg	&iceConn->connection_string)) == NULL)
162266e564dSmrg    {
163266e564dSmrg	free ((char *) iceConn);
164266e564dSmrg	strncpy (errorStringRet, "Could not open network socket", errorLength);
165266e564dSmrg	return (NULL);
166266e564dSmrg    }
167266e564dSmrg
168266e564dSmrg    /*
169266e564dSmrg     * Set close-on-exec so that programs that fork() don't get confused.
170266e564dSmrg     */
171266e564dSmrg
172266e564dSmrg    _IceTransSetOption (iceConn->trans_conn, TRANS_CLOSEONEXEC, 1);
173266e564dSmrg
174266e564dSmrg    iceConn->listen_obj = NULL;
175266e564dSmrg
176266e564dSmrg    iceConn->connection_status = IceConnectPending;
177266e564dSmrg    iceConn->io_ok = True;
178266e564dSmrg    iceConn->dispatch_level = 0;
179266e564dSmrg    iceConn->context = context;
180266e564dSmrg    iceConn->my_ice_version_index = 0;
181266e564dSmrg    iceConn->send_sequence = 0;
182266e564dSmrg    iceConn->receive_sequence = 0;
183266e564dSmrg
184266e564dSmrg    iceConn->vendor = NULL;
185266e564dSmrg    iceConn->release = NULL;
186266e564dSmrg    iceConn->outbuf = NULL;
187266e564dSmrg
188266e564dSmrg    iceConn->scratch = NULL;
189266e564dSmrg    iceConn->scratch_size = 0;
190266e564dSmrg
191266e564dSmrg    iceConn->process_msg_info = NULL;
192266e564dSmrg
193266e564dSmrg    iceConn->connect_to_you = NULL;
194266e564dSmrg    iceConn->protosetup_to_you = NULL;
195266e564dSmrg
196266e564dSmrg    iceConn->connect_to_me = NULL;
197266e564dSmrg    iceConn->protosetup_to_me = NULL;
198266e564dSmrg
199266e564dSmrg    if ((iceConn->inbuf = iceConn->inbufptr =
200266e564dSmrg	(char *) malloc (ICE_INBUFSIZE)) == NULL)
201266e564dSmrg    {
202266e564dSmrg	_IceFreeConnection (iceConn);
203266e564dSmrg	strncpy (errorStringRet, "Can't malloc", errorLength);
204266e564dSmrg	return (NULL);
205266e564dSmrg    }
206266e564dSmrg
207266e564dSmrg    iceConn->inbufmax = iceConn->inbuf + ICE_INBUFSIZE;
208266e564dSmrg
209266e564dSmrg    if ((iceConn->outbuf = iceConn->outbufptr =
210266e564dSmrg	(char *) calloc (1, ICE_OUTBUFSIZE)) == NULL)
211266e564dSmrg    {
212266e564dSmrg	_IceFreeConnection (iceConn);
213266e564dSmrg	strncpy (errorStringRet, "Can't malloc", errorLength);
214266e564dSmrg	return (NULL);
215266e564dSmrg    }
216266e564dSmrg
217266e564dSmrg    iceConn->outbufmax = iceConn->outbuf + ICE_OUTBUFSIZE;
218266e564dSmrg
219266e564dSmrg    iceConn->open_ref_count = 1;
220266e564dSmrg    iceConn->proto_ref_count = 0;
221266e564dSmrg
222266e564dSmrg    iceConn->skip_want_to_close = False;
223266e564dSmrg    iceConn->want_to_close = False;
224266e564dSmrg    iceConn->free_asap = False;
225266e564dSmrg
226266e564dSmrg    iceConn->saved_reply_waits = NULL;
227266e564dSmrg    iceConn->ping_waits = NULL;
228266e564dSmrg
229266e564dSmrg    iceConn->connect_to_you = (_IceConnectToYouInfo *) malloc (
230266e564dSmrg	sizeof (_IceConnectToYouInfo));
231266e564dSmrg    iceConn->connect_to_you->auth_active = 0;
232266e564dSmrg
233266e564dSmrg    /*
234266e564dSmrg     * Send our byte order.
235266e564dSmrg     */
236266e564dSmrg
237266e564dSmrg    IceGetHeader (iceConn, 0, ICE_ByteOrder,
238266e564dSmrg	SIZEOF (iceByteOrderMsg), iceByteOrderMsg, pByteOrderMsg);
239266e564dSmrg
240266e564dSmrg    endian = 1;
241266e564dSmrg    if (*(char *) &endian)
242266e564dSmrg	pByteOrderMsg->byteOrder = IceLSBfirst;
243266e564dSmrg    else
244266e564dSmrg	pByteOrderMsg->byteOrder = IceMSBfirst;
245266e564dSmrg
246266e564dSmrg    IceFlush (iceConn);
247266e564dSmrg
248266e564dSmrg
249266e564dSmrg    /*
250266e564dSmrg     * Now read the ByteOrder message from the other client.
251266e564dSmrg     * iceConn->swap should be set to the appropriate boolean
252266e564dSmrg     * value after the call to IceProcessMessages.
253266e564dSmrg     */
254266e564dSmrg
255266e564dSmrg    iceConn->waiting_for_byteorder = True;
256266e564dSmrg
257266e564dSmrg    ioErrorOccured = False;
258266e564dSmrg    while (iceConn->waiting_for_byteorder == True && !ioErrorOccured)
259266e564dSmrg    {
260266e564dSmrg	ioErrorOccured = (IceProcessMessages (
261266e564dSmrg	    iceConn, NULL, NULL) == IceProcessMessagesIOError);
262266e564dSmrg    }
263266e564dSmrg
264266e564dSmrg    if (ioErrorOccured)
265266e564dSmrg    {
266266e564dSmrg	_IceFreeConnection (iceConn);
267266e564dSmrg	strncpy (errorStringRet, "IO error occured opening connection",
268266e564dSmrg	     errorLength);
269266e564dSmrg	return (NULL);
270266e564dSmrg    }
271266e564dSmrg
272266e564dSmrg    if (iceConn->connection_status == IceConnectRejected)
273266e564dSmrg    {
274266e564dSmrg	/*
275266e564dSmrg	 * We failed to get the required ByteOrder message.
276266e564dSmrg	 */
277266e564dSmrg
278266e564dSmrg	_IceFreeConnection (iceConn);
279266e564dSmrg	strncpy (errorStringRet,
280266e564dSmrg	    "Internal error - did not receive the expected ByteOrder message",
281266e564dSmrg	     errorLength);
282266e564dSmrg	return (NULL);
283266e564dSmrg    }
284266e564dSmrg
285266e564dSmrg
286266e564dSmrg    /*
287266e564dSmrg     * Determine which authentication methods are available for
288266e564dSmrg     * the Connection Setup authentication.
289266e564dSmrg     */
290266e564dSmrg
291266e564dSmrg    _IceGetPoValidAuthIndices (
292266e564dSmrg	"ICE", iceConn->connection_string,
293266e564dSmrg	_IceAuthCount, _IceAuthNames, &authUsableCount, authIndices);
294266e564dSmrg
295266e564dSmrg    for (i = 0; i < _IceAuthCount; i++)
296266e564dSmrg    {
297266e564dSmrg	authUsableFlags[i] = 0;
298266e564dSmrg	for (j = 0; j < authUsableCount && !authUsableFlags[i]; j++)
299266e564dSmrg	    authUsableFlags[i] = (authIndices[j] == i);
300266e564dSmrg    }
301266e564dSmrg
302266e564dSmrg
303266e564dSmrg    /*
304266e564dSmrg     * Now send a Connection Setup message.
305266e564dSmrg     */
306266e564dSmrg
307266e564dSmrg    extra = STRING_BYTES (IceVendorString) + STRING_BYTES (IceReleaseString);
308266e564dSmrg
309266e564dSmrg    for (i = 0; i < _IceAuthCount; i++)
310266e564dSmrg	if (authUsableFlags[i])
311266e564dSmrg	{
312266e564dSmrg	    extra += STRING_BYTES (_IceAuthNames[i]);
313266e564dSmrg	}
314266e564dSmrg
315266e564dSmrg    extra += (_IceVersionCount * 4);
316266e564dSmrg
317266e564dSmrg    IceGetHeaderExtra (iceConn, 0, ICE_ConnectionSetup,
318266e564dSmrg	SIZEOF (iceConnectionSetupMsg), WORD64COUNT (extra),
319266e564dSmrg	iceConnectionSetupMsg, pSetupMsg, pData);
320266e564dSmrg
321266e564dSmrg    setup_sequence = iceConn->send_sequence;
322266e564dSmrg
323266e564dSmrg    pSetupMsg->versionCount = _IceVersionCount;
324266e564dSmrg    pSetupMsg->authCount = authUsableCount;
325266e564dSmrg    pSetupMsg->mustAuthenticate = mustAuthenticate;
326266e564dSmrg
327266e564dSmrg    STORE_STRING (pData, IceVendorString);
328266e564dSmrg    STORE_STRING (pData, IceReleaseString);
329266e564dSmrg
330266e564dSmrg    for (i = 0; i < _IceAuthCount; i++)
331266e564dSmrg	if (authUsableFlags[i])
332266e564dSmrg	{
333266e564dSmrg	    STORE_STRING (pData, _IceAuthNames[i]);
334266e564dSmrg	}
335266e564dSmrg
336266e564dSmrg    for (i = 0; i < _IceVersionCount; i++)
337266e564dSmrg    {
338266e564dSmrg	STORE_CARD16 (pData, _IceVersions[i].major_version);
339266e564dSmrg	STORE_CARD16 (pData, _IceVersions[i].minor_version);
340266e564dSmrg    }
341266e564dSmrg
342266e564dSmrg    IceFlush (iceConn);
343266e564dSmrg
344266e564dSmrg
345266e564dSmrg    /*
346266e564dSmrg     * Process messages until we get a Connection Reply or an Error Message.
347266e564dSmrg     * Authentication will take place behind the scenes.
348266e564dSmrg     */
349266e564dSmrg
350266e564dSmrg    replyWait.sequence_of_request = setup_sequence;
351266e564dSmrg    replyWait.major_opcode_of_request = 0;
352266e564dSmrg    replyWait.minor_opcode_of_request = ICE_ConnectionSetup;
353266e564dSmrg    replyWait.reply = (IcePointer) &reply;
354266e564dSmrg
355266e564dSmrg    gotReply = False;
356266e564dSmrg    ioErrorOccured = False;
357266e564dSmrg
358266e564dSmrg    while (!gotReply && !ioErrorOccured)
359266e564dSmrg    {
360266e564dSmrg	ioErrorOccured = (IceProcessMessages (
361266e564dSmrg	    iceConn, &replyWait, &gotReply) == IceProcessMessagesIOError);
362266e564dSmrg
363266e564dSmrg	if (ioErrorOccured)
364266e564dSmrg	{
365266e564dSmrg	    strncpy (errorStringRet, "IO error occured opening connection",
366266e564dSmrg		errorLength);
367266e564dSmrg	    _IceFreeConnection (iceConn);
368266e564dSmrg	    iceConn = NULL;
369266e564dSmrg	}
370266e564dSmrg	else if (gotReply)
371266e564dSmrg	{
372266e564dSmrg	    if (reply.type == ICE_CONNECTION_REPLY)
373266e564dSmrg	    {
374266e564dSmrg		if (reply.connection_reply.version_index >= _IceVersionCount)
375266e564dSmrg		{
376266e564dSmrg		    strncpy (errorStringRet,
377266e564dSmrg	    		"Got a bad version index in the Connection Reply",
378266e564dSmrg			errorLength);
379266e564dSmrg
380266e564dSmrg		    free (reply.connection_reply.vendor);
381266e564dSmrg		    free (reply.connection_reply.release);
382266e564dSmrg		    _IceFreeConnection (iceConn);
383266e564dSmrg		    iceConn = NULL;
384266e564dSmrg		}
385266e564dSmrg		else
386266e564dSmrg		{
387266e564dSmrg		    iceConn->my_ice_version_index =
388266e564dSmrg			reply.connection_reply.version_index;
389266e564dSmrg		    iceConn->vendor = reply.connection_reply.vendor;
390266e564dSmrg		    iceConn->release = reply.connection_reply.release;
391266e564dSmrg
392266e564dSmrg		    _IceConnectionObjs[_IceConnectionCount] = iceConn;
393266e564dSmrg		    _IceConnectionStrings[_IceConnectionCount] =
394266e564dSmrg			iceConn->connection_string;
395266e564dSmrg		    _IceConnectionCount++;
396266e564dSmrg
397266e564dSmrg		    free ((char *) iceConn->connect_to_you);
398266e564dSmrg		    iceConn->connect_to_you = NULL;
399266e564dSmrg
400266e564dSmrg		    iceConn->connection_status = IceConnectAccepted;
401266e564dSmrg		}
402266e564dSmrg	    }
403266e564dSmrg	    else /* reply.type == ICE_CONNECTION_ERROR */
404266e564dSmrg	    {
405266e564dSmrg		/* Connection failed */
406266e564dSmrg
407266e564dSmrg		strncpy (errorStringRet, reply.connection_error.error_message,
408266e564dSmrg		    errorLength);
409266e564dSmrg
410266e564dSmrg		free (reply.connection_error.error_message);
411266e564dSmrg
412266e564dSmrg		_IceFreeConnection (iceConn);
413266e564dSmrg		iceConn = NULL;
414266e564dSmrg	    }
415266e564dSmrg	}
416266e564dSmrg    }
417266e564dSmrg
418266e564dSmrg    if (iceConn && _IceWatchProcs)
419266e564dSmrg    {
420266e564dSmrg	/*
421266e564dSmrg	 * Notify the watch procedures that an iceConn was opened.
422266e564dSmrg	 */
423266e564dSmrg
424266e564dSmrg	_IceConnectionOpened (iceConn);
425266e564dSmrg    }
426266e564dSmrg
427266e564dSmrg    return (iceConn);
428266e564dSmrg}
429266e564dSmrg
430266e564dSmrg
431266e564dSmrg
432266e564dSmrgIcePointer
433c5629e66SmrgIceGetConnectionContext (
434c5629e66Smrg	IceConn    iceConn
435c5629e66Smrg)
436266e564dSmrg{
437266e564dSmrg    return (iceConn->context);
438266e564dSmrg}
439266e564dSmrg
440266e564dSmrg
441266e564dSmrg
442266e564dSmrg/* ------------------------------------------------------------------------- *
443266e564dSmrg *                            local routines                                 *
444266e564dSmrg * ------------------------------------------------------------------------- */
445266e564dSmrg
446266e564dSmrg#define ICE_CONNECTION_RETRIES 5
447266e564dSmrg
448266e564dSmrg
449266e564dSmrgstatic XtransConnInfo
450266e564dSmrgConnectToPeer (char *networkIdsList, char **actualConnectionRet)
451266e564dSmrg{
452266e564dSmrg    char addrbuf[256];
453266e564dSmrg    char* address;
454266e564dSmrg    char *ptr, *endptr, *delim;
455266e564dSmrg    int  madeConnection = 0;
456266e564dSmrg    int  len, retry;
457266e564dSmrg    int  connect_stat;
458266e564dSmrg    int  address_size;
459266e564dSmrg    XtransConnInfo trans_conn = NULL;
460266e564dSmrg
461266e564dSmrg    *actualConnectionRet = NULL;
462266e564dSmrg
463266e564dSmrg    ptr = networkIdsList;
464266e564dSmrg    len = strlen (networkIdsList);
465266e564dSmrg    endptr = networkIdsList + len;
466266e564dSmrg
467266e564dSmrg    if (len < sizeof addrbuf)
468266e564dSmrg    {
469266e564dSmrg       address = addrbuf;
470266e564dSmrg       address_size = 256;
471266e564dSmrg    }
472266e564dSmrg    else
473266e564dSmrg    {
474266e564dSmrg       address = malloc (len + 1);
475266e564dSmrg       address_size = len;
476266e564dSmrg    }
477266e564dSmrg
478266e564dSmrg    while (ptr < endptr && !madeConnection)
479266e564dSmrg    {
480266e564dSmrg	if ((delim = (char *) strchr (ptr, ',')) == NULL)
481266e564dSmrg	    delim = endptr;
482266e564dSmrg
483266e564dSmrg	len = delim - ptr;
484266e564dSmrg	if (len > address_size - 1)
485266e564dSmrg	    len = address_size - 1;
486266e564dSmrg	strncpy (address, ptr, len);
487266e564dSmrg	address[len] = '\0';
488266e564dSmrg
489266e564dSmrg	ptr = delim + 1;
490266e564dSmrg
491266e564dSmrg	for (retry = ICE_CONNECTION_RETRIES; retry >= 0; retry--)
492266e564dSmrg	{
493266e564dSmrg	    if ((trans_conn = _IceTransOpenCOTSClient (address)) == NULL)
494266e564dSmrg	    {
495266e564dSmrg		break;
496266e564dSmrg	    }
497266e564dSmrg
498266e564dSmrg	    if ((connect_stat = _IceTransConnect (trans_conn, address)) < 0)
499266e564dSmrg	    {
500266e564dSmrg		_IceTransClose (trans_conn);
501266e564dSmrg
502266e564dSmrg		if (connect_stat == TRANS_TRY_CONNECT_AGAIN)
503266e564dSmrg		{
504266e564dSmrg		    sleep(1);
505266e564dSmrg		    continue;
506266e564dSmrg		}
507266e564dSmrg		else
508266e564dSmrg		    break;
509266e564dSmrg	    }
510266e564dSmrg	    else
511266e564dSmrg	    {
512266e564dSmrg		madeConnection = 1;
513266e564dSmrg		break;
514266e564dSmrg	    }
515266e564dSmrg	}
516266e564dSmrg    }
517266e564dSmrg
518266e564dSmrg    if (madeConnection)
519266e564dSmrg    {
520266e564dSmrg	/*
521266e564dSmrg	 * We need to return the actual network connection string
522266e564dSmrg	 */
523266e564dSmrg
524266e564dSmrg	*actualConnectionRet = strdup(address);
525266e564dSmrg
526266e564dSmrg	/*
527266e564dSmrg	 * Return the file descriptor
528266e564dSmrg	 */
529266e564dSmrg    }
530266e564dSmrg    else trans_conn = NULL;
531266e564dSmrg
532266e564dSmrg    if (address != addrbuf) free (address);
533266e564dSmrg
534266e564dSmrg    return trans_conn;
535266e564dSmrg}
536