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
33using namespace std;
34using 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 */
88ServiceModel::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 */
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. */
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 */
127Glib::RefPtr<Gtk::ListStore> &
129{
130 return m_service_list;
131}
132
133/** Access the column record.
134 * @return the column record
135 */
138{
139 return m_service_record;
140}
141
142void
144{
145}
146
147void
149{
150}
151
152void
153ServiceModel::browse_failed(const char *name, const char *type, const char *domain)
154{
155}
156
157void
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
207}
208
209void
210ServiceModel::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
220}
221
222/** Signal handler for the service-added signal. */
223void
225{
226 m_added_services.lock();
227
228 while (!m_added_services.empty()) {
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;
239 row[m_service_record.port] = s.port;
242
243 m_added_services.pop();
244 }
245
246 m_added_services.unlock();
247}
248
249/** Signal handler for the service-removed signal. */
250void
252{
253 m_removed_services.lock();
254
255 while (!m_removed_services.empty()) {
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}
Avahi main thread.
Definition: avahi_thread.h:55
void watch_service(const char *service_type, ServiceBrowseHandler *h)
Add a result handler.
Detects services and manages information about detected services.
Definition: service_model.h:45
Gtk::TreeModelColumn< Glib::ustring > domain
The domain of the service.
Definition: service_model.h:62
Gtk::TreeModelColumn< unsigned short > port
The port the service is running on.
Definition: service_model.h:69
Gtk::TreeModelColumn< Glib::ustring > type
The type of the service.
Definition: service_model.h:61
Gtk::TreeModelColumn< Glib::ustring > addrport
Address:port string.
Definition: service_model.h:70
Gtk::TreeModelColumn< Glib::ustring > name
The name of the service.
Definition: service_model.h:60
Gtk::TreeModelColumn< Glib::ustring > hostname
The name of the host the service is running on.
Definition: service_model.h:64
Gtk::TreeModelColumn< struct sockaddr_storage > sockaddr
sockaddr structure
Definition: service_model.h:71
Gtk::TreeModelColumn< Glib::ustring > ipaddr
The IP address as string of the host the service is running on.
Definition: service_model.h:68
Gtk::TreeModelColumn< Glib::ustring > interface
Name of network interface to reach service.
Definition: service_model.h:66
fawkes::AvahiThread * m_avahi
Avahi thread.
ServiceRecord & get_column_record()
Access the column record.
void service_added(const char *name, const char *type, const char *domain, const char *host_name, const char *interface, const struct sockaddr *addr, const socklen_t addr_size, uint16_t port, std::list< std::string > &txt, int flags)
A service has been announced on the network.
void browse_failed(const char *name, const char *type, const char *domain)
Failed to browse for a given service.
fawkes::LockQueue< ServiceAddedRecord > m_added_services
Queue that holds the newly added services.
virtual void on_service_added()
Signal handler for the service-added signal.
virtual void on_service_removed()
Signal handler for the service-removed signal.
fawkes::LockQueue< ServiceRemovedRecord > m_removed_services
Queue that holds the recently removed services.
Glib::Dispatcher m_signal_service_added
This signal is emitted whenever a new service has been added.
void all_for_now()
All results have been retrieved.
ServiceModel(const char *service="_fawkes._tcp")
Constructor.
Glib::RefPtr< Gtk::ListStore > & get_list_store()
Get a reference to the model.
void cache_exhausted()
Cache exhausted.
Glib::RefPtr< Gtk::ListStore > m_service_list
Storage object.
Glib::Dispatcher m_signal_service_removed
This signal is emitted whenever a service is removed.
void service_removed(const char *name, const char *type, const char *domain)
A service has been removed from the network.
ServiceRecord m_service_record
Column record class.
virtual ~ServiceModel()
Destructor.
static std::string to_string(unsigned int i)
Convert unsigned int value to a string.
void start(bool wait=true)
Call this method to start the thread.
Definition: thread.cpp:499
void join()
Join the thread.
Definition: thread.cpp:597
void cancel()
Cancel a thread.
Definition: thread.cpp:646
Fawkes library namespace.
Data structure to hold information about a newly added services.
Definition: service_model.h:94
std::string name
the name of the new service
Definition: service_model.h:95
unsigned short port
the port the new service is running on
struct sockaddr_storage sockaddr
sockaddr structure
std::string hostname
the hostname of the new service
Definition: service_model.h:98
std::string domain
the domain of the new service
Definition: service_model.h:97
std::string interface
name of network interface to reach service
Definition: service_model.h:99
std::string type
the type of the new service
Definition: service_model.h:96
std::string ipaddr
the IP address of the new service
Data structure to hold information about a recently removed services.
std::string type
the type of the service
std::string domain
the domain of the service
std::string name
the name of the service