Add new file utils.c, Move ast_gethostbyname to utils.c
[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 <asterisk/lock.h>
13 #include <asterisk/utils.h>
14
15 #if defined(__FreeBSD__)
16
17 /* duh? ERANGE value copied from web... */
18 #define ERANGE 34
19 #undef gethostbyname
20
21 int gethostbyname_r (const char *name, struct hostent *ret, char *buf,
22                         size_t buflen, struct hostent **result, 
23                         int *h_errnop) 
24 {
25         int hsave;
26         struct hostent *ph;
27         static ast_mutex_t __mutex = AST_MUTEX_INITIALIZER;
28         ast_mutex_lock(&__mutex); /* begin critical area */
29         hsave = h_errno;
30
31         ph = gethostbyname(name);
32         *h_errnop = h_errno; /* copy h_errno to *h_herrnop */
33         if (ph == NULL) {
34                 *result = NULL;
35         } else {
36                 char **p, **q;
37                 char *pbuf;
38                 int nbytes=0;
39                 int naddr=0, naliases=0;
40                 /* determine if we have enough space in buf */
41
42                 /* count how many addresses */
43                 for (p = ph->h_addr_list; *p != 0; p++) {
44                         nbytes += ph->h_length; /* addresses */
45                         nbytes += sizeof(*p); /* pointers */
46                         naddr++;
47                 }
48                 nbytes += sizeof(*p); /* one more for the terminating NULL */
49
50                 /* count how many aliases, and total length of strings */
51                 for (p = ph->h_aliases; *p != 0; p++) {
52                         nbytes += (strlen(*p)+1); /* aliases */
53                         nbytes += sizeof(*p);  /* pointers */
54                         naliases++;
55                 }
56                 nbytes += sizeof(*p); /* one more for the terminating NULL */
57
58                 /* here nbytes is the number of bytes required in buffer */
59                 /* as a terminator must be there, the minimum value is ph->h_length */
60                 if(nbytes > buflen) {
61                         *result = NULL;
62                         ast_mutex_unlock(&__mutex); /* end critical area */
63                         return ERANGE; /* not enough space in buf!! */
64                 }
65
66                 /* There is enough space. Now we need to do a deep copy! */
67                 /* Allocation in buffer:
68                         from [0] to [(naddr-1) * sizeof(*p)]:
69                         pointers to addresses
70                         at [naddr * sizeof(*p)]:
71                         NULL
72                         from [(naddr+1) * sizeof(*p)] to [(naddr+naliases) * sizeof(*p)] :
73                         pointers to aliases
74                         at [(naddr+naliases+1) * sizeof(*p)]:
75                         NULL
76                         then naddr addresses (fixed length), and naliases aliases (asciiz).
77                 */
78
79                 *ret = *ph;   /* copy whole structure (not its address!) */
80
81                 /* copy addresses */
82                 q = (char **)buf; /* pointer to pointers area (type: char **) */
83                 ret->h_addr_list = q; /* update pointer to address list */
84                 pbuf = buf + ((naddr+naliases+2)*sizeof(*p)); /* skip that area */
85                 for (p = ph->h_addr_list; *p != 0; p++) {
86                         memcpy(pbuf, *p, ph->h_length); /* copy address bytes */
87                         *q++ = pbuf; /* the pointer is the one inside buf... */
88                         pbuf += ph->h_length; /* advance pbuf */
89                 }
90                 *q++ = NULL; /* address list terminator */
91
92                 /* copy aliases */
93                 ret->h_aliases = q; /* update pointer to aliases list */
94                 for (p = ph->h_aliases; *p != 0; p++) {
95                         strcpy(pbuf, *p); /* copy alias strings */
96                         *q++ = pbuf; /* the pointer is the one inside buf... */
97                         pbuf += strlen(*p); /* advance pbuf */
98                         *pbuf++ = 0; /* string terminator */
99                 }
100                 *q++ = NULL; /* terminator */
101
102                 strcpy(pbuf, ph->h_name); /* copy alias strings */
103                 ret->h_name = pbuf;
104                 pbuf += strlen(ph->h_name); /* advance pbuf */
105                 *pbuf++ = 0; /* string terminator */
106
107                 *result = ret;  /* and let *result point to structure */
108
109         }
110         h_errno = hsave;  /* restore h_errno */
111         ast_mutex_unlock(&__mutex); /* end critical area */
112
113         return (*result != NULL);
114 }
115
116
117 #endif
118
119 struct hostent *ast_gethostbyname(const char *host, struct ast_hostent *hp)
120 {
121         int res;
122         int herrno;
123         struct hostent *result = NULL;
124
125         res = gethostbyname_r(host, &hp->hp, hp->buf, sizeof(hp->buf), &result, &herrno);
126
127         if (res || !hp->hp.h_addr_list || !hp->hp.h_addr_list[0])
128                 return NULL;
129         return &hp->hp;
130 }