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