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