2004-07-24 Havoc Pennington <hp@redhat.com>
[platform/upstream/dbus.git] / dbus / dbus-transport.c
1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* dbus-transport.c DBusTransport object (internal to D-BUS implementation)
3  *
4  * Copyright (C) 2002, 2003  Red Hat Inc.
5  *
6  * Licensed under the Academic Free License version 2.0
7  * 
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  * 
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  *
22  */
23
24 #include "dbus-transport-protected.h"
25 #include "dbus-transport-unix.h"
26 #include "dbus-connection-internal.h"
27 #include "dbus-watch.h"
28 #include "dbus-auth.h"
29 #include "dbus-address.h"
30 #ifdef DBUS_BUILD_TESTS
31 #include "dbus-server-debug-pipe.h"
32 #endif
33
34 /**
35  * @defgroup DBusTransport DBusTransport object
36  * @ingroup  DBusInternals
37  * @brief "Backend" for a DBusConnection.
38  *
39  * Types and functions related to DBusTransport.  A transport is an
40  * abstraction that can send and receive data via various kinds of
41  * network connections or other IPC mechanisms.
42  * 
43  * @{
44  */
45
46 /**
47  * @typedef DBusTransport
48  *
49  * Opaque object representing a way message stream.
50  * DBusTransport abstracts various kinds of actual
51  * transport mechanism, such as different network protocols,
52  * or encryption schemes.
53  */
54
55 static void
56 live_messages_size_notify (DBusCounter *counter,
57                            void        *user_data)
58 {
59   DBusTransport *transport = user_data;
60
61   _dbus_transport_ref (transport);
62
63 #if 0
64   _dbus_verbose ("Counter value is now %d\n",
65                  (int) _dbus_counter_get_value (counter));
66 #endif
67   
68   /* disable or re-enable the read watch for the transport if
69    * required.
70    */
71   if (* transport->vtable->live_messages_changed)
72     (* transport->vtable->live_messages_changed) (transport);
73
74   _dbus_transport_unref (transport);
75 }
76
77 /**
78  * Initializes the base class members of DBusTransport.
79  * Chained up to by subclasses in their constructor.
80  *
81  * @param transport the transport being created.
82  * @param vtable the subclass vtable.
83  * @param server #TRUE if this transport is on the server side of a connection
84  * @param address the address of the transport
85  * @returns #TRUE on success.
86  */
87 dbus_bool_t
88 _dbus_transport_init_base (DBusTransport             *transport,
89                            const DBusTransportVTable *vtable,
90                            dbus_bool_t                server,
91                            const DBusString          *address)
92 {
93   DBusMessageLoader *loader;
94   DBusAuth *auth;
95   DBusCounter *counter;
96   char *address_copy;
97   
98   loader = _dbus_message_loader_new ();
99   if (loader == NULL)
100     return FALSE;
101   
102   if (server)
103     auth = _dbus_auth_server_new ();
104   else
105     auth = _dbus_auth_client_new ();
106   if (auth == NULL)
107     {
108       _dbus_message_loader_unref (loader);
109       return FALSE;
110     }
111
112   counter = _dbus_counter_new ();
113   if (counter == NULL)
114     {
115       _dbus_auth_unref (auth);
116       _dbus_message_loader_unref (loader);
117       return FALSE;
118     }  
119   
120   if (server)
121     {
122       _dbus_assert (address == NULL);
123       address_copy = NULL;
124     }
125   else
126     {
127       _dbus_assert (address != NULL);
128
129       if (!_dbus_string_copy_data (address, &address_copy))
130         {
131           _dbus_counter_unref (counter);
132           _dbus_auth_unref (auth);
133           _dbus_message_loader_unref (loader);
134           return FALSE;
135         }
136     }
137   
138   transport->refcount = 1;
139   transport->vtable = vtable;
140   transport->loader = loader;
141   transport->auth = auth;
142   transport->live_messages_size = counter;
143   transport->authenticated = FALSE;
144   transport->messages_need_sending = FALSE;
145   transport->disconnected = FALSE;
146   transport->send_credentials_pending = !server;
147   transport->receive_credentials_pending = server;
148   transport->is_server = server;
149   transport->address = address_copy;
150   
151   transport->unix_user_function = NULL;
152   transport->unix_user_data = NULL;
153   transport->free_unix_user_data = NULL;
154   
155   /* Try to default to something that won't totally hose the system,
156    * but doesn't impose too much of a limitation.
157    */
158   transport->max_live_messages_size = _DBUS_ONE_MEGABYTE * 63;
159   
160   transport->credentials.pid = -1;
161   transport->credentials.uid = -1;
162   transport->credentials.gid = -1;
163
164   _dbus_counter_set_notify (transport->live_messages_size,
165                             transport->max_live_messages_size,
166                             live_messages_size_notify,
167                             transport);
168
169   if (transport->address)
170     _dbus_verbose ("Initialized transport on address %s\n", transport->address);
171   
172   return TRUE;
173 }
174
175 /**
176  * Finalizes base class members of DBusTransport.
177  * Chained up to from subclass finalizers.
178  *
179  * @param transport the transport.
180  */
181 void
182 _dbus_transport_finalize_base (DBusTransport *transport)
183 {
184   if (!transport->disconnected)
185     _dbus_transport_disconnect (transport);
186
187   if (transport->free_unix_user_data != NULL)
188     (* transport->free_unix_user_data) (transport->unix_user_data);
189   
190   _dbus_message_loader_unref (transport->loader);
191   _dbus_auth_unref (transport->auth);
192   _dbus_counter_set_notify (transport->live_messages_size,
193                             0, NULL, NULL);
194   _dbus_counter_unref (transport->live_messages_size);
195   dbus_free (transport->address);
196 }
197
198 /**
199  * Opens a new transport for the given address.  (This opens a
200  * client-side-of-the-connection transport.)
201  *
202  * @todo error messages on bad address could really be better.
203  * DBusResultCode is a bit limiting here.
204  * 
205  * @param address the address.
206  * @param error location to store reason for failure.
207  * @returns new transport of #NULL on failure.
208  */
209 DBusTransport*
210 _dbus_transport_open (const char     *address,
211                       DBusError      *error)
212 {
213   DBusTransport *transport;
214   DBusAddressEntry **entries;
215   DBusError tmp_error;
216   DBusError first_error;
217   int len, i;
218   const char *address_problem_type;
219   const char *address_problem_field;
220   const char *address_problem_other;
221
222   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
223   
224   if (!dbus_parse_address (address, &entries, &len, error))
225     return NULL;
226
227   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
228   
229   transport = NULL;
230   address_problem_type = NULL;
231   address_problem_field = NULL;
232   address_problem_other = NULL;
233
234   dbus_error_init (&tmp_error);
235   dbus_error_init (&first_error);
236   for (i = 0; i < len; i++)
237     {
238       const char *method;
239
240       method = dbus_address_entry_get_method (entries[i]);
241       
242       if (strcmp (method, "unix") == 0)
243         {
244           const char *path = dbus_address_entry_get_value (entries[i], "path");
245           const char *tmpdir = dbus_address_entry_get_value (entries[i], "tmpdir");
246           const char *abstract = dbus_address_entry_get_value (entries[i], "abstract");
247           
248           if (tmpdir != NULL)
249             {
250               address_problem_other = "cannot use the \"tmpdir\" option for an address to connect to, only in an address to listen on";
251               goto bad_address;
252             }
253           
254           if (path == NULL && abstract == NULL)
255             {
256               address_problem_type = "unix";
257               address_problem_field = "path or abstract";  
258               goto bad_address;
259             }
260
261           if (path != NULL && abstract != NULL)
262             {
263               address_problem_other = "can't specify both \"path\" and \"abstract\" options in an address";
264               goto bad_address;
265             }
266
267           if (path)
268             transport = _dbus_transport_new_for_domain_socket (path, FALSE,
269                                                                &tmp_error);
270           else
271             transport = _dbus_transport_new_for_domain_socket (abstract, TRUE,
272                                                                &tmp_error);
273         }
274       else if (strcmp (method, "tcp") == 0)
275         {
276           const char *host = dbus_address_entry_get_value (entries[i], "host");
277           const char *port = dbus_address_entry_get_value (entries[i], "port");
278           DBusString  str;
279           long lport;
280           dbus_bool_t sresult;
281           
282           if (port == NULL)
283             {
284               address_problem_type = "tcp";
285               address_problem_field = "port";
286               goto bad_address;
287             }
288
289           _dbus_string_init_const (&str, port);
290           sresult = _dbus_string_parse_int (&str, 0, &lport, NULL);
291           _dbus_string_free (&str);
292           
293           if (sresult == FALSE || lport <= 0 || lport > 65535)
294             {
295               address_problem_other = "Port is not an integer between 0 and 65535";
296               goto bad_address;
297             }
298           
299           transport = _dbus_transport_new_for_tcp_socket (host, lport, &tmp_error);
300         }
301 #ifdef DBUS_BUILD_TESTS
302       else if (strcmp (method, "debug-pipe") == 0)
303         {
304           const char *name = dbus_address_entry_get_value (entries[i], "name");
305
306           if (name == NULL)
307             {
308               address_problem_type = "debug-pipe";
309               address_problem_field = "name";
310               goto bad_address;
311             }
312           
313           transport = _dbus_transport_debug_pipe_new (name, &tmp_error);
314         }
315 #endif
316       else
317         {
318           address_problem_other = "Unknown address type (examples of valid types are \"unix\" and \"tcp\")";
319           goto bad_address;
320         }
321
322       if (transport)
323         break;
324
325       _DBUS_ASSERT_ERROR_IS_SET (&tmp_error);
326       
327       if (i == 0)
328         dbus_move_error (&tmp_error, &first_error);
329       else
330         dbus_error_free (&tmp_error);
331     }
332
333   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
334   _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error);
335   
336   if (transport == NULL)
337     {
338       _DBUS_ASSERT_ERROR_IS_SET (&first_error);
339       dbus_move_error (&first_error, error);
340     }
341   else
342     {
343       dbus_error_free (&first_error);
344     }
345   
346   dbus_address_entries_free (entries);
347   return transport;
348
349  bad_address:
350   dbus_address_entries_free (entries);
351
352   if (address_problem_type != NULL)
353     dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS,
354                     "Address of type %s was missing argument %s",
355                     address_problem_type, address_problem_field);
356   else
357     dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS,
358                     "Could not parse address: %s",
359                     address_problem_other);
360
361   return NULL;
362 }
363
364 /**
365  * Increments the reference count for the transport.
366  *
367  * @param transport the transport.
368  * @returns the transport.
369  */
370 DBusTransport *
371 _dbus_transport_ref (DBusTransport *transport)
372 {
373   _dbus_assert (transport->refcount > 0);
374   
375   transport->refcount += 1;
376
377   return transport;
378 }
379
380 /**
381  * Decrements the reference count for the transport.
382  * Disconnects and finalizes the transport if
383  * the reference count reaches zero.
384  *
385  * @param transport the transport.
386  */
387 void
388 _dbus_transport_unref (DBusTransport *transport)
389 {
390   _dbus_assert (transport != NULL);
391   _dbus_assert (transport->refcount > 0);
392
393   transport->refcount -= 1;
394   if (transport->refcount == 0)
395     {
396       _dbus_assert (transport->vtable->finalize != NULL);
397       
398       (* transport->vtable->finalize) (transport);
399     }
400 }
401
402 /**
403  * Closes our end of the connection to a remote application. Further
404  * attempts to use this transport will fail. Only the first call to
405  * _dbus_transport_disconnect() will have an effect.
406  *
407  * @param transport the transport.
408  * 
409  */
410 void
411 _dbus_transport_disconnect (DBusTransport *transport)
412 {
413   _dbus_assert (transport->vtable->disconnect != NULL);
414
415   if (transport->disconnected)
416     return;
417
418   (* transport->vtable->disconnect) (transport);
419   
420   transport->disconnected = TRUE;
421 }
422
423 /**
424  * Returns #TRUE if the transport has not been disconnected.
425  * Disconnection can result from _dbus_transport_disconnect()
426  * or because the server drops its end of the connection.
427  *
428  * @param transport the transport.
429  * @returns whether we're connected
430  */
431 dbus_bool_t
432 _dbus_transport_get_is_connected (DBusTransport *transport)
433 {
434   return !transport->disconnected;
435 }
436
437 /**
438  * Returns #TRUE if we have been authenticated.  Will return #TRUE
439  * even if the transport is disconnected.
440  *
441  * @todo needs to drop connection->mutex when calling the unix_user_function
442  *
443  * @param transport the transport
444  * @returns whether we're authenticated
445  */
446 dbus_bool_t
447 _dbus_transport_get_is_authenticated (DBusTransport *transport)
448 {  
449   if (transport->authenticated)
450     return TRUE;
451   else
452     {
453       dbus_bool_t maybe_authenticated;
454       
455       if (transport->disconnected)
456         return FALSE;
457       
458       maybe_authenticated =
459         (!(transport->send_credentials_pending ||
460            transport->receive_credentials_pending));
461
462       if (maybe_authenticated)
463         {
464           switch (_dbus_auth_do_work (transport->auth))
465             {
466             case DBUS_AUTH_STATE_AUTHENTICATED:
467               /* leave as maybe_authenticated */
468               break;
469             default:
470               maybe_authenticated = FALSE;
471             }
472         }
473       
474       /* If we've authenticated as some identity, check that the auth
475        * identity is the same as our own identity.  In the future, we
476        * may have API allowing applications to specify how this is
477        * done, for example they may allow connection as any identity,
478        * but then impose restrictions on certain identities.
479        * Or they may give certain identities extra privileges.
480        */
481       
482       if (maybe_authenticated && transport->is_server)
483         {
484           DBusCredentials auth_identity;
485
486           _dbus_auth_get_identity (transport->auth, &auth_identity);
487
488           if (transport->unix_user_function != NULL)
489             {
490               /* FIXME we hold the connection lock here and should drop it */
491               if (!(* transport->unix_user_function) (transport->connection,
492                                                       auth_identity.uid,
493                                                       transport->unix_user_data))
494                 {
495                   _dbus_verbose ("Client UID "DBUS_UID_FORMAT
496                                  " was rejected, disconnecting\n",
497                                  auth_identity.uid);
498                   _dbus_transport_disconnect (transport);
499                   return FALSE;
500                 }
501               else
502                 {
503                   _dbus_verbose ("Client UID "DBUS_UID_FORMAT" authorized\n", auth_identity.uid);
504                 }
505             }
506           else
507             {
508               DBusCredentials our_identity;
509               
510               _dbus_credentials_from_current_process (&our_identity);
511               
512               if (!_dbus_credentials_match (&our_identity,
513                                             &auth_identity))
514                 {
515                   _dbus_verbose ("Client authorized as UID "DBUS_UID_FORMAT
516                                  " but our UID is "DBUS_UID_FORMAT", disconnecting\n",
517                                  auth_identity.uid, our_identity.uid);
518                   _dbus_transport_disconnect (transport);
519                   return FALSE;
520                 }
521               else
522                 {
523                   _dbus_verbose ("Client authorized as UID "DBUS_UID_FORMAT
524                                  " matching our UID "DBUS_UID_FORMAT"\n",
525                                  auth_identity.uid, our_identity.uid);
526                 }
527             }
528         }
529
530       transport->authenticated = maybe_authenticated;
531       
532       return transport->authenticated;
533     }
534 }
535
536 /**
537  * Gets the address of a transport. It will be
538  * #NULL for a server-side transport.
539  *
540  * @param transport the transport
541  * @returns transport's address
542  */
543 const char*
544 _dbus_transport_get_address (DBusTransport *transport)
545 {
546   return transport->address;
547 }
548
549 /**
550  * Handles a watch by reading data, writing data, or disconnecting
551  * the transport, as appropriate for the given condition.
552  *
553  * @param transport the transport.
554  * @param watch the watch.
555  * @param condition the current state of the watched file descriptor.
556  * @returns #FALSE if not enough memory to fully handle the watch
557  */
558 dbus_bool_t
559 _dbus_transport_handle_watch (DBusTransport           *transport,
560                               DBusWatch               *watch,
561                               unsigned int             condition)
562 {
563   dbus_bool_t retval;
564   
565   _dbus_assert (transport->vtable->handle_watch != NULL);
566
567   if (transport->disconnected)
568     return TRUE;
569
570   if (dbus_watch_get_fd (watch) < 0)
571     {
572       _dbus_warn ("Tried to handle an invalidated watch; this watch should have been removed\n");
573       return TRUE;
574     }
575   
576   _dbus_watch_sanitize_condition (watch, &condition);
577
578   _dbus_transport_ref (transport);
579   _dbus_watch_ref (watch);
580   retval = (* transport->vtable->handle_watch) (transport, watch, condition);
581   _dbus_watch_unref (watch);
582   _dbus_transport_unref (transport);
583
584   return retval;
585 }
586
587 /**
588  * Sets the connection using this transport. Allows the transport
589  * to add watches to the connection, queue incoming messages,
590  * and pull outgoing messages.
591  *
592  * @param transport the transport.
593  * @param connection the connection.
594  * @returns #FALSE if not enough memory
595  */
596 dbus_bool_t
597 _dbus_transport_set_connection (DBusTransport  *transport,
598                                 DBusConnection *connection)
599 {
600   _dbus_assert (transport->vtable->connection_set != NULL);
601   _dbus_assert (transport->connection == NULL);
602   
603   transport->connection = connection;
604
605   _dbus_transport_ref (transport);
606   if (!(* transport->vtable->connection_set) (transport))
607     transport->connection = NULL;
608   _dbus_transport_unref (transport);
609
610   return transport->connection != NULL;
611 }
612
613 /**
614  * Notifies the transport when the outgoing message queue goes from
615  * empty to non-empty or vice versa. Typically causes the transport to
616  * add or remove its DBUS_WATCH_WRITABLE watch.
617  *
618  * @param transport the transport.
619  * @param queue_length the length of the outgoing message queue.
620  *
621  */
622 void
623 _dbus_transport_messages_pending (DBusTransport  *transport,
624                                   int             queue_length)
625 {
626   _dbus_assert (transport->vtable->messages_pending != NULL);
627
628   if (transport->disconnected)
629     return;
630
631   transport->messages_need_sending = queue_length > 0;
632
633   _dbus_transport_ref (transport);
634   (* transport->vtable->messages_pending) (transport,
635                                            queue_length);
636   _dbus_transport_unref (transport);
637 }
638
639 /**
640  * Get the UNIX file descriptor, if any.
641  *
642  * @param transport the transport
643  * @param fd_p pointer to fill in with the descriptor
644  * @returns #TRUE if a descriptor was available
645  */
646 dbus_bool_t
647 _dbus_transport_get_unix_fd (DBusTransport *transport,
648                              int           *fd_p)
649 {
650   dbus_bool_t retval;
651   
652   if (transport->vtable->get_unix_fd == NULL)
653     return FALSE;
654
655   if (transport->disconnected)
656     return FALSE;
657
658   _dbus_transport_ref (transport);
659
660   retval = (* transport->vtable->get_unix_fd) (transport,
661                                                fd_p);
662   
663   _dbus_transport_unref (transport);
664
665   return retval;
666 }
667
668 /**
669  * Performs a single poll()/select() on the transport's file
670  * descriptors and then reads/writes data as appropriate,
671  * queueing incoming messages and sending outgoing messages.
672  * This is the backend for _dbus_connection_do_iteration().
673  * See _dbus_connection_do_iteration() for full details.
674  *
675  * @param transport the transport.
676  * @param flags indicates whether to read or write, and whether to block.
677  * @param timeout_milliseconds if blocking, timeout or -1 for no timeout.
678  */
679 void
680 _dbus_transport_do_iteration (DBusTransport  *transport,
681                               unsigned int    flags,
682                               int             timeout_milliseconds)
683 {
684   _dbus_assert (transport->vtable->do_iteration != NULL);
685
686   _dbus_verbose ("Transport iteration flags 0x%x timeout %d connected = %d\n",
687                  flags, timeout_milliseconds, !transport->disconnected);
688   
689   if ((flags & (DBUS_ITERATION_DO_WRITING |
690                 DBUS_ITERATION_DO_READING)) == 0)
691     return; /* Nothing to do */
692
693   if (transport->disconnected)
694     return;
695
696   _dbus_transport_ref (transport);
697   (* transport->vtable->do_iteration) (transport, flags,
698                                        timeout_milliseconds);
699   _dbus_transport_unref (transport);
700 }
701
702 static dbus_bool_t
703 recover_unused_bytes (DBusTransport *transport)
704 {
705   if (_dbus_auth_needs_decoding (transport->auth))
706     {
707       DBusString plaintext;
708       const DBusString *encoded;
709       DBusString *buffer;
710       int orig_len;
711       
712       if (!_dbus_string_init (&plaintext))
713         goto nomem;
714       
715       _dbus_auth_get_unused_bytes (transport->auth,
716                                    &encoded);
717
718       if (!_dbus_auth_decode_data (transport->auth,
719                                    encoded, &plaintext))
720         {
721           _dbus_string_free (&plaintext);
722           goto nomem;
723         }
724       
725       _dbus_message_loader_get_buffer (transport->loader,
726                                        &buffer);
727       
728       orig_len = _dbus_string_get_length (buffer);
729       
730       if (!_dbus_string_move (&plaintext, 0, buffer,
731                               orig_len))
732         {
733           _dbus_string_free (&plaintext);
734           goto nomem;
735         }
736       
737       _dbus_verbose (" %d unused bytes sent to message loader\n", 
738                      _dbus_string_get_length (buffer) -
739                      orig_len);
740       
741       _dbus_message_loader_return_buffer (transport->loader,
742                                           buffer,
743                                           _dbus_string_get_length (buffer) -
744                                           orig_len);
745
746       _dbus_auth_delete_unused_bytes (transport->auth);
747       
748       _dbus_string_free (&plaintext);
749     }
750   else
751     {
752       const DBusString *bytes;
753       DBusString *buffer;
754       int orig_len;
755       dbus_bool_t succeeded;
756
757       _dbus_message_loader_get_buffer (transport->loader,
758                                        &buffer);
759                 
760       orig_len = _dbus_string_get_length (buffer);
761                 
762       _dbus_auth_get_unused_bytes (transport->auth,
763                                    &bytes);
764
765       succeeded = TRUE;
766       if (!_dbus_string_copy (bytes, 0, buffer, _dbus_string_get_length (buffer)))
767         succeeded = FALSE;
768       
769       _dbus_verbose (" %d unused bytes sent to message loader\n", 
770                      _dbus_string_get_length (buffer) -
771                      orig_len);
772       
773       _dbus_message_loader_return_buffer (transport->loader,
774                                           buffer,
775                                           _dbus_string_get_length (buffer) -
776                                           orig_len);
777
778       if (succeeded)
779         _dbus_auth_delete_unused_bytes (transport->auth);
780       else
781         goto nomem;
782     }
783
784   return TRUE;
785
786  nomem:
787   _dbus_verbose ("Not enough memory to transfer unused bytes from auth conversation\n");
788   return FALSE;
789 }
790
791 /**
792  * Reports our current dispatch status (whether there's buffered
793  * data to be queued as messages, or not, or we need memory).
794  *
795  * @param transport the transport
796  * @returns current status
797  */
798 DBusDispatchStatus
799 _dbus_transport_get_dispatch_status (DBusTransport *transport)
800 {
801   if (_dbus_counter_get_value (transport->live_messages_size) >= transport->max_live_messages_size)
802     return DBUS_DISPATCH_COMPLETE; /* complete for now */
803
804   if (!_dbus_transport_get_is_authenticated (transport))
805     {
806       if (_dbus_auth_do_work (transport->auth) ==
807           DBUS_AUTH_STATE_WAITING_FOR_MEMORY)
808         return DBUS_DISPATCH_NEED_MEMORY;
809       else if (!_dbus_transport_get_is_authenticated (transport))
810         return DBUS_DISPATCH_COMPLETE;
811     }
812
813   if (!transport->unused_bytes_recovered &&
814       !recover_unused_bytes (transport))
815     return DBUS_DISPATCH_NEED_MEMORY;
816
817   transport->unused_bytes_recovered = TRUE;
818   
819   if (!_dbus_message_loader_queue_messages (transport->loader))
820     return DBUS_DISPATCH_NEED_MEMORY;
821
822   if (_dbus_message_loader_peek_message (transport->loader) != NULL)
823     return DBUS_DISPATCH_DATA_REMAINS;
824   else
825     return DBUS_DISPATCH_COMPLETE;
826 }
827
828 /**
829  * Processes data we've read while handling a watch, potentially
830  * converting some of it to messages and queueing those messages on
831  * the connection.
832  *
833  * @param transport the transport
834  * @returns #TRUE if we had enough memory to queue all messages
835  */
836 dbus_bool_t
837 _dbus_transport_queue_messages (DBusTransport *transport)
838 {
839   DBusDispatchStatus status;
840
841 #if 0
842   _dbus_verbose ("_dbus_transport_queue_messages()\n");
843 #endif
844   
845   /* Queue any messages */
846   while ((status = _dbus_transport_get_dispatch_status (transport)) == DBUS_DISPATCH_DATA_REMAINS)
847     {
848       DBusMessage *message;
849       DBusList *link;
850
851       link = _dbus_message_loader_pop_message_link (transport->loader);
852       _dbus_assert (link != NULL);
853       
854       message = link->data;
855       
856       _dbus_verbose ("queueing received message %p\n", message);
857
858       if (!_dbus_message_add_size_counter (message, transport->live_messages_size))
859         {
860           _dbus_message_loader_putback_message_link (transport->loader,
861                                                      link);
862           status = DBUS_DISPATCH_NEED_MEMORY;
863           break;
864         }
865       else
866         {
867           /* pass ownership of link and message ref to connection */
868           _dbus_connection_queue_received_message_link (transport->connection,
869                                                         link);
870         }
871     }
872
873   if (_dbus_message_loader_get_is_corrupted (transport->loader))
874     {
875       _dbus_verbose ("Corrupted message stream, disconnecting\n");
876       _dbus_transport_disconnect (transport);
877     }
878
879   return status != DBUS_DISPATCH_NEED_MEMORY;
880 }
881
882 /**
883  * See dbus_connection_set_max_message_size().
884  *
885  * @param transport the transport
886  * @param size the max size of a single message
887  */
888 void
889 _dbus_transport_set_max_message_size (DBusTransport  *transport,
890                                       long            size)
891 {
892   _dbus_message_loader_set_max_message_size (transport->loader, size);
893 }
894
895 /**
896  * See dbus_connection_get_max_message_size().
897  *
898  * @param transport the transport
899  * @returns max message size
900  */
901 long
902 _dbus_transport_get_max_message_size (DBusTransport  *transport)
903 {
904   return _dbus_message_loader_get_max_message_size (transport->loader);
905 }
906
907 /**
908  * See dbus_connection_set_max_received_size().
909  *
910  * @param transport the transport
911  * @param size the max size of all incoming messages
912  */
913 void
914 _dbus_transport_set_max_received_size (DBusTransport  *transport,
915                                        long            size)
916 {
917   transport->max_live_messages_size = size;
918   _dbus_counter_set_notify (transport->live_messages_size,
919                             transport->max_live_messages_size,
920                             live_messages_size_notify,
921                             transport);
922 }
923
924
925 /**
926  * See dbus_connection_get_max_received_size().
927  *
928  * @param transport the transport
929  * @returns max bytes for all live messages
930  */
931 long
932 _dbus_transport_get_max_received_size (DBusTransport  *transport)
933 {
934   return transport->max_live_messages_size;
935 }
936
937 /**
938  * See dbus_connection_get_unix_user().
939  *
940  * @param transport the transport
941  * @param uid return location for the user ID
942  * @returns #TRUE if uid is filled in with a valid user ID
943  */
944 dbus_bool_t
945 _dbus_transport_get_unix_user (DBusTransport *transport,
946                                unsigned long *uid)
947 {
948   DBusCredentials auth_identity;
949
950   *uid = _DBUS_INT_MAX; /* better than some root or system user in
951                          * case of bugs in the caller. Caller should
952                          * never use this value on purpose, however.
953                          */
954   
955   if (!transport->authenticated)
956     return FALSE;
957   
958   _dbus_auth_get_identity (transport->auth, &auth_identity);
959
960   if (auth_identity.uid != DBUS_UID_UNSET)
961     {
962       *uid = auth_identity.uid;
963       return TRUE;
964     }
965   else
966     return FALSE;
967 }
968
969 /**
970  * See dbus_connection_get_unix_process_id().
971  *
972  * @param transport the transport
973  * @param pid return location for the process ID
974  * @returns #TRUE if uid is filled in with a valid process ID
975  */
976 dbus_bool_t
977 _dbus_transport_get_unix_process_id (DBusTransport *transport,
978                                      unsigned long *pid)
979 {
980   DBusCredentials auth_identity;
981
982   *pid = DBUS_PID_UNSET; /* Caller should never use this value on purpose,
983                           * but we set it to a safe number, INT_MAX,
984                           * just to root out possible bugs in bad callers.
985                           */
986   
987   if (!transport->authenticated)
988     return FALSE;
989   
990   _dbus_auth_get_identity (transport->auth, &auth_identity);
991
992   if (auth_identity.pid != DBUS_PID_UNSET)
993     {
994       *pid = auth_identity.pid;
995       return TRUE;
996     }
997   else
998     return FALSE;
999 }
1000
1001 /**
1002  * See dbus_connection_set_unix_user_function().
1003  *
1004  * @param transport the transport
1005  * @param function the predicate
1006  * @param data data to pass to the predicate
1007  * @param free_data_function function to free the data
1008  * @param old_data the old user data to be freed
1009  * @param old_free_data_function old free data function to free it with
1010  */
1011 void
1012 _dbus_transport_set_unix_user_function (DBusTransport             *transport,
1013                                         DBusAllowUnixUserFunction  function,
1014                                         void                      *data,
1015                                         DBusFreeFunction           free_data_function,
1016                                         void                     **old_data,
1017                                         DBusFreeFunction          *old_free_data_function)
1018 {  
1019   *old_data = transport->unix_user_data;
1020   *old_free_data_function = transport->free_unix_user_data;
1021
1022   transport->unix_user_function = function;
1023   transport->unix_user_data = data;
1024   transport->free_unix_user_data = free_data_function;
1025 }
1026
1027 /**
1028  * Sets the SASL authentication mechanisms supported by this transport.
1029  *
1030  * @param transport the transport
1031  * @param mechanisms the #NULL-terminated array of mechanisms
1032  *
1033  * @returns #FALSE if no memory
1034  */
1035 dbus_bool_t
1036 _dbus_transport_set_auth_mechanisms (DBusTransport  *transport,
1037                                      const char    **mechanisms)
1038 {
1039   return _dbus_auth_set_mechanisms (transport->auth, mechanisms);
1040 }
1041
1042
1043 /** @} */