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>
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
54 {
55 #ifdef _MSWINDOWS_
56 Socket::init();
57 #endif
61
63 }
64
66 {
67 #ifdef _MSWINDOWS_
68 Socket::init();
69 #endif
73 }
74
76 {
78 uint16_t current;
79
80 unsigned index = 0;
81 while(index <
count) {
83 if(current > prior && current < next)
84 next = current;
85 }
87 }
88
90 {
91 uint32_t result = 0;
92 unsigned index = 0;
93
94 while(index <
count) {
95 if(
srvlist[index].priority == priority) {
97 }
98 ++index;
99 }
100 return result;
101 }
102
103 struct sockaddr *
srv::find(uint16_t priority, uint32_t weight)
104 {
106 unsigned index = 0;
107
108 while(index <
count) {
109 if(
srvlist[index].priority == priority) {
111 if(total >= weight) {
113 }
114 }
115 ++index;
116 }
117 return NULL;
118 }
119
121 {
122 int protocol = IPPROTO_UDP;
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
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
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
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
191 while(is(cb)) {
192 srvlist = cb->resolve(uri, &hint);
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;
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
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
295 if(!current || priority < current->priority || weight > current->
weight) {
299 }
301 }
302 cp += result;
303 }
304
305 return;
306 nosrv:
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;
320
321 if(ap)
323 while(ap) {
325 ap = ap->ai_next;
326 }
327 }
328
330 {
332 }
333
335 {
339 }
340
341 if(list) {
342 freeaddrinfo(list);
343 list = NULL;
344 }
345
348 }
349
351 {
352 #ifdef HAVE_RESOLV_H
353 unsigned index = 0;
356 while(index <
count) {
358 if(np->priority <
pri)
359 continue;
361 node = np;
362 }
363 if(!node) {
365 return NULL;
366 }
369 #else
371 #endif
373 }
374
376 {
377 char host[256];
378 const char *schema = "sip";
379 const char *sid = uri;
382
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 }
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.
static voip::context_t udp_context
static voip::context_t tls_context
Manipulate address strings.
static voip::context_t tcp_context
struct sockaddr_storage addr
struct sockaddr * next(void)
static LinkedObject * getGenerics(void)
struct sockaddr * find(uint16_t priority, uint32_t weight)
voip::context_t route(const char *uri, char *buf, size_t size)
Service configuration and component callbacks.
static voip::context_t out_context
static bool hostid(const char *sipuri, char *buffer, size_t size)
uint32_t total(uint16_t priority)
void set(const char *uri)
static unsigned short portid(const char *sipuri)
uint16_t after(uint16_t priority=0)