connect.c revision 266e564d
1/* $Xorg: connect.c,v 1.4 2001/02/09 02:03:26 xorgcvs Exp $ */ 2/****************************************************************************** 3 4 5Copyright 1993, 1998 The Open Group 6 7Permission to use, copy, modify, distribute, and sell this software and its 8documentation for any purpose is hereby granted without fee, provided that 9the above copyright notice appear in all copies and that both that 10copyright notice and this permission notice appear in supporting 11documentation. 12 13The above copyright notice and this permission notice shall be included in 14all copies or substantial portions of the Software. 15 16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 20AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 23Except as contained in this notice, the name of The Open Group shall not be 24used in advertising or otherwise to promote the sale, use or other dealings 25in this Software without prior written authorization from The Open Group. 26 27Author: Ralph Mor, X Consortium 28******************************************************************************/ 29/* $XFree86: xc/lib/ICE/connect.c,v 3.9 2001/12/14 19:53:35 dawes Exp $ */ 30 31#ifdef HAVE_CONFIG_H 32#include <config.h> 33#endif 34#include <X11/ICE/ICElib.h> 35#include "ICElibint.h" 36#include <X11/Xtrans/Xtrans.h> 37#include "globals.h" 38 39static XtransConnInfo ConnectToPeer(char *networkIdsList, 40 char **actualConnectionRet); 41 42#define Strstr strstr 43 44IceConn 45IceOpenConnection (networkIdsList, context, mustAuthenticate, majorOpcodeCheck, 46 errorLength, errorStringRet) 47 48char *networkIdsList; 49IcePointer context; 50Bool mustAuthenticate; 51int majorOpcodeCheck; 52int errorLength; 53char *errorStringRet; 54 55{ 56 IceConn iceConn; 57 int extra, i, j; 58 int endian; 59 Bool gotReply, ioErrorOccured; 60 unsigned long setup_sequence; 61 iceByteOrderMsg *pByteOrderMsg; 62 iceConnectionSetupMsg *pSetupMsg; 63 char *pData; 64 IceReplyWaitInfo replyWait; 65 _IceReply reply; 66 int authUsableCount; 67 int authUsableFlags[MAX_ICE_AUTH_NAMES]; 68 int authIndices[MAX_ICE_AUTH_NAMES]; 69 70 if (errorStringRet && errorLength > 0) 71 *errorStringRet = '\0'; 72 73 if (networkIdsList == NULL || *networkIdsList == '\0') 74 { 75 strncpy (errorStringRet, 76 "networkIdsList argument is NULL", errorLength); 77 return (NULL); 78 } 79 80 /* 81 * Check to see if we can use a previously created ICE connection. 82 * 83 * If iceConn->want_to_close is True, or iceConn->free_asap is True, 84 * we can not use the iceConn. 85 * 86 * If 'context' is non-NULL, we will only use a previously opened ICE 87 * connection if the specified 'context' is equal to the context 88 * associated with the ICE connection, or if the context associated 89 * with the ICE connection is NULL. 90 * 91 * If 'majorOpcodeCheck' is non-zero, it will contain a protocol major 92 * opcode that we should make sure is not already active on the ICE 93 * connection. Some clients will want two seperate connections for the 94 * same protocol to the same destination client. 95 */ 96 97 for (i = 0; i < _IceConnectionCount; i++) 98 { 99 char *strptr; 100 if ((strptr = (char *) Strstr ( 101 networkIdsList, _IceConnectionStrings[i])) != NULL) 102 { 103 char ch = *(strptr + strlen (_IceConnectionStrings[i])); 104 if (ch == ',' || ch == '\0') 105 { 106 /* 107 * OK, we found a connection. Make sure we can reuse it. 108 */ 109 110 IceConn iceConn = _IceConnectionObjs[i]; 111 112 if (iceConn->want_to_close || iceConn->free_asap || 113 (context && iceConn->context && 114 iceConn->context != context)) 115 { 116 /* force a new connection to be created */ 117 break; 118 } 119 120 if (majorOpcodeCheck) 121 { 122 for (j = iceConn->his_min_opcode; 123 j <= iceConn->his_max_opcode; j++) 124 { 125 if (iceConn->process_msg_info[ 126 j - iceConn->his_min_opcode].in_use && 127 iceConn->process_msg_info[ 128 j - iceConn->his_min_opcode].my_opcode == 129 majorOpcodeCheck) 130 break; 131 } 132 133 if (j <= iceConn->his_max_opcode || 134 (iceConn->protosetup_to_you && 135 iceConn->protosetup_to_you->my_opcode == 136 majorOpcodeCheck)) 137 { 138 /* force a new connection to be created */ 139 break; 140 } 141 } 142 143 iceConn->open_ref_count++; 144 if (context && !iceConn->context) 145 iceConn->context = context; 146 return (iceConn); 147 } 148 } 149 } 150 151 if ((iceConn = (IceConn) malloc (sizeof (struct _IceConn))) == NULL) 152 { 153 strncpy (errorStringRet, "Can't malloc", errorLength); 154 return (NULL); 155 } 156 157 158 /* 159 * Open a network connection with the peer client. 160 */ 161 162 if ((iceConn->trans_conn = ConnectToPeer (networkIdsList, 163 &iceConn->connection_string)) == NULL) 164 { 165 free ((char *) iceConn); 166 strncpy (errorStringRet, "Could not open network socket", errorLength); 167 return (NULL); 168 } 169 170 /* 171 * Set close-on-exec so that programs that fork() don't get confused. 172 */ 173 174 _IceTransSetOption (iceConn->trans_conn, TRANS_CLOSEONEXEC, 1); 175 176 iceConn->listen_obj = NULL; 177 178 iceConn->connection_status = IceConnectPending; 179 iceConn->io_ok = True; 180 iceConn->dispatch_level = 0; 181 iceConn->context = context; 182 iceConn->my_ice_version_index = 0; 183 iceConn->send_sequence = 0; 184 iceConn->receive_sequence = 0; 185 186 iceConn->vendor = NULL; 187 iceConn->release = NULL; 188 iceConn->outbuf = NULL; 189 190 iceConn->scratch = NULL; 191 iceConn->scratch_size = 0; 192 193 iceConn->process_msg_info = NULL; 194 195 iceConn->connect_to_you = NULL; 196 iceConn->protosetup_to_you = NULL; 197 198 iceConn->connect_to_me = NULL; 199 iceConn->protosetup_to_me = NULL; 200 201 if ((iceConn->inbuf = iceConn->inbufptr = 202 (char *) malloc (ICE_INBUFSIZE)) == NULL) 203 { 204 _IceFreeConnection (iceConn); 205 strncpy (errorStringRet, "Can't malloc", errorLength); 206 return (NULL); 207 } 208 209 iceConn->inbufmax = iceConn->inbuf + ICE_INBUFSIZE; 210 211 if ((iceConn->outbuf = iceConn->outbufptr = 212 (char *) calloc (1, ICE_OUTBUFSIZE)) == NULL) 213 { 214 _IceFreeConnection (iceConn); 215 strncpy (errorStringRet, "Can't malloc", errorLength); 216 return (NULL); 217 } 218 219 iceConn->outbufmax = iceConn->outbuf + ICE_OUTBUFSIZE; 220 221 iceConn->open_ref_count = 1; 222 iceConn->proto_ref_count = 0; 223 224 iceConn->skip_want_to_close = False; 225 iceConn->want_to_close = False; 226 iceConn->free_asap = False; 227 228 iceConn->saved_reply_waits = NULL; 229 iceConn->ping_waits = NULL; 230 231 iceConn->connect_to_you = (_IceConnectToYouInfo *) malloc ( 232 sizeof (_IceConnectToYouInfo)); 233 iceConn->connect_to_you->auth_active = 0; 234 235 /* 236 * Send our byte order. 237 */ 238 239 IceGetHeader (iceConn, 0, ICE_ByteOrder, 240 SIZEOF (iceByteOrderMsg), iceByteOrderMsg, pByteOrderMsg); 241 242 endian = 1; 243 if (*(char *) &endian) 244 pByteOrderMsg->byteOrder = IceLSBfirst; 245 else 246 pByteOrderMsg->byteOrder = IceMSBfirst; 247 248 IceFlush (iceConn); 249 250 251 /* 252 * Now read the ByteOrder message from the other client. 253 * iceConn->swap should be set to the appropriate boolean 254 * value after the call to IceProcessMessages. 255 */ 256 257 iceConn->waiting_for_byteorder = True; 258 259 ioErrorOccured = False; 260 while (iceConn->waiting_for_byteorder == True && !ioErrorOccured) 261 { 262 ioErrorOccured = (IceProcessMessages ( 263 iceConn, NULL, NULL) == IceProcessMessagesIOError); 264 } 265 266 if (ioErrorOccured) 267 { 268 _IceFreeConnection (iceConn); 269 strncpy (errorStringRet, "IO error occured opening connection", 270 errorLength); 271 return (NULL); 272 } 273 274 if (iceConn->connection_status == IceConnectRejected) 275 { 276 /* 277 * We failed to get the required ByteOrder message. 278 */ 279 280 _IceFreeConnection (iceConn); 281 strncpy (errorStringRet, 282 "Internal error - did not receive the expected ByteOrder message", 283 errorLength); 284 return (NULL); 285 } 286 287 288 /* 289 * Determine which authentication methods are available for 290 * the Connection Setup authentication. 291 */ 292 293 _IceGetPoValidAuthIndices ( 294 "ICE", iceConn->connection_string, 295 _IceAuthCount, _IceAuthNames, &authUsableCount, authIndices); 296 297 for (i = 0; i < _IceAuthCount; i++) 298 { 299 authUsableFlags[i] = 0; 300 for (j = 0; j < authUsableCount && !authUsableFlags[i]; j++) 301 authUsableFlags[i] = (authIndices[j] == i); 302 } 303 304 305 /* 306 * Now send a Connection Setup message. 307 */ 308 309 extra = STRING_BYTES (IceVendorString) + STRING_BYTES (IceReleaseString); 310 311 for (i = 0; i < _IceAuthCount; i++) 312 if (authUsableFlags[i]) 313 { 314 extra += STRING_BYTES (_IceAuthNames[i]); 315 } 316 317 extra += (_IceVersionCount * 4); 318 319 IceGetHeaderExtra (iceConn, 0, ICE_ConnectionSetup, 320 SIZEOF (iceConnectionSetupMsg), WORD64COUNT (extra), 321 iceConnectionSetupMsg, pSetupMsg, pData); 322 323 setup_sequence = iceConn->send_sequence; 324 325 pSetupMsg->versionCount = _IceVersionCount; 326 pSetupMsg->authCount = authUsableCount; 327 pSetupMsg->mustAuthenticate = mustAuthenticate; 328 329 STORE_STRING (pData, IceVendorString); 330 STORE_STRING (pData, IceReleaseString); 331 332 for (i = 0; i < _IceAuthCount; i++) 333 if (authUsableFlags[i]) 334 { 335 STORE_STRING (pData, _IceAuthNames[i]); 336 } 337 338 for (i = 0; i < _IceVersionCount; i++) 339 { 340 STORE_CARD16 (pData, _IceVersions[i].major_version); 341 STORE_CARD16 (pData, _IceVersions[i].minor_version); 342 } 343 344 IceFlush (iceConn); 345 346 347 /* 348 * Process messages until we get a Connection Reply or an Error Message. 349 * Authentication will take place behind the scenes. 350 */ 351 352 replyWait.sequence_of_request = setup_sequence; 353 replyWait.major_opcode_of_request = 0; 354 replyWait.minor_opcode_of_request = ICE_ConnectionSetup; 355 replyWait.reply = (IcePointer) &reply; 356 357 gotReply = False; 358 ioErrorOccured = False; 359 360 while (!gotReply && !ioErrorOccured) 361 { 362 ioErrorOccured = (IceProcessMessages ( 363 iceConn, &replyWait, &gotReply) == IceProcessMessagesIOError); 364 365 if (ioErrorOccured) 366 { 367 strncpy (errorStringRet, "IO error occured opening connection", 368 errorLength); 369 _IceFreeConnection (iceConn); 370 iceConn = NULL; 371 } 372 else if (gotReply) 373 { 374 if (reply.type == ICE_CONNECTION_REPLY) 375 { 376 if (reply.connection_reply.version_index >= _IceVersionCount) 377 { 378 strncpy (errorStringRet, 379 "Got a bad version index in the Connection Reply", 380 errorLength); 381 382 free (reply.connection_reply.vendor); 383 free (reply.connection_reply.release); 384 _IceFreeConnection (iceConn); 385 iceConn = NULL; 386 } 387 else 388 { 389 iceConn->my_ice_version_index = 390 reply.connection_reply.version_index; 391 iceConn->vendor = reply.connection_reply.vendor; 392 iceConn->release = reply.connection_reply.release; 393 394 _IceConnectionObjs[_IceConnectionCount] = iceConn; 395 _IceConnectionStrings[_IceConnectionCount] = 396 iceConn->connection_string; 397 _IceConnectionCount++; 398 399 free ((char *) iceConn->connect_to_you); 400 iceConn->connect_to_you = NULL; 401 402 iceConn->connection_status = IceConnectAccepted; 403 } 404 } 405 else /* reply.type == ICE_CONNECTION_ERROR */ 406 { 407 /* Connection failed */ 408 409 strncpy (errorStringRet, reply.connection_error.error_message, 410 errorLength); 411 412 free (reply.connection_error.error_message); 413 414 _IceFreeConnection (iceConn); 415 iceConn = NULL; 416 } 417 } 418 } 419 420 if (iceConn && _IceWatchProcs) 421 { 422 /* 423 * Notify the watch procedures that an iceConn was opened. 424 */ 425 426 _IceConnectionOpened (iceConn); 427 } 428 429 return (iceConn); 430} 431 432 433 434IcePointer 435IceGetConnectionContext (iceConn) 436 437IceConn iceConn; 438 439{ 440 return (iceConn->context); 441} 442 443 444 445/* ------------------------------------------------------------------------- * 446 * local routines * 447 * ------------------------------------------------------------------------- */ 448 449#define ICE_CONNECTION_RETRIES 5 450 451 452static XtransConnInfo 453ConnectToPeer (char *networkIdsList, char **actualConnectionRet) 454{ 455 char addrbuf[256]; 456 char* address; 457 char *ptr, *endptr, *delim; 458 int madeConnection = 0; 459 int len, retry; 460 int connect_stat; 461 int address_size; 462 XtransConnInfo trans_conn = NULL; 463 464 *actualConnectionRet = NULL; 465 466 ptr = networkIdsList; 467 len = strlen (networkIdsList); 468 endptr = networkIdsList + len; 469 470 if (len < sizeof addrbuf) 471 { 472 address = addrbuf; 473 address_size = 256; 474 } 475 else 476 { 477 address = malloc (len + 1); 478 address_size = len; 479 } 480 481 while (ptr < endptr && !madeConnection) 482 { 483 if ((delim = (char *) strchr (ptr, ',')) == NULL) 484 delim = endptr; 485 486 len = delim - ptr; 487 if (len > address_size - 1) 488 len = address_size - 1; 489 strncpy (address, ptr, len); 490 address[len] = '\0'; 491 492 ptr = delim + 1; 493 494 for (retry = ICE_CONNECTION_RETRIES; retry >= 0; retry--) 495 { 496 if ((trans_conn = _IceTransOpenCOTSClient (address)) == NULL) 497 { 498 break; 499 } 500 501 if ((connect_stat = _IceTransConnect (trans_conn, address)) < 0) 502 { 503 _IceTransClose (trans_conn); 504 505 if (connect_stat == TRANS_TRY_CONNECT_AGAIN) 506 { 507 sleep(1); 508 continue; 509 } 510 else 511 break; 512 } 513 else 514 { 515 madeConnection = 1; 516 break; 517 } 518 } 519 } 520 521 if (madeConnection) 522 { 523 /* 524 * We need to return the actual network connection string 525 */ 526 527 *actualConnectionRet = strdup(address); 528 529 /* 530 * Return the file descriptor 531 */ 532 } 533 else trans_conn = NULL; 534 535 if (address != addrbuf) free (address); 536 537 return trans_conn; 538} 539