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