Add support for compacting DBusStrings to release wasted memory.
[platform/upstream/dbus.git] / dbus / dbus-transport-socket.c
index 6499118..f6d0e9c 100644 (file)
@@ -1,4 +1,4 @@
-/* -*- mode: C; c-file-style: "gnu" -*- */
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
 /* dbus-transport-socket.c  Socket subclasses of DBusTransport
  *
  * Copyright (C) 2002, 2003, 2004, 2006  Red Hat Inc.
@@ -26,6 +26,7 @@
 #include "dbus-transport-socket.h"
 #include "dbus-transport-protected.h"
 #include "dbus-watch.h"
+#include "dbus-credentials.h"
 
 
 /**
@@ -266,17 +267,16 @@ read_data_into_auth (DBusTransport *transport,
     {
       /* EINTR already handled for us */
 
-      if (errno == ENOMEM)
+      if (_dbus_get_is_errno_enomem ())
         {
           *oom = TRUE;
         }
-      else if (errno == EAGAIN ||
-               errno == EWOULDBLOCK)
+      else if (_dbus_get_is_errno_eagain_or_ewouldblock ())
         ; /* do nothing, just return FALSE below */
       else
         {
           _dbus_verbose ("Error reading from remote app: %s\n",
-                         _dbus_strerror (errno));
+                         _dbus_strerror_from_errno ());
           do_io_error (transport);
         }
 
@@ -318,13 +318,12 @@ write_data_from_auth (DBusTransport *transport)
     {
       /* EINTR already handled for us */
       
-      if (errno == EAGAIN ||
-          errno == EWOULDBLOCK)
+      if (_dbus_get_is_errno_eagain_or_ewouldblock ())
         ;
       else
         {
           _dbus_verbose ("Error writing to remote app: %s\n",
-                         _dbus_strerror (errno));
+                         _dbus_strerror_from_errno ());
           do_io_error (transport);
         }
     }
@@ -332,38 +331,53 @@ write_data_from_auth (DBusTransport *transport)
   return FALSE;
 }
 
