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