Main Page | Modules | Data Structures | Directories | File List | Data Fields | Related Pages

dbus-transport-unix.c

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

Generated on Wed Jan 3 04:49:05 2007 for D-BUS by  doxygen 1.4.4