dbus-transport-socket.c

00001 /* -*- mode: C; c-file-style: "gnu" -*- */
00002 /* dbus-transport-socket.c  Socket subclasses of DBusTransport
00003  *
00004  * Copyright (C) 2002, 2003, 2004, 2006  Red Hat Inc.
00005  *
00006  * Licensed under the Academic Free License version 2.1
00007  * 
00008  * This program is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation; either version 2 of the License, or
00011  * (at your option) any later version.
00012  *
00013  * This program is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  * GNU General Public License for more details.
00017  * 
00018  * You should have received a copy of the GNU General Public License
00019  * along with this program; if not, write to the Free Software
00020  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00021  *
00022  */
00023 
00024 #include "dbus-internals.h"
00025 #include "dbus-connection-internal.h"
00026 #include "dbus-transport-socket.h"
00027 #include "dbus-transport-protected.h"
00028 #include "dbus-watch.h"
00029 
00030 
00042 typedef struct DBusTransportSocket DBusTransportSocket;
00043 
00047 struct DBusTransportSocket
00048 {
00049   DBusTransport base;                   
00050   int fd;                               
00051   DBusWatch *read_watch;                
00052   DBusWatch *write_watch;               
00054   int max_bytes_read_per_iteration;     
00055   int max_bytes_written_per_iteration;  
00057   int message_bytes_written;            
00061   DBusString encoded_outgoing;          
00064   DBusString encoded_incoming;          
00067 };
00068 
00069 static void
00070 free_watches (DBusTransport *transport)
00071 {
00072   DBusTransportSocket *socket_transport = (DBusTransportSocket*) transport;
00073 
00074   _dbus_verbose ("%s start\n", _DBUS_FUNCTION_NAME);
00075   
00076   if (socket_transport->read_watch)
00077     {
00078       if (transport->connection)
00079         _dbus_connection_remove_watch_unlocked (transport->connection,
00080                                                 socket_transport->read_watch);
00081       _dbus_watch_invalidate (socket_transport->read_watch);
00082       _dbus_watch_unref (socket_transport->read_watch);
00083       socket_transport->read_watch = NULL;
00084     }
00085 
00086   if (socket_transport->write_watch)
00087     {
00088       if (transport->connection)
00089         _dbus_connection_remove_watch_unlocked (transport->connection,
00090                                                 socket_transport->write_watch);
00091       _dbus_watch_invalidate (socket_transport->write_watch);
00092       _dbus_watch_unref (socket_transport->write_watch);
00093       socket_transport->write_watch = NULL;
00094     }
00095 
00096   _dbus_verbose ("%s end\n", _DBUS_FUNCTION_NAME);
00097 }
00098 
00099 static void
00100 socket_finalize (DBusTransport *transport)
00101 {
00102   DBusTransportSocket *socket_transport = (DBusTransportSocket*) transport;
00103 
00104   _dbus_verbose ("%s\n", _DBUS_FUNCTION_NAME);
00105   
00106   free_watches (transport);
00107 
00108   _dbus_string_free (&socket_transport->encoded_outgoing);
00109   _dbus_string_free (&socket_transport->encoded_incoming);
00110   
00111   _dbus_transport_finalize_base (transport);
00112 
00113   _dbus_assert (socket_transport->read_watch == NULL);
00114   _dbus_assert (socket_transport->write_watch == NULL);
00115   
00116   dbus_free (transport);
00117 }
00118 
00119 static void
00120 check_write_watch (DBusTransport *transport)
00121 {
00122   DBusTransportSocket *socket_transport = (DBusTransportSocket*) transport;
00123   dbus_bool_t needed;
00124 
00125   if (transport->connection == NULL)
00126     return;
00127 
00128   if (transport->disconnected)
00129     {
00130       _dbus_assert (socket_transport->write_watch == NULL);
00131       return;
00132     }
00133   
00134   _dbus_transport_ref (transport);
00135 
00136   if (_dbus_transport_get_is_authenticated (transport))
00137     needed = _dbus_connection_has_messages_to_send_unlocked (transport->connection);
00138   else
00139     {
00140       if (transport->send_credentials_pending)
00141         needed = TRUE;
00142       else
00143         {
00144           DBusAuthState auth_state;
00145           
00146           auth_state = _dbus_auth_do_work (transport->auth);
00147           
00148           /* If we need memory we install the write watch just in case,
00149            * if there's no need for it, it will get de-installed
00150            * next time we try reading.
00151            */
00152           if (auth_state == DBUS_AUTH_STATE_HAVE_BYTES_TO_SEND ||
00153               auth_state == DBUS_AUTH_STATE_WAITING_FOR_MEMORY)
00154             needed = TRUE;
00155           else
00156             needed = FALSE;
00157         }
00158     }
00159 
00160   _dbus_verbose ("check_write_watch(): needed = %d on connection %p watch %p fd = %d outgoing messages exist %d\n",
00161                  needed, transport->connection, socket_transport->write_watch,
00162                  socket_transport->fd,
00163                  _dbus_connection_has_messages_to_send_unlocked (transport->connection));
00164 
00165   _dbus_connection_toggle_watch_unlocked (transport->connection,
00166                                           socket_transport->write_watch,
00167                                           needed);
00168 
00169   _dbus_transport_unref (transport);
00170 }
00171 
00172 static void
00173 check_read_watch (DBusTransport *transport)
00174 {
00175   DBusTransportSocket *socket_transport = (DBusTransportSocket*) transport;
00176   dbus_bool_t need_read_watch;
00177 
00178   _dbus_verbose ("%s: fd = %d\n",
00179                  _DBUS_FUNCTION_NAME, socket_transport->fd);
00180   
00181   if (transport->connection == NULL)
00182     return;
00183 
00184   if (transport->disconnected)
00185     {
00186       _dbus_assert (socket_transport->read_watch == NULL);
00187       return;
00188     }
00189   
00190   _dbus_transport_ref (transport);
00191 
00192   if (_dbus_transport_get_is_authenticated (transport))
00193     need_read_watch =
00194       _dbus_counter_get_value (transport->live_messages_size) < transport->max_live_messages_size;
00195   else
00196     {
00197       if (transport->receive_credentials_pending)
00198         need_read_watch = TRUE;
00199       else
00200         {
00201           /* The reason to disable need_read_watch when not WAITING_FOR_INPUT
00202            * is to avoid spinning on the file descriptor when we're waiting
00203            * to write or for some other part of the auth process
00204            */
00205           DBusAuthState auth_state;
00206           
00207           auth_state = _dbus_auth_do_work (transport->auth);
00208 
00209           /* If we need memory we install the read watch just in case,
00210            * if there's no need for it, it will get de-installed
00211            * next time we try reading. If we're authenticated we
00212            * install it since we normally have it installed while
00213            * authenticated.
00214            */
00215           if (auth_state == DBUS_AUTH_STATE_WAITING_FOR_INPUT ||
00216               auth_state == DBUS_AUTH_STATE_WAITING_FOR_MEMORY ||
00217               auth_state == DBUS_AUTH_STATE_AUTHENTICATED)
00218             need_read_watch = TRUE;
00219           else
00220             need_read_watch = FALSE;
00221         }
00222     }
00223 
00224   _dbus_verbose ("  setting read watch enabled = %d\n", need_read_watch);
00225   _dbus_connection_toggle_watch_unlocked (transport->connection,
00226                                           socket_transport->read_watch,
00227                                           need_read_watch);
00228 
00229   _dbus_transport_unref (transport);
00230 }
00231 
00232 static void
00233 do_io_error (DBusTransport *transport)
00234 {
00235   _dbus_transport_ref (transport);
00236   _dbus_transport_disconnect (transport);
00237   _dbus_transport_unref (transport);
00238 }
00239 
00240 /* return value is whether we successfully read any new data. */
00241 static dbus_bool_t
00242 read_data_into_auth (DBusTransport *transport,
00243                      dbus_bool_t   *oom)
00244 {
00245   DBusTransportSocket *socket_transport = (DBusTransportSocket*) transport;
00246   DBusString *buffer;
00247   int bytes_read;
00248   
00249   *oom = FALSE;
00250 
00251   _dbus_auth_get_buffer (transport->auth, &buffer);
00252   
00253   bytes_read = _dbus_read_socket (socket_transport->fd,
00254                                   buffer, socket_transport->max_bytes_read_per_iteration);
00255 
00256   _dbus_auth_return_buffer (transport->auth, buffer,
00257                             bytes_read > 0 ? bytes_read : 0);
00258 
00259   if (bytes_read > 0)
00260     {
00261       _dbus_verbose (" read %d bytes in auth phase\n", bytes_read);
00262 
00263       return TRUE;
00264     }
00265   else if (bytes_read < 0)
00266     {
00267       /* EINTR already handled for us */
00268 
00269       if (errno == ENOMEM)
00270         {
00271           *oom = TRUE;
00272         }
00273       else if (errno == EAGAIN ||
00274                errno == EWOULDBLOCK)
00275         ; /* do nothing, just return FALSE below */
00276       else
00277         {
00278           _dbus_verbose ("Error reading from remote app: %s\n",
00279                          _dbus_strerror (errno));
00280           do_io_error (transport);
00281         }
00282 
00283       return FALSE;
00284     }
00285   else
00286     {
00287       _dbus_assert (bytes_read == 0);
00288       
00289       _dbus_verbose ("Disconnected from remote app\n");
00290       do_io_error (transport);
00291 
00292       return FALSE;
00293     }
00294 }
00295 
00296 /* Return value is whether we successfully wrote any bytes */
00297 static dbus_bool_t
00298 write_data_from_auth (DBusTransport *transport)
00299 {
00300   DBusTransportSocket *socket_transport = (DBusTransportSocket*) transport;
00301   int bytes_written;
00302   const DBusString *buffer;
00303 
00304   if (!_dbus_auth_get_bytes_to_send (transport->auth,
00305                                      &buffer))
00306     return FALSE;
00307   
00308   bytes_written = _dbus_write_socket (socket_transport->fd,
00309                                       buffer,
00310                                       0, _dbus_string_get_length (buffer));
00311 
00312   if (bytes_written > 0)
00313     {
00314       _dbus_auth_bytes_sent (transport->auth, bytes_written);
00315       return TRUE;
00316     }
00317   else if (bytes_written < 0)
00318     {
00319       /* EINTR already handled for us */
00320       
00321       if (errno == EAGAIN ||
00322           errno == EWOULDBLOCK)
00323         ;
00324       else
00325         {
00326           _dbus_verbose ("Error writing to remote app: %s\n",
00327                          _dbus_strerror (errno));
00328           do_io_error (transport);
00329         }
00330     }
00331 
00332   return FALSE;
00333 }
00334 
00335 static void
00336 exchange_credentials (DBusTransport *transport,
00337                       dbus_bool_t    do_reading,
00338                       dbus_bool_t    do_writing)
00339 {
00340   DBusTransportSocket *socket_transport = (DBusTransportSocket*) transport;
00341   DBusError error;
00342 
00343   _dbus_verbose ("exchange_credentials: do_reading = %d, do_writing = %d\n",
00344                   do_reading, do_writing);
00345 
00346   dbus_error_init (&error);
00347   if (do_writing && transport->send_credentials_pending)
00348     {
00349       if (_dbus_send_credentials_unix_socket (socket_transport->fd,
00350                                               &error))
00351         {
00352           transport->send_credentials_pending = FALSE;
00353         }
00354       else
00355         {
00356           _dbus_verbose ("Failed to write credentials: %s\n", error.message);
00357           dbus_error_free (&error);
00358           do_io_error (transport);
00359         }
00360     }
00361   
00362   if (do_reading && transport->receive_credentials_pending)
00363     {
00364       if (_dbus_read_credentials_unix_socket (socket_transport->fd,
00365                                               &transport->credentials,
00366                                               &error))
00367         {
00368           transport->receive_credentials_pending = FALSE;
00369         }
00370       else
00371         {
00372           _dbus_verbose ("Failed to read credentials %s\n", error.message);
00373           dbus_error_free (&error);
00374           do_io_error (transport);
00375         }
00376     }
00377 
00378   if (!(transport->send_credentials_pending ||
00379         transport->receive_credentials_pending))
00380     {
00381       _dbus_auth_set_credentials (transport->auth,
00382                                   &transport->credentials);
00383     }
00384 }
00385 
00386 static dbus_bool_t
00387 do_authentication (DBusTransport *transport,
00388                    dbus_bool_t    do_reading,
00389                    dbus_bool_t    do_writing,
00390                    dbus_bool_t   *auth_completed)
00391 {
00392   dbus_bool_t oom;
00393   dbus_bool_t orig_auth_state;
00394 
00395   oom = FALSE;
00396   
00397   orig_auth_state = _dbus_transport_get_is_authenticated (transport);
00398 
00399   /* This is essential to avoid the check_write_watch() at the end,
00400    * we don't want to add a write watch in do_iteration before
00401    * we try writing and get EAGAIN
00402    */
00403   if (orig_auth_state)
00404     {
00405       if (auth_completed)
00406         *auth_completed = FALSE;
00407       return TRUE;
00408     }
00409   
00410   _dbus_transport_ref (transport);
00411   
00412   while (!_dbus_transport_get_is_authenticated (transport) &&
00413          _dbus_transport_get_is_connected (transport))
00414     {      
00415       exchange_credentials (transport, do_reading, do_writing);
00416       
00417       if (transport->send_credentials_pending ||
00418           transport->receive_credentials_pending)
00419         {
00420           _dbus_verbose ("send_credentials_pending = %d receive_credentials_pending = %d\n",
00421                          transport->send_credentials_pending,
00422                          transport->receive_credentials_pending);
00423           goto out;
00424         }
00425 
00426 #define TRANSPORT_SIDE(t) ((t)->is_server ? "server" : "client")
00427       switch (_dbus_auth_do_work (transport->auth))
00428         {
00429         case DBUS_AUTH_STATE_WAITING_FOR_INPUT:
00430           _dbus_verbose (" %s auth state: waiting for input\n",
00431                          TRANSPORT_SIDE (transport));
00432           if (!do_reading || !read_data_into_auth (transport, &oom))
00433             goto out;
00434           break;
00435       
00436         case DBUS_AUTH_STATE_WAITING_FOR_MEMORY:
00437           _dbus_verbose (" %s auth state: waiting for memory\n",
00438                          TRANSPORT_SIDE (transport));
00439           oom = TRUE;
00440           goto out;
00441           break;
00442       
00443         case DBUS_AUTH_STATE_HAVE_BYTES_TO_SEND:
00444           _dbus_verbose (" %s auth state: bytes to send\n",
00445                          TRANSPORT_SIDE (transport));
00446           if (!do_writing || !write_data_from_auth (transport))
00447             goto out;
00448           break;
00449       
00450         case DBUS_AUTH_STATE_NEED_DISCONNECT:
00451           _dbus_verbose (" %s auth state: need to disconnect\n",
00452                          TRANSPORT_SIDE (transport));
00453           do_io_error (transport);
00454           break;
00455       
00456         case DBUS_AUTH_STATE_AUTHENTICATED:
00457           _dbus_verbose (" %s auth state: authenticated\n",
00458                          TRANSPORT_SIDE (transport));
00459           break;
00460         }
00461     }
00462 
00463  out:
00464   if (auth_completed)
00465     *auth_completed = (orig_auth_state != _dbus_transport_get_is_authenticated (transport));
00466   
00467   check_read_watch (transport);
00468   check_write_watch (transport);
00469   _dbus_transport_unref (transport);
00470 
00471   if (oom)
00472     return FALSE;
00473   else
00474     return TRUE;
00475 }
00476 
00477 /* returns false on oom */
00478 static dbus_bool_t
00479 do_writing (DBusTransport *transport)
00480 {
00481   int total;
00482   DBusTransportSocket *socket_transport = (DBusTransportSocket*) transport;
00483   dbus_bool_t oom;
00484   
00485   /* No messages without authentication! */
00486   if (!_dbus_transport_get_is_authenticated (transport))
00487     {
00488       _dbus_verbose ("Not authenticated, not writing anything\n");
00489       return TRUE;
00490     }
00491 
00492   if (transport->disconnected)
00493     {
00494       _dbus_verbose ("Not connected, not writing anything\n");
00495       return TRUE;
00496     }
00497 
00498 #if 1
00499   _dbus_verbose ("do_writing(), have_messages = %d, fd = %d\n",
00500                  _dbus_connection_has_messages_to_send_unlocked (transport->connection),
00501                  socket_transport->fd);
00502 #endif
00503   
00504   oom = FALSE;
00505   total = 0;
00506 
00507   while (!transport->disconnected &&
00508          _dbus_connection_has_messages_to_send_unlocked (transport->connection))
00509     {
00510       int bytes_written;
00511       DBusMessage *message;
00512       const DBusString *header;
00513       const DBusString *body;
00514       int header_len, body_len;
00515       int total_bytes_to_write;
00516       
00517       if (total > socket_transport->max_bytes_written_per_iteration)
00518         {
00519           _dbus_verbose ("%d bytes exceeds %d bytes written per iteration, returning\n",
00520                          total, socket_transport->max_bytes_written_per_iteration);
00521           goto out;
00522         }
00523       
00524       message = _dbus_connection_get_message_to_send (transport->connection);
00525       _dbus_assert (message != NULL);
00526       _dbus_message_lock (message);
00527 
00528 #if 0
00529       _dbus_verbose ("writing message %p\n", message);
00530 #endif
00531       
00532       _dbus_message_get_network_data (message,
00533                                       &header, &body);
00534 
00535       header_len = _dbus_string_get_length (header);
00536       body_len = _dbus_string_get_length (body);
00537 
00538       if (_dbus_auth_needs_encoding (transport->auth))
00539         {
00540           if (_dbus_string_get_length (&socket_transport->encoded_outgoing) == 0)
00541             {
00542               if (!_dbus_auth_encode_data (transport->auth,
00543                                            header, &socket_transport->encoded_outgoing))
00544                 {
00545                   oom = TRUE;
00546                   goto out;
00547                 }
00548               
00549               if (!_dbus_auth_encode_data (transport->auth,
00550                                            body, &socket_transport->encoded_outgoing))
00551                 {
00552                   _dbus_string_set_length (&socket_transport->encoded_outgoing, 0);
00553                   oom = TRUE;
00554                   goto out;
00555                 }
00556             }
00557           
00558           total_bytes_to_write = _dbus_string_get_length (&socket_transport->encoded_outgoing);
00559 
00560 #if 0
00561           _dbus_verbose ("encoded message is %d bytes\n",
00562                          total_bytes_to_write);
00563 #endif
00564           
00565           bytes_written =
00566             _dbus_write_socket (socket_transport->fd,
00567                                 &socket_transport->encoded_outgoing,
00568                                 socket_transport->message_bytes_written,
00569                                 total_bytes_to_write - socket_transport->message_bytes_written);
00570         }
00571       else
00572         {
00573           total_bytes_to_write = header_len + body_len;
00574 
00575 #if 0
00576           _dbus_verbose ("message is %d bytes\n",
00577                          total_bytes_to_write);          
00578 #endif
00579           
00580           if (socket_transport->message_bytes_written < header_len)
00581             {
00582               bytes_written =
00583                 _dbus_write_socket_two (socket_transport->fd,
00584                                         header,
00585                                         socket_transport->message_bytes_written,
00586                                         header_len - socket_transport->message_bytes_written,
00587                                         body,
00588                                         0, body_len);
00589             }
00590           else
00591             {
00592               bytes_written =
00593                 _dbus_write_socket (socket_transport->fd,
00594                                     body,
00595                                     (socket_transport->message_bytes_written - header_len),
00596                                     body_len -
00597                                     (socket_transport->message_bytes_written - header_len));
00598             }
00599         }
00600 
00601       if (bytes_written < 0)
00602         {
00603           /* EINTR already handled for us */
00604           
00605           if (errno == EAGAIN ||
00606               errno == EWOULDBLOCK)
00607             goto out;
00608           else
00609             {
00610               _dbus_verbose ("Error writing to remote app: %s\n",
00611                              _dbus_strerror (errno));
00612               do_io_error (transport);
00613               goto out;
00614             }
00615         }
00616       else
00617         {
00618           _dbus_verbose (" wrote %d bytes of %d\n", bytes_written,
00619                          total_bytes_to_write);
00620           
00621           total += bytes_written;
00622           socket_transport->message_bytes_written += bytes_written;
00623 
00624           _dbus_assert (socket_transport->message_bytes_written <=
00625                         total_bytes_to_write);
00626           
00627           if (socket_transport->message_bytes_written == total_bytes_to_write)
00628             {
00629               socket_transport->message_bytes_written = 0;
00630               _dbus_string_set_length (&socket_transport->encoded_outgoing, 0);
00631 
00632               _dbus_connection_message_sent (transport->connection,
00633                                              message);
00634             }
00635         }
00636     }
00637 
00638  out:
00639   if (oom)
00640     return FALSE;
00641   else
00642     return TRUE;
00643 }
00644 
00645 /* returns false on out-of-memory */
00646 static dbus_bool_t
00647 do_reading (DBusTransport *transport)
00648 {
00649   DBusTransportSocket *socket_transport = (DBusTransportSocket*) transport;
00650   DBusString *buffer;
00651   int bytes_read;
00652   int total;
00653   dbus_bool_t oom;
00654 
00655   _dbus_verbose ("%s: fd = %d\n", _DBUS_FUNCTION_NAME,
00656                  socket_transport->fd);
00657   
00658   /* No messages without authentication! */
00659   if (!_dbus_transport_get_is_authenticated (transport))
00660     return TRUE;
00661 
00662   oom = FALSE;
00663   
00664   total = 0;
00665 
00666  again:
00667   
00668   /* See if we've exceeded max messages and need to disable reading */
00669   check_read_watch (transport);
00670   
00671   if (total > socket_transport->max_bytes_read_per_iteration)
00672     {
00673       _dbus_verbose ("%d bytes exceeds %d bytes read per iteration, returning\n",
00674                      total, socket_transport->max_bytes_read_per_iteration);
00675       goto out;
00676     }
00677 
00678   _dbus_assert (socket_transport->read_watch != NULL ||
00679                 transport->disconnected);
00680   
00681   if (transport->disconnected)
00682     goto out;
00683 
00684   if (!dbus_watch_get_enabled (socket_transport->read_watch))
00685     return TRUE;
00686   
00687   if (_dbus_auth_needs_decoding (transport->auth))
00688     {
00689       if (_dbus_string_get_length (&socket_transport->encoded_incoming) > 0)
00690         bytes_read = _dbus_string_get_length (&socket_transport->encoded_incoming);
00691       else
00692         bytes_read = _dbus_read_socket (socket_transport->fd,
00693                                         &socket_transport->encoded_incoming,
00694                                         socket_transport->max_bytes_read_per_iteration);
00695 
00696       _dbus_assert (_dbus_string_get_length (&socket_transport->encoded_incoming) ==
00697                     bytes_read);
00698       
00699       if (bytes_read > 0)
00700         {
00701           int orig_len;
00702           
00703           _dbus_message_loader_get_buffer (transport->loader,
00704                                            &buffer);
00705 
00706           orig_len = _dbus_string_get_length (buffer);
00707           
00708           if (!_dbus_auth_decode_data (transport->auth,
00709                                        &socket_transport->encoded_incoming,
00710                                        buffer))
00711             {
00712               _dbus_verbose ("Out of memory decoding incoming data\n");
00713               oom = TRUE;
00714               goto out;
00715             }
00716 
00717           _dbus_message_loader_return_buffer (transport->loader,
00718                                               buffer,
00719                                               _dbus_string_get_length (buffer) - orig_len);
00720 
00721           _dbus_string_set_length (&socket_transport->encoded_incoming, 0);
00722         }
00723     }
00724   else
00725     {
00726       _dbus_message_loader_get_buffer (transport->loader,
00727                                        &buffer);
00728       
00729       bytes_read = _dbus_read_socket (socket_transport->fd,
00730                                       buffer, socket_transport->max_bytes_read_per_iteration);
00731       
00732       _dbus_message_loader_return_buffer (transport->loader,
00733                                           buffer,
00734                                           bytes_read < 0 ? 0 : bytes_read);
00735     }
00736   
00737   if (bytes_read < 0)
00738     {
00739       /* EINTR already handled for us */
00740 
00741       if (errno == ENOMEM)
00742         {
00743           _dbus_verbose ("Out of memory in read()/do_reading()\n");
00744           oom = TRUE;
00745           goto out;
00746         }
00747       else if (errno == EAGAIN ||
00748                errno == EWOULDBLOCK)
00749         goto out;
00750       else
00751         {
00752           _dbus_verbose ("Error reading from remote app: %s\n",
00753                          _dbus_strerror (errno));
00754           do_io_error (transport);
00755           goto out;
00756         }
00757     }
00758   else if (bytes_read == 0)
00759     {
00760       _dbus_verbose ("Disconnected from remote app\n");
00761       do_io_error (transport);
00762       goto out;
00763     }
00764   else
00765     {
00766       _dbus_verbose (" read %d bytes\n", bytes_read);
00767       
00768       total += bytes_read;      
00769 
00770       if (!_dbus_transport_queue_messages (transport))
00771         {
00772           oom = TRUE;
00773           _dbus_verbose (" out of memory when queueing messages we just read in the transport\n");
00774           goto out;
00775         }
00776       
00777       /* Try reading more data until we get EAGAIN and return, or
00778        * exceed max bytes per iteration.  If in blocking mode of
00779        * course we'll block instead of returning.
00780        */
00781       goto again;
00782     }
00783 
00784  out:
00785   if (oom)
00786     return FALSE;
00787   else
00788     return TRUE;
00789 }
00790 
00791 static dbus_bool_t
00792 socket_handle_watch (DBusTransport *transport,
00793                    DBusWatch     *watch,
00794                    unsigned int   flags)
00795 {
00796   DBusTransportSocket *socket_transport = (DBusTransportSocket*) transport;
00797 
00798   _dbus_assert (watch == socket_transport->read_watch ||
00799                 watch == socket_transport->write_watch);
00800   _dbus_assert (watch != NULL);
00801   
00802   /* Disconnect in case of an error.  In case of hangup do not
00803    * disconnect the transport because data can still be in the buffer
00804    * and do_reading may need several iteration to read it all (because
00805    * of its max_bytes_read_per_iteration limit).  The condition where
00806    * flags == HANGUP (without READABLE) probably never happen in fact.
00807    */
00808   if ((flags & DBUS_WATCH_ERROR) ||
00809       ((flags & DBUS_WATCH_HANGUP) && !(flags & DBUS_WATCH_READABLE)))
00810     {
00811       _dbus_verbose ("Hang up or error on watch\n");
00812       _dbus_transport_disconnect (transport);
00813       return TRUE;
00814     }
00815   
00816   if (watch == socket_transport->read_watch &&
00817       (flags & DBUS_WATCH_READABLE))
00818     {
00819       dbus_bool_t auth_finished;
00820 #if 1
00821       _dbus_verbose ("handling read watch %p flags = %x\n",
00822                      watch, flags);
00823 #endif
00824       if (!do_authentication (transport, TRUE, FALSE, &auth_finished))
00825         return FALSE;
00826 
00827       /* We don't want to do a read immediately following
00828        * a successful authentication.  This is so we
00829        * have a chance to propagate the authentication
00830        * state further up.  Specifically, we need to
00831        * process any pending data from the auth object.
00832        */
00833       if (!auth_finished)
00834         {
00835           if (!do_reading (transport))
00836             {
00837               _dbus_verbose ("no memory to read\n");
00838               return FALSE;
00839             }
00840         }
00841       else
00842         {
00843           _dbus_verbose ("Not reading anything since we just completed the authentication\n");
00844         }
00845     }
00846   else if (watch == socket_transport->write_watch &&
00847            (flags & DBUS_WATCH_WRITABLE))
00848     {
00849 #if 1
00850       _dbus_verbose ("handling write watch, have_outgoing_messages = %d\n",
00851                      _dbus_connection_has_messages_to_send_unlocked (transport->connection));
00852 #endif
00853       if (!do_authentication (transport, FALSE, TRUE, NULL))
00854         return FALSE;
00855       
00856       if (!do_writing (transport))
00857         {
00858           _dbus_verbose ("no memory to write\n");
00859           return FALSE;
00860         }
00861 
00862       /* See if we still need the write watch */
00863       check_write_watch (transport);
00864     }
00865 #ifdef DBUS_ENABLE_VERBOSE_MODE
00866   else
00867     {
00868       if (watch == socket_transport->read_watch)
00869         _dbus_verbose ("asked to handle read watch with non-read condition 0x%x\n",
00870                        flags);
00871       else if (watch == socket_transport->write_watch)
00872         _dbus_verbose ("asked to handle write watch with non-write condition 0x%x\n",
00873                        flags);
00874       else
00875         _dbus_verbose ("asked to handle watch %p on fd %d that we don't recognize\n",
00876                        watch, dbus_watch_get_fd (watch));
00877     }
00878 #endif /* DBUS_ENABLE_VERBOSE_MODE */
00879 
00880   return TRUE;
00881 }
00882 
00883 static void
00884 socket_disconnect (DBusTransport *transport)
00885 {
00886   DBusTransportSocket *socket_transport = (DBusTransportSocket*) transport;
00887 
00888   _dbus_verbose ("%s\n", _DBUS_FUNCTION_NAME);
00889   
00890   free_watches (transport);
00891   
00892   _dbus_close_socket (socket_transport->fd, NULL);
00893   socket_transport->fd = -1;
00894 }
00895 
00896 static dbus_bool_t
00897 socket_connection_set (DBusTransport *transport)
00898 {
00899   DBusTransportSocket *socket_transport = (DBusTransportSocket*) transport;
00900 
00901   _dbus_watch_set_handler (socket_transport->write_watch,
00902                            _dbus_connection_handle_watch,
00903                            transport->connection, NULL);
00904 
00905   _dbus_watch_set_handler (socket_transport->read_watch,
00906                            _dbus_connection_handle_watch,
00907                            transport->connection, NULL);
00908   
00909   if (!_dbus_connection_add_watch_unlocked (transport->connection,
00910                                             socket_transport->write_watch))
00911     return FALSE;
00912 
00913   if (!_dbus_connection_add_watch_unlocked (transport->connection,
00914                                             socket_transport->read_watch))
00915     {
00916       _dbus_connection_remove_watch_unlocked (transport->connection,
00917                                               socket_transport->write_watch);
00918       return FALSE;
00919     }
00920 
00921   check_read_watch (transport);
00922   check_write_watch (transport);
00923 
00924   return TRUE;
00925 }
00926 
00934 static  void
00935 socket_do_iteration (DBusTransport *transport,
00936                    unsigned int   flags,
00937                    int            timeout_milliseconds)
00938 {
00939   DBusTransportSocket *socket_transport = (DBusTransportSocket*) transport;
00940   DBusPollFD poll_fd;
00941   int poll_res;
00942   int poll_timeout;
00943 
00944   _dbus_verbose (" iteration flags = %s%s timeout = %d read_watch = %p write_watch = %p fd = %d\n",
00945                  flags & DBUS_ITERATION_DO_READING ? "read" : "",
00946                  flags & DBUS_ITERATION_DO_WRITING ? "write" : "",
00947                  timeout_milliseconds,
00948                  socket_transport->read_watch,
00949                  socket_transport->write_watch,
00950                  socket_transport->fd);
00951   
00952   /* the passed in DO_READING/DO_WRITING flags indicate whether to
00953    * read/write messages, but regardless of those we may need to block
00954    * for reading/writing to do auth.  But if we do reading for auth,
00955    * we don't want to read any messages yet if not given DO_READING.
00956    */
00957 
00958   poll_fd.fd = socket_transport->fd;
00959   poll_fd.events = 0;
00960   
00961   if (_dbus_transport_get_is_authenticated (transport))
00962     {
00963       /* This is kind of a hack; if we have stuff to write, then try
00964        * to avoid the poll. This is probably about a 5% speedup on an
00965        * echo client/server.
00966        *
00967        * If both reading and writing were requested, we want to avoid this
00968        * since it could have funky effects:
00969        *   - both ends spinning waiting for the other one to read
00970        *     data so they can finish writing
00971        *   - prioritizing all writing ahead of reading
00972        */
00973       if ((flags & DBUS_ITERATION_DO_WRITING) &&
00974           !(flags & (DBUS_ITERATION_DO_READING | DBUS_ITERATION_BLOCK)) &&
00975           !transport->disconnected &&
00976           _dbus_connection_has_messages_to_send_unlocked (transport->connection))
00977         {
00978           do_writing (transport);
00979 
00980           if (transport->disconnected ||
00981               !_dbus_connection_has_messages_to_send_unlocked (transport->connection))
00982             goto out;
00983         }
00984 
00985       /* If we get here, we decided to do the poll() after all */
00986       _dbus_assert (socket_transport->read_watch);
00987       if (flags & DBUS_ITERATION_DO_READING)
00988         poll_fd.events |= _DBUS_POLLIN;
00989 
00990       _dbus_assert (socket_transport->write_watch);
00991       if (flags & DBUS_ITERATION_DO_WRITING)
00992         poll_fd.events |= _DBUS_POLLOUT;
00993     }
00994   else
00995     {
00996       DBusAuthState auth_state;
00997       
00998       auth_state = _dbus_auth_do_work (transport->auth);
00999 
01000       if (transport->receive_credentials_pending ||
01001           auth_state == DBUS_AUTH_STATE_WAITING_FOR_INPUT)
01002         poll_fd.events |= _DBUS_POLLIN;
01003 
01004       if (transport->send_credentials_pending ||
01005           auth_state == DBUS_AUTH_STATE_HAVE_BYTES_TO_SEND)
01006         poll_fd.events |= _DBUS_POLLOUT;
01007     }
01008 
01009   if (poll_fd.events)
01010     {
01011       if (flags & DBUS_ITERATION_BLOCK)
01012         poll_timeout = timeout_milliseconds;
01013       else
01014         poll_timeout = 0;
01015 
01016       /* For blocking selects we drop the connection lock here
01017        * to avoid blocking out connection access during a potentially
01018        * indefinite blocking call. The io path is still protected
01019        * by the io_path_cond condvar, so we won't reenter this.
01020        */
01021       if (flags & DBUS_ITERATION_BLOCK)
01022         {
01023           _dbus_verbose ("unlock %s pre poll\n", _DBUS_FUNCTION_NAME);
01024           _dbus_connection_unlock (transport->connection);
01025         }
01026       
01027     again:
01028       poll_res = _dbus_poll (&poll_fd, 1, poll_timeout);
01029 
01030       if (poll_res < 0 && errno == EINTR)
01031         goto again;
01032 
01033       if (flags & DBUS_ITERATION_BLOCK)
01034         {
01035           _dbus_verbose ("lock %s post poll\n", _DBUS_FUNCTION_NAME);
01036           _dbus_connection_lock (transport->connection);
01037         }
01038       
01039       if (poll_res >= 0)
01040         {
01041           if (poll_res == 0)
01042             poll_fd.revents = 0; /* some concern that posix does not guarantee this;
01043                                   * valgrind flags it as an error. though it probably
01044                                   * is guaranteed on linux at least.
01045                                   */
01046           
01047           if (poll_fd.revents & _DBUS_POLLERR)
01048             do_io_error (transport);
01049           else
01050             {
01051               dbus_bool_t need_read = (poll_fd.revents & _DBUS_POLLIN) > 0;
01052               dbus_bool_t need_write = (poll_fd.revents & _DBUS_POLLOUT) > 0;
01053               dbus_bool_t authentication_completed;
01054 
01055               _dbus_verbose ("in iteration, need_read=%d need_write=%d\n",
01056                              need_read, need_write);
01057               do_authentication (transport, need_read, need_write,
01058                                  &authentication_completed);
01059 
01060               /* See comment in socket_handle_watch. */
01061               if (authentication_completed)
01062                 goto out;
01063                                  
01064               if (need_read && (flags & DBUS_ITERATION_DO_READING))
01065                 do_reading (transport);
01066               if (need_write && (flags & DBUS_ITERATION_DO_WRITING))
01067                 do_writing (transport);
01068             }
01069         }
01070       else
01071         {
01072           _dbus_verbose ("Error from _dbus_poll(): %s\n",
01073                          _dbus_strerror (errno));
01074         }
01075     }
01076 
01077 
01078  out:
01079   /* We need to install the write watch only if we did not
01080    * successfully write everything. Note we need to be careful that we
01081    * don't call check_write_watch *before* do_writing, since it's
01082    * inefficient to add the write watch, and we can avoid it most of
01083    * the time since we can write immediately.
01084    * 
01085    * However, we MUST always call check_write_watch(); DBusConnection code
01086    * relies on the fact that running an iteration will notice that
01087    * messages are pending.
01088    */
01089   check_write_watch (transport);
01090 
01091   _dbus_verbose (" ... leaving do_iteration()\n");
01092 }
01093 
01094 static void
01095 socket_live_messages_changed (DBusTransport *transport)
01096 {
01097   /* See if we should look for incoming messages again */
01098   check_read_watch (transport);
01099 }
01100 
01101 
01102 static dbus_bool_t
01103 socket_get_socket_fd (DBusTransport *transport,
01104                       int           *fd_p)
01105 {
01106   DBusTransportSocket *socket_transport = (DBusTransportSocket*) transport;
01107   
01108   *fd_p = socket_transport->fd;
01109   
01110   return TRUE;
01111 }
01112 
01113 static const DBusTransportVTable socket_vtable = {
01114   socket_finalize,
01115   socket_handle_watch,
01116   socket_disconnect,
01117   socket_connection_set,
01118   socket_do_iteration,
01119   socket_live_messages_changed,
01120   socket_get_socket_fd
01121 };
01122 
01134 DBusTransport*
01135 _dbus_transport_new_for_socket (int               fd,
01136                                 const DBusString *server_guid,
01137                                 const DBusString *address)
01138 {
01139   DBusTransportSocket *socket_transport;
01140   
01141   socket_transport = dbus_new0 (DBusTransportSocket, 1);
01142   if (socket_transport == NULL)
01143     return NULL;
01144 
01145   if (!_dbus_string_init (&socket_transport->encoded_outgoing))
01146     goto failed_0;
01147 
01148   if (!_dbus_string_init (&socket_transport->encoded_incoming))
01149     goto failed_1;
01150   
01151   socket_transport->write_watch = _dbus_watch_new (fd,
01152                                                  DBUS_WATCH_WRITABLE,
01153                                                  FALSE,
01154                                                  NULL, NULL, NULL);
01155   if (socket_transport->write_watch == NULL)
01156     goto failed_2;
01157   
01158   socket_transport->read_watch = _dbus_watch_new (fd,
01159                                                 DBUS_WATCH_READABLE,
01160                                                 FALSE,
01161                                                 NULL, NULL, NULL);
01162   if (socket_transport->read_watch == NULL)
01163     goto failed_3;
01164   
01165   if (!_dbus_transport_init_base (&socket_transport->base,
01166                                   &socket_vtable,
01167                                   server_guid, address))
01168     goto failed_4;
01169   
01170   socket_transport->fd = fd;
01171   socket_transport->message_bytes_written = 0;
01172   
01173   /* These values should probably be tunable or something. */     
01174   socket_transport->max_bytes_read_per_iteration = 2048;
01175   socket_transport->max_bytes_written_per_iteration = 2048;
01176   
01177   return (DBusTransport*) socket_transport;
01178 
01179  failed_4:
01180   _dbus_watch_unref (socket_transport->read_watch);
01181  failed_3:
01182   _dbus_watch_unref (socket_transport->write_watch);
01183  failed_2:
01184   _dbus_string_free (&socket_transport->encoded_incoming);
01185  failed_1:
01186   _dbus_string_free (&socket_transport->encoded_outgoing);
01187  failed_0:
01188   dbus_free (socket_transport);
01189   return NULL;
01190 }
01191 
01200 DBusTransport*
01201 _dbus_transport_new_for_tcp_socket (const char     *host,
01202                                     dbus_int32_t    port,
01203                                     DBusError      *error)
01204 {
01205   int fd;
01206   DBusTransport *transport;
01207   DBusString address;
01208   
01209   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
01210 
01211   if (!_dbus_string_init (&address))
01212     {
01213       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
01214       return NULL;
01215     }
01216   
01217   if (!_dbus_string_append (&address, "tcp:"))
01218     goto error;
01219 
01220   if (host != NULL && 
01221        (!_dbus_string_append (&address, "host=") ||
01222         !_dbus_string_append (&address, host)))
01223     goto error;
01224 
01225   if (!_dbus_string_append (&address, ",port=") ||
01226       !_dbus_string_append_int (&address, port))
01227     goto error;
01228 
01229   fd = _dbus_connect_tcp_socket (host, port, error);
01230   if (fd < 0)
01231     {
01232       _DBUS_ASSERT_ERROR_IS_SET (error);
01233       _dbus_string_free (&address);
01234       return NULL;
01235     }
01236 
01237   _dbus_fd_set_close_on_exec (fd);
01238   
01239   _dbus_verbose ("Successfully connected to tcp socket %s:%d\n",
01240                  host, port);
01241   
01242   transport = _dbus_transport_new_for_socket (fd, NULL, &address);
01243   if (transport == NULL)
01244     {
01245       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
01246       _dbus_close_socket (fd, NULL);
01247       _dbus_string_free (&address);
01248       fd = -1;
01249     }
01250 
01251   _dbus_string_free (&address);
01252   
01253   return transport;
01254 
01255 error:
01256   _dbus_string_free (&address);
01257   dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
01258   return NULL;
01259 }
01260 
01269 DBusTransportOpenResult
01270 _dbus_transport_open_socket(DBusAddressEntry  *entry,
01271                             DBusTransport    **transport_p,                            
01272                             DBusError         *error)
01273 {
01274   const char *method;
01275   
01276   method = dbus_address_entry_get_method (entry);
01277   _dbus_assert (method != NULL);
01278 
01279   if (strcmp (method, "tcp") == 0)
01280     {
01281       const char *host = dbus_address_entry_get_value (entry, "host");
01282       const char *port = dbus_address_entry_get_value (entry, "port");
01283       DBusString  str;
01284       long lport;
01285       dbus_bool_t sresult;
01286           
01287       if (port == NULL)
01288         {
01289           _dbus_set_bad_address (error, "tcp", "port", NULL);
01290           return DBUS_TRANSPORT_OPEN_BAD_ADDRESS;
01291         }
01292 
01293       _dbus_string_init_const (&str, port);
01294       sresult = _dbus_string_parse_int (&str, 0, &lport, NULL);
01295       _dbus_string_free (&str);
01296           
01297       if (sresult == FALSE || lport <= 0 || lport > 65535)
01298         {
01299           _dbus_set_bad_address (error, NULL, NULL,
01300                                  "Port is not an integer between 0 and 65535");
01301           return DBUS_TRANSPORT_OPEN_BAD_ADDRESS;
01302         }
01303           
01304       *transport_p = _dbus_transport_new_for_tcp_socket (host, lport, error);
01305       if (*transport_p == NULL)
01306         {
01307           _DBUS_ASSERT_ERROR_IS_SET (error);
01308           return DBUS_TRANSPORT_OPEN_DID_NOT_CONNECT;
01309         }
01310       else
01311         {
01312           _DBUS_ASSERT_ERROR_IS_CLEAR (error);
01313           return DBUS_TRANSPORT_OPEN_OK;
01314         }
01315     }
01316   else
01317     {
01318       _DBUS_ASSERT_ERROR_IS_CLEAR (error);
01319       return DBUS_TRANSPORT_OPEN_NOT_HANDLED;
01320     }
01321 }
01322 

Generated on Fri Sep 21 18:12:13 2007 for D-Bus by  doxygen 1.5.1