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