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>
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;
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
70 }
71
72 static void group_callback(AvahiEntryGroup *g, AvahiEntryGroupState state, void *userdata)
73 {
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);
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);
181 // if(poller)
182 // avahi_threaded_poll_free(poller);
183 client = NULL;
184 poller = 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
248 {
249 public:
251
253 };
254
255 zeroconf::zeroconf() :
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.
Top level include directory for GNU Telephony SIP Witch Server.
Common interfaces and clases for plugins.