-static void
+/* FALSE on OOM */
+static dbus_bool_t
 exchange_credentials (DBusTransport *transport,
                       dbus_bool_t    do_reading,
                       dbus_bool_t    do_writing)
 {
   DBusTransportSocket *socket_transport = (DBusTransportSocket*) transport;
+  DBusError error;
+
+  _dbus_verbose ("exchange_credentials: do_reading = %d, do_writing = %d\n",
+                  do_reading, do_writing);
 
+  dbus_error_init (&error);
   if (do_writing && transport->send_credentials_pending)
     {
-      if (_dbus_send_credentials_unix_socket (socket_transport->fd,
-                                              NULL))
+      if (_dbus_send_credentials_socket (socket_transport->fd,
+                                         &error))
         {
           transport->send_credentials_pending = FALSE;
         }
       else
         {
-          _dbus_verbose ("Failed to write credentials\n");
+          _dbus_verbose ("Failed to write credentials: %s\n", error.message);
+          dbus_error_free (&error);
           do_io_error (transport);
         }
     }
   
   if (do_reading && transport->receive_credentials_pending)
     {
-      if (_dbus_read_credentials_unix_socket (socket_transport->fd,
-                                              &transport->credentials,
-                                              NULL))
+      /* FIXME this can fail due to IO error _or_ OOM, broken
+       * (somewhat tricky to fix since the OOM error can be set after
+       * we already read the credentials byte, so basically we need to
+       * separate reading the byte and storing it in the
+       * transport->credentials). Does not really matter for now
+       * because storing in credentials never actually fails on unix.
+       */      
+      if (_dbus_read_credentials_socket (socket_transport->fd,
+                                         transport->credentials,
+                                         &error))
         {
           transport->receive_credentials_pending = FALSE;
         }
       else
         {
-          _dbus_verbose ("Failed to read credentials\n");
+          _dbus_verbose ("Failed to read credentials %s\n", error.message);
+          dbus_error_free (&error);
           do_io_error (transport);
         }
     }
@@ -371,9 +385,12 @@ exchange_credentials (DBusTransport *transport,
   if (!(transport->send_credentials_pending ||
         transport->receive_credentials_pending))
     {
-      _dbus_auth_set_credentials (transport->auth,
-                                  &transport->credentials);
+      if (!_dbus_auth_set_credentials (transport->auth,
+                                       transport->credentials))
+        return FALSE;
     }
+
+  return TRUE;
 }
 
 static dbus_bool_t
@@ -405,7 +422,12 @@ do_authentication (DBusTransport *transport,
   while (!_dbus_transport_get_is_authenticated (transport) &&
          _dbus_transport_get_is_connected (transport))
     {      
-      exchange_credentials (transport, do_reading, do_writing);
+      if (!exchange_credentials (transport, do_reading, do_writing))
+        {
+          /* OOM */
+          oom = TRUE;
+          goto out;
+        }
       
       if (transport->send_credentials_pending ||
           transport->receive_credentials_pending)
@@ -595,13 +617,12 @@ do_writing (DBusTransport *transport)
         {
           /* EINTR already handled for us */
           
-          if (errno == EAGAIN ||
-              errno == EWOULDBLOCK)
+          if (_dbus_get_is_errno_eagain_or_ewouldblock ())
             goto out;
           else
             {
               _dbus_verbose ("Error writing to remote app: %s\n",
-                             _dbus_strerror (errno));
+                             _dbus_strerror_from_errno ());
               do_io_error (transport);
               goto out;
             }
@@ -621,6 +642,7 @@ do_writing (DBusTransport *transport)
             {
               socket_transport->message_bytes_written = 0;
               _dbus_string_set_length (&socket_transport->encoded_outgoing, 0);
+              _dbus_string_compact (&socket_transport->encoded_outgoing, 2048);
 
               _dbus_connection_message_sent (transport->connection,
                                              message);
@@ -712,6 +734,7 @@ do_reading (DBusTransport *transport)
                                               _dbus_string_get_length (buffer) - orig_len);
 
           _dbus_string_set_length (&socket_transport->encoded_incoming, 0);
+          _dbus_string_compact (&socket_transport->encoded_incoming, 2048);
         }
     }
   else
@@ -731,19 +754,18 @@ do_reading (DBusTransport *transport)
     {
       /* EINTR already handled for us */
 
-      if (errno == ENOMEM)
+      if (_dbus_get_is_errno_enomem ())
         {
           _dbus_verbose ("Out of memory in read()/do_reading()\n");
           oom = TRUE;
           goto out;
         }
-      else if (errno == EAGAIN ||
-               errno == EWOULDBLOCK)
+      else if (_dbus_get_is_errno_eagain_or_ewouldblock ())
         goto out;
       else
         {
           _dbus_verbose ("Error reading from remote app: %s\n",
-                         _dbus_strerror (errno));
+                         _dbus_strerror_from_errno ());
           do_io_error (transport);
           goto out;
         }
@@ -866,7 +888,7 @@ socket_handle_watch (DBusTransport *transport,
                        flags);
       else
         _dbus_verbose ("asked to handle watch %p on fd %d that we don't recognize\n",
-                       watch, dbus_watch_get_fd (watch));
+                       watch, dbus_watch_get_socket (watch));
     }
 #endif /* DBUS_ENABLE_VERBOSE_MODE */
 
@@ -1020,7 +1042,7 @@ socket_do_iteration (DBusTransport *transport,
     again:
       poll_res = _dbus_poll (&poll_fd, 1, poll_timeout);
 
-      if (poll_res < 0 && errno == EINTR)
+      if (poll_res < 0 && _dbus_get_is_errno_eintr ())
        goto again;
 
       if (flags & DBUS_ITERATION_BLOCK)
@@ -1063,7 +1085,7 @@ socket_do_iteration (DBusTransport *transport,
       else
         {
           _dbus_verbose ("Error from _dbus_poll(): %s\n",
-                         _dbus_strerror (errno));
+                         _dbus_strerror_from_errno ());
         }
     }
 
@@ -1154,7 +1176,7 @@ _dbus_transport_new_for_socket (int               fd,
                                                 NULL, NULL, NULL);
   if (socket_transport->read_watch == NULL)
     goto failed_3;
