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