SIP Witch 1.9.15
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
zeroconf.cpp
Go to the documentation of this file.
1 // Copyright (C) 2007-2014 David Sugar, Tycho Softworks.
2 // Copyright (C) 2015 Cherokees of Idaho.
3 //
4 // This program is free software; you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation; either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
16 
17 #include <sipwitch-config.h>
18 #include <sipwitch/sipwitch.h>
19 
20 namespace sipwitch {
21 
22 #ifdef ZEROCONF_AVAHI
23 
24 extern "C" {
25  #include <avahi-client/client.h>
26  #include <avahi-client/publish.h>
27  #include <avahi-common/alternative.h>
28  #include <avahi-common/thread-watch.h>
29  #include <avahi-common/malloc.h>
30  #include <avahi-common/error.h>
31  #include <avahi-common/timeval.h>
32 }
33 
34 class __LOCAL zeroconf : public modules::generic
35 {
36 public:
37  zeroconf();
38 
39  void setClient(AvahiClientState state);
40  void setGroup(AvahiEntryGroupState state);
41 
42  inline void setClient(AvahiClient *c)
43  {client = c;};
44 
45  static zeroconf plugin;
46 
47 private:
48  void start(service *cfg);
49  void stop(service *cfg);
50  void reload(service *cfg);
51  void publish(service *cfg);
52 
53  AvahiThreadedPoll *poller;
54  AvahiClient *client;
55  AvahiEntryGroup *group;
56  char *name;
57  const char *protocol;
58  int error;
59 };
60 
61 extern "C" {
62 
63  static void client_callback(AvahiClient *c, AvahiClientState state, void *userdata)
64  {
65  if(!c)
66  return;
67 
68  zeroconf::plugin.setClient(c);
69  zeroconf::plugin.setClient(state);
70  }
71 
72  static void group_callback(AvahiEntryGroup *g, AvahiEntryGroupState state, void *userdata)
73  {
74  zeroconf::plugin.setGroup(state);
75  }
76 }
77 
79 modules::generic()
80 {
81  protocol = "_sip._udp";
82  poller = NULL;
83  client = NULL;
84  group = NULL;
85  name = avahi_strdup("sipwitch");
86  shell::log(shell::ERR, "zeroconf plugin using avahi");
87 }
88 
89 void zeroconf::setGroup(AvahiEntryGroupState state)
90 {
91  char *newname;
92 
93  switch(state)
94  {
95  case AVAHI_ENTRY_GROUP_ESTABLISHED:
96  shell::log(shell::INFO, "zeroconf %s service(s) established", name);
97  break;
98  case AVAHI_ENTRY_GROUP_COLLISION:
99  newname = avahi_alternative_service_name(name);
100  shell::log(shell::NOTIFY, "zeroconf service %s renamed %s", name, newname);
101  avahi_free(name);
102  name = newname;
103  setClient(AVAHI_CLIENT_S_RUNNING);
104  break;
105  case AVAHI_ENTRY_GROUP_FAILURE:
106  shell::log(shell::ERR, "zeroconf service failure; error=%s",
107  avahi_strerror(avahi_client_errno(client)));
108  // avahi_thread_poll_quit(poller);
109  default:
110  break;
111  }
112 }
113 
114 void zeroconf::setClient(AvahiClientState state)
115 {
116  int ret;
117  AvahiProtocol avifamily = AVAHI_PROTO_UNSPEC;
118 
119  switch(state) {
120  case AVAHI_CLIENT_S_RUNNING:
121  goto add;
122  case AVAHI_CLIENT_FAILURE:
123 failed:
124  shell::log(shell::ERR, "zeroconf failure; error=%s",
125  avahi_strerror(avahi_client_errno(client)));
126  break;
127  case AVAHI_CLIENT_S_COLLISION:
128  case AVAHI_CLIENT_S_REGISTERING:
129  if(group)
130  avahi_entry_group_reset(group);
131  default:
132  break;
133  }
134  return;
135 add:
136  if(!group)
137  group = avahi_entry_group_new(client, group_callback, NULL);
138  if(!group)
139  goto failed;
140 
141  shell::log(shell::INFO, "zeroconf adding sip on port %d", sip_port);
142  if(sip_domain) {
143  char domain[256];
144  char prefix[32];
145  char range[32];
146  char uuid[64];
147 
148  snprintf(domain, sizeof(domain), "domain=%s", sip_domain);
149  snprintf(prefix, sizeof(prefix), "prefix=%u", sip_prefix);
150  snprintf(range, sizeof(range), "range=%u", sip_range);
151  snprintf(uuid, sizeof(uuid), "uuid=%s", session_uuid);
152  ret = avahi_entry_group_add_service(group, AVAHI_IF_UNSPEC, avifamily,
153  (AvahiPublishFlags)0, name, protocol, NULL, NULL, sip_port,
154  "type=sipwitch", domain, prefix, range, uuid, NULL);
155  }
156  else
157  ret = avahi_entry_group_add_service(group, AVAHI_IF_UNSPEC, avifamily,
158  (AvahiPublishFlags)0, name, protocol, NULL, NULL, sip_port,
159  "type=sipwitch", NULL);
160 
161  if(ret < 0)
162  shell::log(shell::ERR, "zeroconf %s failed; error=%s",
163  protocol, avahi_strerror(ret));
164 
165  ret = avahi_entry_group_commit(group);
166  if(ret >= 0)
167  return;
168 
169  shell::log(shell::ERR, "zeroconf service commit failure; error=%s",
170  avahi_strerror(ret));
171 }
172 
173 void zeroconf::stop(service *cfg)
174 {
175  if(poller)
176  avahi_threaded_poll_stop(poller);
177  if(client)
178  avahi_client_free(client);
179  if(name)
180  avahi_free(name);
181 // if(poller)
182 // avahi_threaded_poll_free(poller);
183  client = NULL;
184  poller = NULL;
185  name = NULL;
186 }
187 
188 void zeroconf::start(service *cfg)
189 {
190  poller = avahi_threaded_poll_new();
191 
192  if(!poller) {
193  shell::log(shell::ERR, "zeroconf service failed to start");
194  return;
195  }
196 
197  client = avahi_client_new(avahi_threaded_poll_get(poller),
198  (AvahiClientFlags)0, client_callback, NULL, &error);
199 
200  shell::log(shell::INFO, "zeroconf service started");
201  avahi_threaded_poll_start(poller);
202 }
203 
204 void zeroconf::reload(service *cfg)
205 {
206  if(sip_protocol == IPPROTO_TCP)
207  protocol = "_sip._tcp";
208 }
209 
210 void zeroconf::publish(service *cfg)
211 {
212  assert(cfg != NULL);
213 
214  char domain[256];
215  char prefix[32];
216  char range[32];
217  char uuid[64];
218 
219  static bool started = false;
220  AvahiProtocol avifamily = AVAHI_PROTO_UNSPEC;
221  int ret = 0;
222 
223  if(started && group && sip_domain) {
224  snprintf(domain, sizeof(domain), "domain=%s", sip_domain);
225  snprintf(prefix, sizeof(prefix), "prefix=%u", sip_prefix);
226  snprintf(range, sizeof(range), "range=%u", sip_range);
227  snprintf(uuid, sizeof(uuid), "uuid=%s", session_uuid);
228  ret = avahi_entry_group_update_service_txt(group, AVAHI_IF_UNSPEC, avifamily,
229  (AvahiPublishFlags)0, name, protocol, NULL,
230  "type=sipwitch", domain, prefix, range, uuid, NULL);
231  }
232  else if(started && group) {
233  ret = avahi_entry_group_update_service_txt(group, AVAHI_IF_UNSPEC, avifamily,
234  (AvahiPublishFlags)0, name, protocol, NULL,
235  "type=sipwitch", NULL);
236  }
237 
238  if(ret < 0)
239  shell::log(shell::ERR, "zeroconf %s failed; error=%s",
240  protocol, avahi_strerror(ret));
241 
242  started = true;
243 }
244 
245 #else
246 
247 class __LOCAL zeroconf : modules::generic
248 {
249 public:
250  static zeroconf plugin;
251 
252  zeroconf();
253 };
254 
255 zeroconf::zeroconf() :
256 modules::generic()
257 {
258  shell::log(shell::ERR, "zeroconf plugin could not be built");
259 }
260 
261 #endif
262 
264 
265 } // end namespace
A more generic service class for use by plugins.
Definition: modules.h:159
Top level include directory for GNU Telephony SIP Witch Server.
char * name[96]
Definition: cgiserver.cpp:88
static zeroconf plugin
Definition: zeroconf.cpp:250
Common interfaces and clases for plugins.
Definition: modules.h:55