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