1 /*
2 * $Id: helper.c 397 2006-01-28 21:11:50Z calrissian $
3 *
4 * Copyright (C) 2002-2004 Fhg Fokus
5 * Copyright (C) 2004-2005 Nils Ohlmeier
6 *
7 * This file belongs to sipsak, a free sip testing tool.
8 *
9 * sipsak is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * sipsak is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 */
19 #include "sipsak.h"
20
21 #ifdef HAVE_NETDB_H
22 # include <netdb.h>
23 #endif
24 #ifdef HAVE_UNISTD_H
25 # ifdef HAVE_SYS_TYPES_H
26 # include <sys/types.h>
27 # endif
28 # include <unistd.h>
29 #endif
30 #ifdef HAVE_SYS_UTSNAME_H
31 # include <sys/utsname.h>
32 #endif
33 #ifdef HAVE_CTYPE_H
34 # include <ctype.h>
35 #endif
36 #ifdef HAVE_ARPA_INET_H
37 # include <arpa/inet.h>
38 #endif
39 #ifdef HAVE_NETINET_IN_H
40 # include <netinet/in.h>
41 #endif
42 #ifdef HAVE_RULI_H
43 # include <ruli.h>
44 #endif
45 #ifdef HAVE_ERRNO_H
46 # include <errno.h>
47 #endif
48 #ifdef HAVE_CARES_H
49 # ifdef HAVE_ARPA_NAMESER_H
50 # include <arpa/nameser.h>
51 # endif
52 # include <ares.h>
53 # ifndef NS_RRFIXEDSZ
54 # define NS_RRFIXEDSZ 10
55 # define NS_QFIXEDSZ 4
56 # define NS_HFIXEDSZ 12
57 # endif
58 int caport;
59 unsigned long caadr;
60 char *ca_tmpname;
61 ares_channel channel;
62
63 #endif // HAVE_CARES_H
64
65 #include "helper.h"
66 #include "exit_code.h"
67
68 /* returns 1 if the string an IP address otherwise zero */
is_ip(char * str)69 int is_ip(char *str) {
70 int i = 0;
71 int dotcount = 0;
72
73 /*try understanding if this is a valid ip address
74 we are skipping the values of the octets specified here.
75 for instance, this code will allow 952.0.320.567 through*/
76 while (*str != '\0')
77 {
78 for (i = 0; i < 3; i++, str++)
79 if (isdigit((int)*str) == 0)
80 break;
81 if (*str != '.')
82 break;
83 str++;
84 dotcount++;
85 }
86
87 /* three dots with upto three digits in before, between and after ? */
88 if (dotcount == 3 && i > 0 && i <= 3)
89 return 1;
90 else
91 return 0;
92 }
93
94 /* take either a dot.decimal string of ip address or a
95 domain name and returns a NETWORK ordered long int containing
96 the address. i chose to internally represent the address as long for speedier
97 comparisions.
98
99 any changes to getaddress have to be patched back to the net library.
100 contact: farhan@hotfoon.com
101
102 returns zero if there is an error.
103 this is convenient as 0 means 'this' host and the traffic of
104 a badly behaving dns system remains inside (you send to 0.0.0.0)
105 */
106
getaddress(char * host)107 unsigned long getaddress(char *host) {
108 struct hostent* pent;
109 long l, *lp;
110
111 if (is_ip(host))
112 return inet_addr(host);
113
114 /* try the system's own resolution mechanism for dns lookup:
115 required only for domain names.
116 inspite of what the rfc2543 :D Using SRV DNS Records recommends,
117 we are leaving it to the operating system to do the name caching.
118
119 this is an important implementational issue especially in the light
120 dynamic dns servers like dynip.com or dyndns.com where a dial
121 ip address is dynamically assigned a sub domain like farhan.dynip.com
122
123 although expensive, this is a must to allow OS to take
124 the decision to expire the DNS records as it deems fit.
125 */
126 pent = gethostbyname(host);
127 if (!pent) {
128 printf("'%s' is unresolveable\n", host);
129 exit_code(2);
130 }
131 lp = (long *) (pent->h_addr);
132 l = *lp;
133 return l;
134 }
135
136 #ifdef HAVE_CARES_H
parse_rr(const unsigned char * aptr,const unsigned char * abuf,int alen)137 static const unsigned char *parse_rr(const unsigned char *aptr, const unsigned char *abuf, int alen) {
138 char *name;
139 long len;
140 int status, type, dnsclass, dlen;
141 struct in_addr addr;
142
143 #ifdef DEBUG
144 printf("ca_tmpname: %s\n", ca_tmpname);
145 #endif
146 status = ares_expand_name(aptr, abuf, alen, &name, &len);
147 if (status != ARES_SUCCESS) {
148 printf("error: failed to expand query name\n");
149 exit_code(2);
150 }
151 aptr += len;
152 if (aptr + NS_RRFIXEDSZ > abuf + alen) {
153 printf("error: not enough data in DNS answer 1\n");
154 free(name);
155 return NULL;
156 }
157 type = DNS_RR_TYPE(aptr);
158 dnsclass = DNS_RR_CLASS(aptr);
159 dlen = DNS_RR_LEN(aptr);
160 aptr += NS_RRFIXEDSZ;
161 if (aptr + dlen > abuf + alen) {
162 printf("error: not enough data in DNS answer 2\n");
163 free(name);
164 return NULL;
165 }
166 if (dnsclass != CARES_CLASS_C_IN) {
167 printf("error: unsupported dnsclass (%i) in DNS answer\n", dnsclass);
168 free(name);
169 return NULL;
170 }
171 if ((ca_tmpname == NULL && type != CARES_TYPE_SRV) ||
172 (ca_tmpname != NULL &&
173 (type != CARES_TYPE_A && type != CARES_TYPE_CNAME))) {
174 printf("error: unsupported DNS response type (%i)\n", type);
175 free(name);
176 return NULL;
177 }
178 if (type == CARES_TYPE_SRV) {
179 free(name);
180 caport = DNS__16BIT(aptr + 4);
181 #ifdef DEBUG
182 printf("caport: %i\n", caport);
183 #endif
184 status = ares_expand_name(aptr + 6, abuf, alen, &name, &len);
185 if (status != ARES_SUCCESS) {
186 printf("error: failed to expand SRV name\n");
187 return NULL;
188 }
189 #ifdef DEBUG
190 printf("SRV name: %s\n", name);
191 #endif
192 if (is_ip(name)) {
193 caadr = inet_addr(name);
194 free(name);
195 }
196 else {
197 ca_tmpname = name;
198 }
199 }
200 else if (type == CARES_TYPE_CNAME) {
201 if (STRNCASECMP(ca_tmpname, name, strlen(ca_tmpname)) == 0) {
202 ca_tmpname = malloc(strlen(name));
203 if (ca_tmpname == NULL) {
204 printf("error: failed to allocate memory\n");
205 exit_code(2);
206 }
207 strcpy(ca_tmpname, name);
208 }
209 free(name);
210 }
211 else if (type == CARES_TYPE_A) {
212 if (dlen == 4 && STRNCASECMP(ca_tmpname, name, strlen(ca_tmpname)) == 0) {
213 memcpy(&addr, aptr, sizeof(struct in_addr));
214 caadr = addr.s_addr;
215 }
216 free(name);
217 }
218 return aptr + dlen;
219 }
220
skip_rr(const unsigned char * aptr,const unsigned char * abuf,int alen)221 static const unsigned char *skip_rr(const unsigned char *aptr, const unsigned char *abuf, int alen) {
222 int status, dlen;
223 long len;
224 char *name;
225
226 #ifdef DEBUG
227 printf("skipping rr section...\n");
228 #endif
229 status = ares_expand_name(aptr, abuf, alen, &name, &len);
230 aptr += len;
231 dlen = DNS_RR_LEN(aptr);
232 aptr += NS_RRFIXEDSZ;
233 aptr += dlen;
234 free(name);
235 return aptr;
236 }
237
skip_query(const unsigned char * aptr,const unsigned char * abuf,int alen)238 static const unsigned char *skip_query(const unsigned char *aptr, const unsigned char *abuf, int alen) {
239 int status;
240 long len;
241 char *name;
242
243 #ifdef DEBUG
244 printf("skipping query section...\n");
245 #endif
246 status = ares_expand_name(aptr, abuf, alen, &name, &len);
247 aptr += len;
248 aptr += NS_QFIXEDSZ;
249 free(name);
250 return aptr;
251 }
252
cares_callback(void * arg,int status,unsigned char * abuf,int alen)253 static void cares_callback(void *arg, int status, unsigned char *abuf, int alen) {
254 int i;
255 unsigned int ancount, nscount, arcount;
256 const unsigned char *aptr;
257
258 #ifdef DEBUG
259 printf("cares_callback: status=%i, alen=%i\n", status, alen);
260 #endif
261 if (status != ARES_SUCCESS) {
262 if (verbose > 1)
263 printf("ares failed: %s\n", ares_strerror(status));
264 return;
265 }
266
267 ancount = DNS_HEADER_ANCOUNT(abuf);
268 nscount = DNS_HEADER_NSCOUNT(abuf);
269 arcount = DNS_HEADER_ARCOUNT(abuf);
270
271 #ifdef DEBUG
272 printf("ancount: %i, nscount: %i, arcount: %i\n", ancount, nscount, arcount);
273 #endif
274
275 /* safety check */
276 if (alen < NS_HFIXEDSZ)
277 return;
278 aptr = abuf + NS_HFIXEDSZ;
279
280 aptr = skip_query(aptr, abuf, alen);
281
282 for (i = 0; i < ancount && caadr == 0; i++) {
283 if (ca_tmpname == NULL)
284 aptr = parse_rr(aptr, abuf, alen);
285 else
286 aptr = skip_rr(aptr, abuf, alen);
287 }
288 if (caadr == 0) {
289 for (i = 0; i < nscount; i++) {
290 aptr = skip_rr(aptr, abuf, alen);
291 }
292 for (i = 0; i < arcount && caadr == 0; i++) {
293 aptr = parse_rr(aptr, abuf, alen);
294 }
295 }
296 }
297
srv_ares(char * host,int * port,char * srv)298 inline unsigned long srv_ares(char *host, int *port, char *srv) {
299 int nfds, count, srvh_len;
300 char *srvh;
301 fd_set read_fds, write_fds;
302 struct timeval *tvp, tv;
303
304 caport = 0;
305 caadr = 0;
306 ca_tmpname = NULL;
307 #ifdef DEBUG
308 printf("!!! ARES query !!!\n");
309 #endif
310
311 srvh_len = strlen(host) + strlen(srv) + 2;
312 srvh = malloc(srvh_len);
313 if (srvh == NULL) {
314 printf("error: failed to allocate memory (%i) for ares query\n", srvh_len);
315 exit_code(2);
316 }
317 memset(srvh, 0, srvh_len);
318 strncpy(srvh, srv, strlen(srv));
319 memcpy(srvh + strlen(srv), ".", 1);
320 strcpy(srvh + strlen(srv) + 1, host);
321 #ifdef DEBUG
322 printf("hostname: '%s', len: %i\n", srvh, srvh_len);
323 #endif
324
325 ares_query(channel, srvh, CARES_CLASS_C_IN, CARES_TYPE_SRV, cares_callback, (char *) NULL);
326 #ifdef DEBUG
327 printf("after ares_query\n");
328 #endif
329 /* wait for query to complete */
330 while (1) {
331 FD_ZERO(&read_fds);
332 FD_ZERO(&write_fds);
333 nfds = ares_fds(channel, &read_fds, &write_fds);
334 if (nfds == 0)
335 break;
336 tvp = ares_timeout(channel, NULL, &tv);
337 count = select(nfds, &read_fds, &write_fds, NULL, tvp);
338 if (count < 0 && errno != EINVAL) {
339 perror("ares select");
340 exit_code(2);
341 }
342 ares_process(channel, &read_fds, &write_fds);
343 }
344 #ifdef DEBUG
345 printf("end of while\n");
346 #endif
347 *port = caport;
348 if (caadr == 0 && ca_tmpname != NULL) {
349 caadr = getaddress(ca_tmpname);
350 }
351 if (ca_tmpname != NULL)
352 free(ca_tmpname);
353 free(srvh);
354 return caadr;
355 }
356 #endif // HAVE_CARES_H
357
358 #ifdef HAVE_RULI_H
srv_ruli(char * host,int * port,char * srv)359 inline unsigned long srv_ruli(char *host, int *port, char *srv) {
360 int srv_code;
361 int ruli_opts = RULI_RES_OPT_SEARCH | RULI_RES_OPT_SRV_NOINET6 | RULI_RES_OPT_SRV_NOSORT6 | RULI_RES_OPT_SRV_NOFALL;
362 #ifdef RULI_RES_OPT_SRV_CNAME
363 ruli_opts |= RULI_RES_OPT_SRV_CNAME;
364 #endif
365
366 ruli_sync_t *sync_query = ruli_sync_query(srv, host, *port, ruli_opts);
367
368 /* sync query failure? */
369 if (!sync_query) {
370 printf("DNS SRV lookup failed for: %s\n", host);
371 exit_code(2);
372 }
373
374 srv_code = ruli_sync_srv_code(sync_query);
375 /* timeout? */
376 if (srv_code == RULI_SRV_CODE_ALARM) {
377 printf("Timeout during DNS SRV lookup for: %s\n", host);
378 ruli_sync_delete(sync_query);
379 exit_code(2);
380 }
381 /* service provided? */
382 else if (srv_code == RULI_SRV_CODE_UNAVAILABLE) {
383 printf("SRV service not provided for: %s\n", host);
384 ruli_sync_delete(sync_query);
385 exit_code(2);
386 }
387 else if (srv_code) {
388 int rcode = ruli_sync_rcode(sync_query);
389 if (verbose > 1)
390 printf("SRV query failed for: %s, srv_code=%d, rcode=%d\n", host, srv_code, rcode);
391 ruli_sync_delete(sync_query);
392 return 0;
393 }
394
395 ruli_list_t *srv_list = ruli_sync_srv_list(sync_query);
396
397 int srv_list_size = ruli_list_size(srv_list);
398
399 if (srv_list_size < 1) {
400 if (verbose > 1)
401 printf("No SRV record: %s.%s\n", srv, host);
402 return 0;
403 }
404
405 ruli_srv_entry_t *entry = (ruli_srv_entry_t *) ruli_list_get(srv_list, 0);
406 ruli_list_t *addr_list = &entry->addr_list;
407 int addr_list_size = ruli_list_size(addr_list);
408
409 if (addr_list_size < 1) {
410 printf("missing addresses in SRV lookup for: %s\n", host);
411 ruli_sync_delete(sync_query);
412 exit_code(2);
413 }
414
415 *port = entry->port;
416 ruli_addr_t *addr = (ruli_addr_t *) ruli_list_get(addr_list, 0);
417 return addr->addr.ipv4.s_addr;
418 }
419 #endif // HAVE_RULI_H
420
getsrvaddress(char * host,int * port,char * srv)421 unsigned long getsrvaddress(char *host, int *port, char *srv) {
422 #ifdef HAVE_RULI_H
423 return srv_ruli(host, port, srv);
424 #else
425 # ifdef HAVE_CARES_H // HAVE_RULI_H
426 return srv_ares(host, port, srv);
427 # else // HAVE_CARES_H
428 return 0;
429 # endif
430 #endif
431 }
432
433 /* Finds the SRV records for the given host. It returns the target IP
434 * address and fills the port and transport if a suitable SRV record
435 * exists. Otherwise it returns 0. The function follows 3263: first
436 * TLS, then TCP and finally UDP. */
getsrvadr(char * host,int * port,unsigned int * transport)437 unsigned long getsrvadr(char *host, int *port, unsigned int *transport) {
438 unsigned long adr = 0;
439
440 #ifdef HAVE_SRV
441 int srvport = 5060;
442
443 #ifdef HAVE_CARES_H
444 int status;
445 int optmask = ARES_OPT_FLAGS;
446 struct ares_options options;
447
448 options.flags = ARES_FLAG_NOCHECKRESP;
449 options.servers = NULL;
450 options.nservers = 0;
451
452 status = ares_init_options(&channel, &options, optmask);
453 if (status != ARES_SUCCESS) {
454 printf("error: failed to initialize ares\n");
455 exit_code(2);
456 }
457 #endif
458
459 #ifdef WITH_TLS_TRANSP
460 adr = getsrvaddress(host, &srvport, SRV_SIP_TLS);
461 if (adr != 0) {
462 *transport = SIP_TLS_TRANSPORT;
463 if (verbose > 1)
464 printf("using SRV record: %s.%s:%i\n", SRV_SIP_TLS, host, srvport);
465 printf("TLS transport not yet supported\n");
466 exit_code(2);
467 }
468 else {
469 #endif
470 adr = getsrvaddress(host, &srvport, SRV_SIP_TCP);
471 if (adr != 0) {
472 *transport = SIP_TCP_TRANSPORT;
473 if (verbose > 1)
474 printf("using SRV record: %s.%s:%i\n", SRV_SIP_TCP, host, srvport);
475 }
476 else {
477 adr = getsrvaddress(host, &srvport, SRV_SIP_UDP);
478 if (adr != 0) {
479 *transport = SIP_UDP_TRANSPORT;
480 if (verbose > 1)
481 printf("using SRV record: %s.%s:%i\n", SRV_SIP_UDP, host, srvport);
482 }
483 }
484 #ifdef WITH_TLS_TRANSP
485 }
486 #endif
487
488 #ifdef HAVE_CARES_H
489 ares_destroy(channel);
490 #endif
491
492 *port = srvport;
493 #endif // HAVE_SRV
494 return adr;
495 }
496
497 /* because the full qualified domain name is needed by many other
498 functions it will be determined by this function.
499 */
get_fqdn()500 void get_fqdn(){
501 char hname[100], dname[100], hlp[18];
502 size_t namelen=100;
503 struct hostent* he;
504 struct utsname un;
505
506 memset(&hname, 0, sizeof(hname));
507 memset(&dname, 0, sizeof(dname));
508 memset(&hlp, 0, sizeof(hlp));
509
510 if (hostname) {
511 strncpy(fqdn, hostname, FQDN_SIZE);
512 strncpy(hname, hostname, 100);
513 }
514 else {
515 if ((uname(&un))==0) {
516 strncpy(hname, un.nodename, 100);
517 }
518 else {
519 if (gethostname(&hname[0], namelen) < 0) {
520 fprintf(stderr, "error: cannot determine hostname\n");
521 exit_code(2);
522 }
523 }
524 #ifdef HAVE_GETDOMAINNAME
525 /* a hostname with dots should be a domainname */
526 if ((strchr(hname, '.'))==NULL) {
527 if (getdomainname(&dname[0], namelen) < 0) {
528 fprintf(stderr, "error: cannot determine domainname\n");
529 exit_code(2);
530 }
531 if (strcmp(&dname[0],"(none)")!=0)
532 snprintf(fqdn, FQDN_SIZE, "%s.%s", hname, dname);
533 }
534 else {
535 strncpy(fqdn, hname, FQDN_SIZE);
536 }
537 #endif
538 }
539
540 if (!(numeric == 1 && is_ip(fqdn))) {
541 he=gethostbyname(hname);
542 if (he) {
543 if (numeric == 1) {
544 snprintf(hlp, 15, "%s", inet_ntoa(*(struct in_addr *) he->h_addr_list[0]));
545 strncpy(fqdn, hlp, FQDN_SIZE);
546 }
547 else {
548 if ((strchr(he->h_name, '.'))!=NULL && (strchr(hname, '.'))==NULL) {
549 strncpy(fqdn, he->h_name, FQDN_SIZE);
550 }
551 else {
552 strncpy(fqdn, hname, FQDN_SIZE);
553 }
554 }
555 }
556 else {
557 fprintf(stderr, "error: cannot resolve local hostname: %s\n", hname);
558 exit_code(2);
559 }
560 }
561 if ((strchr(fqdn, '.'))==NULL) {
562 if (hostname) {
563 fprintf(stderr, "warning: %s is not resolvable... continouing anyway\n", fqdn);
564 strncpy(fqdn, hostname, FQDN_SIZE);
565 }
566 else {
567 fprintf(stderr, "error: this FQDN or IP is not valid: %s\n", fqdn);
568 exit_code(2);
569 }
570 }
571
572 if (verbose > 2)
573 printf("fqdnhostname: %s\n", fqdn);
574 }
575
576 /* this function searches for search in mess and replaces it with
577 replacement */
replace_string(char * mess,char * search,char * replacement)578 void replace_string(char *mess, char *search, char *replacement){
579 char *backup, *insert;
580
581 insert=STRCASESTR(mess, search);
582 if (insert==NULL){
583 if (verbose > 2)
584 fprintf(stderr, "warning: could not find this '%s' replacement string in "
585 "message\n", search);
586 }
587 else {
588 while (insert){
589 backup=str_alloc(strlen(insert)+1);
590 strcpy(backup, insert+strlen(search));
591 strcpy(insert, replacement);
592 strcpy(insert+strlen(replacement), backup);
593 free(backup);
594 insert=STRCASESTR(mess, search);
595 }
596 }
597 }
598
599 /* checks if the strings contains special double marks and then
600 * replace all occurences of this strings in the message */
replace_strings(char * mes,char * strings)601 void replace_strings(char *mes, char *strings) {
602 char *pos, *atr, *val, *repl, *end;
603 char sep;
604
605 pos=atr=val=repl = NULL;
606 #ifdef DEBUG
607 printf("replace_strings entered\nstrings: '%s'\n", strings);
608 #endif
609 if ((isalnum(*strings) != 0) &&
610 (isalnum(*(strings + strlen(strings) - 1)) != 0)) {
611 replace_string(req, "$replace$", replace_str);
612 }
613 else {
614 sep = *strings;
615 #ifdef DEBUG
616 printf("sep: '%c'\n", sep);
617 #endif
618 end = strings + strlen(strings);
619 pos = strings + 1;
620 while (pos < end) {
621 atr = pos;
622 pos = strchr(atr, sep);
623 if (pos != NULL) {
624 *pos = '\0';
625 val = pos + 1;
626 pos = strchr(val, sep);
627 if (pos != NULL) {
628 *pos = '\0';
629 pos++;
630 }
631 }
632 #ifdef DEBUG
633 printf("atr: '%s'\nval: '%s'\n", atr, val);
634 #endif
635 if ((atr != NULL) && (val != NULL)) {
636 repl = str_alloc(strlen(val) + 3);
637 if (repl == NULL) {
638 printf("failed to allocate memory\n");
639 exit_code(2);
640 }
641 sprintf(repl, "$%s$", atr);
642 replace_string(mes, repl, val);
643 free(repl);
644 }
645 #ifdef DEBUG
646 printf("pos: '%s'\n", pos);
647 #endif
648 }
649 }
650 #ifdef DEBUG
651 printf("mes:\n'%s'\n", mes);
652 #endif
653 }
654
655 /* insert \r in front of all \n if it is not present allready */
insert_cr(char * mes)656 void insert_cr(char *mes){
657 char *lf, *pos, *backup;
658
659 pos = mes;
660 lf = strchr(pos, '\n');
661 while ((lf != NULL) && (*(--lf) != '\r')) {
662 backup=str_alloc(strlen(lf)+2);
663 strcpy(backup, lf+1);
664 *(lf+1) = '\r';
665 strcpy(lf+2, backup);
666 free(backup);
667 pos = lf+3;
668 lf = strchr(pos, '\n');
669 }
670 lf = STRCASESTR(mes, "\r\n\r\n");
671 if (lf == NULL) {
672 lf = mes + strlen(mes);
673 sprintf(lf, "\r\n");
674 }
675 }
676
677 /* sipmly swappes the content of the two buffers */
swap_buffers(char * fst,char * snd)678 void swap_buffers(char *fst, char *snd) {
679 char *tmp;
680
681 if (fst == snd)
682 return;
683 tmp = str_alloc(strlen(fst)+1);
684 strcpy(tmp, fst);
685 strcpy(fst, snd);
686 strcpy(snd, tmp);
687 free(tmp);
688 }
689
swap_ptr(char ** fst,char ** snd)690 void swap_ptr(char **fst, char **snd)
691 {
692 char *tmp;
693
694 tmp = *fst;
695 *fst = *snd;
696 *snd = tmp;
697 }
698
699 /* trashes one character in buff randomly */
trash_random(char * message)700 void trash_random(char *message)
701 {
702 int r;
703 float t;
704 char *position;
705
706 t=(float)rand()/RAND_MAX;
707 r=(int)(t * (float)strlen(message));
708 position=message+r;
709 r=(int)(t*(float)255);
710 *position=(char)r;
711 if (verbose > 2)
712 printf("request:\n%s\n", message);
713 }
714
715 /* this function is taken from traceroute-1.4_p12
716 which is distributed under the GPL and it returns
717 the difference between to timeval structs */
deltaT(struct timeval * t1p,struct timeval * t2p)718 double deltaT(struct timeval *t1p, struct timeval *t2p)
719 {
720 register double dt;
721
722 dt = (double)(t2p->tv_sec - t1p->tv_sec) * 1000.0 +
723 (double)(t2p->tv_usec - t1p->tv_usec) / 1000.0;
724 return (dt);
725 }
726
727 /* returns one if the string contains only numbers otherwise zero */
is_number(char * number)728 int is_number(char *number)
729 {
730 int digit = 1;
731 while (digit && (*number != '\0')) {
732 digit = isdigit(*number);
733 number++;
734 }
735 return digit;
736 }
737
738 /* tries to convert the given string into an integer. it strips
739 * white-spaces and exits if an error happens */
str_to_int(char * num)740 int str_to_int(char *num)
741 {
742 int ret;
743
744 #ifdef HAVE_STRTOL
745 errno = 0;
746 ret = strtol(num, NULL, 10);
747 if (errno == EINVAL || errno == ERANGE) {
748 printf("%s\n", num);
749 perror("integer converting error");
750 exit_code(2);
751 }
752 #else
753 char backup;
754 int len = strlen(num);
755 char *start = num;
756 char *end = num + len;
757
758 while (!isdigit(*start) && isspace(*start) && start < end)
759 start++;
760 end = start;
761 end++;
762 while (end < num + len && *end != '\0' && !isspace(*end))
763 end++;
764 backup = *end;
765 *end = '\0';
766 if (!is_number(start)) {
767 fprintf(stderr, "error: string is not a number: %s\n", start);
768 exit_code(2);
769 }
770 ret = atoi(start);
771 *end = backup;
772 if (ret <= 0) {
773 fprintf(stderr, "error: failed to convert string to integer: %s\n", num);
774 exit_code(2);
775 }
776 #endif
777 return ret;
778 }
779
780 /* reads into the given buffer from standard input until the EOF
781 * character, LF character or the given size of the buffer is exceeded */
read_stdin(char * buf,int size,int ret)782 int read_stdin(char *buf, int size, int ret)
783 {
784 int i, j;
785
786 for(i = 0; i < size - 1; i++) {
787 j = getchar();
788 if (((ret == 0) && (j == EOF)) ||
789 ((ret == 1) && (j == '\n'))) {
790 *(buf + i) = '\0';
791 return i;
792 }
793 else {
794 *(buf + i) = j;
795 }
796 }
797 *(buf + i) = '\0';
798 if (verbose)
799 fprintf(stderr, "warning: readin buffer size exceeded\n");
800 return i;
801 }
802
803 /* tries to allocate the given size of memory and sets it all to zero.
804 * if the allocation fails it exits */
str_alloc(size_t size)805 void *str_alloc(size_t size)
806 {
807 char *ptr;
808 #ifdef HAVE_CALLOC
809 ptr = calloc(1, size);
810 #else
811 ptr = malloc(size);
812 #endif
813 if (ptr == NULL) {
814 fprintf(stderr, "error: memory allocation failed\n");
815 exit_code(255);
816 }
817 #ifndef HAVE_CALLOC
818 memset(ptr, 0, size);
819 #endif
820 return ptr;
821 }
822