:pserver:anonymous@cvs.middle-man.sourceforge.net:/cvsroot/middle-man middleman
[middleman.git] / src / compat.c
1 /*
2     MiddleMan filtering proxy server
3     Copyright (C) 2002  Jason McLaughlin
4
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14
15     You should have received a copy of the GNU General Public License
16     along with this program; if not, write to the Free Software
17     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18 */
19
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <unistd.h>
23 #include <fcntl.h>
24 #include <string.h>
25 #include <netinet/in.h>
26 #include <sys/time.h>
27 #include <sys/wait.h>
28 #include <sys/types.h>
29 #include <netdb.h>
30 #include "proto.h"
31
32 extern char **environ;
33
34 #ifdef HAVE_GETHOSTBYNAME_R
35
36 /*
37 wrapper for reentrant gethostbyname function
38 */
39 HOSTENT *p_gethostbyname(char *host)
40 {
41         int ret, err;
42         char buf[1024];
43         HOSTENT *hostent;
44         struct hostent h, *hp;
45
46         ret = gethostbyname_r(host, &h, buf, sizeof(buf), &hp, &err);
47         if (ret != 0)
48                 return NULL;
49
50         hostent = xmalloc(sizeof(HOSTENT));
51         hostent->addr = xmalloc(sizeof(struct in_addr));
52         memcpy(hostent->addr, h.h_addr_list[0], sizeof(struct in_addr));
53         hostent->len = sizeof(struct in_addr);
54
55         return hostent;
56 }
57
58 #else
59
60 pthread_mutex_t gethostbyname_mutex = PTHREAD_MUTEX_INITIALIZER;
61
62 /*
63 stupid work-around for systems without gethostbyname_r
64 */
65 HOSTENT *p_gethostbyname(char *host)
66 {
67         HOSTENT *hostent;
68         struct hostent *h;
69
70         pthread_mutex_lock(&gethostbyname_mutex);
71
72         h = gethostbyname(host);
73         if (h == NULL) {
74                 pthread_mutex_unlock(&gethostbyname_mutex);
75
76                 return NULL;
77         }
78
79         hostent = xmalloc(sizeof(HOSTENT));
80         hostent->addr = xmalloc(h->h_length);
81         memcpy(hostent->addr, h->h_addr_list[0], h->h_length);
82         hostent->len = h->h_length;
83
84         pthread_mutex_unlock(&gethostbyname_mutex);
85
86         return hostent;
87 }
88
89 #endif                          /* HAVE_GETHOSTBYNAME_R */
90
91 #ifdef HAVE_POLL
92
93 /* 
94 wrapper for poll() for systems that actually implement this
95 */
96 int p_poll(struct pollfd *pollfd, int fds, int timeout)
97 {
98         return poll(pollfd, fds, timeout);
99 }
100
101 #else
102
103 /*
104 basic poll() wrapper using select for system's lacking that feature
105 */
106 int p_poll(struct pollfd *pfd, int fds, int timeout)
107 {
108         int i, ret, hfd = 0;
109         fd_set readlist, writelist;
110         struct timeval tv;
111
112         FD_ZERO(&readlist);
113         FD_ZERO(&writelist);
114
115         if (timeout >= 0) {
116                 tv.tv_usec = timeout * 1000;
117                 tv.tv_sec = tv.tv_usec / 1000000;
118                 tv.tv_usec %= 1000000;
119         }
120
121         for (i = 0; i < fds; i++) {
122                 if (pfd[i].fd >= hfd)
123                         hfd = pfd[i].fd + 1;
124
125                 pfd[i].revents = 0;
126
127                 if (pfd[i].events & POLLIN)
128                         FD_SET(pfd[i].fd, &readlist);
129
130                 if (pfd[i].events & POLLOUT)
131                         FD_SET(pfd[i].fd, &writelist);
132         }
133
134         ret = select(hfd, &readlist, &writelist, NULL, (timeout >= 0) ? &tv : NULL);
135
136         if (ret > 0) {
137                 for (i = 0; i < fds; i++) {
138                         if (FD_ISSET(pfd[i].fd, &readlist))
139                                 pfd[i].revents |= POLLIN;
140
141                         if (FD_ISSET(pfd[i].fd, &writelist))
142                                 pfd[i].revents |= POLLOUT;
143
144                         if (fcntl(pfd[i].fd, F_GETFL, O_NDELAY) == -1)
145                                 pfd[i].revents |= POLLHUP;
146                 }
147         }
148
149         return ret;
150 }
151
152 #endif                          /* HAVE_POLL */
153
154 #ifdef HAVE_SETENV
155
156 int p_setenv(char *var, char *value, int overwrite)
157 {
158         return setenv(var, value, overwrite);
159 }
160
161 #else
162
163 /*
164 solaris, et al lack setenv(), this will emulate it's behavior
165 */
166 int p_setenv(char *var, char *value, int overwrite)
167 {
168         char *buf;
169
170         if (!overwrite && getenv(var))
171                 return -1;
172
173         buf = xmalloc(strlen(var) + strlen(value) + 2);
174
175         sprintf(buf, "%s=%s", var, value);
176
177         return putenv(buf);
178 }
179
180 #endif                          /* HAVE_SETENV */
181
182
183 /*
184 clearenv() is glibc-specific, setting environ to NULL will do for other platforms
185 */
186 void p_clearenv()
187 {
188 #ifdef HAVE_CLEARENV
189         clearenv();
190 #else
191         environ = NULL;
192 #endif
193 }