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