dbus-transport-socket.c

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

Generated on Mon Feb 1 19:15:26 2010 for D-Bus by  doxygen 1.4.7