D-Bus 1.4.20

dbus-watch.c

00001 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
00002 /* dbus-watch.c DBusWatch implementation
00003  *
00004  * Copyright (C) 2002, 2003  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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
00021  *
00022  */
00023 
00024 #include <config.h>
00025 #include "dbus-internals.h"
00026 #include "dbus-watch.h"
00027 #include "dbus-list.h"
00028 
00040 struct DBusWatch
00041 {
00042   int refcount;                        
00043   int fd;                              
00044   unsigned int flags;                  
00046   DBusWatchHandler handler;                    
00047   void *handler_data;                          
00048   DBusFreeFunction free_handler_data_function; 
00050   void *data;                          
00051   DBusFreeFunction free_data_function; 
00052   unsigned int enabled : 1;            
00053 };
00054 
00055 dbus_bool_t
00056 _dbus_watch_get_enabled (DBusWatch *watch)
00057 {
00058   return watch->enabled;
00059 }
00060 
00073 DBusWatch*
00074 _dbus_watch_new (int               fd,
00075                  unsigned int      flags,
00076                  dbus_bool_t       enabled,
00077                  DBusWatchHandler  handler,
00078                  void             *data,
00079                  DBusFreeFunction  free_data_function)
00080 {
00081   DBusWatch *watch;
00082 
00083 #define VALID_WATCH_FLAGS (DBUS_WATCH_WRITABLE | DBUS_WATCH_READABLE)
00084   
00085   _dbus_assert ((flags & VALID_WATCH_FLAGS) == flags);
00086   
00087   watch = dbus_new0 (DBusWatch, 1);
00088   if (watch == NULL)
00089     return NULL;
00090   
00091   watch->refcount = 1;
00092   watch->fd = fd;
00093   watch->flags = flags;
00094   watch->enabled = enabled;
00095 
00096   watch->handler = handler;
00097   watch->handler_data = data;
00098   watch->free_handler_data_function = free_data_function;
00099   
00100   return watch;
00101 }
00102 
00109 DBusWatch *
00110 _dbus_watch_ref (DBusWatch *watch)
00111 {
00112   watch->refcount += 1;
00113 
00114   return watch;
00115 }
00116 
00123 void
00124 _dbus_watch_unref (DBusWatch *watch)
00125 {
00126   _dbus_assert (watch != NULL);
00127   _dbus_assert (watch->refcount > 0);
00128 
00129   watch->refcount -= 1;
00130   if (watch->refcount == 0)
00131     {
00132       dbus_watch_set_data (watch, NULL, NULL); /* call free_data_function */
00133 
00134       if (watch->free_handler_data_function)
00135         (* watch->free_handler_data_function) (watch->handler_data);
00136       
00137       dbus_free (watch);
00138     }
00139 }
00140 
00151 void
00152 _dbus_watch_invalidate (DBusWatch *watch)
00153 {
00154   watch->fd = -1;
00155   watch->flags = 0;
00156 }
00157 
00167 void
00168 _dbus_watch_sanitize_condition (DBusWatch    *watch,
00169                                 unsigned int *condition)
00170 {
00171   if (!(watch->flags & DBUS_WATCH_READABLE))
00172     *condition &= ~DBUS_WATCH_READABLE;
00173   if (!(watch->flags & DBUS_WATCH_WRITABLE))
00174     *condition &= ~DBUS_WATCH_WRITABLE;
00175 }
00176 
00177 
00197 struct DBusWatchList
00198 {
00199   DBusList *watches;           
00201   DBusAddWatchFunction add_watch_function;    
00202   DBusRemoveWatchFunction remove_watch_function; 
00203   DBusWatchToggledFunction watch_toggled_function; 
00204   void *watch_data;                           
00205   DBusFreeFunction watch_free_data_function;  
00206 };
00207 
00214 DBusWatchList*
00215 _dbus_watch_list_new (void)
00216 {
00217   DBusWatchList *watch_list;
00218 
00219   watch_list = dbus_new0 (DBusWatchList, 1);
00220   if (watch_list == NULL)
00221     return NULL;
00222 
00223   return watch_list;
00224 }
00225 
00231 void
00232 _dbus_watch_list_free (DBusWatchList *watch_list)
00233 {
00234   /* free watch_data and removes watches as a side effect */
00235   _dbus_watch_list_set_functions (watch_list,
00236                                   NULL, NULL, NULL, NULL, NULL);
00237   _dbus_list_foreach (&watch_list->watches,
00238                       (DBusForeachFunction) _dbus_watch_unref,
00239                       NULL);
00240   _dbus_list_clear (&watch_list->watches);
00241 
00242   dbus_free (watch_list);
00243 }
00244 
00259 dbus_bool_t
00260 _dbus_watch_list_set_functions (DBusWatchList           *watch_list,
00261                                 DBusAddWatchFunction     add_function,
00262                                 DBusRemoveWatchFunction  remove_function,
00263                                 DBusWatchToggledFunction toggled_function,
00264                                 void                    *data,
00265                                 DBusFreeFunction         free_data_function)
00266 {
00267   /* Add watches with the new watch function, failing on OOM */
00268   if (add_function != NULL)
00269     {
00270       DBusList *link;
00271       
00272       link = _dbus_list_get_first_link (&watch_list->watches);
00273       while (link != NULL)
00274         {
00275           DBusList *next = _dbus_list_get_next_link (&watch_list->watches,
00276                                                      link);
00277 
00278 #ifdef DBUS_ENABLE_VERBOSE_MODE
00279           {
00280             const char *watch_type;
00281             int flags;
00282 
00283             flags = dbus_watch_get_flags (link->data);
00284             if ((flags & DBUS_WATCH_READABLE) &&
00285                 (flags & DBUS_WATCH_WRITABLE))
00286               watch_type = "readwrite";
00287             else if (flags & DBUS_WATCH_READABLE)
00288               watch_type = "read";
00289             else if (flags & DBUS_WATCH_WRITABLE)
00290               watch_type = "write";
00291             else
00292               watch_type = "not read or write";
00293             
00294             _dbus_verbose ("Adding a %s watch on fd %d using newly-set add watch function\n",
00295                            watch_type,
00296                            dbus_watch_get_socket (link->data));
00297           }
00298 #endif /* DBUS_ENABLE_VERBOSE_MODE */
00299           
00300           if (!(* add_function) (link->data, data))
00301             {
00302               /* remove it all again and return FALSE */
00303               DBusList *link2;
00304               
00305               link2 = _dbus_list_get_first_link (&watch_list->watches);
00306               while (link2 != link)
00307                 {
00308                   DBusList *next = _dbus_list_get_next_link (&watch_list->watches,
00309                                                              link2);
00310                   
00311                   _dbus_verbose ("Removing watch on fd %d using newly-set remove function because initial add failed\n",
00312                                  dbus_watch_get_socket (link2->data));
00313                   
00314                   (* remove_function) (link2->data, data);
00315                   
00316                   link2 = next;
00317                 }
00318 
00319               return FALSE;
00320             }
00321       
00322           link = next;
00323         }
00324     }
00325   
00326   /* Remove all current watches from previous watch handlers */
00327 
00328   if (watch_list->remove_watch_function != NULL)
00329     {
00330       _dbus_verbose ("Removing all pre-existing watches\n");
00331       
00332       _dbus_list_foreach (&watch_list->watches,
00333                           (DBusForeachFunction) watch_list->remove_watch_function,
00334                           watch_list->watch_data);
00335     }
00336 
00337   if (watch_list->watch_free_data_function != NULL)
00338     (* watch_list->watch_free_data_function) (watch_list->watch_data);
00339   
00340   watch_list->add_watch_function = add_function;
00341   watch_list->remove_watch_function = remove_function;
00342   watch_list->watch_toggled_function = toggled_function;
00343   watch_list->watch_data = data;
00344   watch_list->watch_free_data_function = free_data_function;
00345 
00346   return TRUE;
00347 }
00348 
00357 dbus_bool_t
00358 _dbus_watch_list_add_watch (DBusWatchList *watch_list,
00359                             DBusWatch     *watch)
00360 {
00361   if (!_dbus_list_append (&watch_list->watches, watch))
00362     return FALSE;
00363   
00364   _dbus_watch_ref (watch);
00365 
00366   if (watch_list->add_watch_function != NULL)
00367     {
00368       _dbus_verbose ("Adding watch on fd %d\n",
00369                      dbus_watch_get_socket (watch));
00370       
00371       if (!(* watch_list->add_watch_function) (watch,
00372                                                watch_list->watch_data))
00373         {
00374           _dbus_list_remove_last (&watch_list->watches, watch);
00375           _dbus_watch_unref (watch);
00376           return FALSE;
00377         }
00378     }
00379   
00380   return TRUE;
00381 }
00382 
00390 void
00391 _dbus_watch_list_remove_watch  (DBusWatchList *watch_list,
00392                                 DBusWatch     *watch)
00393 {
00394   if (!_dbus_list_remove (&watch_list->watches, watch))
00395     _dbus_assert_not_reached ("Nonexistent watch was removed");
00396   
00397   if (watch_list->remove_watch_function != NULL)
00398     {
00399       _dbus_verbose ("Removing watch on fd %d\n",
00400                      dbus_watch_get_socket (watch));
00401       
00402       (* watch_list->remove_watch_function) (watch,
00403                                              watch_list->watch_data);
00404     }
00405   
00406   _dbus_watch_unref (watch);
00407 }
00408 
00417 void
00418 _dbus_watch_list_toggle_watch (DBusWatchList           *watch_list,
00419                                DBusWatch               *watch,
00420                                dbus_bool_t              enabled)
00421 {
00422   enabled = !!enabled;
00423   
00424   if (enabled == watch->enabled)
00425     return;
00426 
00427   watch->enabled = enabled;
00428   
00429   if (watch_list->watch_toggled_function != NULL)
00430     {
00431       _dbus_verbose ("Toggling watch %p on fd %d to %d\n",
00432                      watch, dbus_watch_get_socket (watch), watch->enabled);
00433       
00434       (* watch_list->watch_toggled_function) (watch,
00435                                               watch_list->watch_data);
00436     }
00437 }
00438 
00451 void
00452 _dbus_watch_set_handler (DBusWatch        *watch,
00453                          DBusWatchHandler  handler,
00454                          void             *data,
00455                          DBusFreeFunction  free_data_function)
00456 {
00457   if (watch->free_handler_data_function)
00458     (* watch->free_handler_data_function) (watch->handler_data);
00459 
00460   watch->handler = handler;
00461   watch->handler_data = data;
00462   watch->free_handler_data_function = free_data_function;
00463 }
00464 
00496 int
00497 dbus_watch_get_fd (DBusWatch *watch)
00498 {
00499   _dbus_return_val_if_fail (watch != NULL, -1);
00500 
00501   return dbus_watch_get_unix_fd(watch);
00502 }
00503 
00517 int
00518 dbus_watch_get_unix_fd (DBusWatch *watch)
00519 {
00520   _dbus_return_val_if_fail (watch != NULL, -1);
00521 
00522   /* FIXME remove #ifdef and do this on a lower level
00523    * (watch should have set_socket and set_unix_fd and track
00524    * which it has, and the transport should provide the
00525    * appropriate watch type)
00526    */
00527 #ifdef DBUS_UNIX
00528   return watch->fd;
00529 #else
00530   return dbus_watch_get_socket( watch );
00531 #endif
00532 }
00533 
00546 int
00547 dbus_watch_get_socket (DBusWatch *watch)
00548 {
00549   _dbus_return_val_if_fail (watch != NULL, -1);
00550 
00551   return watch->fd;
00552 }
00553 
00567 unsigned int
00568 dbus_watch_get_flags (DBusWatch *watch)
00569 {
00570   _dbus_return_val_if_fail (watch != NULL, 0);
00571   _dbus_assert ((watch->flags & VALID_WATCH_FLAGS) == watch->flags);
00572 
00573   return watch->flags;
00574 }
00575 
00583 void*
00584 dbus_watch_get_data (DBusWatch *watch)
00585 {
00586   _dbus_return_val_if_fail (watch != NULL, NULL);
00587 
00588   return watch->data;
00589 }
00590 
00602 void
00603 dbus_watch_set_data (DBusWatch        *watch,
00604                      void             *data,
00605                      DBusFreeFunction  free_data_function)
00606 {
00607   _dbus_return_if_fail (watch != NULL);
00608 
00609   _dbus_verbose ("Setting watch fd %d data to data = %p function = %p from data = %p function = %p\n",
00610                  dbus_watch_get_socket (watch),
00611                  data, free_data_function, watch->data, watch->free_data_function);
00612   
00613   if (watch->free_data_function != NULL)
00614     (* watch->free_data_function) (watch->data);
00615   
00616   watch->data = data;
00617   watch->free_data_function = free_data_function;
00618 }
00619 
00627 dbus_bool_t
00628 dbus_watch_get_enabled (DBusWatch *watch)
00629 {
00630   _dbus_return_val_if_fail (watch != NULL, FALSE);
00631 
00632   return watch->enabled;
00633 }
00634 
00635 
00658 dbus_bool_t
00659 dbus_watch_handle (DBusWatch    *watch,
00660                    unsigned int  flags)
00661 {
00662   _dbus_return_val_if_fail (watch != NULL, FALSE);
00663 
00664 #ifndef DBUS_DISABLE_CHECKS
00665   if (watch->fd < 0 || watch->flags == 0)
00666     {
00667       _dbus_warn_check_failed ("Watch is invalid, it should have been removed\n");
00668       return TRUE;
00669     }
00670 #endif
00671     
00672   _dbus_return_val_if_fail (watch->fd >= 0 /* fails if watch was removed */, TRUE);
00673   
00674   _dbus_watch_sanitize_condition (watch, &flags);
00675 
00676   if (flags == 0)
00677     {
00678       _dbus_verbose ("After sanitization, watch flags on fd %d were 0\n",
00679                      watch->fd);
00680       return TRUE;
00681     }
00682   else
00683     return (* watch->handler) (watch, flags,
00684                                watch->handler_data);
00685 }
00686 
00687