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 = DBUS_ERROR_INIT;
00342 
00343   _dbus_verbose ("exchange_credentials: do_reading = %d, do_writing = %d\n",
00344                   do_reading, do_writing);
00345 
00346   if (do_writing && transport->send_credentials_pending)
00347     {
00348       if (_dbus_send_credentials_socket (socket_transport->fd,
00349                                          &error))
00350         {
00351           transport->send_credentials_pending = FALSE;
00352         }
00353       else
00354         {
00355           _dbus_verbose ("Failed to write credentials: %s\n", error.message);
00356           dbus_error_free (&error);
00357           do_io_error (transport);
00358         }
00359     }
00360   
00361   if (do_reading && transport->receive_credentials_pending)
00362     {
00363       /* FIXME this can fail due to IO error _or_ OOM, broken
00364        * (somewhat tricky to fix since the OOM error can be set after
00365        * we already read the credentials byte, so basically we need to
00366        * separate reading the byte and storing it in the
00367        * transport->credentials). Does not really matter for now
00368        * because storing in credentials never actually fails on unix.
00369        */      
00370       if (_dbus_read_credentials_socket (socket_transport->fd,
00371                                          transport->credentials,
00372                                          &error))
00373         {
00374           transport->receive_credentials_pending = FALSE;
00375         }
00376       else
00377         {
00378           _dbus_verbose ("Failed to read credentials %s\n", error.message);
00379           dbus_error_free (&error);
00380           do_io_error (transport);
00381         }
00382     }
00383 
00384   if (!(transport->send_credentials_pending ||
00385         transport->receive_credentials_pending))
00386     {
00387       if (!_dbus_auth_set_credentials (transport->auth,
00388                                        transport->credentials))
00389         return FALSE;
00390     }
00391 
00392   return TRUE;
00393 }
00394 
00395 static dbus_bool_t
00396 do_authentication (DBusTransport *transport,
00397                    dbus_bool_t    do_reading,
00398                    dbus_bool_t    do_writing,
00399                    dbus_bool_t   *auth_completed)
00400 {
00401   dbus_bool_t oom;
00402   dbus_bool_t orig_auth_state;
00403 
00404   oom = FALSE;
00405   
00406   orig_auth_state = _dbus_transport_get_is_authenticated (transport);
00407 
00408   /* This is essential to avoid the check_write_watch() at the end,
00409    * we don't want to add a write watch in do_iteration before
00410    * we try writing and get EAGAIN
00411    */
00412   if (orig_auth_state)
00413     {
00414       if (auth_completed)
00415         *auth_completed = FALSE;
00416       return TRUE;
00417     }
00418   
00419   _dbus_transport_ref (transport);
00420   
00421   while (!_dbus_transport_get_is_authenticated (transport) &&
00422          _dbus_transport_get_is_connected (transport))
00423     {      
00424       if (!exchange_credentials (transport, do_reading, do_writing))
00425         {
00426           /* OOM */
00427           oom = TRUE;
00428           goto out;
00429         }
00430       
00431       if (transport->send_credentials_pending ||
00432           transport->receive_credentials_pending)
00433         {
00434           _dbus_verbose ("send_credentials_pending = %d receive_credentials_pending = %d\n",
00435                          transport->send_credentials_pending,
00436                          transport->receive_credentials_pending);
00437           goto out;
00438         }
00439 
00440 #define TRANSPORT_SIDE(t) ((t)->is_server ? "server" : "client")
00441       switch (_dbus_auth_do_work (transport->auth))
00442         {
00443         case DBUS_AUTH_STATE_WAITING_FOR_INPUT:
00444           _dbus_verbose (" %s auth state: waiting for input\n",
00445                          TRANSPORT_SIDE (transport));
00446           if (!do_reading || !read_data_into_auth (transport, &oom))
00447             goto out;
00448           break;
00449       
00450         case DBUS_AUTH_STATE_WAITING_FOR_MEMORY:
00451           _dbus_verbose (" %s auth state: waiting for memory\n",
00452                          TRANSPORT_SIDE (transport));
00453           oom = TRUE;
00454           goto out;
00455           break;
00456       
00457         case DBUS_AUTH_STATE_HAVE_BYTES_TO_SEND:
00458           _dbus_verbose (" %s auth state: bytes to send\n",
00459                          TRANSPORT_SIDE (transport));
00460           if (!do_writing || !write_data_from_auth (transport))
00461             goto out;
00462           break;
00463       
00464         case DBUS_AUTH_STATE_NEED_DISCONNECT:
00465           _dbus_verbose (" %s auth state: need to disconnect\n",
00466                          TRANSPORT_SIDE (transport));
00467           do_io_error (transport);
00468           break;
00469       
00470         case DBUS_AUTH_STATE_AUTHENTICATED:
00471           _dbus_verbose (" %s auth state: authenticated\n",
00472                          TRANSPORT_SIDE (transport));
00473           break;
00474         }
00475     }
00476 
00477  out:
00478   if (auth_completed)
00479     *auth_completed = (orig_auth_state != _dbus_transport_get_is_authenticated (transport));
00480   
00481   check_read_watch (transport);
00482   check_write_watch (transport);
00483   _dbus_transport_unref (transport);
00484 
00485   if (oom)
00486     return FALSE;
00487   else
00488     return TRUE;
00489 }
00490 
00491 /* returns false on oom */
00492 static dbus_bool_t
00493 do_writing (DBusTransport *transport)
00494 {
00495   int total;
00496   DBusTransportSocket *socket_transport = (DBusTransportSocket*) transport;
00497   dbus_bool_t oom;
00498   
00499   /* No messages without authentication! */
00500   if (!_dbus_transport_get_is_authenticated (transport))
00501     {
00502       _dbus_verbose ("Not authenticated, not writing anything\n");
00503       return TRUE;
00504     }
00505 
00506   if (transport->disconnected)
00507     {
00508       _dbus_verbose ("Not connected, not writing anything\n");
00509       return TRUE;
00510     }
00511 
00512 #if 1
00513   _dbus_verbose ("do_writing(), have_messages = %d, fd = %d\n",
00514                  _dbus_connection_has_messages_to_send_unlocked (transport->connection),
00515                  socket_transport->fd);
00516 #endif
00517   
00518   oom = FALSE;
00519   total = 0;
00520 
00521   while (!transport->disconnected &&
00522          _dbus_connection_has_messages_to_send_unlocked (transport->connection))
00523     {
00524       int bytes_written;
00525       DBusMessage *message;
00526       const DBusString *header;
00527       const DBusString *body;
00528       int header_len, body_len;
00529       int total_bytes_to_write;
00530       
00531       if (total > socket_transport->max_bytes_written_per_iteration)
00532         {
00533           _dbus_verbose ("%d bytes exceeds %d bytes written per iteration, returning\n",
00534                          total, socket_transport->max_bytes_written_per_iteration);
00535           goto out;
00536         }
00537       
00538       message = _dbus_connection_get_message_to_send (transport->connection);
00539       _dbus_assert (message != NULL);
00540       _dbus_message_lock (message);
00541 
00542 #if 0
00543       _dbus_verbose ("writing message %p\n", message);
00544 #endif
00545       
00546       _dbus_message_get_network_data (message,
00547                                       &header, &body);
00548 
00549       header_len = _dbus_string_get_length (header);
00550       body_len = _dbus_string_get_length (body);
00551 
00552       if (_dbus_auth_needs_encoding (transport->auth))
00553         {
00554           if (_dbus_string_get_length (&socket_transport->encoded_outgoing) == 0)
00555             {
00556               if (!_dbus_auth_encode_data (transport->auth,
00557                                            header, &socket_transport->encoded_outgoing))
00558                 {
00559                   oom = TRUE;
00560                   goto out;
00561                 }
00562               
00563               if (!_dbus_auth_encode_data (transport->auth,
00564                                            body, &socket_transport->encoded_outgoing))
00565                 {
00566                   _dbus_string_set_length (&socket_transport->encoded_outgoing, 0);
00567                   oom = TRUE;
00568                   goto out;
00569                 }
00570             }
00571           
00572           total_bytes_to_write = _dbus_string_get_length (&socket_transport->encoded_outgoing);
00573 
00574 #if 0
00575           _dbus_verbose ("encoded message is %d bytes\n",
00576                          total_bytes_to_write);
00577 #endif
00578           
00579           bytes_written =
00580             _dbus_write_socket (socket_transport->fd,
00581                                 &socket_transport->encoded_outgoing,
00582                                 socket_transport->message_bytes_written,
00583                                 total_bytes_to_write - socket_transport->message_bytes_written);
00584         }
00585       else
00586         {
00587           total_bytes_to_write = header_len + body_len;
00588 
00589 #if 0
00590           _dbus_verbose ("message is %d bytes\n",
00591                          total_bytes_to_write);          
00592 #endif
00593           
00594           if (socket_transport->message_bytes_written < header_len)
00595             {
00596               bytes_written =
00597                 _dbus_write_socket_two (socket_transport->fd,
00598                                         header,
00599                                         socket_transport->message_bytes_written,
00600                                         header_len - socket_transport->message_bytes_written,
00601                                         body,
00602                                         0, body_len);
00603             }
00604           else
00605             {
00606               bytes_written =
00607                 _dbus_write_socket (socket_transport->fd,
00608                                     body,
00609                                     (socket_transport->message_bytes_written - header_len),
00610                                     body_len -
00611                                     (socket_transport->message_bytes_written - header_len));
00612             }
00613         }
00614 
00615       if (bytes_written < 0)
00616         {
00617           /* EINTR already handled for us */
00618           
00619           if (_dbus_get_is_errno_eagain_or_ewouldblock ())
00620             goto out;
00621           else
00622             {
00623               _dbus_verbose ("Error writing to remote app: %s\n",
00624                              _dbus_strerror_from_errno ());
00625               do_io_error (transport);
00626               goto out;
00627             }
00628         }
00629       else
00630         {
00631           _dbus_verbose (" wrote %d bytes of %d\n", bytes_written,
00632                          total_bytes_to_write);
00633           
00634           total += bytes_written;
00635           socket_transport->message_bytes_written += bytes_written;
00636 
00637           _dbus_assert (socket_transport->message_bytes_written <=
00638                         total_bytes_to_write);
00639           
00640           if (socket_transport->message_bytes_written == total_bytes_to_write)
00641             {
00642               socket_transport->message_bytes_written = 0;
00643               _dbus_string_set_length (&socket_transport->encoded_outgoing, 0);
00644               _dbus_string_compact (&socket_transport->encoded_outgoing, 2048);
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               _dbus_message_loader_return_buffer (transport->loader,
00728                                               buffer,
00729                                               _dbus_string_get_length (buffer) - orig_len);
00730 
00731               oom = TRUE;
00732               goto out;
00733             }
00734 
00735           _dbus_message_loader_return_buffer (transport->loader,
00736                                               buffer,
00737                                               _dbus_string_get_length (buffer) - orig_len);
00738 
00739           _dbus_string_set_length (&socket_transport->encoded_incoming, 0);
00740           _dbus_string_compact (&socket_transport->encoded_incoming, 2048);
00741         }
00742     }
00743   else
00744     {
00745       _dbus_message_loader_get_buffer (transport->loader,
00746                                        &buffer);
00747       
00748       bytes_read = _dbus_read_socket (socket_transport->fd,
00749                                       buffer, socket_transport->max_bytes_read_per_iteration);
00750       
00751       _dbus_message_loader_return_buffer (transport->loader,
00752                                           buffer,
00753                                           bytes_read < 0 ? 0 : bytes_read);
00754     }
00755   
00756   if (bytes_read < 0)
00757     {
00758       /* EINTR already handled for us */
00759 
00760       if (_dbus_get_is_errno_enomem ())
00761         {
00762           _dbus_verbose ("Out of memory in read()/do_reading()\n");
00763           oom = TRUE;
00764           goto out;
00765         }
00766       else if (_dbus_get_is_errno_eagain_or_ewouldblock ())
00767         goto out;
00768       else
00769         {
00770           _dbus_verbose ("Error reading from remote app: %s\n",
00771                          _dbus_strerror_from_errno ());
00772           do_io_error (transport);
00773           goto out;
00774         }
00775     }
00776   else if (bytes_read == 0)
00777     {
00778       _dbus_verbose ("Disconnected from remote app\n");
00779       do_io_error (transport);
00780       goto out;
00781     }
00782   else
00783     {
00784       _dbus_verbose (" read %d bytes\n", bytes_read);
00785       
00786       total += bytes_read;      
00787 
00788       if (!_dbus_transport_queue_messages (transport))
00789         {
00790           oom = TRUE;
00791           _dbus_verbose (" out of memory when queueing messages we just read in the transport\n");
00792           goto out;
00793         }
00794       
00795       /* Try reading more data until we get EAGAIN and return, or
00796        * exceed max bytes per iteration.  If in blocking mode of
00797        * course we'll block instead of returning.
00798        */
00799       goto again;
00800     }
00801 
00802  out:
00803   if (oom)
00804     return FALSE;
00805   else
00806     return TRUE;
00807 }
00808 
00809 static dbus_bool_t
00810 socket_handle_watch (DBusTransport *transport,
00811                    DBusWatch     *watch,
00812                    unsigned int   flags)
00813 {
00814   DBusTransportSocket *socket_transport = (DBusTransportSocket*) transport;
00815 
00816   _dbus_assert (watch == socket_transport->read_watch ||
00817                 watch == socket_transport->write_watch);
00818   _dbus_assert (watch != NULL);
00819   
00820   /* Disconnect in case of an error.  In case of hangup do not
00821    * disconnect the transport because data can still be in the buffer
00822    * and do_reading may need several iteration to read it all (because
00823    * of its max_bytes_read_per_iteration limit).  The condition where
00824    * flags == HANGUP (without READABLE) probably never happen in fact.
00825    */
00826   if ((flags & DBUS_WATCH_ERROR) ||
00827       ((flags & DBUS_WATCH_HANGUP) && !(flags & DBUS_WATCH_READABLE)))
00828     {
00829       _dbus_verbose ("Hang up or error on watch\n");
00830       _dbus_transport_disconnect (transport);
00831       return TRUE;
00832     }
00833   
00834   if (watch == socket_transport->read_watch &&
00835       (flags & DBUS_WATCH_READABLE))
00836     {
00837       dbus_bool_t auth_finished;
00838 #if 1
00839       _dbus_verbose ("handling read watch %p flags = %x\n",
00840                      watch, flags);
00841 #endif
00842       if (!do_authentication (transport, TRUE, FALSE, &auth_finished))
00843         return FALSE;
00844 
00845       /* We don't want to do a read immediately following
00846        * a successful authentication.  This is so we
00847        * have a chance to propagate the authentication
00848        * state further up.  Specifically, we need to
00849        * process any pending data from the auth object.
00850        */
00851       if (!auth_finished)
00852         {
00853           if (!do_reading (transport))
00854             {
00855               _dbus_verbose ("no memory to read\n");
00856               return FALSE;
00857             }
00858         }
00859       else
00860         {
00861           _dbus_verbose ("Not reading anything since we just completed the authentication\n");
00862         }
00863     }
00864   else if (watch == socket_transport->write_watch &&
00865            (flags & DBUS_WATCH_WRITABLE))
00866     {
00867 #if 1
00868       _dbus_verbose ("handling write watch, have_outgoing_messages = %d\n",
00869                      _dbus_connection_has_messages_to_send_unlocked (transport->connection));
00870 #endif
00871       if (!do_authentication (transport, FALSE, TRUE, NULL))
00872         return FALSE;
00873       
00874       if (!do_writing (transport))
00875         {
00876           _dbus_verbose ("no memory to write\n");
00877           return FALSE;
00878         }
00879 
00880       /* See if we still need the write watch */
00881       check_write_watch (transport);
00882     }
00883 #ifdef DBUS_ENABLE_VERBOSE_MODE
00884   else
00885     {
00886       if (watch == socket_transport->read_watch)
00887         _dbus_verbose ("asked to handle read watch with non-read condition 0x%x\n",
00888                        flags);
00889       else if (watch == socket_transport->write_watch)
00890         _dbus_verbose ("asked to handle write watch with non-write condition 0x%x\n",
00891                        flags);
00892       else
00893         _dbus_verbose ("asked to handle watch %p on fd %d that we don't recognize\n",
00894                        watch, dbus_watch_get_socket (watch));
00895     }
00896 #endif /* DBUS_ENABLE_VERBOSE_MODE */
00897 
00898   return TRUE;
00899 }
00900 
00901 static void
00902 socket_disconnect (DBusTransport *transport)
00903 {
00904   DBusTransportSocket *socket_transport = (DBusTransportSocket*) transport;
00905 
00906   _dbus_verbose ("%s\n", _DBUS_FUNCTION_NAME);
00907   
00908   free_watches (transport);
00909   
00910   _dbus_close_socket (socket_transport->fd, NULL);
00911   socket_transport->fd = -1;
00912 }
00913 
00914 static dbus_bool_t
00915 socket_connection_set (DBusTransport *transport)
00916 {
00917   DBusTransportSocket *socket_transport = (DBusTransportSocket*) transport;
00918 
00919   _dbus_watch_set_handler (socket_transport->write_watch,
00920                            _dbus_connection_handle_watch,
00921                            transport->connection, NULL);
00922 
00923   _dbus_watch_set_handler (socket_transport->read_watch,
00924                            _dbus_connection_handle_watch,
00925                            transport->connection, NULL);
00926   
00927   if (!_dbus_connection_add_watch_unlocked (transport->connection,
00928                                             socket_transport->write_watch))
00929     return FALSE;
00930 
00931   if (!_dbus_connection_add_watch_unlocked (transport->connection,
00932                                             socket_transport->read_watch))
00933     {
00934       _dbus_connection_remove_watch_unlocked (transport->connection,
00935                                               socket_transport->write_watch);
00936       return FALSE;
00937     }
00938 
00939   check_read_watch (transport);
00940   check_write_watch (transport);
00941 
00942   return TRUE;
00943 }
00944 
00952 static  void
00953 socket_do_iteration (DBusTransport *transport,
00954                    unsigned int   flags,
00955                    int            timeout_milliseconds)
00956 {
00957   DBusTransportSocket *socket_transport = (DBusTransportSocket*) transport;
00958   DBusPollFD poll_fd;
00959   int poll_res;
00960   int poll_timeout;
00961 
00962   _dbus_verbose (" iteration flags = %s%s timeout = %d read_watch = %p write_watch = %p fd = %d\n",
00963                  flags & DBUS_ITERATION_DO_READING ? "read" : "",
00964                  flags & DBUS_ITERATION_DO_WRITING ? "write" : "",
00965                  timeout_milliseconds,
00966                  socket_transport->read_watch,
00967                  socket_transport->write_watch,
00968                  socket_transport->fd);
00969   
00970   /* the passed in DO_READING/DO_WRITING flags indicate whether to
00971    * read/write messages, but regardless of those we may need to block
00972    * for reading/writing to do auth.  But if we do reading for auth,
00973    * we don't want to read any messages yet if not given DO_READING.
00974    */
00975 
00976   poll_fd.fd = socket_transport->fd;
00977   poll_fd.events = 0;
00978   
00979   if (_dbus_transport_get_is_authenticated (transport))
00980     {
00981       /* This is kind of a hack; if we have stuff to write, then try
00982        * to avoid the poll. This is probably about a 5% speedup on an
00983        * echo client/server.
00984        *
00985        * If both reading and writing were requested, we want to avoid this
00986        * since it could have funky effects:
00987        *   - both ends spinning waiting for the other one to read
00988        *     data so they can finish writing
00989        *   - prioritizing all writing ahead of reading
00990        */
00991       if ((flags & DBUS_ITERATION_DO_WRITING) &&
00992           !(flags & (DBUS_ITERATION_DO_READING | DBUS_ITERATION_BLOCK)) &&
00993           !transport->disconnected &&
00994           _dbus_connection_has_messages_to_send_unlocked (transport->connection))
00995         {
00996           do_writing (transport);
00997 
00998           if (transport->disconnected ||
00999               !_dbus_connection_has_messages_to_send_unlocked (transport->connection))
01000             goto out;
01001         }
01002 
01003       /* If we get here, we decided to do the poll() after all */
01004       _dbus_assert (socket_transport->read_watch);
01005       if (flags & DBUS_ITERATION_DO_READING)
01006         poll_fd.events |= _DBUS_POLLIN;
01007 
01008       _dbus_assert (socket_transport->write_watch);
01009       if (flags & DBUS_ITERATION_DO_WRITING)
01010         poll_fd.events |= _DBUS_POLLOUT;
01011     }
01012   else
01013     {
01014       DBusAuthState auth_state;
01015       
01016       auth_state = _dbus_auth_do_work (transport->auth);
01017 
01018       if (transport->receive_credentials_pending ||
01019           auth_state == DBUS_AUTH_STATE_WAITING_FOR_INPUT)
01020         poll_fd.events |= _DBUS_POLLIN;
01021 
01022       if (transport->send_credentials_pending ||
01023           auth_state == DBUS_AUTH_STATE_HAVE_BYTES_TO_SEND)
01024         poll_fd.events |= _DBUS_POLLOUT;
01025     }
01026 
01027   if (poll_fd.events)
01028     {
01029       if (flags & DBUS_ITERATION_BLOCK)
01030         poll_timeout = timeout_milliseconds;
01031       else
01032         poll_timeout = 0;
01033 
01034       /* For blocking selects we drop the connection lock here
01035        * to avoid blocking out connection access during a potentially
01036        * indefinite blocking call. The io path is still protected
01037        * by the io_path_cond condvar, so we won't reenter this.
01038        */
01039       if (flags & DBUS_ITERATION_BLOCK)
01040         {
01041           _dbus_verbose ("unlock %s pre poll\n", _DBUS_FUNCTION_NAME);
01042           _dbus_connection_unlock (transport->connection);
01043         }
01044       
01045     again:
01046       poll_res = _dbus_poll (&poll_fd, 1, poll_timeout);
01047 
01048       if (poll_res < 0 && _dbus_get_is_errno_eintr ())
01049         goto again;
01050 
01051       if (flags & DBUS_ITERATION_BLOCK)
01052         {
01053           _dbus_verbose ("lock %s post poll\n", _DBUS_FUNCTION_NAME);
01054           _dbus_connection_lock (transport->connection);
01055         }
01056       
01057       if (poll_res >= 0)
01058         {
01059           if (poll_res == 0)
01060             poll_fd.revents = 0; /* some concern that posix does not guarantee this;
01061                                   * valgrind flags it as an error. though it probably
01062                                   * is guaranteed on linux at least.
01063                                   */
01064           
01065           if (poll_fd.revents & _DBUS_POLLERR)
01066             do_io_error (transport);
01067           else
01068             {
01069               dbus_bool_t need_read = (poll_fd.revents & _DBUS_POLLIN) > 0;
01070               dbus_bool_t need_write = (poll_fd.revents & _DBUS_POLLOUT) > 0;
01071               dbus_bool_t authentication_completed;
01072 
01073               _dbus_verbose ("in iteration, need_read=%d need_write=%d\n",
01074                              need_read, need_write);
01075               do_authentication (transport, need_read, need_write,
01076                                  &authentication_completed);
01077 
01078               /* See comment in socket_handle_watch. */
01079               if (authentication_completed)
01080                 goto out;
01081                                  
01082               if (need_read && (flags & DBUS_ITERATION_DO_READING))
01083                 do_reading (transport);
01084               if (need_write && (flags & DBUS_ITERATION_DO_WRITING))
01085                 do_writing (transport);
01086             }
01087         }
01088       else
01089         {
01090           _dbus_verbose ("Error from _dbus_poll(): %s\n",
01091                          _dbus_strerror_from_errno ());
01092         }
01093     }
01094 
01095 
01096  out:
01097   /* We need to install the write watch only if we did not
01098    * successfully write everything. Note we need to be careful that we
01099    * don't call check_write_watch *before* do_writing, since it's
01100    * inefficient to add the write watch, and we can avoid it most of
01101    * the time since we can write immediately.
01102    * 
01103    * However, we MUST always call check_write_watch(); DBusConnection code
01104    * relies on the fact that running an iteration will notice that
01105    * messages are pending.
01106    */
01107   check_write_watch (transport);
01108 
01109   _dbus_verbose (" ... leaving do_iteration()\n");
01110 }
01111 
01112 static void
01113 socket_live_messages_changed (DBusTransport *transport)
01114 {
01115   /* See if we should look for incoming messages again */
01116   check_read_watch (transport);
01117 }
01118 
01119 
01120 static dbus_bool_t
01121 socket_get_socket_fd (DBusTransport *transport,
01122                       int           *fd_p)
01123 {
01124   DBusTransportSocket *socket_transport = (DBusTransportSocket*) transport;
01125   
01126   *fd_p = socket_transport->fd;
01127   
01128   return TRUE;
01129 }
01130 
01131 static const DBusTransportVTable socket_vtable = {
01132   socket_finalize,
01133   socket_handle_watch,
01134   socket_disconnect,
01135   socket_connection_set,
01136   socket_do_iteration,
01137   socket_live_messages_changed,
01138   socket_get_socket_fd
01139 };
01140 
01152 DBusTransport*
01153 _dbus_transport_new_for_socket (int               fd,
01154                                 const DBusString *server_guid,
01155                                 const DBusString *address)
01156 {
01157   DBusTransportSocket *socket_transport;
01158   
01159   socket_transport = dbus_new0 (DBusTransportSocket, 1);
01160   if (socket_transport == NULL)
01161     return NULL;
01162 
01163   if (!_dbus_string_init (&socket_transport->encoded_outgoing))
01164     goto failed_0;
01165 
01166   if (!_dbus_string_init (&socket_transport->encoded_incoming))
01167     goto failed_1;
01168   
01169   socket_transport->write_watch = _dbus_watch_new (fd,
01170                                                  DBUS_WATCH_WRITABLE,
01171                                                  FALSE,
01172                                                  NULL, NULL, NULL);
01173   if (socket_transport->write_watch == NULL)
01174     goto failed_2;
01175   
01176   socket_transport->read_watch = _dbus_watch_new (fd,
01177                                                 DBUS_WATCH_READABLE,
01178                                                 FALSE,
01179                                                 NULL, NULL, NULL);
01180   if (socket_transport->read_watch == NULL)
01181     goto failed_3;
01182 
01183   if (!_dbus_transport_init_base (&socket_transport->base,
01184                                   &socket_vtable,
01185                                   server_guid, address))
01186     goto failed_4;
01187   
01188   socket_transport->fd = fd;
01189   socket_transport->message_bytes_written = 0;
01190   
01191   /* These values should probably be tunable or something. */     
01192   socket_transport->max_bytes_read_per_iteration = 2048;
01193   socket_transport->max_bytes_written_per_iteration = 2048;
01194   
01195   return (DBusTransport*) socket_transport;
01196 
01197  failed_4:
01198   _dbus_watch_unref (socket_transport->read_watch);
01199  failed_3:
01200   _dbus_watch_unref (socket_transport->write_watch);
01201  failed_2:
01202   _dbus_string_free (&socket_transport->encoded_incoming);
01203  failed_1:
01204   _dbus_string_free (&socket_transport->encoded_outgoing);
01205  failed_0:
01206   dbus_free (socket_transport);
01207   return NULL;
01208 }
01209 
01220 DBusTransport*
01221 _dbus_transport_new_for_tcp_socket (const char     *host,
01222                                     const char     *port,
01223                                     const char     *family,
01224                                     DBusError      *error)
01225 {
01226   int fd;
01227   DBusTransport *transport;
01228   DBusString address;
01229   
01230   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
01231 
01232   if (!_dbus_string_init (&address))
01233     {
01234       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
01235       return NULL;
01236     }
01237 
01238   if (host == NULL)
01239     host = "localhost";
01240 
01241   if (!_dbus_string_append (&address, "tcp:"))
01242     goto error;
01243 
01244   if (!_dbus_string_append (&address, "host=") ||
01245       !_dbus_string_append (&address, host))
01246     goto error;
01247 
01248   if (!_dbus_string_append (&address, ",port=") ||
01249       !_dbus_string_append (&address, port))
01250     goto error;
01251 
01252   if (family != NULL &&
01253       (!_dbus_string_append (&address, "family=") ||
01254        !_dbus_string_append (&address, family)))
01255     goto error;
01256 
01257   fd = _dbus_connect_tcp_socket (host, port, family, error);
01258   if (fd < 0)
01259     {
01260       _DBUS_ASSERT_ERROR_IS_SET (error);
01261       _dbus_string_free (&address);
01262       return NULL;
01263     }
01264 
01265   _dbus_fd_set_close_on_exec (fd);
01266   
01267   _dbus_verbose ("Successfully connected to tcp socket %s:%s\n",
01268                  host, port);
01269   
01270   transport = _dbus_transport_new_for_socket (fd, NULL, &address);
01271   if (transport == NULL)
01272     {
01273       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
01274       _dbus_close_socket (fd, NULL);
01275       _dbus_string_free (&address);
01276       fd = -1;
01277     }
01278 
01279   _dbus_string_free (&address);
01280   
01281   return transport;
01282 
01283 error:
01284   _dbus_string_free (&address);
01285   dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
01286   return NULL;
01287 }
01288 
01297 DBusTransportOpenResult
01298 _dbus_transport_open_socket(DBusAddressEntry  *entry,
01299                             DBusTransport    **transport_p,                            
01300                             DBusError         *error)
01301 {
01302   const char *method;
01303   
01304   method = dbus_address_entry_get_method (entry);
01305   _dbus_assert (method != NULL);
01306 
01307   if (strcmp (method, "tcp") == 0)
01308     {
01309       const char *host = dbus_address_entry_get_value (entry, "host");
01310       const char *port = dbus_address_entry_get_value (entry, "port");
01311       const char *family = dbus_address_entry_get_value (entry, "family");
01312 
01313       if (port == NULL)
01314         {
01315           _dbus_set_bad_address (error, "tcp", "port", NULL);
01316           return DBUS_TRANSPORT_OPEN_BAD_ADDRESS;
01317         }
01318 
01319       *transport_p = _dbus_transport_new_for_tcp_socket (host, port, family, error);
01320       if (*transport_p == NULL)
01321         {
01322           _DBUS_ASSERT_ERROR_IS_SET (error);
01323           return DBUS_TRANSPORT_OPEN_DID_NOT_CONNECT;
01324         }
01325       else
01326         {
01327           _DBUS_ASSERT_ERROR_IS_CLEAR (error);
01328           return DBUS_TRANSPORT_OPEN_OK;
01329         }
01330     }
01331   else
01332     {
01333       _DBUS_ASSERT_ERROR_IS_CLEAR (error);
01334       return DBUS_TRANSPORT_OPEN_NOT_HANDLED;
01335     }
01336 }
01337 

Generated on Thu Jan 22 16:37:06 2009 for D-Bus by  doxygen 1.5.1