1 // Copyright (C) 2008-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 #define INDEX_SIZE 177
23
25 {
26 public:
28 {
29 public:
33 };
34
49
51
59
60 private:
66 bool announce(
MappedRegistry *rr,
const char *msgtype,
const char *event,
const char *expires,
const char *body);
67 bool authenticate(int id, const char *remote_realm);
68 char *referLocal(
MappedRegistry *rr,
const char *target,
char *buffer,
size_t size);
69 };
70
72
75 {
76 shell::log(shell::INFO, "%s\n",
77 _TEXT("server forward plugin loaded"));
78
82 realm = (
char *)
"GNU Telephony";
88 }
89
91 {
92 if(rr)
94 }
95
97 {
98 bool activeflag = false;
99
100 linked_pointer<regmap> mp;
104 while(is(mp)) {
105 if(mp->active) {
106 activeflag = true;
107 break;
108 }
109 mp.next();
110 }
112 return activeflag;
113 }
114
116 {
117 linked_pointer<regmap> mp;
121 while(is(mp)) {
122 if(mp->entry->rid == id)
124 mp.next();
125 }
127 return NULL;
128 }
129
131 {
132 linked_pointer<regmap> mp;
136 while(is(mp)) {
137 if(mp->entry->rid == id) {
139 break;
140 }
141 mp.next();
142 }
144 }
145
147 {
148 linked_pointer<regmap> mp;
152 while(is(mp)) {
153 if(mp->entry->rid == id) {
155 break;
156 }
157 mp.next();
158 }
160 }
161
163 {
165 linked_pointer<regmap> mp;
169 while(is(mp)) {
170 if(mp->entry->rid == id) {
171 if(prior)
172 prior->Next = mp->Next;
173 else
177 shell::debug(3, "forward unmap %s from %d", mp->entry->userid, id);
180 mp->entry->rid = -1;
181 return;
182 }
183 mp.next();
184 }
185 shell::debug(3, "forward map %d not found", id);
187 }
188
190 {
195 if(map)
197 else {
200 }
202 map->Next = index[path];
204 locking.commit();
205 shell::debug(3, "forward mapped %s as %d", rr->userid, rr->rid);
206 ++active;
207 }
208
210 {
211 assert(cfg != NULL);
212
213 char buffer[160];
214 bool refering = false;
215 bool enable = false;
217 char *tmp_realm = (char *)realm, *tmp_digest = cfg->dup((char *)digest);
218 char *tmp_schema = (char *)"sip";
220 linked_pointer<service::keynode> fp = cfg->
getList(
"forward");
221 linked_pointer<service::keynode> sp = cfg->
getList(
"registry");
222
223 while(is(sp)) {
224 key = sp->getId();
225 value = sp->getPointer();
226 if(key && value) {
227 if(String::equal(key, "digest"))
228 tmp_digest = cfg->dup(value);
229 else if(String::equal(key, "realm"))
230 tmp_realm = cfg->dup(value);
231 }
232 sp.next();
233 }
234
236
237 while(is(fp)) {
238 key = fp->getId();
239 value = fp->getPointer();
240 if(key && value) {
241 if(String::equal(key, "refer")) {
242 if(resolver.
route(value, buffer,
sizeof(buffer))) {
243 refer = cfg->dup(buffer);
244 refering = true;
245 shell::debug(2, "forward refer resolved as %s", buffer);
246 }
247 else {
248 shell::log(shell::ERR, "forward: %s: cannot resolve", value);
250 }
251 }
252 else if(String::equal(key, "server")) {
253 tmp_context = resolver.
route(value, buffer,
sizeof(buffer));
254 if(context) {
255 server = cfg->dup(buffer);
256 shell::debug(2, "forward server resolved as %s", buffer);
257 }
258 else {
259 shell::log(shell::ERR, "forward: %s: cannot resolve", value);
261 }
263 enable = true;
264 service::dialmode = service::EXT_DIALING;
265 }
266 }
267 else if(String::equal(key, "expires"))
268 expires = atoi(value);
269 else if(String::equal(key, "digest"))
270 tmp_digest = cfg->dup(value);
271 else if(String::equal(key, "realm"))
272 tmp_realm = cfg->dup(value);
273 }
274 fp.next();
275 }
276
277 if(!refering)
278 refer = NULL;
279
280 String::upper(tmp_digest);
281 if(tmp_context)
282 context = tmp_context;
283 schema = tmp_schema;
284 realm = tmp_realm;
285 digest = tmp_digest;
286
287 if(enable && !enabled)
288 shell::log(shell::INFO, "server forward plugin activated");
289 else if(!enable && enabled)
290 shell::log(shell::INFO, "server forward plugin disabled");
291 enabled = enable;
292 }
293
295 {
296 assert(cfg != NULL);
297 }
298
300 {
304 unsigned len;
305
306 if(!enabled || rr->
rid != -1)
307 return;
308
309 // must also have extension to forward...
310 if(rr->
remote[0] && rr->
ext && rr->
type == MappedRegistry::USER) {
311 snprintf(uri,
sizeof(uri),
"%s:%s@%s", schema, rr->
userid,
server);
312 snprintf(reg,
sizeof(reg),
"%s:%s", schema,
server);
313 snprintf(contact,
sizeof(contact),
"%s:%s@", schema, rr->
remote);
314 len = strlen(contact);
315 Socket::query((
struct sockaddr *)&rr->
contact, contact + len,
sizeof(contact) - len);
316 len = strlen(contact);
317 snprintf(contact + len,
sizeof(contact) - len,
":%d", Socket::address::getPort((
struct sockaddr *)&rr->
contact));
318 shell::debug(3,
"registering %s with %s", contact,
server);
320 rr->
rid = voip::make_registry_request(context, uri, reg, contact, (
unsigned)expires, &msg);
321 if(rr->
rid != -1 && msg) {
322 voip::server_supports(msg, "100rel");
323 voip::header(msg, "Event", "Registration");
324 voip::header(msg, "Allow-Events", "presence");
325 voip::send_registry_request(context, rr->
rid, msg);
326 add(rr);
327 }
328 }
329 }
330
331 bool forward::announce(
MappedRegistry *rr,
const char *msgtype,
const char *event,
const char *expiration,
const char *body)
332 {
335 size_t len;
336
338 return false;
339
340 snprintf(uri_to,
sizeof(uri_to),
"sip:%s@%s", rr->
userid,
server);
341 snprintf(contact,
sizeof(contact),
"sip:%s@", rr->
remote);
342 len = strlen(contact);
343 Socket::query((
struct sockaddr *)&rr->
contact, contact + len,
sizeof(contact) - len);
344 len = strlen(contact);
345 snprintf(contact + len,
sizeof(contact) - len,
":%d", Socket::address::getPort((
struct sockaddr *)&rr->
contact));
346 shell::debug(3,
"publishing %s with %s", contact,
server);
347
348 voip::publish(context, uri_to, contact, event, expiration, msgtype, body);
349 return true;
350 }
351
353 {
355
356 if(id == -1)
357 return;
358
360
361 if(!enabled)
362 return;
363
364 voip::release_registry(context, id);
365 }
366
367 char *forward::referLocal(
MappedRegistry *rr,
const char *target,
char *buffer,
size_t size)
368 {
369 if(!refer)
370 return NULL;
371
372 if(!isActive(rr->
rid))
373 return NULL;
374
375 if(sip_tlsmode)
376 snprintf(buffer, size, "sips:%s@%s", target, refer);
377 else
378 snprintf(buffer, size, "sip:%s@%s", target, refer);
379 return buffer;
380 }
381
382 bool forward::authenticate(
int id,
const char *remote_realm)
383 {
386 const char *secret = NULL;
387
388 if(id == -1)
389 return false;
390
391 rr = find(id);
392 if(!rr)
393 return false;
394
395 node = service::getUser(rr->
userid);
396 if(node) {
397 leaf = node->leaf("secret");
398 if(leaf)
399 secret = leaf->getPointer();
400 }
401
402 if(secret && *secret)
403 shell::debug(3,
"authorizing %s for %s", rr->
userid, remote_realm);
404 else {
405 shell::debug(3,
"cannot authorize %s for %s", rr->
userid, remote_realm);
406 service::release(node);
407 releaseMap(rr);
408 remove(id);
409 return false;
410 }
411 voip::add_authentication(context, rr->
userid, secret, remote_realm,
true);
412 service::release(node);
413 releaseMap(rr);
414 return true;
415 }
416
418 {
419 switch(mode) {
420 case modules::REG_FAILED:
421 remove(id);
422 return;
423 case modules::REG_SUCCESS:
424 activate(id);
425 return;
426 }
427 }
428
429 } // end namespace
Structure for SIP Message (REQUEST and RESPONSE).
void activate(voip::reg_t id)
Some convenience methods for manipulating SIP uri's.
void add(MappedRegistry *rr)
Representation of a mapped active user record.
sockaddr_internet contact
keynode * getList(const char *path)
bool isActive(voip::reg_t id)
void releaseMap(MappedRegistry *rr)
Top level include directory for GNU Telephony SIP Witch Server.
void remove(voip::reg_t id)
voip::context_t route(const char *uri, char *buf, size_t size)
System configuration instance and service functions.
Common interfaces and clases for plugins.
Common base class for sipwitch plugin services.
treemap< char * > keynode
Definition of a xml node.
MappedRegistry * find(voip::reg_t id)
enum sipwitch::MappedRegistry::@5 type
void disable(voip::reg_t id)