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