Remove pthread.h from source. We should be using asterisk/lock.h everywhere instead...
[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 <unistd.h>
15 #include <asterisk/lock.h>
16 #include <asterisk/utils.h>
17
18 #if defined(__FreeBSD__) || defined(__OpenBSD__)
19
20 /* duh? ERANGE value copied from web... */
21 #define ERANGE 34
22 #undef gethostbyname
23
24 AST_MUTEX_DEFINE_STATIC(__mutex);
25
26 static int gethostbyname_r (const char *name, struct hostent *ret, char *buf,
27                             size_t buflen, struct hostent **result, 
28                             int *h_errnop) 
29 {
30         int hsave;
31         struct hostent *ph;
32         ast_mutex_lock(&__mutex); /* begin critical area */
33         hsave = h_errno;
34
35         ph = gethostbyname(name);
36         *h_errnop = h_errno; /* copy h_errno to *h_herrnop */
37         if (ph == NULL) {
38                 *result = NULL;
39         } else {
40                 char **p, **q;
41                 char *pbuf;
42                 int nbytes=0;
43                 int naddr=0, naliases=0;
44                 /* determine if we have enough space in buf */
45
46                 /* count how many addresses */
47                 for (p = ph->h_addr_list; *p != 0; p++) {
48                         nbytes += ph->h_length; /* addresses */
49                         nbytes += sizeof(*p); /* pointers */
50                         naddr++;
51                 }
52                 nbytes += sizeof(*p); /* one more for the terminating NULL */
53
54                 /* count how many aliases, and total length of strings */
55                 for (p = ph->h_aliases; *p != 0; p++) {
56                         nbytes += (strlen(*p)+1); /* aliases */
57                         nbytes += sizeof(*p);  /* pointers */
58                         naliases++;
59                 }
60                 nbytes += sizeof(*p); /* one more for the terminating NULL */
61
62                 /* here nbytes is the number of bytes required in buffer */
63                 /* as a terminator must be there, the minimum value is ph->h_length */
64                 if(nbytes > buflen) {
65                         *result = NULL;
66                         ast_mutex_unlock(&__mutex); /* end critical area */
67                         return ERANGE; /* not enough space in buf!! */
68                 }
69
70                 /* There is enough space. Now we need to do a deep copy! */
71                 /* Allocation in buffer:
72                         from [0] to [(naddr-1) * sizeof(*p)]:
73                         pointers to addresses
74                         at [naddr * sizeof(*p)]:
75                         NULL
76                         from [(naddr+1) * sizeof(*p)] to [(naddr+naliases) * sizeof(*p)] :
77                         pointers to aliases
78                         at [(naddr+naliases+1) * sizeof(*p)]:
79                         NULL
80                         then naddr addresses (fixed length), and naliases aliases (asciiz).
81                 */
82
83                 *ret = *ph;   /* copy whole structure (not its address!) */
84
85                 /* copy addresses */
86                 q = (char **)buf; /* pointer to pointers area (type: char **) */
87                 ret->h_addr_list = q; /* update pointer to address list */
88                 pbuf = buf + ((naddr+naliases+2)*sizeof(*p)); /* skip that area */
89                 for (p = ph->h_addr_list; *p != 0; p++) {
90                         memcpy(pbuf, *p, ph->h_length); /* copy address bytes */
91                         *q++ = pbuf; /* the pointer is the one inside buf... */
92                         pbuf += ph->h_length; /* advance pbuf */
93                 }
94                 *q++ = NULL; /* address list terminator */
95
96                 /* copy aliases */
97                 ret->h_aliases = q; /* update pointer to aliases list */
98                 for (p = ph->h_aliases; *p != 0; p++) {
99                         strcpy(pbuf, *p); /* copy alias strings */
100                         *q++ = pbuf; /* the pointer is the one inside buf... */
101                         pbuf += strlen(*p); /* advance pbuf */
102                         *pbuf++ = 0; /* string terminator */
103                 }
104                 *q++ = NULL; /* terminator */
105
106                 strcpy(pbuf, ph->h_name); /* copy alias strings */
107                 ret->h_name = pbuf;
108                 pbuf += strlen(ph->h_name); /* advance pbuf */
109                 *pbuf++ = 0; /* string terminator */
110
111                 *result = ret;  /* and let *result point to structure */
112
113         }
114         h_errno = hsave;  /* restore h_errno */
115         ast_mutex_unlock(&__mutex); /* end critical area */
116
117         return (*result == NULL); /* return 0 on success, non-zero on error */
118 }
119
120
121 #endif
122
123 struct hostent *ast_gethostbyname(const char *host, struct ast_hostent *hp)
124 {
125         int res;
126         int herrno;
127         const char *s;
128         struct hostent *result = NULL;
129         /* Although it is perfectly legitimate to lookup a pure integer, for
130            the sake of the sanity of people who like to name their peers as
131            integers, we break with tradition and refuse to look up a
132            pure integer */
133         s = host;
134         while(s && *s) {
135                 if (!isdigit(*s))
136                         break;
137                 s++;
138         }
139         if (!s || !*s)
140                 return NULL;
141         res = gethostbyname_r(host, &hp->hp, hp->buf, sizeof(hp->buf), &result, &herrno);
142
143         if (res || !result || !hp->hp.h_addr_list || !hp->hp.h_addr_list[0])
144                 return NULL;
145         return &hp->hp;
146 }
147
148
149 /* This is a regression test for recursive mutexes.
150    test_for_thread_safety() will return 0 if recursive mutex locks are
151    working properly, and non-zero if they are not working properly. */
152
153 AST_MUTEX_DEFINE_STATIC(test_lock);
154 AST_MUTEX_DEFINE_STATIC(test_lock2);
155 static pthread_t test_thread; 
156 static int lock_count = 0;
157 static int test_errors = 0;
158
159 static void *test_thread_body(void *data) 
160
161   ast_mutex_lock(&test_lock);
162   lock_count += 10;
163   if(lock_count != 10) test_errors++;
164   ast_mutex_lock(&test_lock);
165   lock_count += 10;
166   if(lock_count != 20) test_errors++;
167   ast_mutex_lock(&test_lock2);
168   ast_mutex_unlock(&test_lock);
169   lock_count -= 10;
170   if(lock_count != 10) test_errors++;
171   ast_mutex_unlock(&test_lock);
172   lock_count -= 10;
173   ast_mutex_unlock(&test_lock2);
174   if(lock_count != 0) test_errors++;
175   return NULL;
176
177
178 int test_for_thread_safety(void)
179
180   ast_mutex_lock(&test_lock2);
181   ast_mutex_lock(&test_lock);
182   lock_count += 1;
183   ast_mutex_lock(&test_lock);
184   lock_count += 1;
185   pthread_create(&test_thread, NULL, test_thread_body, NULL); 
186   pthread_yield();
187   usleep(100);
188   if(lock_count != 2) test_errors++;
189   ast_mutex_unlock(&test_lock);
190   lock_count -= 1;
191   pthread_yield(); 
192   usleep(100); 
193   if(lock_count != 1) test_errors++;
194   ast_mutex_unlock(&test_lock);
195   lock_count -= 1;
196   if(lock_count != 0) test_errors++;
197   ast_mutex_unlock(&test_lock2);
198   pthread_yield();
199   usleep(100);
200   if(lock_count != 0) test_errors++;
201   pthread_join(test_thread, NULL);
202   return(test_errors);          /* return 0 on success. */
203 }