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