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