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