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