Merge "Optional autogen.sh flag --enable-kdbus-transport added allowing to compile...
[platform/upstream/dbus.git] / dbus / dbus-transport-socket.c
index c9d4d93..bd19f9b 100644 (file)
  * 
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  *
  */
 
+#include <config.h>
 #include "dbus-internals.h"
 #include "dbus-connection-internal.h"
+#include "dbus-nonce.h"
 #include "dbus-transport-socket.h"
 #include "dbus-transport-protected.h"
 #include "dbus-watch.h"
@@ -71,7 +73,7 @@ free_watches (DBusTransport *transport)
 {
   DBusTransportSocket *socket_transport = (DBusTransportSocket*) transport;
 
-  _dbus_verbose ("%s start\n", _DBUS_FUNCTION_NAME);
+  _dbus_verbose ("start\n");
   
   if (socket_transport->read_watch)
     {
@@ -93,7 +95,7 @@ free_watches (DBusTransport *transport)
       socket_transport->write_watch = NULL;
     }
 
-  _dbus_verbose ("%s end\n", _DBUS_FUNCTION_NAME);
+  _dbus_verbose ("end\n");
 }
 
 static void
@@ -101,7 +103,7 @@ socket_finalize (DBusTransport *transport)
 {
   DBusTransportSocket *socket_transport = (DBusTransportSocket*) transport;
 
-  _dbus_verbose ("%s\n", _DBUS_FUNCTION_NAME);
+  _dbus_verbose ("\n");
   
   free_watches (transport);
 
@@ -133,7 +135,7 @@ check_write_watch (DBusTransport *transport)
   
   _dbus_transport_ref (transport);
 
-  if (_dbus_transport_get_is_authenticated (transport))
+  if (_dbus_transport_try_to_authenticate (transport))
     needed = _dbus_connection_has_messages_to_send_unlocked (transport->connection);
   else
     {
@@ -175,8 +177,7 @@ check_read_watch (DBusTransport *transport)
   DBusTransportSocket *socket_transport = (DBusTransportSocket*) transport;
   dbus_bool_t need_read_watch;
 
-  _dbus_verbose ("%s: fd = %d\n",
-                 _DBUS_FUNCTION_NAME, socket_transport->fd);
+  _dbus_verbose ("fd = %d\n",socket_transport->fd);
   
   if (transport->connection == NULL)
     return;
@@ -189,9 +190,10 @@ check_read_watch (DBusTransport *transport)
   
   _dbus_transport_ref (transport);
 
-  if (_dbus_transport_get_is_authenticated (transport))
+  if (_dbus_transport_try_to_authenticate (transport))
     need_read_watch =
-      _dbus_counter_get_value (transport->live_messages_size) < transport->max_live_messages_size;
+      (_dbus_counter_get_size_value (transport->live_messages) < transport->max_live_messages_size) &&
+      (_dbus_counter_get_unix_fd_value (transport->live_messages) < transport->max_live_messages_unix_fds);
   else
     {
       if (transport->receive_credentials_pending)
@@ -402,7 +404,7 @@ do_authentication (DBusTransport *transport,
 
   oom = FALSE;
   
-  orig_auth_state = _dbus_transport_get_is_authenticated (transport);
+  orig_auth_state = _dbus_transport_try_to_authenticate (transport);
 
   /* This is essential to avoid the check_write_watch() at the end,
    * we don't want to add a write watch in do_iteration before
@@ -417,7 +419,7 @@ do_authentication (DBusTransport *transport,
   
   _dbus_transport_ref (transport);
   
-  while (!_dbus_transport_get_is_authenticated (transport) &&
+  while (!_dbus_transport_try_to_authenticate (transport) &&
          _dbus_transport_get_is_connected (transport))
     {      
       if (!exchange_credentials (transport, do_reading, do_writing))
@@ -475,7 +477,7 @@ do_authentication (DBusTransport *transport,
 
  out:
   if (auth_completed)
-    *auth_completed = (orig_auth_state != _dbus_transport_get_is_authenticated (transport));
+    *auth_completed = (orig_auth_state != _dbus_transport_try_to_authenticate (transport));
   
   check_read_watch (transport);
   check_write_watch (transport);
@@ -496,7 +498,7 @@ do_writing (DBusTransport *transport)
   dbus_bool_t oom;
   
   /* No messages without authentication! */
-  if (!_dbus_transport_get_is_authenticated (transport))
+  if (!_dbus_transport_try_to_authenticate (transport))
     {
       _dbus_verbose ("Not authenticated, not writing anything\n");
       return TRUE;
@@ -594,7 +596,7 @@ do_writing (DBusTransport *transport)
 #endif
 
 #ifdef HAVE_UNIX_FD_PASSING
-          if (socket_transport->message_bytes_written <= 0 && transport->can_pass_unix_fd)
+          if (socket_transport->message_bytes_written <= 0 && DBUS_TRANSPORT_CAN_SEND_UNIX_FD(transport))
             {
               /* Send the fds along with the first byte of the message */
               const int *unix_fds;
@@ -644,7 +646,11 @@ do_writing (DBusTransport *transport)
         {
           /* EINTR already handled for us */
           
-          if (_dbus_get_is_errno_eagain_or_ewouldblock ())
+          /* For some discussion of why we also ignore EPIPE here, see
+           * http://lists.freedesktop.org/archives/dbus/2008-March/009526.html
+           */
+          
+          if (_dbus_get_is_errno_eagain_or_ewouldblock () || _dbus_get_is_errno_epipe ())
             goto out;
           else
             {
@@ -671,8 +677,8 @@ do_writing (DBusTransport *transport)
               _dbus_string_set_length (&socket_transport->encoded_outgoing, 0);
               _dbus_string_compact (&socket_transport->encoded_outgoing, 2048);
 
-              _dbus_connection_message_sent (transport->connection,
-                                             message);
+              _dbus_connection_message_sent_unlocked (transport->connection,
+                                                      message);
             }
         }
     }
@@ -694,11 +700,10 @@ do_reading (DBusTransport *transport)
   int total;
   dbus_bool_t oom;
 
-  _dbus_verbose ("%s: fd = %d\n", _DBUS_FUNCTION_NAME,
-                 socket_transport->fd);
+  _dbus_verbose ("fd = %d\n",socket_transport->fd);
   
   /* No messages without authentication! */
-  if (!_dbus_transport_get_is_authenticated (transport))
+  if (!_dbus_transport_try_to_authenticate (transport))
     return TRUE;
 
   oom = FALSE;
@@ -777,7 +782,7 @@ do_reading (DBusTransport *transport)
                                        &buffer);
 
 #ifdef HAVE_UNIX_FD_PASSING
-      if (transport->can_pass_unix_fd)
+      if (DBUS_TRANSPORT_CAN_SEND_UNIX_FD(transport))
         {
           int *fds, n_fds;
 
@@ -810,7 +815,7 @@ do_reading (DBusTransport *transport)
                                           buffer,
                                           bytes_read < 0 ? 0 : bytes_read);
     }
-  
+
   if (bytes_read < 0)
     {
       /* EINTR already handled for us */
@@ -865,6 +870,25 @@ do_reading (DBusTransport *transport)
 }
 
 static dbus_bool_t
+unix_error_with_read_to_come (DBusTransport *itransport,
+                              DBusWatch     *watch,
+                              unsigned int   flags)
+{
+  DBusTransportSocket *transport = (DBusTransportSocket *) itransport;
+
+  if (!(flags & DBUS_WATCH_HANGUP || flags & DBUS_WATCH_ERROR))
+    return FALSE;
+   
+  /* If we have a read watch enabled ...
+     we -might have data incoming ... => handle the HANGUP there */
+  if (watch != transport->read_watch &&
+      _dbus_watch_get_enabled (transport->read_watch))
+    return FALSE;
+      
+  return TRUE; 
+}
+
+static dbus_bool_t
 socket_handle_watch (DBusTransport *transport,
                    DBusWatch     *watch,
                    unsigned int   flags)
@@ -875,14 +899,11 @@ socket_handle_watch (DBusTransport *transport,
                 watch == socket_transport->write_watch);
   _dbus_assert (watch != NULL);
   
-  /* Disconnect in case of an error.  In case of hangup do not
-   * disconnect the transport because data can still be in the buffer
-   * and do_reading may need several iteration to read it all (because
-   * of its max_bytes_read_per_iteration limit).  The condition where
-   * flags == HANGUP (without READABLE) probably never happen in fact.
+  /* If we hit an error here on a write watch, don't disconnect the transport yet because data can
+   * still be in the buffer and do_reading may need several iteration to read
+   * it all (because of its max_bytes_read_per_iteration limit). 
    */
-  if ((flags & DBUS_WATCH_ERROR) ||
-      ((flags & DBUS_WATCH_HANGUP) && !(flags & DBUS_WATCH_READABLE)))
+  if (!(flags & DBUS_WATCH_READABLE) && unix_error_with_read_to_come (transport, watch, flags))
     {
       _dbus_verbose ("Hang up or error on watch\n");
       _dbus_transport_disconnect (transport);
@@ -961,7 +982,7 @@ socket_disconnect (DBusTransport *transport)
 {
   DBusTransportSocket *socket_transport = (DBusTransportSocket*) transport;
 
-  _dbus_verbose ("%s\n", _DBUS_FUNCTION_NAME);
+  _dbus_verbose ("\n");
   
   free_watches (transport);
   
@@ -1034,7 +1055,7 @@ socket_do_iteration (DBusTransport *transport,
   poll_fd.fd = socket_transport->fd;
   poll_fd.events = 0;
   
-  if (_dbus_transport_get_is_authenticated (transport))
+  if (_dbus_transport_try_to_authenticate (transport))
     {
       /* This is kind of a hack; if we have stuff to write, then try
        * to avoid the poll. This is probably about a 5% speedup on an
@@ -1096,7 +1117,7 @@ socket_do_iteration (DBusTransport *transport,
        */
       if (flags & DBUS_ITERATION_BLOCK)
         {
-          _dbus_verbose ("unlock %s pre poll\n", _DBUS_FUNCTION_NAME);
+          _dbus_verbose ("unlock pre poll\n");
           _dbus_connection_unlock (transport->connection);
         }
       
@@ -1108,7 +1129,7 @@ socket_do_iteration (DBusTransport *transport,
 
       if (flags & DBUS_ITERATION_BLOCK)
         {
-          _dbus_verbose ("lock %s post poll\n", _DBUS_FUNCTION_NAME);
+          _dbus_verbose ("lock post poll\n");
           _dbus_connection_lock (transport->connection);
         }
       
@@ -1244,7 +1265,7 @@ _dbus_transport_new_for_socket (int               fd,
     goto failed_4;
 
 #ifdef HAVE_UNIX_FD_PASSING
-  socket_transport->base.can_pass_unix_fd = _dbus_socket_can_pass_unix_fd(fd);
+  _dbus_auth_set_unix_fd_possible(socket_transport->base.auth, _dbus_socket_can_pass_unix_fd(fd));
 #endif
 
   socket_transport->fd = fd;
@@ -1257,8 +1278,10 @@ _dbus_transport_new_for_socket (int               fd,
   return (DBusTransport*) socket_transport;
 
  failed_4:
+  _dbus_watch_invalidate (socket_transport->read_watch);
   _dbus_watch_unref (socket_transport->read_watch);
  failed_3:
+  _dbus_watch_invalidate (socket_transport->write_watch);
   _dbus_watch_unref (socket_transport->write_watch);
  failed_2:
   _dbus_string_free (&socket_transport->encoded_incoming);
@@ -1276,6 +1299,7 @@ _dbus_transport_new_for_socket (int               fd,
  * @param host the host to connect to
  * @param port the port to connect to
  * @param family the address family to connect to
+ * @param noncefile path to nonce file
  * @param error location to store reason for failure.
  * @returns a new transport, or #NULL on failure.
  */
@@ -1283,6 +1307,7 @@ DBusTransport*
 _dbus_transport_new_for_tcp_socket (const char     *host,
                                     const char     *port,
                                     const char     *family,
+                                    const char     *noncefile,
                                     DBusError      *error)
 {
   int fd;
@@ -1300,7 +1325,7 @@ _dbus_transport_new_for_tcp_socket (const char     *host,
   if (host == NULL)
     host = "localhost";
 
-  if (!_dbus_string_append (&address, "tcp:"))
+  if (!_dbus_string_append (&address, noncefile ? "nonce-tcp:" : "tcp:"))
     goto error;
 
   if (!_dbus_string_append (&address, "host=") ||
@@ -1312,11 +1337,16 @@ _dbus_transport_new_for_tcp_socket (const char     *host,
     goto error;
 
   if (family != NULL &&
-      (!_dbus_string_append (&address, "family=") ||
+      (!_dbus_string_append (&address, ",family=") ||
        !_dbus_string_append (&address, family)))
     goto error;
 
-  fd = _dbus_connect_tcp_socket (host, port, family, error);
+  if (noncefile != NULL &&
+      (!_dbus_string_append (&address, ",noncefile=") ||
+       !_dbus_string_append (&address, noncefile)))
+    goto error;
+
+  fd = _dbus_connect_tcp_socket_with_nonce (host, port, family, noncefile, error);
   if (fd < 0)
     {
       _DBUS_ASSERT_ERROR_IS_SET (error);
@@ -1324,22 +1354,18 @@ _dbus_transport_new_for_tcp_socket (const char     *host,
       return NULL;
     }
 
-  _dbus_fd_set_close_on_exec (fd);
-  
   _dbus_verbose ("Successfully connected to tcp socket %s:%s\n",
                  host, port);
   
   transport = _dbus_transport_new_for_socket (fd, NULL, &address);
+  _dbus_string_free (&address);
   if (transport == NULL)
     {
       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
       _dbus_close_socket (fd, NULL);
-      _dbus_string_free (&address);
       fd = -1;
     }
 
-  _dbus_string_free (&address);
-  
   return transport;
 
 error:
@@ -1362,23 +1388,34 @@ _dbus_transport_open_socket(DBusAddressEntry  *entry,
                             DBusError         *error)
 {
   const char *method;
+  dbus_bool_t isTcp;
+  dbus_bool_t isNonceTcp;
   
   method = dbus_address_entry_get_method (entry);
   _dbus_assert (method != NULL);
 
-  if (strcmp (method, "tcp") == 0)
+  isTcp = strcmp (method, "tcp") == 0;
+  isNonceTcp = strcmp (method, "nonce-tcp") == 0;
+
+  if (isTcp || isNonceTcp)
     {
       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");
+      const char *noncefile = dbus_address_entry_get_value (entry, "noncefile");
+
+      if ((isNonceTcp == TRUE) != (noncefile != NULL)) {
+          _dbus_set_bad_address (error, method, "noncefile", NULL);
+          return DBUS_TRANSPORT_OPEN_BAD_ADDRESS;
+      }
 
       if (port == NULL)
         {
-          _dbus_set_bad_address (error, "tcp", "port", NULL);
+          _dbus_set_bad_address (error, method, "port", NULL);
           return DBUS_TRANSPORT_OPEN_BAD_ADDRESS;
         }
 
-      *transport_p = _dbus_transport_new_for_tcp_socket (host, port, family, error);
+      *transport_p = _dbus_transport_new_for_tcp_socket (host, port, family, noncefile, error);
       if (*transport_p == NULL)
         {
           _DBUS_ASSERT_ERROR_IS_SET (error);