Fawkes API  Fawkes Development Version
service_model.cpp
1 
2 /***************************************************************************
3  * service_model.cpp - Manages list of discovered services of given type
4  *
5  * Created: Mon Sep 29 16:37:14 2008
6  * Copyright 2008 Daniel Beck
7  *
8  ****************************************************************************/
9 
10 /* This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version. A runtime exception applies to
14  * this software (see LICENSE.GPL_WRE file mentioned below for details).
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  * GNU Library General Public License for more details.
20  *
21  * Read the full text in the LICENSE.GPL_WRE file in the doc directory.
22  */
23 
24 #include <gui_utils/service_model.h>
25 #include <netcomm/dns-sd/avahi_thread.h>
26 #include <utils/misc/string_conversions.h>
27 
28 #include <sys/types.h>
29 #include <sys/socket.h>
30 #include <arpa/inet.h>
31 #include <cerrno>
32 
33 using namespace std;
34 using namespace fawkes;
35 
36 /** @class fawkes::ServiceModel::ServiceRecord gui_utils/service_model.h
37  * Detects services and manages information about detected services.
38  *
39  * @author Daniel Beck
40  */
41 
42 /** @class fawkes::ServiceModel gui_utils/service_model.h
43  * Abstract base class for widgets that allow to view the detected
44  * services of a certain type.
45  *
46  * @author Daniel Beck
47  */
48 
49 /** @var fawkes::ServiceModel::m_service_list
50  * Storage object.
51  */
52 
53 /** @var fawkes::ServiceModel::m_service_record
54  * Column record class
55  */
56 
57 /** @var fawkes::ServiceModel::m_avahi
58  * Avahi thread.
59  */
60 
61 /** @var fawkes::ServiceModel::m_signal_service_added
62  * This signal is emitted whenever a new service has been added.
63  */
64 
65 /** @var fawkes::ServiceModel::m_signal_service_removed
66  * This signal is emitted whenever a service is removed
67  */
68 
69 /** @struct fawkes::ServiceModel::ServiceAddedRecord
70  * Data structure to hold information about a newly added services.
71  */
72 
73 /** @struct fawkes::ServiceModel::ServiceRemovedRecord
74  * Data structure to hold information about a recently removed services.
75  */
76 
77 /** @var fawkes::ServiceModel::m_added_services
78  * Queue that holds the newly added services.
79  */
80 
81 /** @var fawkes::ServiceModel::m_removed_services
82  * Queue that holds the recently removed services.
83  */
84 
85 /** Constructor.
86  * @param service the service identifier
87  */
88 ServiceModel::ServiceModel(const char* service)
89 {
90  m_service_list = Gtk::ListStore::create(m_service_record);
91 
92  m_avahi = new AvahiThread();
93  m_avahi->watch_service(service, this);
94  m_avahi->start();
95 
96  m_own_avahi_thread = true;
97 
98  m_signal_service_added.connect( sigc::mem_fun(*this, &ServiceModel::on_service_added) );
99  m_signal_service_removed.connect( sigc::mem_fun(*this, &ServiceModel::on_service_removed) );
100 }
101 
102 /** Constructor.
103  * @param avahi_thread an AvahiThread that already watches for the
104  * desired type of services
105  */
106 ServiceModel::ServiceModel(fawkes::AvahiThread* avahi_thread)
107 {
108  m_service_list = Gtk::ListStore::create(m_service_record);
109 
110  m_avahi = avahi_thread;
111  m_own_avahi_thread = false;
112 }
113 
114 /** Destructor. */
115 ServiceModel::~ServiceModel()
116 {
117  if (m_own_avahi_thread)
118  {
119  m_avahi->cancel();
120  m_avahi->join();
121  delete m_avahi;
122  }
123 }
124 
125 /** Get a reference to the model.
126  * @return a reference to the model
127  */
128 Glib::RefPtr<Gtk::ListStore>&
129 ServiceModel::get_list_store()
130 {
131  return m_service_list;
132 }
133 
134 /** Access the column record.
135  * @return the column record
136  */
138 ServiceModel::get_column_record()
139 {
140  return m_service_record;
141 }
142 
143 void
144 ServiceModel::all_for_now()
145 {
146 }
147 
148 void
149 ServiceModel::cache_exhausted()
150 {
151 }
152 
153 void
154 ServiceModel::browse_failed( const char* name,
155  const char* type,
156  const char* domain )
157 {
158 }
159 
160 void
161 ServiceModel::service_added( const char* name, const char* type,
162  const char* domain, const char* host_name, const char *interface,
163  const struct sockaddr* addr, const socklen_t addr_size,
164  uint16_t port, std::list<std::string>& txt, int flags )
165 {
167  if (addr->sa_family == AF_INET) {
168  char ipaddr[INET_ADDRSTRLEN];
169  struct sockaddr_in *saddr = (struct sockaddr_in *)addr;
170  if (inet_ntop(AF_INET, &(saddr->sin_addr), ipaddr, sizeof(ipaddr)) != NULL) {
171  s.ipaddr = ipaddr;
172  s.addrport = std::string(ipaddr) + ":" + StringConversions::to_string(port);
173  } else {
174  s.ipaddr = "";
175  s.addrport = std::string("Failed to convert IPv4: ") + strerror(errno);
176  }
177  } else if (addr->sa_family == AF_INET6) {
178  char ipaddr[INET6_ADDRSTRLEN];
179  struct sockaddr_in6 *saddr = (struct sockaddr_in6 *)addr;
180  if (inet_ntop(AF_INET6, &(saddr->sin6_addr), ipaddr, sizeof(ipaddr)) != NULL) {
181  s.ipaddr = ipaddr;
182  s.addrport = std::string("[") + ipaddr + "%" + interface + "]:" + StringConversions::to_string(port);
183  } else {
184  s.ipaddr = "";
185  s.addrport = std::string("Failed to convert IPv6: ") + strerror(errno);
186  }
187  } else {
188  s.ipaddr = "";
189  s.addrport = "Unknown address family";
190  }
191 
192  s.name = name;
193  s.type = type;
194  s.domain = domain;
195  s.hostname = host_name;
196  s.interface = interface;
197  s.port = port;
198  memcpy(&s.sockaddr, addr, addr_size);
199 
200  m_added_services.push_locked(s);
201 
202  m_signal_service_added();
203 }
204 
205 void
206 ServiceModel::service_removed(const char* name, const char* type, const char* domain)
207 {
209  s.name = string(name);
210  s.type = string(type);
211  s.domain = string(domain);
212 
213  m_removed_services.push_locked(s);
214 
215  m_signal_service_removed();
216 }
217 
218 /** Signal handler for the service-added signal. */
219 void
220 ServiceModel::on_service_added()
221 {
222  m_added_services.lock();
223 
224  while ( !m_added_services.empty() )
225  {
226  ServiceAddedRecord& s = m_added_services.front();
227 
228  Gtk::TreeModel::Row row = *m_service_list->append();
229 
230  row[m_service_record.name] = s.name;
231  row[m_service_record.type] = s.type;
232  row[m_service_record.domain] = s.domain;
233  row[m_service_record.hostname] = s.hostname;
234  row[m_service_record.interface] = s.interface;
235  row[m_service_record.ipaddr] = s.ipaddr;
236  row[m_service_record.port] = s.port;
237  row[m_service_record.addrport] = s.addrport;
238  row[m_service_record.sockaddr] = s.sockaddr;
239 
240  m_added_services.pop();
241  }
242 
243  m_added_services.unlock();
244 }
245 
246 /** Signal handler for the service-removed signal. */
247 void
248 ServiceModel::on_service_removed()
249 {
250  m_removed_services.lock();
251 
252  while ( !m_removed_services.empty() )
253  {
254  ServiceRemovedRecord& s = m_removed_services.front();
255 
256  Gtk::TreeIter iter;
257  iter = m_service_list->children().begin();
258 
259  while ( iter != m_service_list->children().end() )
260  {
261  Gtk::TreeModel::Row row = *iter;
262  if ( (row[m_service_record.name] == s.name) &&
263  (row[m_service_record.type] == s.type) &&
264  (row[m_service_record.domain] == s.domain) )
265  {
266  m_service_list->row_deleted( m_service_list->get_path(iter) );
267  iter = m_service_list->erase(iter);
268  }
269  else
270  { ++iter; }
271  }
272 
273  m_removed_services.pop();
274  }
275 
276  m_removed_services.unlock();
277 }
std::string ipaddr
the IP address of the new service
Definition: service_model.h:92
struct sockaddr_storage sockaddr
sockaddr structure
Definition: service_model.h:95
std::string hostname
the hostname of the new service
Definition: service_model.h:90
Fawkes library namespace.
STL namespace.
Detects services and manages information about detected services.
Definition: service_model.h:43
std::string type
the type of the service
std::string interface
name of network interface to reach service
Definition: service_model.h:91
unsigned short port
the port the new service is running on
Definition: service_model.h:93
Data structure to hold information about a recently removed services.
Definition: service_model.h:98
std::string type
the type of the new service
Definition: service_model.h:88
std::string name
the name of the new service
Definition: service_model.h:87
Avahi main thread.
Definition: avahi_thread.h:54
void cancel()
Cancel a thread.
Definition: thread.cpp:651
std::string domain
the domain of the service
Data structure to hold information about a newly added services.
Definition: service_model.h:85
std::string domain
the domain of the new service
Definition: service_model.h:89
std::string name
the name of the service