2003-03-16 Havoc Pennington <hp@pobox.com>
[platform/upstream/dbus.git] / dbus / dbus-transport-unix.c
1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* dbus-transport-unix.c UNIX socket subclasses of DBusTransport
3  *
4  * Copyright (C) 2002, 2003  Red Hat Inc.
5  *
6  * Licensed under the Academic Free License version 1.2
7  * 
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  * 
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  *
22  */
23
24 #include "dbus-internals.h"
25 #include "dbus-connection-internal.h"
26 #include "dbus-transport-unix.h"
27 #include "dbus-transport-protected.h"
28 #include "dbus-watch.h"
29 #include <sys/types.h>
30 #include <sys/time.h>
31 #include <unistd.h>
32
33
34 /**
35  * @defgroup DBusTransportUnix DBusTransport implementations for UNIX
36  * @ingroup  DBusInternals
37  * @brief Implementation details of DBusTransport on UNIX
38  *
39  * @{
40  */
41
42 /**
43  * Opaque object representing a Unix file descriptor transport.
44  */
45 typedef struct DBusTransportUnix DBusTransportUnix;
46
47 /**
48  * Implementation details of DBusTransportUnix. All members are private.
49  */
50 struct DBusTransportUnix
51 {
52   DBusTransport base;                   /**< Parent instance */
53   int fd;                               /**< File descriptor. */
54   DBusWatch *read_watch;                /**< Watch for readability. */
55   DBusWatch *write_watch;               /**< Watch for writability. */
56
57   int max_bytes_read_per_iteration;     /**< To avoid blocking too long. */
58   int max_bytes_written_per_iteration;  /**< To avoid blocking too long. */
59
60   int message_bytes_written;            /**< Number of bytes of current
61                                          *   outgoing message that have
62                                          *   been written.
63                                          */
64   DBusString encoded_message;           /**< Encoded version of current
65                                          *   outgoing message.
66                                          */
67 };
68
69 static void
70 free_watches (DBusTransport *transport)
71 {
72   DBusTransportUnix *unix_transport = (DBusTransportUnix*) transport;
73   
74   if (unix_transport->read_watch)
75     {
76       if (transport->connection)
77         _dbus_connection_remove_watch (transport->connection,
78                                        unix_transport->read_watch);
79       _dbus_watch_invalidate (unix_transport->read_watch);
80       _dbus_watch_unref (unix_transport->read_watch);
81       unix_transport->read_watch = NULL;
82     }
83
84   if (unix_transport->write_watch)
85     {
86       if (transport->connection)
87         _dbus_connection_remove_watch (transport->connection,
88                                        unix_transport->write_watch);
89       _dbus_watch_invalidate (unix_transport->write_watch);
90       _dbus_watch_unref (unix_transport->write_watch);
91       unix_transport->write_watch = NULL;
92     }
93 }
94
95 static void
96 unix_finalize (DBusTransport *transport)
97 {
98   DBusTransportUnix *unix_transport = (DBusTransportUnix*) transport;
99   
100   free_watches (transport);
101
102   _dbus_string_free (&unix_transport->encoded_message);
103   
104   _dbus_transport_finalize_base (transport);
105
106   _dbus_assert (unix_transport->read_watch == NULL);
107   _dbus_assert (unix_transport->write_watch == NULL);
108   
109   dbus_free (transport);
110 }
111
112 static void
113 check_write_watch (DBusTransport *transport)
114 {
115   DBusTransportUnix *unix_transport = (DBusTransportUnix*) transport;
116   dbus_bool_t need_write_watch;
117
118   if (transport->connection == NULL)
119     return;
120
121   if (transport->disconnected)
122     {
123       _dbus_assert (unix_transport->write_watch == NULL);
124       return;
125     }
126   
127   _dbus_transport_ref (transport);
128
129   if (_dbus_transport_get_is_authenticated (transport))
130     need_write_watch = transport->messages_need_sending;
131   else
132     need_write_watch = transport->send_credentials_pending ||
133       _dbus_auth_do_work (transport->auth) == DBUS_AUTH_STATE_HAVE_BYTES_TO_SEND;
134
135   _dbus_connection_toggle_watch (transport->connection,
136                                  unix_transport->write_watch,
137                                  need_write_watch);
138
139   _dbus_transport_unref (transport);
140 }
141
142 static void
143 check_read_watch (DBusTransport *transport)
144 {
145   DBusTransportUnix *unix_transport = (DBusTransportUnix*) transport;
146   dbus_bool_t need_read_watch;
147
148   if (transport->connection == NULL)
149     return;
150
151   if (transport->disconnected)
152     {
153       _dbus_assert (unix_transport->read_watch == NULL);
154       return;
155     }
156   
157   _dbus_transport_ref (transport);
158
159   if (_dbus_transport_get_is_authenticated (transport))
160     need_read_watch =
161       _dbus_counter_get_value (transport->live_messages_size) < transport->max_live_messages_size;
162   else
163     need_read_watch = transport->receive_credentials_pending ||
164       _dbus_auth_do_work (transport->auth) == DBUS_AUTH_STATE_WAITING_FOR_INPUT;
165
166   _dbus_connection_toggle_watch (transport->connection,
167                                  unix_transport->read_watch,
168                                  need_read_watch);
169
170   _dbus_transport_unref (transport);
171 }
172
173 static void
174 do_io_error (DBusTransport *transport)
175 {
176   _dbus_transport_ref (transport);
177   _dbus_transport_disconnect (transport);
178   _dbus_transport_unref (transport);
179 }
180
181 static void
182 queue_messages (DBusTransport *transport)
183 {
184   DBusMessage *message;
185   
186   /* Queue any messages */
187   while ((message = _dbus_message_loader_pop_message (transport->loader)))
188     {
189       _dbus_verbose ("queueing received message %p\n", message);
190
191       _dbus_message_add_size_counter (message, transport->live_messages_size);
192       if (!_dbus_connection_queue_received_message (transport->connection,
193                                                     message))
194         /* FIXME woops! */;
195         
196       dbus_message_unref (message);
197     }
198
199   if (_dbus_message_loader_get_is_corrupted (transport->loader))
200     {
201       _dbus_verbose ("Corrupted message stream, disconnecting\n");
202       do_io_error (transport);
203     }
204
205   /* check read watch in case we've now exceeded max outstanding messages */
206   check_read_watch (transport);
207 }
208
209 /* return value is whether we successfully read any new data. */
210 static dbus_bool_t
211 read_data_into_auth (DBusTransport *transport)
212 {
213   DBusTransportUnix *unix_transport = (DBusTransportUnix*) transport;
214   DBusString buffer;
215   int bytes_read;
216   
217   if (!_dbus_string_init (&buffer, _DBUS_INT_MAX))
218     {
219       /* just disconnect if we don't have memory
220        * to do an authentication
221        */
222       _dbus_verbose ("No memory for authentication\n");
223       do_io_error (transport);
224       return FALSE;
225     }
226   
227   bytes_read = _dbus_read (unix_transport->fd,
228                            &buffer, unix_transport->max_bytes_read_per_iteration);
229
230   if (bytes_read > 0)
231     {
232       _dbus_verbose (" read %d bytes in auth phase\n", bytes_read);
233       
234       if (_dbus_auth_bytes_received (transport->auth,
235                                      &buffer))
236         {
237           _dbus_string_free (&buffer);
238           return TRUE; /* We did read some data! woo! */
239         }
240       else
241         {
242           /* just disconnect if we don't have memory to do an
243            * authentication, don't fool with trying to save the buffer
244            * and who knows what.
245            */
246           _dbus_verbose ("No memory for authentication\n");
247           do_io_error (transport);
248         }
249     }
250   else if (bytes_read < 0)
251     {
252       /* EINTR already handled for us */
253       
254       if (errno == EAGAIN ||
255           errno == EWOULDBLOCK)
256         ; /* do nothing, just return FALSE below */
257       else
258         {
259           _dbus_verbose ("Error reading from remote app: %s\n",
260                          _dbus_strerror (errno));
261           do_io_error (transport);
262         }
263     }
264   else if (bytes_read == 0)
265     {
266       _dbus_verbose ("Disconnected from remote app\n");
267       do_io_error (transport);      
268     }
269   
270   _dbus_string_free (&buffer);
271   return FALSE;
272 }
273
274 /* Return value is whether we successfully wrote any bytes */
275 static dbus_bool_t
276 write_data_from_auth (DBusTransport *transport)
277 {
278   DBusTransportUnix *unix_transport = (DBusTransportUnix*) transport;
279   int bytes_written;
280   const DBusString *buffer;
281
282   if (!_dbus_auth_get_bytes_to_send (transport->auth,
283                                      &buffer))
284     return FALSE;
285   
286   bytes_written = _dbus_write (unix_transport->fd,
287                                buffer,
288                                0, _dbus_string_get_length (buffer));
289
290   if (bytes_written > 0)
291     {
292       _dbus_auth_bytes_sent (transport->auth, bytes_written);
293       return TRUE;
294     }
295   else if (bytes_written < 0)
296     {
297       /* EINTR already handled for us */
298       
299       if (errno == EAGAIN ||
300           errno == EWOULDBLOCK)
301         ;
302       else
303         {
304           _dbus_verbose ("Error writing to remote app: %s\n",
305                          _dbus_strerror (errno));
306           do_io_error (transport);
307         }
308     }
309
310   return FALSE;
311 }
312
313 static void
314 recover_unused_bytes (DBusTransport *transport)
315 {
316   
317   if (_dbus_auth_needs_decoding (transport->auth))
318     {
319       DBusString plaintext;
320       DBusString encoded;
321       DBusString *buffer;
322       int orig_len;
323       
324       if (!_dbus_string_init (&plaintext, _DBUS_INT_MAX))
325         goto nomem;
326
327       if (!_dbus_string_init (&encoded, _DBUS_INT_MAX))
328         {
329           _dbus_string_free (&plaintext);
330           goto nomem;
331         }
332       
333       if (!_dbus_auth_get_unused_bytes (transport->auth,
334                                         &encoded))
335         {
336           _dbus_string_free (&plaintext);
337           _dbus_string_free (&encoded);
338           goto nomem;
339         }
340       
341       if (!_dbus_auth_decode_data (transport->auth,
342                                    &encoded, &plaintext))
343         {
344           _dbus_string_free (&plaintext);
345           _dbus_string_free (&encoded);
346           goto nomem;
347         }
348       
349       _dbus_message_loader_get_buffer (transport->loader,
350                                        &buffer);
351       
352       orig_len = _dbus_string_get_length (buffer);
353
354       if (!_dbus_string_move (&plaintext, 0, buffer,
355                               orig_len))
356         {
357           _dbus_string_free (&plaintext);
358           _dbus_string_free (&encoded);
359           goto nomem;
360         }
361       
362       _dbus_verbose (" %d unused bytes sent to message loader\n", 
363                      _dbus_string_get_length (buffer) -
364                      orig_len);
365       
366       _dbus_message_loader_return_buffer (transport->loader,
367                                           buffer,
368                                           _dbus_string_get_length (buffer) -
369                                           orig_len);
370
371       _dbus_string_free (&plaintext);
372       _dbus_string_free (&encoded);
373     }
374   else
375     {
376       DBusString *buffer;
377       int orig_len;
378
379       _dbus_message_loader_get_buffer (transport->loader,
380                                        &buffer);
381                 
382       orig_len = _dbus_string_get_length (buffer);
383                 
384       if (!_dbus_auth_get_unused_bytes (transport->auth,
385                                         buffer))
386         goto nomem;
387                 
388       _dbus_verbose (" %d unused bytes sent to message loader\n", 
389                      _dbus_string_get_length (buffer) -
390                      orig_len);
391       
392       _dbus_message_loader_return_buffer (transport->loader,
393                                           buffer,
394                                           _dbus_string_get_length (buffer) -
395                                           orig_len);
396     }
397   
398   queue_messages (transport);
399
400   return;
401
402  nomem:
403   _dbus_verbose ("Not enough memory to transfer unused bytes from auth conversation\n");
404   do_io_error (transport);
405 }
406
407 static void
408 exchange_credentials (DBusTransport *transport,
409                       dbus_bool_t    do_reading,
410                       dbus_bool_t    do_writing)
411 {
412   DBusTransportUnix *unix_transport = (DBusTransportUnix*) transport;
413
414   if (do_writing && transport->send_credentials_pending)
415     {
416       if (_dbus_send_credentials_unix_socket (unix_transport->fd,
417                                               NULL))
418         {
419           transport->send_credentials_pending = FALSE;
420         }
421       else
422         {
423           _dbus_verbose ("Failed to write credentials\n");
424           do_io_error (transport);
425         }
426     }
427   
428   if (do_reading && transport->receive_credentials_pending)
429     {
430       if (_dbus_read_credentials_unix_socket (unix_transport->fd,
431                                                &transport->credentials,
432                                                NULL))
433         {
434           transport->receive_credentials_pending = FALSE;
435         }
436       else
437         {
438           _dbus_verbose ("Failed to read credentials\n");
439           do_io_error (transport);
440         }
441     }
442
443   if (!(transport->send_credentials_pending ||
444         transport->receive_credentials_pending))
445     {
446       _dbus_auth_set_credentials (transport->auth,
447                                   &transport->credentials);
448     }
449 }
450
451 static void
452 do_authentication (DBusTransport *transport,
453                    dbus_bool_t    do_reading,
454                    dbus_bool_t    do_writing)
455 {  
456   _dbus_transport_ref (transport);
457   
458   while (!_dbus_transport_get_is_authenticated (transport) &&
459          _dbus_transport_get_is_connected (transport))
460     {
461       exchange_credentials (transport, do_reading, do_writing);
462       
463       if (transport->send_credentials_pending ||
464           transport->receive_credentials_pending)
465         {
466           _dbus_verbose ("send_credentials_pending = %d receive_credentials_pending = %d\n",
467                          transport->send_credentials_pending,
468                          transport->receive_credentials_pending);
469           goto out;
470         }
471       
472       switch (_dbus_auth_do_work (transport->auth))
473         {
474         case DBUS_AUTH_STATE_WAITING_FOR_INPUT:
475           _dbus_verbose (" auth state: waiting for input\n");
476           if (!do_reading || !read_data_into_auth (transport))
477             goto out;
478           break;
479       
480         case DBUS_AUTH_STATE_WAITING_FOR_MEMORY:
481           /* Screw it, just disconnect */
482           _dbus_verbose (" auth state: waiting for memory\n");
483           do_io_error (transport);
484           break;
485       
486         case DBUS_AUTH_STATE_HAVE_BYTES_TO_SEND:
487           _dbus_verbose (" auth state: bytes to send\n");
488           if (!do_writing || !write_data_from_auth (transport))
489             goto out;
490           break;
491       
492         case DBUS_AUTH_STATE_NEED_DISCONNECT:
493           _dbus_verbose (" auth state: need to disconnect\n");
494           do_io_error (transport);
495           break;
496       
497         case DBUS_AUTH_STATE_AUTHENTICATED_WITH_UNUSED_BYTES:
498           _dbus_verbose (" auth state: auth with unused bytes\n");
499           recover_unused_bytes (transport);
500           break;
501           
502         case DBUS_AUTH_STATE_AUTHENTICATED:
503           _dbus_verbose (" auth state: authenticated\n");
504           break;
505         }
506     }
507
508  out:
509   check_read_watch (transport);
510   check_write_watch (transport);
511   _dbus_transport_unref (transport);
512 }
513
514 static void
515 do_writing (DBusTransport *transport)
516 {
517   int total;
518   DBusTransportUnix *unix_transport = (DBusTransportUnix*) transport;
519
520   /* No messages without authentication! */
521   if (!_dbus_transport_get_is_authenticated (transport))
522     return;
523
524   if (transport->disconnected)
525     return;
526   
527   total = 0;
528
529   while (!transport->disconnected &&
530          _dbus_connection_have_messages_to_send (transport->connection))
531     {
532       int bytes_written;
533       DBusMessage *message;
534       const DBusString *header;
535       const DBusString *body;
536       int header_len, body_len;
537       int total_bytes_to_write;
538       
539       if (total > unix_transport->max_bytes_written_per_iteration)
540         {
541           _dbus_verbose ("%d bytes exceeds %d bytes written per iteration, returning\n",
542                          total, unix_transport->max_bytes_written_per_iteration);
543           goto out;
544         }
545
546       if (unix_transport->write_watch == NULL)
547         {
548           _dbus_verbose ("write watch removed, not writing more stuff\n");
549           goto out;
550         }
551       
552       message = _dbus_connection_get_message_to_send (transport->connection);
553       _dbus_assert (message != NULL);
554       _dbus_message_lock (message);
555
556 #if 0
557       _dbus_verbose ("writing message %p\n", message);
558 #endif
559       
560       _dbus_message_get_network_data (message,
561                                       &header, &body);
562
563       header_len = _dbus_string_get_length (header);
564       body_len = _dbus_string_get_length (body);
565
566       if (_dbus_auth_needs_encoding (transport->auth))
567         {
568           if (_dbus_string_get_length (&unix_transport->encoded_message) == 0)
569             {
570               if (!_dbus_auth_encode_data (transport->auth,
571                                            header, &unix_transport->encoded_message))
572                 goto out;
573               
574               if (!_dbus_auth_encode_data (transport->auth,
575                                            body, &unix_transport->encoded_message))
576                 {
577                   _dbus_string_set_length (&unix_transport->encoded_message, 0);
578                   goto out;
579                 }
580             }
581           
582           total_bytes_to_write = _dbus_string_get_length (&unix_transport->encoded_message);
583
584 #if 0
585           _dbus_verbose ("encoded message is %d bytes\n",
586                          total_bytes_to_write);
587 #endif
588           
589           bytes_written =
590             _dbus_write (unix_transport->fd,
591                          &unix_transport->encoded_message,
592                          unix_transport->message_bytes_written,
593                          total_bytes_to_write - unix_transport->message_bytes_written);
594         }
595       else
596         {
597           total_bytes_to_write = header_len + body_len;
598
599 #if 0
600           _dbus_verbose ("message is %d bytes\n",
601                          total_bytes_to_write);          
602 #endif
603           
604           if (unix_transport->message_bytes_written < header_len)
605             {
606               bytes_written =
607                 _dbus_write_two (unix_transport->fd,
608                                  header,
609                                  unix_transport->message_bytes_written,
610                                  header_len - unix_transport->message_bytes_written,
611                                  body,
612                                  0, body_len);
613             }
614           else
615             {
616               bytes_written =
617                 _dbus_write (unix_transport->fd,
618                              body,
619                              (unix_transport->message_bytes_written - header_len),
620                              body_len -
621                              (unix_transport->message_bytes_written - header_len));
622             }
623         }
624
625       if (bytes_written < 0)
626         {
627           /* EINTR already handled for us */
628           
629           if (errno == EAGAIN ||
630               errno == EWOULDBLOCK)
631             goto out;
632           else
633             {
634               _dbus_verbose ("Error writing to remote app: %s\n",
635                              _dbus_strerror (errno));
636               do_io_error (transport);
637               goto out;
638             }
639         }
640       else
641         {          
642           _dbus_verbose (" wrote %d bytes of %d\n", bytes_written,
643                          total_bytes_to_write);
644           
645           total += bytes_written;
646           unix_transport->message_bytes_written += bytes_written;
647
648           _dbus_assert (unix_transport->message_bytes_written <=
649                         total_bytes_to_write);
650           
651           if (unix_transport->message_bytes_written == total_bytes_to_write)
652             {
653               unix_transport->message_bytes_written = 0;
654               _dbus_string_set_length (&unix_transport->encoded_message, 0);
655
656               _dbus_connection_message_sent (transport->connection,
657                                              message);
658             }
659         }
660     }
661
662  out:
663   return; /* I think some C compilers require a statement after a label */
664 }
665
666 static void
667 do_reading (DBusTransport *transport)
668 {
669   DBusTransportUnix *unix_transport = (DBusTransportUnix*) transport;
670   DBusString *buffer;
671   int bytes_read;
672   int total;
673
674   /* No messages without authentication! */
675   if (!_dbus_transport_get_is_authenticated (transport))
676     return;
677   
678   total = 0;
679
680  again:
681
682   /* See if we've exceeded max messages and need to disable reading */
683   check_read_watch (transport);
684   if (unix_transport->read_watch == NULL)
685     return;
686   
687   if (total > unix_transport->max_bytes_read_per_iteration)
688     {
689       _dbus_verbose ("%d bytes exceeds %d bytes read per iteration, returning\n",
690                      total, unix_transport->max_bytes_read_per_iteration);
691       goto out;
692     }
693
694   if (transport->disconnected)
695     goto out;
696
697   if (_dbus_auth_needs_decoding (transport->auth))
698     {
699       DBusString encoded;
700
701       if (!_dbus_string_init (&encoded, _DBUS_INT_MAX))
702         goto out; /* not enough memory for the moment */
703
704       bytes_read = _dbus_read (unix_transport->fd,
705                                &encoded,
706                                unix_transport->max_bytes_read_per_iteration);
707
708       if (bytes_read > 0)
709         {
710           int orig_len;
711           
712           _dbus_message_loader_get_buffer (transport->loader,
713                                            &buffer);
714
715           orig_len = _dbus_string_get_length (buffer);
716           
717           if (!_dbus_auth_decode_data (transport->auth,
718                                        &encoded, buffer))
719             {
720               /* FIXME argh, we are really fucked here - nowhere to
721                * put "encoded" while we wait for more memory.  Just
722                * screw it for now and disconnect.  The failure may be
723                * due to badly-encoded data instead of lack of memory
724                * anyhow.
725                */
726               _dbus_verbose ("Disconnected from remote app due to failure decoding data\n");
727               do_io_error (transport);
728             }
729
730           _dbus_message_loader_return_buffer (transport->loader,
731                                               buffer,
732                                               _dbus_string_get_length (buffer) - orig_len);
733         }
734
735       _dbus_string_free (&encoded);
736     }
737   else
738     {
739       _dbus_message_loader_get_buffer (transport->loader,
740                                        &buffer);
741       
742       bytes_read = _dbus_read (unix_transport->fd,
743                                buffer, unix_transport->max_bytes_read_per_iteration);
744       
745       _dbus_message_loader_return_buffer (transport->loader,
746                                           buffer,
747                                           bytes_read < 0 ? 0 : bytes_read);
748     }
749   
750   if (bytes_read < 0)
751     {
752       /* EINTR already handled for us */
753       
754       if (errno == EAGAIN ||
755           errno == EWOULDBLOCK)
756         goto out;
757       else
758         {
759           _dbus_verbose ("Error reading from remote app: %s\n",
760                          _dbus_strerror (errno));
761           do_io_error (transport);
762           goto out;
763         }
764     }
765   else if (bytes_read == 0)
766     {
767       _dbus_verbose ("Disconnected from remote app\n");
768       do_io_error (transport);
769       goto out;
770     }
771   else
772     {
773       _dbus_verbose (" read %d bytes\n", bytes_read);
774       
775       total += bytes_read;      
776
777       queue_messages (transport);
778       
779       /* Try reading more data until we get EAGAIN and return, or
780        * exceed max bytes per iteration.  If in blocking mode of
781        * course we'll block instead of returning.
782        */
783       goto again;
784     }
785
786  out:
787   return; /* I think some C compilers require a statement after a label */
788 }
789
790 static void
791 unix_handle_watch (DBusTransport *transport,
792                    DBusWatch     *watch,
793                    unsigned int   flags)
794 {
795   DBusTransportUnix *unix_transport = (DBusTransportUnix*) transport;
796
797   _dbus_assert (watch == unix_transport->read_watch ||
798                 watch == unix_transport->write_watch);
799   
800   if (flags & (DBUS_WATCH_HANGUP | DBUS_WATCH_ERROR))
801     {
802       _dbus_transport_disconnect (transport);
803       return;
804     }
805   
806   if (watch == unix_transport->read_watch &&
807       (flags & DBUS_WATCH_READABLE))
808     {
809 #if 0
810       _dbus_verbose ("handling read watch\n");
811 #endif
812       do_authentication (transport, TRUE, FALSE);
813       do_reading (transport);
814     }
815   else if (watch == unix_transport->write_watch &&
816            (flags & DBUS_WATCH_WRITABLE))
817     {
818 #if 0
819       _dbus_verbose ("handling write watch\n");
820 #endif
821       do_authentication (transport, FALSE, TRUE);
822       do_writing (transport);
823     }
824 }
825
826 static void
827 unix_disconnect (DBusTransport *transport)
828 {
829   DBusTransportUnix *unix_transport = (DBusTransportUnix*) transport;
830   
831   free_watches (transport);
832   
833   _dbus_close (unix_transport->fd, NULL);
834   unix_transport->fd = -1;
835 }
836
837 static dbus_bool_t
838 unix_connection_set (DBusTransport *transport)
839 {
840   DBusTransportUnix *unix_transport = (DBusTransportUnix*) transport;
841   
842   if (!_dbus_connection_add_watch (transport->connection,
843                                    unix_transport->write_watch))
844     return FALSE;
845
846   if (!_dbus_connection_add_watch (transport->connection,
847                                    unix_transport->read_watch))
848     {
849       _dbus_connection_remove_watch (transport->connection,
850                                      unix_transport->write_watch);
851       return FALSE;
852     }
853
854   check_read_watch (transport);
855   check_write_watch (transport);
856
857   return TRUE;
858 }
859
860 static void
861 unix_messages_pending (DBusTransport *transport,
862                        int            messages_pending)
863 {
864   check_write_watch (transport);
865 }
866
867 /* FIXME use _dbus_poll(), not select() */
868 /**
869  * @todo We need to have a way to wake up the select sleep if
870  * a new iteration request comes in with a flag (read/write) that
871  * we're not currently serving. Otherwise a call that just reads
872  * could block a write call forever (if there are no incoming
873  * messages).
874  */
875 static  void
876 unix_do_iteration (DBusTransport *transport,
877                    unsigned int   flags,
878                    int            timeout_milliseconds)
879 {
880   DBusTransportUnix *unix_transport = (DBusTransportUnix*) transport;
881   fd_set read_set;
882   fd_set write_set;
883   dbus_bool_t do_select;
884   int select_res;
885
886   _dbus_verbose (" iteration flags = %s%s timeout = %d read_watch = %p write_watch = %p\n",
887                  flags & DBUS_ITERATION_DO_READING ? "read" : "",
888                  flags & DBUS_ITERATION_DO_WRITING ? "write" : "",
889                  timeout_milliseconds,
890                  unix_transport->read_watch,
891                  unix_transport->write_watch);
892   
893   /* "again" has to be up here because on EINTR the fd sets become
894    * undefined
895    */
896  again:
897   
898   do_select = FALSE;
899
900   /* the passed in DO_READING/DO_WRITING flags indicate whether to
901    * read/write messages, but regardless of those we may need to block
902    * for reading/writing to do auth.  But if we do reading for auth,
903    * we don't want to read any messages yet if not given DO_READING.
904    *
905    * Also, if read_watch == NULL or write_watch == NULL, we don't
906    * want to read/write so don't.
907    */
908
909   FD_ZERO (&read_set);
910   FD_ZERO (&write_set);
911   
912   if (_dbus_transport_get_is_authenticated (transport))
913     {
914       if (unix_transport->read_watch &&
915           (flags & DBUS_ITERATION_DO_READING))
916         {
917           FD_SET (unix_transport->fd, &read_set);
918           do_select = TRUE;
919         }
920       
921       if (unix_transport->write_watch &&
922           (flags & DBUS_ITERATION_DO_WRITING))
923         {
924           FD_SET (unix_transport->fd, &write_set);
925           do_select = TRUE;
926         }
927     }
928   else
929     {
930       DBusAuthState auth_state;
931       
932       auth_state = _dbus_auth_do_work (transport->auth);
933
934       if (transport->receive_credentials_pending ||
935           auth_state == DBUS_AUTH_STATE_WAITING_FOR_INPUT)
936         {
937           FD_SET (unix_transport->fd, &read_set);
938           do_select = TRUE;
939         }
940
941       if (transport->send_credentials_pending ||
942           auth_state == DBUS_AUTH_STATE_HAVE_BYTES_TO_SEND)
943         {
944           FD_SET (unix_transport->fd, &write_set);
945           do_select = TRUE;
946         }
947     } 
948
949   if (do_select)
950     {
951       fd_set err_set;
952       struct timeval timeout;
953       dbus_bool_t use_timeout;
954       
955       FD_ZERO (&err_set);
956       FD_SET (unix_transport->fd, &err_set);
957   
958       if (flags & DBUS_ITERATION_BLOCK)
959         {
960           if (timeout_milliseconds >= 0)
961             {
962               timeout.tv_sec = timeout_milliseconds / 1000;
963               timeout.tv_usec = (timeout_milliseconds % 1000) * 1000;
964               
965               /* Always use timeout if one is passed in. */
966               use_timeout = TRUE;
967             }
968           else
969             {
970               use_timeout = FALSE; /* NULL timeout to block forever */
971             }
972         }
973       else
974         {
975           /* 0 timeout to not block */
976           timeout.tv_sec = 0;
977           timeout.tv_usec = 0;
978           use_timeout = TRUE;
979         }
980
981       /* For blocking selects we drop the connection lock here
982        * to avoid blocking out connection access during a potentially
983        * indefinite blocking call. The io path is still protected
984        * by the io_path_cond condvar, so we won't reenter this.
985        */
986       if (flags & DBUS_ITERATION_BLOCK)
987         _dbus_connection_unlock (transport->connection);
988       
989       select_res = select (unix_transport->fd + 1,
990                            &read_set, &write_set, &err_set,
991                            use_timeout ? &timeout : NULL);
992
993       if (flags & DBUS_ITERATION_BLOCK)
994         _dbus_connection_lock (transport->connection);
995       
996       
997       if (select_res >= 0)
998         {
999           if (FD_ISSET (unix_transport->fd, &err_set))
1000             do_io_error (transport);
1001           else
1002             {
1003               dbus_bool_t need_read = FD_ISSET (unix_transport->fd, &read_set);
1004               dbus_bool_t need_write = FD_ISSET (unix_transport->fd, &write_set);
1005
1006               _dbus_verbose ("in iteration, need_read=%d need_write=%d\n",
1007                              need_read, need_write);
1008               do_authentication (transport, need_read, need_write);
1009                                  
1010               if (need_read && (flags & DBUS_ITERATION_DO_READING))
1011                 do_reading (transport);
1012               if (need_write && (flags & DBUS_ITERATION_DO_WRITING))
1013                 do_writing (transport);
1014             }
1015         }
1016       else if (errno == EINTR)
1017         goto again;
1018       else
1019         {
1020           _dbus_verbose ("Error from select(): %s\n",
1021                          _dbus_strerror (errno));
1022         }
1023     }
1024 }
1025
1026 static void
1027 unix_live_messages_changed (DBusTransport *transport)
1028 {
1029   /* See if we should look for incoming messages again */
1030   check_read_watch (transport);
1031 }
1032
1033 static DBusTransportVTable unix_vtable = {
1034   unix_finalize,
1035   unix_handle_watch,
1036   unix_disconnect,
1037   unix_connection_set,
1038   unix_messages_pending,
1039   unix_do_iteration,
1040   unix_live_messages_changed
1041 };
1042
1043 /**
1044  * Creates a new transport for the given file descriptor.  The file
1045  * descriptor must be nonblocking (use _dbus_set_fd_nonblocking() to
1046  * make it so). This function is shared by various transports that
1047  * boil down to a full duplex file descriptor.
1048  *
1049  * @param fd the file descriptor.
1050  * @param server #TRUE if this transport is on the server side of a connection
1051  * @returns the new transport, or #NULL if no memory.
1052  */
1053 DBusTransport*
1054 _dbus_transport_new_for_fd (int         fd,
1055                             dbus_bool_t server)
1056 {
1057   DBusTransportUnix *unix_transport;
1058   
1059   unix_transport = dbus_new0 (DBusTransportUnix, 1);
1060   if (unix_transport == NULL)
1061     return NULL;
1062
1063   if (!_dbus_string_init (&unix_transport->encoded_message,
1064                           _DBUS_INT_MAX))
1065     goto failed_0;
1066
1067   unix_transport->write_watch = _dbus_watch_new (fd,
1068                                                  DBUS_WATCH_WRITABLE,
1069                                                  FALSE);
1070   if (unix_transport->write_watch == NULL)
1071     goto failed_1;
1072   
1073   unix_transport->read_watch = _dbus_watch_new (fd,
1074                                                 DBUS_WATCH_READABLE,
1075                                                 FALSE);
1076   if (unix_transport->read_watch == NULL)
1077     goto failed_2;
1078   
1079   if (!_dbus_transport_init_base (&unix_transport->base,
1080                                   &unix_vtable,
1081                                   server))
1082     goto failed_3;
1083   
1084   unix_transport->fd = fd;
1085   unix_transport->message_bytes_written = 0;
1086   
1087   /* These values should probably be tunable or something. */     
1088   unix_transport->max_bytes_read_per_iteration = 2048;
1089   unix_transport->max_bytes_written_per_iteration = 2048;
1090   
1091   return (DBusTransport*) unix_transport;
1092
1093  failed_3:
1094   _dbus_watch_unref (unix_transport->read_watch);
1095  failed_2:
1096   _dbus_watch_unref (unix_transport->write_watch);
1097  failed_1:
1098   _dbus_string_free (&unix_transport->encoded_message);  
1099  failed_0:
1100   dbus_free (unix_transport);
1101   return NULL;
1102 }
1103
1104 /**
1105  * Creates a new transport for the given Unix domain socket
1106  * path.
1107  *
1108  * @param path the path to the domain socket.
1109  * @param server #TRUE if this transport is on the server side of a connection
1110  * @param result location to store reason for failure.
1111  * @returns a new transport, or #NULL on failure.
1112  */
1113 DBusTransport*
1114 _dbus_transport_new_for_domain_socket (const char     *path,
1115                                        dbus_bool_t     server,
1116                                        DBusResultCode *result)
1117 {
1118   int fd;
1119   DBusTransport *transport;
1120
1121   fd = _dbus_connect_unix_socket (path, result);
1122   if (fd < 0)
1123     return NULL;
1124
1125   _dbus_fd_set_close_on_exec (fd);
1126   
1127   _dbus_verbose ("Successfully connected to unix socket %s\n",
1128                  path);
1129   
1130   transport = _dbus_transport_new_for_fd (fd, server);
1131   if (transport == NULL)
1132     {
1133       dbus_set_result (result, DBUS_RESULT_NO_MEMORY);
1134       _dbus_close (fd, NULL);
1135       fd = -1;
1136     }
1137   
1138   return transport;
1139 }
1140
1141 /**
1142  * Creates a new transport for the given hostname and port.
1143  *
1144  * @param host the host to connect to
1145  * @param port the port to connect to
1146  * @param server #TRUE if this transport is on the server side of a connection
1147  * @param result location to store reason for failure.
1148  * @returns a new transport, or #NULL on failure.
1149  */
1150 DBusTransport*
1151 _dbus_transport_new_for_tcp_socket (const char     *host,
1152                                     dbus_int32_t    port,
1153                                     dbus_bool_t     server,
1154                                     DBusResultCode *result)
1155 {
1156   int fd;
1157   DBusTransport *transport;
1158   
1159   fd = _dbus_connect_tcp_socket (host, port, result);
1160   if (fd < 0)
1161     return NULL;
1162
1163   _dbus_fd_set_close_on_exec (fd);
1164   
1165   _dbus_verbose ("Successfully connected to tcp socket %s:%d\n",
1166                  host, port);
1167   
1168   transport = _dbus_transport_new_for_fd (fd, server);
1169   if (transport == NULL)
1170     {
1171       dbus_set_result (result, DBUS_RESULT_NO_MEMORY);
1172       _dbus_close (fd, NULL);
1173       fd = -1;
1174     }
1175
1176   return transport;
1177 }
1178
1179 /** @} */
1180