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