SIP Witch 1.9.15
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
srv.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 <ucommon/secure.h>
19 #include <ucommon/export.h>
20 #include <sipwitch/uri.h>
21 #include <sipwitch/service.h>
22 #include <sipwitch/modules.h>
23 
24 #ifdef HAVE_RESOLV_H
25 extern "C" {
26 #include <resolv.h>
27 
28 #if defined(__APPLE__) && defined(__MACH__)
29 #include <arpa/nameser_compat.h>
30 #endif
31 
32 }
33 
34 #if PACKETSZ > 1024
35 #define MAXPACKET PACKETSZ
36 #else
37 #define MAXPACKET 1024
38 #endif
39 
40 typedef union {
41  HEADER hdr;
42  char buf[MAXPACKET];
43 } query;
44 
45 #ifndef T_SRV
46 #define T_SRV 33
47 #endif
48 
49 #endif
50 
51 namespace sipwitch {
52 
53 srv::srv(const char *uri) : Socket::address()
54 {
55 #ifdef _MSWINDOWS_
56  Socket::init();
57 #endif
58  srvlist = NULL;
59  entry = NULL;
60  count = 0;
61 
62  set(uri);
63 }
64 
65 srv::srv() : Socket::address()
66 {
67 #ifdef _MSWINDOWS_
68  Socket::init();
69 #endif
70  srvlist = NULL;
71  entry = NULL;
72  count = 0;
73 }
74 
75 uint16_t srv::after(uint16_t prior)
76 {
77  uint16_t next = 0;
78  uint16_t current;
79 
80  unsigned index = 0;
81  while(index < count) {
82  current = srvlist[index++].priority;
83  if(current > prior && current < next)
84  next = current;
85  }
86  return next;
87 }
88 
89 uint32_t srv::total(uint16_t priority)
90 {
91  uint32_t result = 0;
92  unsigned index = 0;
93 
94  while(index < count) {
95  if(srvlist[index].priority == priority) {
96  result += srvlist[index].weight;
97  }
98  ++index;
99  }
100  return result;
101 }
102 
103 struct sockaddr *srv::find(uint16_t priority, uint32_t weight)
104 {
105  uint32_t total = 0;
106  unsigned index = 0;
107 
108  while(index < count) {
109  if(srvlist[index].priority == priority) {
110  total += srvlist[index].weight;
111  if(total >= weight) {
112  return (struct sockaddr *)&srvlist[index].addr;
113  }
114  }
115  ++index;
116  }
117  return NULL;
118 }
119 
120 void srv::set(const char *uri)
121 {
122  int protocol = IPPROTO_UDP;
123  int port = uri::portid(uri);
124  char host[256], svc[10];
125  struct addrinfo hint;
126 
128  protocol = IPPROTO_TCP;
129 
130 #if defined(HAVE_RESOLV_H)
131  bool nosrv = false;
132 #endif
133 
134  clear();
135 
136  String::set(svc, sizeof(svc), "sip");
137 
138  if(port) {
139 #ifdef HAVE_RESOLV_H
140  nosrv = true;
141 #endif
142  snprintf(svc, sizeof(svc), "%d", port);
143  }
144  else if(eq(uri, "sips:", 5)) {
145  protocol = IPPROTO_TCP;
146  String::set(svc, sizeof(svc), "sips");
147  }
148  else if(eq(uri, "tcp:", 4)) {
149  protocol = IPPROTO_TCP;
150  uri += 4;
151  }
152  else if(eq(uri, "udp:", 4)) {
153  protocol = IPPROTO_UDP;
154  uri += 4;
155  }
156 
157  uri::hostid(uri, host, sizeof(host));
158  memset(&hint, 0, sizeof(hint));
159 
160  hint.ai_socktype = 0;
161  hint.ai_protocol = protocol;
162 
163  if(hint.ai_protocol == IPPROTO_UDP)
164  hint.ai_socktype = SOCK_DGRAM;
165  else
166  hint.ai_socktype = SOCK_STREAM;
167 
168 #ifdef PF_UNSPEC
169  hint.ai_flags = AI_PASSIVE;
170 #endif
171 
172  if(Socket::is_numeric(host)) {
173  hint.ai_flags |= AI_NUMERICHOST;
174 #ifdef HAVE_RESOLV_H
175  nosrv = true;
176 #endif
177  }
178 
179  hint.ai_family = service::callback::sip_family;
180 
181 #if defined(AF_INET6) && defined(AI_V4MAPPED)
182  if(hint.ai_family == AF_INET6)
183  hint.ai_flags |= AI_V4MAPPED;
184 #endif
185 #ifdef AI_NUMERICSERV
186  if(atoi(svc) > 0)
187  hint.ai_flags |= AI_NUMERICSERV;
188 #endif
189 
190  linked_pointer<modules::generic> cb = service::getGenerics();
191  while(is(cb)) {
192  srvlist = cb->resolve(uri, &hint);
193  if(srvlist) {
194  count = 1;
195  entry = (struct sockaddr *)&srvlist[0].addr;
196  pri = srvlist[0].priority;
197  return;
198  }
199  cb.next();
200  }
201 
202 #ifdef HAVE_RESOLV_H
203  int result;
204  HEADER *hp;
205  char hbuf[256];
206  uint16_t acount, qcount;
207  unsigned char *mp, *ep, *cp;
208  uint16_t type, weight, priority, hport, dlen;
209  srv::address *current = NULL;
210 
211  if(nosrv)
212  goto nosrv;
213 
214  query reply;
215  char zone[256];
216 
217  if(hint.ai_protocol == IPPROTO_TCP)
218  snprintf(zone, sizeof(zone), "_%s._tcp.%s", svc, host);
219  else
220  snprintf(zone, sizeof(zone), "_%s._udp.%s", svc, host);
221 
222  result = res_query(zone, C_IN, T_SRV, (unsigned char *)&reply, sizeof(reply));
223  if(result < (int)sizeof(HEADER))
224  goto nosrv;
225 
226  hp = (HEADER *)&reply;
227  acount = ntohs(hp->ancount);
228  qcount = ntohs(hp->qdcount);
229  mp = (unsigned char *)&reply;
230  ep = (unsigned char *)&reply + result;
231  cp = (unsigned char *)&reply + sizeof(HEADER);
232 
233  if(!acount)
234  goto nosrv;
235 
236  srvlist = new srv::address[acount];
237  while(qcount-- > 0 && cp < ep) {
238  result = dn_expand(mp, ep, cp, hbuf, sizeof(hbuf));
239  if(result < 0)
240  goto nosrv;
241  cp += result + QFIXEDSZ;
242  }
243 
244  while(acount-- > 0 && cp < ep) {
245  result = dn_expand(mp, ep, cp, hbuf, sizeof(hbuf));
246  if(result < 0)
247  goto nosrv;
248 
249  cp += result;
250 
251  type = ntohs(*((uint16_t *)cp));
252  cp += sizeof(uint16_t);
253 
254  // class
255  cp += sizeof(uint16_t);
256 
257  // ttl
258  cp += sizeof(uint32_t);
259 
260  dlen = ntohs(*((uint16_t *)cp));
261  cp += sizeof(uint16_t);
262 
263  if(type != T_SRV) {
264  cp += dlen;
265  continue;
266  }
267 
268  priority = ntohs(*((uint16_t *)cp));
269  cp += sizeof(uint16_t);
270 
271  weight = ntohs(*((uint16_t *)cp));
272  cp += sizeof(uint16_t);
273 
274  hport = ntohs(*((uint16_t *)cp));
275  cp += sizeof(uint16_t);
276 
277  result = dn_expand(mp, ep, cp, hbuf, sizeof(hbuf));
278  if(result < 0)
279  break;
280 
281  Socket::address resolv(hbuf, hport);
282  const struct sockaddr *sp = resolv.getAddr();
283 
284  if(sp) {
285  uint16_t rand;
286 
287  Random::fill((unsigned char *)&rand, sizeof(rand));
288  rand &= 0x7fff;
289  if(weight)
290  weight = (1 + rand) % ( 10000 * weight);
291 
292  srvlist[count].weight = weight;
293  srvlist[count].priority = priority;
294  Socket::store(&srvlist[count].addr, sp);
295  if(!current || priority < current->priority || weight > current->weight) {
296  current = &srvlist[count];
297  entry = (struct sockaddr *)&srvlist[count].addr;
298  pri = priority;
299  }
300  ++count;
301  }
302  cp += result;
303  }
304 
305  return;
306 nosrv:
307  if(srvlist) {
308  delete[] srvlist;
309  srvlist = NULL;
310  }
311 #endif
312 
313  if(eq(svc, "sips"))
314  String::set(svc, sizeof(svc), "5061");
315  else if(eq(svc, "sip"))
316  String::set(svc, sizeof(svc), "5060");
317  getaddrinfo(host, svc, &hint, &list);
318  struct addrinfo *ap = list;
319  count = 0;
320 
321  if(ap)
322  entry = ap->ai_addr;
323  while(ap) {
324  ++count;
325  ap = ap->ai_next;
326  }
327 }
328 
330 {
331  clear();
332 }
333 
334 void srv::clear(void)
335 {
336  if(srvlist) {
337  delete[] srvlist;
338  srvlist = NULL;
339  }
340 
341  if(list) {
342  freeaddrinfo(list);
343  list = NULL;
344  }
345 
346  entry = NULL;
347  count = 0;
348 }
349 
350 struct sockaddr *srv::next(void)
351 {
352 #ifdef HAVE_RESOLV_H
353  unsigned index = 0;
354  srv::address *node = NULL, *np = NULL;
355  ++pri;
356  while(index < count) {
357  np = &srvlist[index++];
358  if(np->priority < pri)
359  continue;
360  if(!node || np->priority < node->priority || np->weight > node->weight)
361  node = np;
362  }
363  if(!node) {
364  entry = NULL;
365  return NULL;
366  }
367  pri = node->priority;
368  entry = (struct sockaddr *)&node->addr;
369 #else
370  entry = NULL;
371 #endif
372  return entry;
373 }
374 
375 voip::context_t srv::route(const char *uri, char *buf, size_t size)
376 {
377  char host[256];
378  const char *schema = "sip";
379  const char *sid = uri;
380  unsigned short port = uri::portid(uri);
382 
383  if(!uri::hostid(uri, host, sizeof(host)))
384  return NULL;
385 
386  if(eq(uri, "sips:", 5)) {
387  schema = "sips";
389  }
390  else if(eq(uri, "tcp:", 4)) {
392  }
393  else if(eq(uri, "udp:", 4)) {
395  }
396 
397  buf[0] = 0;
398  char *cp = strrchr(host, '.');
399  if(Socket::is_numeric(host) || !cp || eq(cp, ".local") || eq(cp, ".localdomain")) {
400  if(!port) {
401  if(eq(schema, "sips"))
402  port = 5061;
403  else
404  port = 5060;
405  }
406  if(strchr(host, ':'))
407  snprintf(buf, size, "%s:[%s]:%u", schema, host, port);
408  else
409  snprintf(buf, size, "%s:%s:%u", schema, host, port);
410  sid = buf;
411  }
412  set(sid);
413  if(!entry)
414  return NULL;
415  if(!Socket::query(entry, host, sizeof(host)))
416  return NULL;
417 #ifdef AF_INET6
418  if(entry->sa_family == AF_INET6)
419  snprintf(buf, size, "%s:[%s]:%u", schema, host, (unsigned)ntohs(((struct sockaddr_in6 *)(entry))->sin6_port) & 0xffff);
420  else
421 #endif
422  snprintf(buf, size, "%s:%s:%u", schema, host, (unsigned)ntohs(((struct sockaddr_in *)(entry))->sin_port) & 0xffff);
423  return ctx;
424 }
425 
426 } // end namespace
Used for definitions of plugin modules.
Some convenience methods for manipulating SIP uri's.
Definition: uri.h:55
static voip::context_t udp_context
Definition: service.h:235
static voip::context_t tls_context
Definition: service.h:236
struct sockaddr * entry
Definition: uri.h:81
Manipulate address strings.
static voip::context_t tcp_context
Definition: service.h:234
uint16_t pri
Definition: uri.h:82
struct sockaddr_storage addr
Definition: uri.h:75
struct sockaddr * next(void)
Definition: srv.cpp:350
address * srvlist
Definition: uri.h:80
uint16_t priority
Definition: uri.h:76
static LinkedObject * getGenerics(void)
Definition: service.h:273
unsigned count
Definition: uri.h:83
struct sockaddr * find(uint16_t priority, uint32_t weight)
Definition: srv.cpp:103
uint16_t weight
Definition: uri.h:76
voip::context_t route(const char *uri, char *buf, size_t size)
Definition: srv.cpp:375
void * context_t
Definition: voip.h:53
Service configuration and component callbacks.
void clear(void)
Definition: srv.cpp:334
static voip::context_t out_context
Definition: service.h:233
static bool hostid(const char *sipuri, char *buffer, size_t size)
Definition: uri.cpp:41
uint32_t total(uint16_t priority)
Definition: srv.cpp:89
void set(const char *uri)
Definition: srv.cpp:120
static unsigned short portid(const char *sipuri)
Definition: uri.cpp:99
uint16_t after(uint16_t priority=0)
Definition: srv.cpp:75