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