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 <arpa/inet.h>
25 #include <gui_utils/service_model.h>
26 #include <netcomm/dns-sd/avahi_thread.h>
27 #include <sys/socket.h>
28 #include <sys/types.h>
29 #include <utils/misc/string_conversions.h>
30 
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  m_avahi->cancel();
119  m_avahi->join();
120  delete m_avahi;
121  }
122 }
123 
124 /** Get a reference to the model.
125  * @return a reference to the model
126  */
127 Glib::RefPtr<Gtk::ListStore> &
128 ServiceModel::get_list_store()
129 {
130  return m_service_list;
131 }
132 
133 /** Access the column record.
134  * @return the column record
135  */
137 ServiceModel::get_column_record()
138 {
139  return m_service_record;
140 }
141 
142 void
143 ServiceModel::all_for_now()
144 {
145 }
146 
147 void
148 ServiceModel::cache_exhausted()
149 {
150 }
151 
152 void
153 ServiceModel::browse_failed(const char *name, const char *type, const char *domain)
154 {
155 }
156 
157 void
158 ServiceModel::service_added(const char * name,
159  const char * type,
160  const char * domain,
161  const char * host_name,
162  const char * interface,
163  const struct sockaddr * addr,
164  const socklen_t addr_size,
165  uint16_t port,
166  std::list<std::string> &txt,
167  int flags)
168 {
170  if (addr->sa_family == AF_INET) {
171  char ipaddr[INET_ADDRSTRLEN];
172  struct sockaddr_in *saddr = (struct sockaddr_in *)addr;
173  if (inet_ntop(AF_INET, &(saddr->sin_addr), ipaddr, sizeof(ipaddr)) != NULL) {
174  s.ipaddr = ipaddr;
175  s.addrport = std::string(ipaddr) + ":" + StringConversions::to_string(port);
176  } else {
177  s.ipaddr = "";
178  s.addrport = std::string("Failed to convert IPv4: ") + strerror(errno);
179  }
180  } else if (addr->sa_family == AF_INET6) {
181  char ipaddr[INET6_ADDRSTRLEN];
182  struct sockaddr_in6 *saddr = (struct sockaddr_in6 *)addr;
183  if (inet_ntop(AF_INET6, &(saddr->sin6_addr), ipaddr, sizeof(ipaddr)) != NULL) {
184  s.ipaddr = ipaddr;
185  s.addrport =
186  std::string("[") + ipaddr + "%" + interface + "]:" + StringConversions::to_string(port);
187  } else {
188  s.ipaddr = "";
189  s.addrport = std::string("Failed to convert IPv6: ") + strerror(errno);
190  }
191  } else {
192  s.ipaddr = "";
193  s.addrport = "Unknown address family";
194  }
195 
196  s.name = name;
197  s.type = type;
198  s.domain = domain;
199  s.hostname = host_name;
200  s.interface = interface;
201  s.port = port;
202  memcpy(&s.sockaddr, addr, addr_size);
203 
204  m_added_services.push_locked(s);
205 
206  m_signal_service_added();
207 }
208 
209 void
210 ServiceModel::service_removed(const char *name, const char *type, const char *domain)
211 {
213  s.name = string(name);
214  s.type = string(type);
215  s.domain = string(domain);
216 
217  m_removed_services.push_locked(s);
218 
219  m_signal_service_removed();
220 }
221 
222 /** Signal handler for the service-added signal. */
223 void
224 ServiceModel::on_service_added()
225 {
226  m_added_services.lock();
227 
228  while (!m_added_services.empty()) {
229  ServiceAddedRecord &s = m_added_services.front();
230 
231  Gtk::TreeModel::Row row = *m_service_list->append();
232 
233  row[m_service_record.name] = s.name;
234  row[m_service_record.type] = s.type;
235  row[m_service_record.domain] = s.domain;
236  row[m_service_record.hostname] = s.hostname;
237  row[m_service_record.interface] = s.interface;
238  row[m_service_record.ipaddr] = s.ipaddr;
239  row[m_service_record.port] = s.port;
240  row[m_service_record.addrport] = s.addrport;
241  row[m_service_record.sockaddr] = s.sockaddr;
242 
243  m_added_services.pop();
244  }
245 
246  m_added_services.unlock();
247 }
248 
249 /** Signal handler for the service-removed signal. */
250 void
251 ServiceModel::on_service_removed()
252 {
253  m_removed_services.lock();
254 
255  while (!m_removed_services.empty()) {
256  ServiceRemovedRecord &s = m_removed_services.front();
257 
258  Gtk::TreeIter iter;
259  iter = m_service_list->children().begin();
260 
261  while (iter != m_service_list->children().end()) {
262  Gtk::TreeModel::Row row = *iter;
263  if ((row[m_service_record.name] == s.name) && (row[m_service_record.type] == s.type)
264  && (row[m_service_record.domain] == s.domain)) {
265  m_service_list->row_deleted(m_service_list->get_path(iter));
266  iter = m_service_list->erase(iter);
267  } else {
268  ++iter;
269  }
270  }
271 
272  m_removed_services.pop();
273  }
274 
275  m_removed_services.unlock();
276 }
fawkes::ServiceModel::ServiceRecord
Detects services and manages information about detected services.
Definition: service_model.h:45
fawkes::ServiceModel::ServiceAddedRecord::name
std::string name
the name of the new service
Definition: service_model.h:95
fawkes::ServiceModel::ServiceAddedRecord::domain
std::string domain
the domain of the new service
Definition: service_model.h:97
fawkes::ServiceModel::ServiceAddedRecord::ipaddr
std::string ipaddr
the IP address of the new service
Definition: service_model.h:100
fawkes::ServiceModel::ServiceRemovedRecord
Data structure to hold information about a recently removed services.
Definition: service_model.h:107
fawkes::ServiceModel::ServiceAddedRecord::sockaddr
struct sockaddr_storage sockaddr
sockaddr structure
Definition: service_model.h:103
fawkes::ServiceModel::ServiceRemovedRecord::type
std::string type
the type of the service
Definition: service_model.h:109
fawkes::AvahiThread
Avahi main thread.
Definition: avahi_thread.h:55
fawkes
Fawkes library namespace.
fawkes::ServiceModel::ServiceAddedRecord::interface
std::string interface
name of network interface to reach service
Definition: service_model.h:99
fawkes::ServiceModel::ServiceRemovedRecord::name
std::string name
the name of the service
Definition: service_model.h:108
fawkes::ServiceModel::ServiceAddedRecord::type
std::string type
the type of the new service
Definition: service_model.h:96
fawkes::ServiceModel::ServiceAddedRecord::hostname
std::string hostname
the hostname of the new service
Definition: service_model.h:98
fawkes::ServiceModel::ServiceAddedRecord::port
unsigned short port
the port the new service is running on
Definition: service_model.h:101
fawkes::ServiceModel::ServiceAddedRecord::addrport
std::string addrport
address:port
Definition: service_model.h:102
fawkes::Thread::cancel
void cancel()
Cancel a thread.
Definition: thread.cpp:646
fawkes::ServiceModel::ServiceRemovedRecord::domain
std::string domain
the domain of the service
Definition: service_model.h:110
fawkes::ServiceModel::ServiceAddedRecord
Data structure to hold information about a newly added services.
Definition: service_model.h:94