1 /******************************************************************************
4 Copyright 1993, 1998 The Open Group
6 Permission to use, copy, modify, distribute, and sell this software and its
7 documentation for any purpose is hereby granted without fee, provided that
8 the above copyright notice appear in all copies and that both that
9 copyright notice and this permission notice appear in supporting
12 The above copyright notice and this permission notice shall be included in
13 all copies or substantial portions of the Software.
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
19 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 Except as contained in this notice, the name of The Open Group shall not be
23 used in advertising or otherwise to promote the sale, use or other dealings
24 in this Software without prior written authorization from The Open Group.
26 Author: Ralph Mor, X Consortium
27 ******************************************************************************/
32 #include <X11/ICE/ICElib.h>
33 #include "ICElibint.h"
34 #include <X11/Xtrans/Xtrans.h>
37 static XtransConnInfo ConnectToPeer(char *networkIdsList,
38 char **actualConnectionRet);
46 Bool mustAuthenticate,
55 Bool gotReply, ioErrorOccured;
56 unsigned long setup_sequence;
57 iceByteOrderMsg *pByteOrderMsg;
58 iceConnectionSetupMsg *pSetupMsg;
60 IceReplyWaitInfo replyWait;
63 int authUsableFlags[MAX_ICE_AUTH_NAMES];
64 int authIndices[MAX_ICE_AUTH_NAMES];
66 if (errorStringRet && errorLength > 0)
67 *errorStringRet = '\0';
69 if (networkIdsList == NULL || *networkIdsList == '\0')
71 strncpy (errorStringRet,
72 "networkIdsList argument is NULL", errorLength);
77 * Check to see if we can use a previously created ICE connection.
79 * If iceConn->want_to_close is True, or iceConn->free_asap is True,
80 * we can not use the iceConn.
82 * If 'context' is non-NULL, we will only use a previously opened ICE
83 * connection if the specified 'context' is equal to the context
84 * associated with the ICE connection, or if the context associated
85 * with the ICE connection is NULL.
87 * If 'majorOpcodeCheck' is non-zero, it will contain a protocol major
88 * opcode that we should make sure is not already active on the ICE
89 * connection. Some clients will want two seperate connections for the
90 * same protocol to the same destination client.
93 for (i = 0; i < _IceConnectionCount; i++)
96 if ((strptr = (char *) Strstr (
97 networkIdsList, _IceConnectionStrings[i])) != NULL)
99 char ch = *(strptr + strlen (_IceConnectionStrings[i]));
100 if (ch == ',' || ch == '\0')
103 * OK, we found a connection. Make sure we can reuse it.
106 IceConn iceConn = _IceConnectionObjs[i];
108 if (iceConn->want_to_close || iceConn->free_asap ||
109 (context && iceConn->context &&
110 iceConn->context != context))
112 /* force a new connection to be created */
116 if (majorOpcodeCheck)
118 for (j = iceConn->his_min_opcode;
119 j <= iceConn->his_max_opcode; j++)
121 if (iceConn->process_msg_info[
122 j - iceConn->his_min_opcode].in_use &&
123 iceConn->process_msg_info[
124 j - iceConn->his_min_opcode].my_opcode ==
129 if (j <= iceConn->his_max_opcode ||
130 (iceConn->protosetup_to_you &&
131 iceConn->protosetup_to_you->my_opcode ==
134 /* force a new connection to be created */
139 iceConn->open_ref_count++;
140 if (context && !iceConn->context)
141 iceConn->context = context;
147 if ((iceConn = (IceConn) malloc (sizeof (struct _IceConn))) == NULL)
149 strncpy (errorStringRet, "Can't malloc", errorLength);
155 * Open a network connection with the peer client.
158 if ((iceConn->trans_conn = ConnectToPeer (networkIdsList,
159 &iceConn->connection_string)) == NULL)
161 free ((char *) iceConn);
162 strncpy (errorStringRet, "Could not open network socket", errorLength);
167 * Set close-on-exec so that programs that fork() don't get confused.
170 _IceTransSetOption (iceConn->trans_conn, TRANS_CLOSEONEXEC, 1);
172 iceConn->listen_obj = NULL;
174 iceConn->connection_status = IceConnectPending;
175 iceConn->io_ok = True;
176 iceConn->dispatch_level = 0;
177 iceConn->context = context;
178 iceConn->my_ice_version_index = 0;
179 iceConn->send_sequence = 0;
180 iceConn->receive_sequence = 0;
182 iceConn->vendor = NULL;
183 iceConn->release = NULL;
184 iceConn->outbuf = NULL;
186 iceConn->scratch = NULL;
187 iceConn->scratch_size = 0;
189 iceConn->process_msg_info = NULL;
191 iceConn->connect_to_you = NULL;
192 iceConn->protosetup_to_you = NULL;
194 iceConn->connect_to_me = NULL;
195 iceConn->protosetup_to_me = NULL;
197 if ((iceConn->inbuf = iceConn->inbufptr =
198 (char *) malloc (ICE_INBUFSIZE)) == NULL)
200 _IceFreeConnection (iceConn);
201 strncpy (errorStringRet, "Can't malloc", errorLength);
205 iceConn->inbufmax = iceConn->inbuf + ICE_INBUFSIZE;
207 if ((iceConn->outbuf = iceConn->outbufptr =
208 (char *) calloc (1, ICE_OUTBUFSIZE)) == NULL)
210 _IceFreeConnection (iceConn);
211 strncpy (errorStringRet, "Can't malloc", errorLength);
215 iceConn->outbufmax = iceConn->outbuf + ICE_OUTBUFSIZE;
217 iceConn->open_ref_count = 1;
218 iceConn->proto_ref_count = 0;
220 iceConn->skip_want_to_close = False;
221 iceConn->want_to_close = False;
222 iceConn->free_asap = False;
224 iceConn->saved_reply_waits = NULL;
225 iceConn->ping_waits = NULL;
227 iceConn->connect_to_you = (_IceConnectToYouInfo *) malloc (
228 sizeof (_IceConnectToYouInfo));
229 iceConn->connect_to_you->auth_active = 0;
232 * Send our byte order.
235 IceGetHeader (iceConn, 0, ICE_ByteOrder,
236 SIZEOF (iceByteOrderMsg), iceByteOrderMsg, pByteOrderMsg);
239 if (*(char *) &endian)
240 pByteOrderMsg->byteOrder = IceLSBfirst;
242 pByteOrderMsg->byteOrder = IceMSBfirst;
248 * Now read the ByteOrder message from the other client.
249 * iceConn->swap should be set to the appropriate boolean
250 * value after the call to IceProcessMessages.
253 iceConn->waiting_for_byteorder = True;
255 ioErrorOccured = False;
256 while (iceConn->waiting_for_byteorder == True && !ioErrorOccured)
258 ioErrorOccured = (IceProcessMessages (
259 iceConn, NULL, NULL) == IceProcessMessagesIOError);
264 _IceFreeConnection (iceConn);
265 strncpy (errorStringRet, "IO error occured opening connection",
270 if (iceConn->connection_status == IceConnectRejected)
273 * We failed to get the required ByteOrder message.
276 _IceFreeConnection (iceConn);
277 strncpy (errorStringRet,
278 "Internal error - did not receive the expected ByteOrder message",
285 * Determine which authentication methods are available for
286 * the Connection Setup authentication.
289 _IceGetPoValidAuthIndices (
290 "ICE", iceConn->connection_string,
291 _IceAuthCount, _IceAuthNames, &authUsableCount, authIndices);
293 for (i = 0; i < _IceAuthCount; i++)
295 authUsableFlags[i] = 0;
296 for (j = 0; j < authUsableCount && !authUsableFlags[i]; j++)
297 authUsableFlags[i] = (authIndices[j] == i);
302 * Now send a Connection Setup message.
305 extra = STRING_BYTES (IceVendorString) + STRING_BYTES (IceReleaseString);
307 for (i = 0; i < _IceAuthCount; i++)
308 if (authUsableFlags[i])
310 extra += STRING_BYTES (_IceAuthNames[i]);
313 extra += (_IceVersionCount * 4);
315 IceGetHeaderExtra (iceConn, 0, ICE_ConnectionSetup,
316 SIZEOF (iceConnectionSetupMsg), WORD64COUNT (extra),
317 iceConnectionSetupMsg, pSetupMsg, pData);
319 setup_sequence = iceConn->send_sequence;
321 pSetupMsg->versionCount = _IceVersionCount;
322 pSetupMsg->authCount = authUsableCount;
323 pSetupMsg->mustAuthenticate = mustAuthenticate;
325 STORE_STRING (pData, IceVendorString);
326 STORE_STRING (pData, IceReleaseString);
328 for (i = 0; i < _IceAuthCount; i++)
329 if (authUsableFlags[i])
331 STORE_STRING (pData, _IceAuthNames[i]);
334 for (i = 0; i < _IceVersionCount; i++)
336 STORE_CARD16 (pData, _IceVersions[i].major_version);
337 STORE_CARD16 (pData, _IceVersions[i].minor_version);
344 * Process messages until we get a Connection Reply or an Error Message.
345 * Authentication will take place behind the scenes.
348 replyWait.sequence_of_request = setup_sequence;
349 replyWait.major_opcode_of_request = 0;
350 replyWait.minor_opcode_of_request = ICE_ConnectionSetup;
351 replyWait.reply = (IcePointer) &reply;
354 ioErrorOccured = False;
356 while (!gotReply && !ioErrorOccured)
358 ioErrorOccured = (IceProcessMessages (
359 iceConn, &replyWait, &gotReply) == IceProcessMessagesIOError);
363 strncpy (errorStringRet, "IO error occured opening connection",
365 _IceFreeConnection (iceConn);
370 if (reply.type == ICE_CONNECTION_REPLY)
372 if (reply.connection_reply.version_index >= _IceVersionCount)
374 strncpy (errorStringRet,
375 "Got a bad version index in the Connection Reply",
378 free (reply.connection_reply.vendor);
379 free (reply.connection_reply.release);
380 _IceFreeConnection (iceConn);
385 iceConn->my_ice_version_index =
386 reply.connection_reply.version_index;
387 iceConn->vendor = reply.connection_reply.vendor;
388 iceConn->release = reply.connection_reply.release;
390 _IceConnectionObjs[_IceConnectionCount] = iceConn;
391 _IceConnectionStrings[_IceConnectionCount] =
392 iceConn->connection_string;
393 _IceConnectionCount++;
395 free ((char *) iceConn->connect_to_you);
396 iceConn->connect_to_you = NULL;
398 iceConn->connection_status = IceConnectAccepted;
401 else /* reply.type == ICE_CONNECTION_ERROR */
403 /* Connection failed */
405 strncpy (errorStringRet, reply.connection_error.error_message,
408 free (reply.connection_error.error_message);
410 _IceFreeConnection (iceConn);
416 if (iceConn && _IceWatchProcs)
419 * Notify the watch procedures that an iceConn was opened.
422 _IceConnectionOpened (iceConn);
431 IceGetConnectionContext (
435 return (iceConn->context);
440 /* ------------------------------------------------------------------------- *
442 * ------------------------------------------------------------------------- */
444 #define ICE_CONNECTION_RETRIES 5
447 static XtransConnInfo
448 ConnectToPeer (char *networkIdsList, char **actualConnectionRet)
452 char *ptr, *endptr, *delim;
453 int madeConnection = 0;
457 XtransConnInfo trans_conn = NULL;
459 *actualConnectionRet = NULL;
461 ptr = networkIdsList;
462 len = strlen (networkIdsList);
463 endptr = networkIdsList + len;
465 if (len < sizeof addrbuf)
472 address = malloc (len + 1);
476 while (ptr < endptr && !madeConnection)
478 if ((delim = (char *) strchr (ptr, ',')) == NULL)
482 if (len > address_size - 1)
483 len = address_size - 1;
484 strncpy (address, ptr, len);
489 for (retry = ICE_CONNECTION_RETRIES; retry >= 0; retry--)
491 if ((trans_conn = _IceTransOpenCOTSClient (address)) == NULL)
496 if ((connect_stat = _IceTransConnect (trans_conn, address)) < 0)
498 _IceTransClose (trans_conn);
500 if (connect_stat == TRANS_TRY_CONNECT_AGAIN)
519 * We need to return the actual network connection string
522 *actualConnectionRet = strdup(address);
525 * Return the file descriptor
528 else trans_conn = NULL;
530 if (address != addrbuf) free (address);