SIP Witch 1.9.15
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
forward.cpp
Go to the documentation of this file.
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>
18 #include <sipwitch/sipwitch.h>
19 
20 namespace sipwitch {
21 
22 #define INDEX_SIZE 177
23 
24 class __LOCAL forward : public modules::sipwitch
25 {
26 public:
27  class __LOCAL regmap : public LinkedObject
28  {
29  public:
30  friend class forward;
32  bool active;
33  };
34 
35  char *volatile proxy;
36  char *volatile realm;
37  char *volatile digest;
38  char *volatile server;
39  char *volatile schema;
40  char *volatile refer;
42  time_t expires;
43  bool enabled;
44  condlock_t locking;
45  unsigned allocated, active;
47  regmap *index[INDEX_SIZE];
48  memalloc pager;
49 
50  forward();
51 
52  void activate(voip::reg_t id);
53  void disable(voip::reg_t id);
54  bool isActive(voip::reg_t id);
55  void remove(voip::reg_t id);
56  void add(MappedRegistry *rr);
57  MappedRegistry *find(voip::reg_t id);
58  void releaseMap(MappedRegistry *rr);
59 
60 private:
61  void start(service *cfg);
62  void reload(service *cfg);
63  void activating(MappedRegistry *rr);
64  void expiring(MappedRegistry *rr);
65  void registration(voip::reg_t id, modules::regmode_t mode);
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 
71 static forward forward_plugin;
72 
74 modules::sipwitch()
75 {
76  shell::log(shell::INFO, "%s\n",
77  _TEXT("server forward plugin loaded"));
78 
79  enabled = false;
80  refer = NULL;
81  digest = (char *)"MD5";
82  realm = (char *)"GNU Telephony";
83  proxy = NULL;
84  freelist = NULL;
85  memset(index, 0, sizeof(index));
86  allocated = active = 0;
87  expires = 120;
88 }
89 
91 {
92  if(rr)
93  locking.release();
94 }
95 
97 {
98  bool activeflag = false;
99 
100  linked_pointer<regmap> mp;
101  int path = id % INDEX_SIZE;
102  locking.access();
103  mp = index[path];
104  while(is(mp)) {
105  if(mp->active) {
106  activeflag = true;
107  break;
108  }
109  mp.next();
110  }
111  locking.release();
112  return activeflag;
113 }
114 
116 {
117  linked_pointer<regmap> mp;
118  int path = id % INDEX_SIZE;
119  locking.access();
120  mp = index[path];
121  while(is(mp)) {
122  if(mp->entry->rid == id)
123  return mp->entry;
124  mp.next();
125  }
126  locking.release();
127  return NULL;
128 }
129 
131 {
132  linked_pointer<regmap> mp;
133  int path = id % INDEX_SIZE;
134  locking.access();
135  mp = index[path];
136  while(is(mp)) {
137  if(mp->entry->rid == id) {
138  mp->active = false;
139  break;
140  }
141  mp.next();
142  }
143  locking.release();
144 }
145 
147 {
148  linked_pointer<regmap> mp;
149  int path = id % INDEX_SIZE;
150  locking.access();
151  mp = index[path];
152  while(is(mp)) {
153  if(mp->entry->rid == id) {
154  mp->active = true;
155  break;
156  }
157  mp.next();
158  }
159  locking.release();
160 }
161 
163 {
164  regmap *prior = NULL;
165  linked_pointer<regmap> mp;
166  int path = id % INDEX_SIZE;
167  locking.modify();
168  mp = index[path];
169  while(is(mp)) {
170  if(mp->entry->rid == id) {
171  if(prior)
172  prior->Next = mp->Next;
173  else
174  index[path] = (regmap *)mp->Next;
175  mp->Next = freelist;
176  freelist = *mp;
177  shell::debug(3, "forward unmap %s from %d", mp->entry->userid, id);
178  --active;
179  locking.commit();
180  mp->entry->rid = -1;
181  return;
182  }
183  mp.next();
184  }
185  shell::debug(3, "forward map %d not found", id);
186  locking.commit();
187 }
188 
190 {
191  regmap *map;
192  int path = rr->rid % INDEX_SIZE;
193  locking.modify();
194  map = freelist;
195  if(map)
196  freelist = (regmap *)map->Next;
197  else {
198  ++allocated;
199  map = (regmap *)pager.alloc(sizeof(regmap));
200  }
201  map->entry = rr;
202  map->Next = index[path];
203  index[path] = map;
204  locking.commit();
205  shell::debug(3, "forward mapped %s as %d", rr->userid, rr->rid);
206  ++active;
207 }
208 
209 void forward::reload(service *cfg)
210 {
211  assert(cfg != NULL);
212 
213  char buffer[160];
214  bool refering = false;
215  bool enable = false;
216  const char *key = NULL, *value;
217  char *tmp_realm = (char *)realm, *tmp_digest = cfg->dup((char *)digest);
218  char *tmp_schema = (char *)"sip";
219  voip::context_t tmp_context = NULL;
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 
235  srv resolver;
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);
249  server = NULL;
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);
260  server = NULL;
261  }
262  if(server && *server) {
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 
294 void forward::start(service *cfg)
295 {
296  assert(cfg != NULL);
297 }
298 
299 void forward::activating(MappedRegistry *rr)
300 {
301  char contact[MAX_URI_SIZE];
302  char uri[MAX_URI_SIZE];
303  char reg[MAX_URI_SIZE];
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);
319  voip::msg_t msg = NULL;
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 {
333  char uri_to[MAX_URI_SIZE];
334  char contact[MAX_URI_SIZE];
335  size_t len;
336 
337  if(!isActive(rr->rid) || !rr->remote[0])
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 
352 void forward::expiring(MappedRegistry *rr)
353 {
354  int id = rr->rid;
355 
356  if(id == -1)
357  return;
358 
359  remove(rr->rid);
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 {
384  MappedRegistry *rr;
385  service::keynode *node, *leaf;
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 
417 void forward::registration(int id, modules::regmode_t mode)
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).
Definition: osip_message.h:55
void activate(voip::reg_t id)
Definition: forward.cpp:146
Some convenience methods for manipulating SIP uri's.
Definition: uri.h:55
void add(MappedRegistry *rr)
Definition: forward.cpp:189
regmap * freelist
Definition: forward.cpp:46
Representation of a mapped active user record.
Definition: mapped.h:95
sockaddr_internet contact
Definition: mapped.h:111
keynode * getList(const char *path)
Definition: service.cpp:376
bool isActive(voip::reg_t id)
Definition: forward.cpp:96
#define INDEX_SIZE
Definition: forward.cpp:22
condlock_t locking
Definition: forward.cpp:44
unsigned active
Definition: forward.cpp:45
void releaseMap(MappedRegistry *rr)
Definition: forward.cpp:90
Top level include directory for GNU Telephony SIP Witch Server.
char *volatile server
Definition: forward.cpp:38
memalloc pager
Definition: forward.cpp:48
char * value[96]
Definition: cgiserver.cpp:90
MappedRegistry * entry
Definition: forward.cpp:31
void remove(voip::reg_t id)
Definition: forward.cpp:162
voip::context_t route(const char *uri, char *buf, size_t size)
Definition: srv.cpp:375
void * context_t
Definition: voip.h:53
char *volatile realm
Definition: forward.cpp:36
int reg_t
Definition: voip.h:59
char *volatile proxy
Definition: forward.cpp:35
voip::context_t context
Definition: forward.cpp:41
System configuration instance and service functions.
Definition: service.h:78
Common interfaces and clases for plugins.
Definition: modules.h:55
Common base class for sipwitch plugin services.
Definition: modules.h:66
char * map[96]
Definition: cgiserver.cpp:89
char *volatile digest
Definition: forward.cpp:37
unsigned allocated
Definition: forward.cpp:45
regmap * index[177]
Definition: forward.cpp:47
char *volatile refer
Definition: forward.cpp:40
treemap< char * > keynode
Definition of a xml node.
Definition: service.h:84
char *volatile schema
Definition: forward.cpp:39
MappedRegistry * find(voip::reg_t id)
Definition: forward.cpp:115
enum sipwitch::MappedRegistry::@5 type
void disable(voip::reg_t id)
Definition: forward.cpp:130
#define MAX_URI_SIZE
Definition: mapped.h:71