D-Bus  1.8.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   unsigned int oom_last_time : 1;      
00054 };
00055 
00056 dbus_bool_t
00057 _dbus_watch_get_enabled (DBusWatch *watch)
00058 {
00059   return watch->enabled;
00060 }
00061 
00062 dbus_bool_t
00063 _dbus_watch_get_oom_last_time (DBusWatch *watch)
00064 {
00065   return watch->oom_last_time;
00066 }
00067 
00068 void
00069 _dbus_watch_set_oom_last_time (DBusWatch   *watch,
00070                                dbus_bool_t  oom)
00071 {
00072   watch->oom_last_time = oom;
00073 }
00074 
00087 DBusWatch*
00088 _dbus_watch_new (int               fd,
00089                  unsigned int      flags,
00090                  dbus_bool_t       enabled,
00091                  DBusWatchHandler  handler,
00092                  void             *data,
00093                  DBusFreeFunction  free_data_function)
00094 {
00095   DBusWatch *watch;
00096 
00097 #define VALID_WATCH_FLAGS (DBUS_WATCH_WRITABLE | DBUS_WATCH_READABLE)
00098   
00099   _dbus_assert ((flags & VALID_WATCH_FLAGS) == flags);
00100   
00101   watch = dbus_new0 (DBusWatch, 1);
00102   if (watch == NULL)
00103     return NULL;
00104   
00105   watch->refcount = 1;
00106   watch->fd = fd;
00107   watch->flags = flags;
00108   watch->enabled = enabled;
00109 
00110   watch->handler = handler;
00111   watch->handler_data = data;
00112   watch->free_handler_data_function = free_data_function;
00113   
00114   return watch;
00115 }
00116 
00123 DBusWatch *
00124 _dbus_watch_ref (DBusWatch *watch)
00125 {
00126   watch->refcount += 1;
00127 
00128   return watch;
00129 }
00130 
00137 void
00138 _dbus_watch_unref (DBusWatch *watch)
00139 {
00140   _dbus_assert (watch != NULL);
00141   _dbus_assert (watch->refcount > 0);
00142 
00143   watch->refcount -= 1;
00144   if (watch->refcount == 0)
00145     {
00146       if (watch->fd != -1)
00147         _dbus_warn ("this watch should have been invalidated");
00148 
00149       dbus_watch_set_data (watch, NULL, NULL); /* call free_data_function */
00150 
00151       if (watch->free_handler_data_function)
00152         (* watch->free_handler_data_function) (watch->handler_data);
00153       
00154       dbus_free (watch);
00155     }
00156 }
00157 
00168 void
00169 _dbus_watch_invalidate (DBusWatch *watch)
00170 {
00171   watch->fd = -1;
00172   watch->flags = 0;
00173 }
00174 
00184 void
00185 _dbus_watch_sanitize_condition (DBusWatch    *watch,
00186                                 unsigned int *condition)
00187 {
00188   if (!(watch->flags & DBUS_WATCH_READABLE))
00189     *condition &= ~DBUS_WATCH_READABLE;
00190   if (!(watch->flags & DBUS_WATCH_WRITABLE))
00191     *condition &= ~DBUS_WATCH_WRITABLE;
00192 }
00193 
00194 
00214 struct DBusWatchList
00215 {
00216   DBusList *watches;           
00218   DBusAddWatchFunction add_watch_function;    
00219   DBusRemoveWatchFunction remove_watch_function; 
00220   DBusWatchToggledFunction watch_toggled_function; 
00221   void *watch_data;                           
00222   DBusFreeFunction watch_free_data_function;  
00223 };
00224 
00231 DBusWatchList*
00232 _dbus_watch_list_new (void)
00233 {
00234   DBusWatchList *watch_list;
00235 
00236   watch_list = dbus_new0 (DBusWatchList, 1);
00237   if (watch_list == NULL)
00238     return NULL;
00239 
00240   return watch_list;
00241 }
00242 
00248 void
00249 _dbus_watch_list_free (DBusWatchList *watch_list)
00250 {
00251   /* free watch_data and removes watches as a side effect */
00252   _dbus_watch_list_set_functions (watch_list,
00253                                   NULL, NULL, NULL, NULL, NULL);
00254   _dbus_list_foreach (&watch_list->watches,
00255                       (DBusForeachFunction) _dbus_watch_unref,
00256                       NULL);
00257   _dbus_list_clear (&watch_list->watches);
00258 
00259   dbus_free (watch_list);
00260 }
00261 
00262 #ifdef DBUS_ENABLE_VERBOSE_MODE
00263 static const char*
00264 watch_flags_to_string (int flags)
00265 {
00266   const char *watch_type;
00267 
00268   if ((flags & DBUS_WATCH_READABLE) &&
00269       (flags & DBUS_WATCH_WRITABLE))
00270     watch_type = "readwrite";
00271   else if (flags & DBUS_WATCH_READABLE)
00272     watch_type = "read";
00273   else if (flags & DBUS_WATCH_WRITABLE)
00274     watch_type = "write";
00275   else
00276     watch_type = "not read or write";
00277   return watch_type;
00278 }
00279 #endif /* DBUS_ENABLE_VERBOSE_MODE */
00280 
00295 dbus_bool_t
00296 _dbus_watch_list_set_functions (DBusWatchList           *watch_list,
00297                                 DBusAddWatchFunction     add_function,
00298                                 DBusRemoveWatchFunction  remove_function,
00299                                 DBusWatchToggledFunction toggled_function,
00300                                 void                    *data,
00301                                 DBusFreeFunction         free_data_function)
00302 {
00303   /* Add watches with the new watch function, failing on OOM */
00304   if (add_function != NULL)
00305     {
00306       DBusList *link;
00307       
00308       link = _dbus_list_get_first_link (&watch_list->watches);
00309       while (link != NULL)
00310         {
00311           DBusList *next = _dbus_list_get_next_link (&watch_list->watches,
00312                                                      link);
00313 
00314           _dbus_verbose ("Adding a %s watch on fd %d using newly-set add watch function\n",
00315                          watch_flags_to_string (dbus_watch_get_flags (link->data)),
00316                          dbus_watch_get_socket (link->data));
00317           
00318           if (!(* add_function) (link->data, data))
00319             {
00320               /* remove it all again and return FALSE */
00321               DBusList *link2;
00322               
00323               link2 = _dbus_list_get_first_link (&watch_list->watches);
00324               while (link2 != link)
00325                 {
00326                   DBusList *next = _dbus_list_get_next_link (&watch_list->watches,
00327                                                              link2);
00328                   
00329                   _dbus_verbose ("Removing watch on fd %d using newly-set remove function because initial add failed\n",
00330                                  dbus_watch_get_socket (link2->data));
00331                   
00332                   (* remove_function) (link2->data, data);
00333                   
00334                   link2 = next;
00335                 }
00336 
00337               return FALSE;
00338             }
00339       
00340           link = next;
00341         }
00342     }
00343   
00344   /* Remove all current watches from previous watch handlers */
00345 
00346   if (watch_list->remove_watch_function != NULL)
00347     {
00348       _dbus_verbose ("Removing all pre-existing watches\n");
00349       
00350       _dbus_list_foreach (&watch_list->watches,
00351                           (DBusForeachFunction) watch_list->remove_watch_function,
00352                           watch_list->watch_data);
00353     }
00354 
00355   if (watch_list->watch_free_data_function != NULL)
00356     (* watch_list->watch_free_data_function) (watch_list->watch_data);
00357   
00358   watch_list->add_watch_function = add_function;
00359   watch_list->remove_watch_function = remove_function;
00360   watch_list->watch_toggled_function = toggled_function;
00361   watch_list->watch_data = data;
00362   watch_list->watch_free_data_function = free_data_function;
00363 
00364   return TRUE;
00365 }
00366 
00375 dbus_bool_t
00376 _dbus_watch_list_add_watch (DBusWatchList *watch_list,
00377                             DBusWatch     *watch)
00378 {
00379   if (!_dbus_list_append (&watch_list->watches, watch))
00380     return FALSE;
00381   
00382   _dbus_watch_ref (watch);
00383 
00384   if (watch_list->add_watch_function != NULL)
00385     {
00386       _dbus_verbose ("Adding watch on fd %d\n",
00387                      dbus_watch_get_socket (watch));
00388       
00389       if (!(* watch_list->add_watch_function) (watch,
00390                                                watch_list->watch_data))
00391         {
00392           _dbus_list_remove_last (&watch_list->watches, watch);
00393           _dbus_watch_unref (watch);
00394           return FALSE;
00395         }
00396     }
00397   
00398   return TRUE;
00399 }
00400 
00408 void
00409 _dbus_watch_list_remove_watch  (DBusWatchList *watch_list,
00410                                 DBusWatch     *watch)
00411 {
00412   if (!_dbus_list_remove (&watch_list->watches, watch))
00413     _dbus_assert_not_reached ("Nonexistent watch was removed");
00414   
00415   if (watch_list->remove_watch_function != NULL)
00416     {
00417       _dbus_verbose ("Removing watch on fd %d\n",
00418                      dbus_watch_get_socket (watch));
00419       
00420       (* watch_list->remove_watch_function) (watch,
00421                                              watch_list->watch_data);
00422     }
00423   
00424   _dbus_watch_unref (watch);
00425 }
00426 
00435 void
00436 _dbus_watch_list_toggle_watch (DBusWatchList           *watch_list,
00437                                DBusWatch               *watch,
00438                                dbus_bool_t              enabled)
00439 {
00440   enabled = !!enabled;
00441   
00442   if (enabled == watch->enabled)
00443     return;
00444 
00445   watch->enabled = enabled;
00446   
00447   if (watch_list->watch_toggled_function != NULL)
00448     {
00449       _dbus_verbose ("Toggling watch %p on fd %d to %d\n",
00450                      watch, dbus_watch_get_socket (watch), watch->enabled);
00451       
00452       (* watch_list->watch_toggled_function) (watch,
00453                                               watch_list->watch_data);
00454     }
00455 }
00456 
00464 void
00465 _dbus_watch_list_toggle_all_watches (DBusWatchList           *watch_list,
00466                                      dbus_bool_t              enabled)
00467 {
00468   DBusList *link;
00469 
00470   for (link = _dbus_list_get_first_link (&watch_list->watches);
00471        link != NULL;
00472        link = _dbus_list_get_next_link (&watch_list->watches, link))
00473     {
00474       _dbus_watch_list_toggle_watch (watch_list, link->data, enabled);
00475     }
00476 }
00477 
00490 void
00491 _dbus_watch_set_handler (DBusWatch        *watch,
00492                          DBusWatchHandler  handler,
00493                          void             *data,
00494                          DBusFreeFunction  free_data_function)
00495 {
00496   if (watch->free_handler_data_function)
00497     (* watch->free_handler_data_function) (watch->handler_data);
00498 
00499   watch->handler = handler;
00500   watch->handler_data = data;
00501   watch->free_handler_data_function = free_data_function;
00502 }
00503 
00535 int
00536 dbus_watch_get_fd (DBusWatch *watch)
00537 {
00538   _dbus_return_val_if_fail (watch != NULL, -1);
00539 
00540   return dbus_watch_get_unix_fd(watch);
00541 }
00542 
00556 int
00557 dbus_watch_get_unix_fd (DBusWatch *watch)
00558 {
00559   _dbus_return_val_if_fail (watch != NULL, -1);
00560 
00561   /* FIXME remove #ifdef and do this on a lower level
00562    * (watch should have set_socket and set_unix_fd and track
00563    * which it has, and the transport should provide the
00564    * appropriate watch type)
00565    */
00566 #ifdef DBUS_UNIX
00567   return watch->fd;
00568 #else
00569   return dbus_watch_get_socket( watch );
00570 #endif
00571 }
00572 
00585 int
00586 dbus_watch_get_socket (DBusWatch *watch)
00587 {
00588   _dbus_return_val_if_fail (watch != NULL, -1);
00589 
00590   return watch->fd;
00591 }
00592 
00606 unsigned int
00607 dbus_watch_get_flags (DBusWatch *watch)
00608 {
00609   _dbus_return_val_if_fail (watch != NULL, 0);
00610   _dbus_assert ((watch->flags & VALID_WATCH_FLAGS) == watch->flags);
00611 
00612   return watch->flags;
00613 }
00614 
00622 void*
00623 dbus_watch_get_data (DBusWatch *watch)
00624 {
00625   _dbus_return_val_if_fail (watch != NULL, NULL);
00626 
00627   return watch->data;
00628 }
00629 
00641 void
00642 dbus_watch_set_data (DBusWatch        *watch,
00643                      void             *data,
00644                      DBusFreeFunction  free_data_function)
00645 {
00646   _dbus_return_if_fail (watch != NULL);
00647 
00648   _dbus_verbose ("Setting watch fd %d data to data = %p function = %p from data = %p function = %p\n",
00649                  dbus_watch_get_socket (watch),
00650                  data, free_data_function, watch->data, watch->free_data_function);
00651   
00652   if (watch->free_data_function != NULL)
00653     (* watch->free_data_function) (watch->data);
00654   
00655   watch->data = data;
00656   watch->free_data_function = free_data_function;
00657 }
00658 
00666 dbus_bool_t
00667 dbus_watch_get_enabled (DBusWatch *watch)
00668 {
00669   _dbus_return_val_if_fail (watch != NULL, FALSE);
00670 
00671   return watch->enabled;
00672 }
00673 
00674 
00697 dbus_bool_t
00698 dbus_watch_handle (DBusWatch    *watch,
00699                    unsigned int  flags)
00700 {
00701   _dbus_return_val_if_fail (watch != NULL, FALSE);
00702 
00703 #ifndef DBUS_DISABLE_CHECKS
00704   if (watch->fd < 0 || watch->flags == 0)
00705     {
00706       _dbus_warn_check_failed ("Watch is invalid, it should have been removed\n");
00707       return TRUE;
00708     }
00709 #endif
00710     
00711   _dbus_return_val_if_fail (watch->fd >= 0 /* fails if watch was removed */, TRUE);
00712   
00713   _dbus_watch_sanitize_condition (watch, &flags);
00714 
00715   if (flags == 0)
00716     {
00717       _dbus_verbose ("After sanitization, watch flags on fd %d were 0\n",
00718                      watch->fd);
00719       return TRUE;
00720     }
00721   else
00722     return (* watch->handler) (watch, flags,
00723                                watch->handler_data);
00724 }
00725 
00726