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