x86-64 compile fixes and cleanups
[asterisk/asterisk.git] / utils.c
1 /*
2  * Asterisk -- A telephony toolkit for Linux.
3  *
4  * Utility functions
5  *
6  * Copyright (C) 2004, Digium
7  *
8  * This program is free software, distributed under the terms of
9  * the GNU General Public License
10  */
11
12 #include <ctype.h>
13 #include <string.h>
14 #include <asterisk/lock.h>
15 #include <asterisk/utils.h>
16
17 #if defined(__FreeBSD__) || defined(__OpenBSD__)
18
19 /* duh? ERANGE value copied from web... */
20 #define ERANGE 34
21 #undef gethostbyname
22
23 AST_MUTEX_DEFINE_STATIC(__mutex);
24
25 int gethostbyname_r (const char *name, struct hostent *ret, char *buf,
26                         size_t buflen, struct hostent **result, 
27                         int *h_errnop) 
28 {
29         int hsave;
30         struct hostent *ph;
31         ast_mutex_lock(&__mutex); /* begin critical area */
32         hsave = h_errno;
33
34         ph = gethostbyname(name);
35         *h_errnop = h_errno; /* copy h_errno to *h_herrnop */
36         if (ph == NULL) {
37                 *result = NULL;
38         } else {
39                 char **p, **q;
40                 char *pbuf;
41                 int nbytes=0;
42                 int naddr=0, naliases=0;
43                 /* determine if we have enough space in buf */
44
45                 /* count how many addresses */
46                 for (p = ph->h_addr_list; *p != 0; p++) {
47                         nbytes += ph->h_length; /* addresses */
48                         nbytes += sizeof(*p); /* pointers */
49                         naddr++;
50                 }
51                 nbytes += sizeof(*p); /* one more for the terminating NULL */
52
53                 /* count how many aliases, and total length of strings */
54                 for (p = ph->h_aliases; *p != 0; p++) {
55                         nbytes += (strlen(*p)+1); /* aliases */
56                         nbytes += sizeof(*p);  /* pointers */
57                         naliases++;
58                 }
59                 nbytes += sizeof(*p); /* one more for the terminating NULL */
60
61                 /* here nbytes is the number of bytes required in buffer */
62                 /* as a terminator must be there, the minimum value is ph->h_length */
63                 if(nbytes > buflen) {
64                         *result = NULL;
65                         ast_mutex_unlock(&__mutex); /* end critical area */
66                         return ERANGE; /* not enough space in buf!! */
67                 }
68
69                 /* There is enough space. Now we need to do a deep copy! */
70                 /* Allocation in buffer:
71                         from [0] to [(naddr-1) * sizeof(*p)]:
72                         pointers to addresses
73                         at [naddr * sizeof(*p)]:
74                         NULL
75                         from [(naddr+1) * sizeof(*p)] to [(naddr+naliases) * sizeof(*p)] :
76                         pointers to aliases
77                         at [(naddr+naliases+1) * sizeof(*p)]:
78                         NULL
79                         then naddr addresses (fixed length), and naliases aliases (asciiz).
80                 */
81
82                 *ret = *ph;   /* copy whole structure (not its address!) */
83
84                 /* copy addresses */
85                 q = (char **)buf; /* pointer to pointers area (type: char **) */
86                 ret->h_addr_list = q; /* update pointer to address list */
87                 pbuf = buf + ((naddr+naliases+2)*sizeof(*p)); /* skip that area */
88                 for (p = ph->h_addr_list; *p != 0; p++) {
89                         memcpy(pbuf, *p, ph->h_length); /* copy address bytes */
90                         *q++ = pbuf; /* the pointer is the one inside buf... */
91                         pbuf += ph->h_length; /* advance pbuf */
92                 }
93                 *q++ = NULL; /* address list terminator */
94
95                 /* copy aliases */
96                 ret->h_aliases = q; /* update pointer to aliases list */
97                 for (p = ph->h_aliases; *p != 0; p++) {
98                         strcpy(pbuf, *p); /* copy alias strings */
99                         *q++ = pbuf; /* the pointer is the one inside buf... */
100                         pbuf += strlen(*p); /* advance pbuf */
101                         *pbuf++ = 0; /* string terminator */
102                 }
103                 *q++ = NULL; /* terminator */
104
105                 strcpy(pbuf, ph->h_name); /* copy alias strings */
106                 ret->h_name = pbuf;
107                 pbuf += strlen(ph->h_name); /* advance pbuf */
108                 *pbuf++ = 0; /* string terminator */
109
110                 *result = ret;  /* and let *result point to structure */
111
112         }
113         h_errno = hsave;  /* restore h_errno */
114         ast_mutex_unlock(&__mutex); /* end critical area */
115
116         return (*result == NULL); /* return 0 on success, non-zero on error */
117 }
118
119
120 #endif
121
122 struct hostent *ast_gethostbyname(const char *host, struct ast_hostent *hp)
123 {
124         int res;
125         int herrno;
126         const char *s;
127         struct hostent *result = NULL;
128         /* Although it is perfectly legitimate to lookup a pure integer, for
129            the sake of the sanity of people who like to name their peers as
130            integers, we break with tradition and refuse to look up a
131            pure integer */
132         s = host;
133         while(s && *s) {
134                 if (!isdigit(*s))
135                         break;
136                 s++;
137         }
138         if (!s || !*s)
139                 return NULL;
140         res = gethostbyname_r(host, &hp->hp, hp->buf, sizeof(hp->buf), &result, &herrno);
141
142         if (res || !result || !hp->hp.h_addr_list || !hp->hp.h_addr_list[0])
143                 return NULL;
144         return &hp->hp;
145 }