Fawkes API
Fawkes Development Version
|
00001 00002 /*************************************************************************** 00003 * service_model.cpp - Manages list of discovered services of given type 00004 * 00005 * Created: Mon Sep 29 16:37:14 2008 00006 * Copyright 2008 Daniel Beck 00007 * 00008 ****************************************************************************/ 00009 00010 /* This program is free software; you can redistribute it and/or modify 00011 * it under the terms of the GNU General Public License as published by 00012 * the Free Software Foundation; either version 2 of the License, or 00013 * (at your option) any later version. A runtime exception applies to 00014 * this software (see LICENSE.GPL_WRE file mentioned below for details). 00015 * 00016 * This program is distributed in the hope that it will be useful, 00017 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00018 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00019 * GNU Library General Public License for more details. 00020 * 00021 * Read the full text in the LICENSE.GPL_WRE file in the doc directory. 00022 */ 00023 00024 #include <gui_utils/service_model.h> 00025 #include <netcomm/dns-sd/avahi_thread.h> 00026 00027 #include <sys/types.h> 00028 #include <sys/socket.h> 00029 #include <arpa/inet.h> 00030 00031 using namespace std; 00032 using namespace fawkes; 00033 00034 /** @class fawkes::ServiceModel::ServiceRecord gui_utils/service_model.h 00035 * Detects services and manages information about detected services. 00036 * 00037 * @author Daniel Beck 00038 */ 00039 00040 /** @class fawkes::ServiceModel gui_utils/service_model.h 00041 * Abstract base class for widgets that allow to view the detected 00042 * services of a certain type. 00043 * 00044 * @author Daniel Beck 00045 */ 00046 00047 /** @var fawkes::ServiceModel::m_service_list 00048 * Storage object. 00049 */ 00050 00051 /** @var fawkes::ServiceModel::m_service_record 00052 * Column record class 00053 */ 00054 00055 /** @var fawkes::ServiceModel::m_avahi 00056 * Avahi thread. 00057 */ 00058 00059 /** @var fawkes::ServiceModel::m_signal_service_added 00060 * This signal is emitted whenever a new service has been added. 00061 */ 00062 00063 /** @var fawkes::ServiceModel::m_signal_service_removed 00064 * This signal is emitted whenever a service is removed 00065 */ 00066 00067 /** @struct fawkes::ServiceModel::ServiceAddedRecord 00068 * Data structure to hold information about a newly added services. 00069 */ 00070 00071 /** @struct fawkes::ServiceModel::ServiceRemovedRecord 00072 * Data structure to hold information about a recently removed services. 00073 */ 00074 00075 /** @var fawkes::ServiceModel::m_added_services 00076 * Queue that holds the newly added services. 00077 */ 00078 00079 /** @var fawkes::ServiceModel::m_removed_services 00080 * Queue that holds the recently removed services. 00081 */ 00082 00083 /** Constructor. 00084 * @param service the service identifier 00085 */ 00086 ServiceModel::ServiceModel(const char* service) 00087 { 00088 m_service_list = Gtk::ListStore::create(m_service_record); 00089 00090 m_avahi = new AvahiThread(); 00091 m_avahi->watch_service(service, this); 00092 m_avahi->start(); 00093 00094 m_own_avahi_thread = true; 00095 00096 m_signal_service_added.connect( sigc::mem_fun(*this, &ServiceModel::on_service_added) ); 00097 m_signal_service_removed.connect( sigc::mem_fun(*this, &ServiceModel::on_service_removed) ); 00098 } 00099 00100 /** Constructor. 00101 * @param avahi_thread an AvahiThread that already watches for the 00102 * desired type of services 00103 */ 00104 ServiceModel::ServiceModel(fawkes::AvahiThread* avahi_thread) 00105 { 00106 m_service_list = Gtk::ListStore::create(m_service_record); 00107 00108 m_avahi = avahi_thread; 00109 m_own_avahi_thread = false; 00110 } 00111 00112 /** Destructor. */ 00113 ServiceModel::~ServiceModel() 00114 { 00115 if (m_own_avahi_thread) 00116 { 00117 m_avahi->cancel(); 00118 m_avahi->join(); 00119 delete m_avahi; 00120 } 00121 } 00122 00123 /** Get a reference to the model. 00124 * @return a reference to the model 00125 */ 00126 Glib::RefPtr<Gtk::ListStore>& 00127 ServiceModel::get_list_store() 00128 { 00129 return m_service_list; 00130 } 00131 00132 /** Access the column record. 00133 * @return the column record 00134 */ 00135 ServiceModel::ServiceRecord& 00136 ServiceModel::get_column_record() 00137 { 00138 return m_service_record; 00139 } 00140 00141 void 00142 ServiceModel::all_for_now() 00143 { 00144 } 00145 00146 void 00147 ServiceModel::cache_exhausted() 00148 { 00149 } 00150 00151 void 00152 ServiceModel::browse_failed( const char* name, 00153 const char* type, 00154 const char* domain ) 00155 { 00156 } 00157 00158 void 00159 ServiceModel::service_added( const char* name, 00160 const char* type, 00161 const char* domain, 00162 const char* host_name, 00163 const struct sockaddr* addr, 00164 const socklen_t addr_size, 00165 uint16_t port, 00166 std::list<std::string>& txt, 00167 int flags ) 00168 { 00169 ServiceAddedRecord s; 00170 char ipaddr[INET_ADDRSTRLEN]; 00171 struct sockaddr_in *saddr = (struct sockaddr_in *)addr; 00172 s.name = string(name); 00173 s.type = string(type); 00174 s.domain = string(domain); 00175 s.hostname = string(host_name); 00176 s.ipaddr = inet_ntop(AF_INET, &(saddr->sin_addr), ipaddr, sizeof(ipaddr)); 00177 s.port = port; 00178 00179 m_added_services.push_locked(s); 00180 00181 m_signal_service_added(); 00182 } 00183 00184 void 00185 ServiceModel::service_removed( const char* name, 00186 const char* type, 00187 const char* domain ) 00188 { 00189 ServiceRemovedRecord s; 00190 s.name = string(name); 00191 s.type = string(type); 00192 s.domain = string(domain); 00193 00194 m_removed_services.push_locked(s); 00195 00196 m_signal_service_removed(); 00197 } 00198 00199 /** Signal handler for the service-added signal. */ 00200 void 00201 ServiceModel::on_service_added() 00202 { 00203 m_added_services.lock(); 00204 00205 while ( !m_added_services.empty() ) 00206 { 00207 ServiceAddedRecord& s = m_added_services.front(); 00208 00209 Gtk::TreeModel::Row row = *m_service_list->append(); 00210 00211 row[m_service_record.name] = s.name; 00212 row[m_service_record.type] = s.type; 00213 row[m_service_record.domain] = s.domain; 00214 row[m_service_record.hostname] = s.hostname; 00215 row[m_service_record.ipaddr] = s.ipaddr; 00216 row[m_service_record.port] = s.port; 00217 00218 m_added_services.pop(); 00219 } 00220 00221 m_added_services.unlock(); 00222 } 00223 00224 /** Signal handler for the service-removed signal. */ 00225 void 00226 ServiceModel::on_service_removed() 00227 { 00228 m_removed_services.lock(); 00229 00230 while ( !m_removed_services.empty() ) 00231 { 00232 ServiceRemovedRecord& s = m_removed_services.front(); 00233 00234 Gtk::TreeIter iter; 00235 iter = m_service_list->children().begin(); 00236 00237 while ( iter != m_service_list->children().end() ) 00238 { 00239 Gtk::TreeModel::Row row = *iter; 00240 if ( (row[m_service_record.name] == s.name) && 00241 (row[m_service_record.type] == s.type) && 00242 (row[m_service_record.domain] == s.domain) ) 00243 { 00244 iter = m_service_list->erase(iter); 00245 m_service_list->row_deleted( m_service_list->get_path(iter) ); 00246 } 00247 else 00248 { ++iter; } 00249 } 00250 00251 m_removed_services.pop(); 00252 } 00253 00254 m_removed_services.unlock(); 00255 }