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 <sys/mman.h>
30 #include <netdb.h>
31 #include "proto.h"
32
33 extern char **environ;
34
35 #ifdef HAVE_GETHOSTBYNAME_R
36
37 /*
38 wrapper for reentrant gethostbyname function
39 */
p_gethostbyname(char * host)40 HOSTENT *p_gethostbyname(char *host)
41 {
42 int ret, err;
43 char buf[1024];
44 HOSTENT *hostent;
45 struct hostent h, *hp;
46
47 ret = gethostbyname_r(host, &h, buf, sizeof(buf), &hp, &err);
48 if (hp == NULL)
49 return NULL;
50
51 hostent = xmalloc(sizeof(HOSTENT));
52 hostent->addr = xmalloc(sizeof(struct in_addr));
53 memcpy(hostent->addr, hp->h_addr_list[0], sizeof(struct in_addr));
54 hostent->len = sizeof(struct in_addr);
55
56 return hostent;
57 }
58
59 #else
60
61 /*
62 stupid work-around for systems without gethostbyname_r
63 */
p_gethostbyname(char * host)64 HOSTENT *p_gethostbyname(char *host)
65 {
66 HOSTENT *hostent;
67 struct hostent *h;
68 static pthread_mutex_t gethostbyname_mutex = PTHREAD_MUTEX_INITIALIZER;
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 */
p_poll(struct pollfd * pollfd,int fds,int timeout)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 */
p_poll(struct pollfd * pfd,int fds,int timeout)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
p_setenv(char * var,char * value,int overwrite)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 */
p_setenv(char * var,char * value,int overwrite)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 */
p_clearenv()186 void p_clearenv()
187 {
188 #ifdef HAVE_CLEARENV
189 clearenv();
190 #else
191 environ = NULL;
192 #endif
193 }
194
195 #ifdef HAVE_MREMAP
p_mremap(void * old_address,size_t old_size,size_t new_size,int fd)196 void *p_mremap(void *old_address, size_t old_size, size_t new_size, int fd)
197 {
198 return mremap(old_address, old_size, new_size, MREMAP_MAYMOVE);
199 }
200 #else
p_mremap(void * old_address,size_t old_size,size_t new_size,int fd)201 void *p_mremap(void *old_address, size_t old_size, size_t new_size, int fd)
202 {
203 void *ptr;
204
205 if (fd != -1) {
206 /* unmap and remap file */
207 munmap(old_address, old_size);
208 ptr = mmap(NULL, new_size, PROT_WRITE | PROT_READ, MAP_SHARED, fd, 0);
209 } else {
210 ptr = mmap(NULL, new_size, PROT_WRITE | PROT_READ, MAP_PRIVATE | MAP_ANON, -1, 0);
211 if (ptr != MAP_FAILED) {
212 memcpy(ptr, old_address, (new_size < old_size) ? new_size : old_size);
213
214 munmap(old_address, old_size);
215 } else
216 munmap(old_address, old_size);
217 }
218
219 return ptr;
220 }
221 #endif
222
223