1 /******************************************************************************
2
3
4 Copyright 1993, 1998 The Open Group
5
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
10 documentation.
11
12 The above copyright notice and this permission notice shall be included in
13 all copies or substantial portions of the Software.
14
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.
21
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.
25
26 Author: 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
37 static XtransConnInfo ConnectToPeer(char *networkIdsList,
38 char **actualConnectionRet);
39
40 IceConn
IceOpenConnection(char * networkIdsList,IcePointer context,Bool mustAuthenticate,int majorOpcodeCheck,int errorLength,char * errorStringRet)41 IceOpenConnection (
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 seperate 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 = (char *) 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 iceConn = _IceConnectionObjs[i];
108
109 if (iceConn->want_to_close || iceConn->free_asap ||
110 (context && iceConn->context &&
111 iceConn->context != context))
112 {
113 /* force a new connection to be created */
114 break;
115 }
116
117 if (majorOpcodeCheck)
118 {
119 for (j = iceConn->his_min_opcode;
120 j <= iceConn->his_max_opcode; j++)
121 {
122 if (iceConn->process_msg_info[
123 j - iceConn->his_min_opcode].in_use &&
124 iceConn->process_msg_info[
125 j - iceConn->his_min_opcode].my_opcode ==
126 majorOpcodeCheck)
127 break;
128 }
129
130 if (j <= iceConn->his_max_opcode ||
131 (iceConn->protosetup_to_you &&
132 iceConn->protosetup_to_you->my_opcode ==
133 majorOpcodeCheck))
134 {
135 /* force a new connection to be created */
136 break;
137 }
138 }
139
140 iceConn->open_ref_count++;
141 if (context && !iceConn->context)
142 iceConn->context = context;
143 return (iceConn);
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 occured 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 STORE_STRING (pData, IceVendorString);
351 STORE_STRING (pData, IceReleaseString);
352
353 for (i = 0; i < _IceAuthCount; i++)
354 if (authUsableFlags[i])
355 {
356 STORE_STRING (pData, _IceAuthNames[i]);
357 }
358
359 for (i = 0; i < _IceVersionCount; i++)
360 {
361 STORE_CARD16 (pData, _IceVersions[i].major_version);
362 STORE_CARD16 (pData, _IceVersions[i].minor_version);
363 }
364
365 IceFlush (iceConn);
366
367
368 /*
369 * Process messages until we get a Connection Reply or an Error Message.
370 * Authentication will take place behind the scenes.
371 */
372
373 replyWait.sequence_of_request = setup_sequence;
374 replyWait.major_opcode_of_request = 0;
375 replyWait.minor_opcode_of_request = ICE_ConnectionSetup;
376 replyWait.reply = (IcePointer) &reply;
377
378 gotReply = False;
379 ioErrorOccured = False;
380
381 while (!gotReply && !ioErrorOccured)
382 {
383 ioErrorOccured = (IceProcessMessages (
384 iceConn, &replyWait, &gotReply) == IceProcessMessagesIOError);
385
386 if (ioErrorOccured)
387 {
388 if (errorStringRet && errorLength > 0) {
389 strncpy (errorStringRet, "IO error occured opening connection",
390 errorLength);
391 errorStringRet[errorLength - 1] = '\0';
392 }
393 _IceFreeConnection (iceConn);
394 iceConn = NULL;
395 }
396 else if (gotReply)
397 {
398 if (reply.type == ICE_CONNECTION_REPLY)
399 {
400 if (reply.connection_reply.version_index >= _IceVersionCount)
401 {
402 if (errorStringRet && errorLength > 0) {
403 strncpy (errorStringRet,
404 "Got a bad version index in the Connection Reply",
405 errorLength);
406 errorStringRet[errorLength - 1] = '\0';
407 }
408
409 free (reply.connection_reply.vendor);
410 free (reply.connection_reply.release);
411 _IceFreeConnection (iceConn);
412 iceConn = NULL;
413 }
414 else
415 {
416 iceConn->my_ice_version_index =
417 reply.connection_reply.version_index;
418 iceConn->vendor = reply.connection_reply.vendor;
419 iceConn->release = reply.connection_reply.release;
420
421 _IceConnectionObjs[_IceConnectionCount] = iceConn;
422 _IceConnectionStrings[_IceConnectionCount] =
423 iceConn->connection_string;
424 _IceConnectionCount++;
425
426 free (iceConn->connect_to_you);
427 iceConn->connect_to_you = NULL;
428
429 iceConn->connection_status = IceConnectAccepted;
430 }
431 }
432 else /* reply.type == ICE_CONNECTION_ERROR */
433 {
434 /* Connection failed */
435
436 if (errorStringRet && errorLength > 0) {
437 strncpy (errorStringRet,
438 reply.connection_error.error_message, errorLength);
439 errorStringRet[errorLength - 1] = '\0';
440 }
441
442 free (reply.connection_error.error_message);
443
444 _IceFreeConnection (iceConn);
445 iceConn = NULL;
446 }
447 }
448 }
449
450 if (iceConn && _IceWatchProcs)
451 {
452 /*
453 * Notify the watch procedures that an iceConn was opened.
454 */
455
456 _IceConnectionOpened (iceConn);
457 }
458
459 return (iceConn);
460 }
461
462
463
464 IcePointer
IceGetConnectionContext(IceConn iceConn)465 IceGetConnectionContext (
466 IceConn iceConn
467 )
468 {
469 return (iceConn->context);
470 }
471
472
473
474 /* ------------------------------------------------------------------------- *
475 * local routines *
476 * ------------------------------------------------------------------------- */
477
478 #define ICE_CONNECTION_RETRIES 5
479
480
481 static XtransConnInfo
ConnectToPeer(char * networkIdsList,char ** actualConnectionRet)482 ConnectToPeer (char *networkIdsList, char **actualConnectionRet)
483 {
484 char addrbuf[256];
485 char* address;
486 char *ptr, *endptr, *delim;
487 int madeConnection = 0;
488 size_t len;
489 int retry, connect_stat;
490 size_t address_size;
491 XtransConnInfo trans_conn = NULL;
492
493 *actualConnectionRet = NULL;
494
495 ptr = networkIdsList;
496 len = strlen (networkIdsList);
497 endptr = networkIdsList + len;
498
499 if (len < sizeof addrbuf)
500 {
501 address = addrbuf;
502 address_size = 256;
503 }
504 else
505 {
506 address = malloc (len + 1);
507 address_size = len;
508 }
509
510 while (ptr < endptr && !madeConnection)
511 {
512 if ((delim = (char *) strchr (ptr, ',')) == NULL)
513 delim = endptr;
514
515 len = delim - ptr;
516 if (len > address_size - 1)
517 len = address_size - 1;
518 strncpy (address, ptr, len);
519 address[len] = '\0';
520
521 ptr = delim + 1;
522
523 for (retry = ICE_CONNECTION_RETRIES; retry >= 0; retry--)
524 {
525 if ((trans_conn = _IceTransOpenCOTSClient (address)) == NULL)
526 {
527 break;
528 }
529
530 if ((connect_stat = _IceTransConnect (trans_conn, address)) < 0)
531 {
532 _IceTransClose (trans_conn);
533
534 if (connect_stat == TRANS_TRY_CONNECT_AGAIN)
535 {
536 sleep(1);
537 continue;
538 }
539 else
540 break;
541 }
542 else
543 {
544 madeConnection = 1;
545 break;
546 }
547 }
548 }
549
550 if (madeConnection)
551 {
552 /*
553 * We need to return the actual network connection string
554 */
555
556 *actualConnectionRet = strdup(address);
557
558 /*
559 * Return the file descriptor
560 */
561 }
562 else trans_conn = NULL;
563
564 if (address != addrbuf) free (address);
565
566 return trans_conn;
567 }
568