-  
+
   if (!_dbus_transport_init_base (&socket_transport->base,
                                   &socket_vtable,
                                   server_guid, address))
@@ -1184,15 +1206,18 @@ _dbus_transport_new_for_socket (int               fd,
 
 /**
  * Creates a new transport for the given hostname and port.
+ * If host is NULL, it will default to localhost
  *
  * @param host the host to connect to
  * @param port the port to connect to
+ * @param family the address family to connect to
  * @param error location to store reason for failure.
  * @returns a new transport, or #NULL on failure.
  */
 DBusTransport*
 _dbus_transport_new_for_tcp_socket (const char     *host,
-                                    dbus_int32_t    port,
+                                    const char     *port,
+                                    const char     *family,
                                     DBusError      *error)
 {
   int fd;
@@ -1206,20 +1231,27 @@ _dbus_transport_new_for_tcp_socket (const char     *host,
       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
       return NULL;
     }
-  
+
+  if (host == NULL)
+    host = "localhost";
+
   if (!_dbus_string_append (&address, "tcp:"))
     goto error;
 
-  if (host != NULL && 
-       (!_dbus_string_append (&address, "host=") ||
-        !_dbus_string_append (&address, host)))
+  if (!_dbus_string_append (&address, "host=") ||
+      !_dbus_string_append (&address, host))
     goto error;
 
   if (!_dbus_string_append (&address, ",port=") ||
-      !_dbus_string_append_int (&address, port))
+      !_dbus_string_append (&address, port))
     goto error;
 
-  fd = _dbus_connect_tcp_socket (host, port, error);
+  if (family != NULL &&
+      (!_dbus_string_append (&address, "family=") ||
+       !_dbus_string_append (&address, family)))
+    goto error;
+
+  fd = _dbus_connect_tcp_socket (host, port, family, error);
   if (fd < 0)
     {
       _DBUS_ASSERT_ERROR_IS_SET (error);
@@ -1229,7 +1261,7 @@ _dbus_transport_new_for_tcp_socket (const char     *host,
 
   _dbus_fd_set_close_on_exec (fd);
   
-  _dbus_verbose ("Successfully connected to tcp socket %s:%d\n",
+  _dbus_verbose ("Successfully connected to tcp socket %s:%s\n",
                  host, port);
   
   transport = _dbus_transport_new_for_socket (fd, NULL, &address);
@@ -1251,5 +1283,54 @@ error:
   return NULL;
 }
 
+/**
+ * Opens a TCP socket transport.
+ * 
+ * @param entry the address entry to try opening as a tcp transport.
+ * @param transport_p return location for the opened transport
+ * @param error error to be set
+ * @returns result of the attempt
+ */
+DBusTransportOpenResult
+_dbus_transport_open_socket(DBusAddressEntry  *entry,
+                            DBusTransport    **transport_p,                            
+                            DBusError         *error)
+{
+  const char *method;
+  
+  method = dbus_address_entry_get_method (entry);
+  _dbus_assert (method != NULL);
+
+  if (strcmp (method, "tcp") == 0)
+    {
+      const char *host = dbus_address_entry_get_value (entry, "host");
+      const char *port = dbus_address_entry_get_value (entry, "port");
+      const char *family = dbus_address_entry_get_value (entry, "family");
+
+      if (port == NULL)
+        {
+          _dbus_set_bad_address (error, "tcp", "port", NULL);
+          return DBUS_TRANSPORT_OPEN_BAD_ADDRESS;
+        }
+
+      *transport_p = _dbus_transport_new_for_tcp_socket (host, port, family, error);
+      if (*transport_p == NULL)
+        {
+          _DBUS_ASSERT_ERROR_IS_SET (error);
+          return DBUS_TRANSPORT_OPEN_DID_NOT_CONNECT;
+        }
+      else
+        {
+          _DBUS_ASSERT_ERROR_IS_CLEAR (error);
+          return DBUS_TRANSPORT_OPEN_OK;
+        }
+    }
+  else
+    {
+      _DBUS_ASSERT_ERROR_IS_CLEAR (error);
+      return DBUS_TRANSPORT_OPEN_NOT_HANDLED;
+    }
+}
+
 /** @} */