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