2003-04-22 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 #define TRANSPORT_SIDE(t) ((t)->is_server ? "server" : "client")
350       switch (_dbus_auth_do_work (transport->auth))
351         {
352         case DBUS_AUTH_STATE_WAITING_FOR_INPUT:
353           _dbus_verbose (" %s auth state: waiting for input\n",
354                          TRANSPORT_SIDE (transport));
355           if (!do_reading || !read_data_into_auth (transport, &oom))
356             goto out;
357           break;
358       
359         case DBUS_AUTH_STATE_WAITING_FOR_MEMORY:
360           _dbus_verbose (" %s auth state: waiting for memory\n",
361                          TRANSPORT_SIDE (transport));
362           oom = TRUE;
363           goto out;
364           break;
365       
366         case DBUS_AUTH_STATE_HAVE_BYTES_TO_SEND:
367           _dbus_verbose (" %s auth state: bytes to send\n",
368                          TRANSPORT_SIDE (transport));
369           if (!do_writing || !write_data_from_auth (transport))
370             goto out;
371           break;
372       
373         case DBUS_AUTH_STATE_NEED_DISCONNECT:
374           _dbus_verbose (" %s auth state: need to disconnect\n",
375                          TRANSPORT_SIDE (transport));
376           do_io_error (transport);
377           break;
378       
379         case DBUS_AUTH_STATE_AUTHENTICATED_WITH_UNUSED_BYTES:
380           _dbus_verbose (" %s auth state: auth with unused bytes\n",
381                          TRANSPORT_SIDE (transport));
382           /* We'll recover the unused bytes in dbus-transport.c */
383           goto out;
384           break;
385           
386         case DBUS_AUTH_STATE_AUTHENTICATED:
387           _dbus_verbose (" %s auth state: authenticated\n",
388                          TRANSPORT_SIDE (transport));
389           break;
390         }
391     }
392   
393  out:
394   check_read_watch (transport);
395   check_write_watch (transport);
396   _dbus_transport_unref (transport);
397
398   if (oom)
399     return FALSE;
400   else
401     return TRUE;
402 }
403
404 /* returns false on oom */
405 static dbus_bool_t
406 do_writing (DBusTransport *transport)
407 {
408   int total;
409   DBusTransportUnix *unix_transport = (DBusTransportUnix*) transport;
410   dbus_bool_t oom;
411   
412   /* No messages without authentication! */
413   if (!_dbus_transport_get_is_authenticated (transport))
414     {
415       _dbus_verbose ("Not authenticated, not writing anything\n");
416       return TRUE;
417     }
418
419   if (transport->disconnected)
420     {
421       _dbus_verbose ("Not connected, not writing anything\n");
422       return TRUE;
423     }
424
425 #if 0
426   _dbus_verbose ("do_writing(), have_messages = %d\n",
427                  _dbus_connection_have_messages_to_send (transport->connection));
428 #endif
429   
430   oom = FALSE;
431   total = 0;
432
433   while (!transport->disconnected &&
434          _dbus_connection_have_messages_to_send (transport->connection))
435     {
436       int bytes_written;
437       DBusMessage *message;
438       const DBusString *header;
439       const DBusString *body;
440       int header_len, body_len;
441       int total_bytes_to_write;
442       
443       if (total > unix_transport->max_bytes_written_per_iteration)
444         {
445           _dbus_verbose ("%d bytes exceeds %d bytes written per iteration, returning\n",
446                          total, unix_transport->max_bytes_written_per_iteration);
447           goto out;
448         }
449
450       if (!dbus_watch_get_enabled (unix_transport->write_watch))
451         {
452           _dbus_verbose ("write watch disabled, not writing more stuff\n");
453           goto out;
454         }
455       
456       message = _dbus_connection_get_message_to_send (transport->connection);
457       _dbus_assert (message != NULL);
458       _dbus_message_lock (message);
459
460 #if 0
461       _dbus_verbose ("writing message %p\n", message);
462 #endif
463       
464       _dbus_message_get_network_data (message,
465                                       &header, &body);
466
467       header_len = _dbus_string_get_length (header);
468       body_len = _dbus_string_get_length (body);
469
470       if (_dbus_auth_needs_encoding (transport->auth))
471         {
472           if (_dbus_string_get_length (&unix_transport->encoded_outgoing) == 0)
473             {
474               if (!_dbus_auth_encode_data (transport->auth,
475                                            header, &unix_transport->encoded_outgoing))
476                 {
477                   oom = TRUE;
478                   goto out;
479                 }
480               
481               if (!_dbus_auth_encode_data (transport->auth,
482                                            body, &unix_transport->encoded_outgoing))
483                 {
484                   _dbus_string_set_length (&unix_transport->encoded_outgoing, 0);
485                   oom = TRUE;
486                   goto out;
487                 }
488             }
489           
490           total_bytes_to_write = _dbus_string_get_length (&unix_transport->encoded_outgoing);
491
492 #if 0
493           _dbus_verbose ("encoded message is %d bytes\n",
494                          total_bytes_to_write);
495 #endif
496           
497           bytes_written =
498             _dbus_write (unix_transport->fd,
499                          &unix_transport->encoded_outgoing,
500                          unix_transport->message_bytes_written,
501                          total_bytes_to_write - unix_transport->message_bytes_written);
502         }
503       else
504         {
505           total_bytes_to_write = header_len + body_len;
506
507 #if 0
508           _dbus_verbose ("message is %d bytes\n",
509                          total_bytes_to_write);          
510 #endif
511           
512           if (unix_transport->message_bytes_written < header_len)
513             {
514               bytes_written =
515                 _dbus_write_two (unix_transport->fd,
516                                  header,
517                                  unix_transport->message_bytes_written,
518                                  header_len - unix_transport->message_bytes_written,
519                                  body,
520                                  0, body_len);
521             }
522           else
523             {
524               bytes_written =
525                 _dbus_write (unix_transport->fd,
526                              body,
527                              (unix_transport->message_bytes_written - header_len),
528                              body_len -
529                              (unix_transport->message_bytes_written - header_len));
530             }
531         }
532
533       if (bytes_written < 0)
534         {
535           /* EINTR already handled for us */
536           
537           if (errno == EAGAIN ||
538               errno == EWOULDBLOCK)
539             goto out;
540           else
541             {
542               _dbus_verbose ("Error writing to remote app: %s\n",
543                              _dbus_strerror (errno));
544               do_io_error (transport);
545               goto out;
546             }
547         }
548       else
549         {
550           _dbus_verbose (" wrote %d bytes of %d\n", bytes_written,
551                          total_bytes_to_write);
552           
553           total += bytes_written;
554           unix_transport->message_bytes_written += bytes_written;
555
556           _dbus_assert (unix_transport->message_bytes_written <=
557                         total_bytes_to_write);
558           
559           if (unix_transport->message_bytes_written == total_bytes_to_write)
560             {
561               unix_transport->message_bytes_written = 0;
562               _dbus_string_set_length (&unix_transport->encoded_outgoing, 0);
563
564               _dbus_connection_message_sent (transport->connection,
565                                              message);
566             }
567         }
568     }
569
570  out:
571   if (oom)
572     return FALSE;
573   else
574     return TRUE;
575 }
576
577 /* returns false on out-of-memory */
578 static dbus_bool_t
579 do_reading (DBusTransport *transport)
580 {
581   DBusTransportUnix *unix_transport = (DBusTransportUnix*) transport;
582   DBusString *buffer;
583   int bytes_read;
584   int total;
585   dbus_bool_t oom;
586
587   /* No messages without authentication! */
588   if (!_dbus_transport_get_is_authenticated (transport))
589     return TRUE;
590
591   oom = FALSE;
592   
593   total = 0;
594
595  again:
596
597   /* See if we've exceeded max messages and need to disable reading */
598   check_read_watch (transport);
599   if (!dbus_watch_get_enabled (unix_transport->read_watch))
600     return TRUE;
601   
602   if (total > unix_transport->max_bytes_read_per_iteration)
603     {
604       _dbus_verbose ("%d bytes exceeds %d bytes read per iteration, returning\n",
605                      total, unix_transport->max_bytes_read_per_iteration);
606       goto out;
607     }
608
609   if (transport->disconnected)
610     goto out;
611
612   if (_dbus_auth_needs_decoding (transport->auth))
613     {
614       if (_dbus_string_get_length (&unix_transport->encoded_incoming) > 0)
615         bytes_read = _dbus_string_get_length (&unix_transport->encoded_incoming);
616       else
617         bytes_read = _dbus_read (unix_transport->fd,
618                                  &unix_transport->encoded_incoming,
619                                  unix_transport->max_bytes_read_per_iteration);
620
621       _dbus_assert (_dbus_string_get_length (&unix_transport->encoded_incoming) ==
622                     bytes_read);
623       
624       if (bytes_read > 0)
625         {
626           int orig_len;
627           
628           _dbus_message_loader_get_buffer (transport->loader,
629                                            &buffer);
630
631           orig_len = _dbus_string_get_length (buffer);
632           
633           if (!_dbus_auth_decode_data (transport->auth,
634                                        &unix_transport->encoded_incoming,
635                                        buffer))
636             {
637               _dbus_verbose ("Out of memory decoding incoming data\n");
638               oom = TRUE;
639               goto out;
640             }
641
642           _dbus_message_loader_return_buffer (transport->loader,
643                                               buffer,
644                                               _dbus_string_get_length (buffer) - orig_len);
645
646           _dbus_string_set_length (&unix_transport->encoded_incoming, 0);
647         }
648     }
649   else
650     {
651       _dbus_message_loader_get_buffer (transport->loader,
652                                        &buffer);
653       
654       bytes_read = _dbus_read (unix_transport->fd,
655                                buffer, unix_transport->max_bytes_read_per_iteration);
656       
657       _dbus_message_loader_return_buffer (transport->loader,
658                                           buffer,
659                                           bytes_read < 0 ? 0 : bytes_read);
660     }
661   
662   if (bytes_read < 0)
663     {
664       /* EINTR already handled for us */
665
666       if (errno == ENOMEM)
667         {
668           _dbus_verbose ("Out of memory in read()/do_reading()\n");
669           oom = TRUE;
670           goto out;
671         }
672       else if (errno == EAGAIN ||
673                errno == EWOULDBLOCK)
674         goto out;
675       else
676         {
677           _dbus_verbose ("Error reading from remote app: %s\n",
678                          _dbus_strerror (errno));
679           do_io_error (transport);
680           goto out;
681         }
682     }
683   else if (bytes_read == 0)
684     {
685       _dbus_verbose ("Disconnected from remote app\n");
686       do_io_error (transport);
687       goto out;
688     }
689   else
690     {
691       _dbus_verbose (" read %d bytes\n", bytes_read);
692       
693       total += bytes_read;      
694
695       if (_dbus_transport_queue_messages (transport) == DBUS_DISPATCH_NEED_MEMORY)
696         {
697           oom = TRUE;
698           _dbus_verbose (" out of memory when queueing messages we just read in the transport\n");
699           goto out;
700         }
701       
702       /* Try reading more data until we get EAGAIN and return, or
703        * exceed max bytes per iteration.  If in blocking mode of
704        * course we'll block instead of returning.
705        */
706       goto again;
707     }
708
709  out:
710   if (oom)
711     return FALSE;
712   else
713     return TRUE;
714 }
715
716 static dbus_bool_t
717 unix_handle_watch (DBusTransport *transport,
718                    DBusWatch     *watch,
719                    unsigned int   flags)
720 {
721   DBusTransportUnix *unix_transport = (DBusTransportUnix*) transport;
722
723   _dbus_assert (watch == unix_transport->read_watch ||
724                 watch == unix_transport->write_watch);
725   
726   if (flags & (DBUS_WATCH_HANGUP | DBUS_WATCH_ERROR))
727     {
728       _dbus_transport_disconnect (transport);
729       return TRUE;
730     }
731   
732   if (watch == unix_transport->read_watch &&
733       (flags & DBUS_WATCH_READABLE))
734     {
735 #if 1
736       _dbus_verbose ("handling read watch\n");
737 #endif
738       if (!do_authentication (transport, TRUE, FALSE))
739         return FALSE;
740       
741       if (!do_reading (transport))
742         {
743           _dbus_verbose ("no memory to read\n");
744           return FALSE;
745         }
746     }
747   else if (watch == unix_transport->write_watch &&
748            (flags & DBUS_WATCH_WRITABLE))
749     {
750 #if 0
751       _dbus_verbose ("handling write watch, messages_need_sending = %d\n",
752                      transport->messages_need_sending);
753 #endif
754       if (!do_authentication (transport, FALSE, TRUE))
755         return FALSE;
756       
757       if (!do_writing (transport))
758         {
759           _dbus_verbose ("no memory to write\n");
760           return FALSE;
761         }
762     }
763 #ifdef DBUS_ENABLE_VERBOSE_MODE
764   else
765     {
766       if (watch == unix_transport->read_watch)
767         _dbus_verbose ("asked to handle read watch with non-read condition 0x%x\n",
768                        flags);
769       else if (watch == unix_transport->write_watch)
770         _dbus_verbose ("asked to handle write watch with non-write condition 0x%x\n",
771                        flags);
772       else
773         _dbus_verbose ("asked to handle watch %p on fd %d that we don't recognize\n",
774                        watch, dbus_watch_get_fd (watch));
775     }
776 #endif /* DBUS_ENABLE_VERBOSE_MODE */
777
778   return TRUE;
779 }
780
781 static void
782 unix_disconnect (DBusTransport *transport)
783 {
784   DBusTransportUnix *unix_transport = (DBusTransportUnix*) transport;
785   
786   free_watches (transport);
787   
788   _dbus_close (unix_transport->fd, NULL);
789   unix_transport->fd = -1;
790 }
791
792 static dbus_bool_t
793 unix_connection_set (DBusTransport *transport)
794 {
795   DBusTransportUnix *unix_transport = (DBusTransportUnix*) transport;
796
797   _dbus_watch_set_handler (unix_transport->write_watch,
798                            _dbus_connection_handle_watch,
799                            transport->connection, NULL);
800
801   _dbus_watch_set_handler (unix_transport->read_watch,
802                            _dbus_connection_handle_watch,
803                            transport->connection, NULL);
804   
805   if (!_dbus_connection_add_watch (transport->connection,
806                                    unix_transport->write_watch))
807     return FALSE;
808
809   if (!_dbus_connection_add_watch (transport->connection,
810                                    unix_transport->read_watch))
811     {
812       _dbus_connection_remove_watch (transport->connection,
813                                      unix_transport->write_watch);
814       return FALSE;
815     }
816
817   check_read_watch (transport);
818   check_write_watch (transport);
819
820   return TRUE;
821 }
822
823 static void
824 unix_messages_pending (DBusTransport *transport,
825                        int            messages_pending)
826 {
827   check_write_watch (transport);
828 }
829
830 /* FIXME use _dbus_poll(), not select() */
831 /**
832  * @todo We need to have a way to wake up the select sleep if
833  * a new iteration request comes in with a flag (read/write) that
834  * we're not currently serving. Otherwise a call that just reads
835  * could block a write call forever (if there are no incoming
836  * messages).
837  */
838 static  void
839 unix_do_iteration (DBusTransport *transport,
840                    unsigned int   flags,
841                    int            timeout_milliseconds)
842 {
843   DBusTransportUnix *unix_transport = (DBusTransportUnix*) transport;
844   fd_set read_set;
845   fd_set write_set;
846   dbus_bool_t do_select;
847   int select_res;
848
849   _dbus_verbose (" iteration flags = %s%s timeout = %d read_watch = %p write_watch = %p\n",
850                  flags & DBUS_ITERATION_DO_READING ? "read" : "",
851                  flags & DBUS_ITERATION_DO_WRITING ? "write" : "",
852                  timeout_milliseconds,
853                  unix_transport->read_watch,
854                  unix_transport->write_watch);
855   
856   /* "again" has to be up here because on EINTR the fd sets become
857    * undefined
858    */
859  again:
860   
861   do_select = FALSE;
862
863   /* the passed in DO_READING/DO_WRITING flags indicate whether to
864    * read/write messages, but regardless of those we may need to block
865    * for reading/writing to do auth.  But if we do reading for auth,
866    * we don't want to read any messages yet if not given DO_READING.
867    *
868    * Also, if read_watch == NULL or write_watch == NULL, we don't
869    * want to read/write so don't.
870    */
871
872   FD_ZERO (&read_set);
873   FD_ZERO (&write_set);
874   
875   if (_dbus_transport_get_is_authenticated (transport))
876     {
877       if (unix_transport->read_watch &&
878           (flags & DBUS_ITERATION_DO_READING))
879         {
880           FD_SET (unix_transport->fd, &read_set);
881           do_select = TRUE;
882         }
883       
884       if (unix_transport->write_watch &&
885           (flags & DBUS_ITERATION_DO_WRITING))
886         {
887           FD_SET (unix_transport->fd, &write_set);
888           do_select = TRUE;
889         }
890     }
891   else
892     {
893       DBusAuthState auth_state;
894       
895       auth_state = _dbus_auth_do_work (transport->auth);
896
897       if (transport->receive_credentials_pending ||
898           auth_state == DBUS_AUTH_STATE_WAITING_FOR_INPUT)
899         {
900           FD_SET (unix_transport->fd, &read_set);
901           do_select = TRUE;
902         }
903
904       if (transport->send_credentials_pending ||
905           auth_state == DBUS_AUTH_STATE_HAVE_BYTES_TO_SEND)
906         {
907           FD_SET (unix_transport->fd, &write_set);
908           do_select = TRUE;
909         }
910     } 
911
912   if (do_select)
913     {
914       fd_set err_set;
915       struct timeval timeout;
916       dbus_bool_t use_timeout;
917       
918       FD_ZERO (&err_set);
919       FD_SET (unix_transport->fd, &err_set);
920   
921       if (flags & DBUS_ITERATION_BLOCK)
922         {
923           if (timeout_milliseconds >= 0)
924             {
925               timeout.tv_sec = timeout_milliseconds / 1000;
926               timeout.tv_usec = (timeout_milliseconds % 1000) * 1000;
927               
928               /* Always use timeout if one is passed in. */
929               use_timeout = TRUE;
930             }
931           else
932             {
933               use_timeout = FALSE; /* NULL timeout to block forever */
934             }
935         }
936       else
937         {
938           /* 0 timeout to not block */
939           timeout.tv_sec = 0;
940           timeout.tv_usec = 0;
941           use_timeout = TRUE;
942         }
943
944       /* For blocking selects we drop the connection lock here
945        * to avoid blocking out connection access during a potentially
946        * indefinite blocking call. The io path is still protected
947        * by the io_path_cond condvar, so we won't reenter this.
948        */
949       if (flags & DBUS_ITERATION_BLOCK)
950         _dbus_connection_unlock (transport->connection);
951       
952       select_res = select (unix_transport->fd + 1,
953                            &read_set, &write_set, &err_set,
954                            use_timeout ? &timeout : NULL);
955
956       if (flags & DBUS_ITERATION_BLOCK)
957         _dbus_connection_lock (transport->connection);
958       
959       
960       if (select_res >= 0)
961         {
962           if (FD_ISSET (unix_transport->fd, &err_set))
963             do_io_error (transport);
964           else
965             {
966               dbus_bool_t need_read = FD_ISSET (unix_transport->fd, &read_set);
967               dbus_bool_t need_write = FD_ISSET (unix_transport->fd, &write_set);
968
969               _dbus_verbose ("in iteration, need_read=%d need_write=%d\n",
970                              need_read, need_write);
971               do_authentication (transport, need_read, need_write);
972                                  
973               if (need_read && (flags & DBUS_ITERATION_DO_READING))
974                 do_reading (transport);
975               if (need_write && (flags & DBUS_ITERATION_DO_WRITING))
976                 do_writing (transport);
977             }
978         }
979       else if (errno == EINTR)
980         goto again;
981       else
982         {
983           _dbus_verbose ("Error from select(): %s\n",
984                          _dbus_strerror (errno));
985         }
986     }
987 }
988
989 static void
990 unix_live_messages_changed (DBusTransport *transport)
991 {
992   /* See if we should look for incoming messages again */
993   check_read_watch (transport);
994 }
995
996 static DBusTransportVTable unix_vtable = {
997   unix_finalize,
998   unix_handle_watch,
999   unix_disconnect,
1000   unix_connection_set,
1001   unix_messages_pending,
1002   unix_do_iteration,
1003   unix_live_messages_changed
1004 };
1005
1006 /**
1007  * Creates a new transport for the given file descriptor.  The file
1008  * descriptor must be nonblocking (use _dbus_set_fd_nonblocking() to
1009  * make it so). This function is shared by various transports that
1010  * boil down to a full duplex file descriptor.
1011  *
1012  * @param fd the file descriptor.
1013  * @param server #TRUE if this transport is on the server side of a connection
1014  * @param address the transport's address
1015  * @returns the new transport, or #NULL if no memory.
1016  */
1017 DBusTransport*
1018 _dbus_transport_new_for_fd (int               fd,
1019                             dbus_bool_t       server,
1020                             const DBusString *address)
1021 {
1022   DBusTransportUnix *unix_transport;
1023   
1024   unix_transport = dbus_new0 (DBusTransportUnix, 1);
1025   if (unix_transport == NULL)
1026     return NULL;
1027
1028   if (!_dbus_string_init (&unix_transport->encoded_outgoing))
1029     goto failed_0;
1030
1031   if (!_dbus_string_init (&unix_transport->encoded_incoming))
1032     goto failed_1;
1033   
1034   unix_transport->write_watch = _dbus_watch_new (fd,
1035                                                  DBUS_WATCH_WRITABLE,
1036                                                  FALSE,
1037                                                  NULL, NULL, NULL);
1038   if (unix_transport->write_watch == NULL)
1039     goto failed_2;
1040   
1041   unix_transport->read_watch = _dbus_watch_new (fd,
1042                                                 DBUS_WATCH_READABLE,
1043                                                 FALSE,
1044                                                 NULL, NULL, NULL);
1045   if (unix_transport->read_watch == NULL)
1046     goto failed_3;
1047   
1048   if (!_dbus_transport_init_base (&unix_transport->base,
1049                                   &unix_vtable,
1050                                   server, address))
1051     goto failed_4;
1052   
1053   unix_transport->fd = fd;
1054   unix_transport->message_bytes_written = 0;
1055   
1056   /* These values should probably be tunable or something. */     
1057   unix_transport->max_bytes_read_per_iteration = 2048;
1058   unix_transport->max_bytes_written_per_iteration = 2048;
1059   
1060   return (DBusTransport*) unix_transport;
1061
1062  failed_4:
1063   _dbus_watch_unref (unix_transport->read_watch);
1064  failed_3:
1065   _dbus_watch_unref (unix_transport->write_watch);
1066  failed_2:
1067   _dbus_string_free (&unix_transport->encoded_incoming);
1068  failed_1:
1069   _dbus_string_free (&unix_transport->encoded_outgoing);
1070  failed_0:
1071   dbus_free (unix_transport);
1072   return NULL;
1073 }
1074
1075 /**
1076  * Creates a new transport for the given Unix domain socket
1077  * path. This creates a client-side of a transport.
1078  *
1079  * @param path the path to the domain socket.
1080  * @param error address where an error can be returned.
1081  * @returns a new transport, or #NULL on failure.
1082  */
1083 DBusTransport*
1084 _dbus_transport_new_for_domain_socket (const char     *path,
1085                                        DBusError      *error)
1086 {
1087   int fd;
1088   DBusTransport *transport;
1089   DBusString address;
1090   
1091   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
1092
1093   if (!_dbus_string_init (&address))
1094     {
1095       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
1096       return NULL;
1097     }
1098
1099   fd = -1;
1100   
1101   if (!_dbus_string_append (&address, "unix:path=") ||
1102       !_dbus_string_append (&address, path))
1103     {
1104       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
1105       goto failed_0;
1106     }
1107   
1108   fd = _dbus_connect_unix_socket (path, error);
1109   if (fd < 0)
1110     {
1111       _DBUS_ASSERT_ERROR_IS_SET (error);
1112       goto failed_0;
1113     }
1114
1115   _dbus_fd_set_close_on_exec (fd);
1116   
1117   _dbus_verbose ("Successfully connected to unix socket %s\n",
1118                  path);
1119
1120   transport = _dbus_transport_new_for_fd (fd, FALSE, &address);
1121   if (transport == NULL)
1122     {
1123       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
1124       goto failed_1;
1125     }
1126   
1127   _dbus_string_free (&address);
1128   
1129   return transport;
1130
1131  failed_1:
1132   _dbus_close (fd, NULL);
1133  failed_0:
1134   _dbus_string_free (&address);
1135   return NULL;
1136 }
1137
1138 /**
1139  * Creates a new transport for the given hostname and port.
1140  *
1141  * @param host the host to connect to
1142  * @param port the port to connect to
1143  * @param error location to store reason for failure.
1144  * @returns a new transport, or #NULL on failure.
1145  */
1146 DBusTransport*
1147 _dbus_transport_new_for_tcp_socket (const char     *host,
1148                                     dbus_int32_t    port,
1149                                     DBusError      *error)
1150 {
1151   int fd;
1152   DBusTransport *transport;
1153   DBusString address;
1154   
1155   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
1156
1157   if (!_dbus_string_init (&address))
1158     {
1159       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
1160       return NULL;
1161     }
1162   
1163   if (!_dbus_string_append (&address, "tcp:host=") ||
1164       !_dbus_string_append (&address, host) ||
1165       !_dbus_string_append (&address, ",port=") ||
1166       !_dbus_string_append_int (&address, port))
1167     {
1168       _dbus_string_free (&address);
1169       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
1170       return NULL;
1171     }
1172   
1173   fd = _dbus_connect_tcp_socket (host, port, error);
1174   if (fd < 0)
1175     {
1176       _DBUS_ASSERT_ERROR_IS_SET (error);
1177       _dbus_string_free (&address);
1178       return NULL;
1179     }
1180
1181   _dbus_fd_set_close_on_exec (fd);
1182   
1183   _dbus_verbose ("Successfully connected to tcp socket %s:%d\n",
1184                  host, port);
1185   
1186   transport = _dbus_transport_new_for_fd (fd, FALSE, &address);
1187   if (transport == NULL)
1188     {
1189       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
1190       _dbus_close (fd, NULL);
1191       _dbus_string_free (&address);
1192       fd = -1;
1193     }
1194
1195   _dbus_string_free (&address);
1196   
1197   return transport;
1198 }
1199
1200 /** @} */
1201