Index: trunk/willow/Makefile.in |
— | — | @@ -7,6 +7,7 @@ |
8 | 8 | SUBDIRS=src errors mk |
9 | 9 | |
10 | 10 | @include@ @q@@top_srcdir@/mk/subdir.mk@q@ |
| 11 | +@include@ @q@@top_srcdir@/mk/vars.mk@q@ |
11 | 12 | |
12 | 13 | DISTFILES=\ |
13 | 14 | Makefile.in \ |
— | — | @@ -22,3 +23,16 @@ |
23 | 24 | tar cf $(DISTNAME).tar $(DISTNAME) |
24 | 25 | compress $(DISTNAME).tar |
25 | 26 | rm -rf $(PACKAGE)-$(VERSION) $(PACKAGE)-$(VERSION).tar |
| 27 | + |
| 28 | +svr4-package: |
| 29 | + $(_RMF) -r stage-install |
| 30 | + ./configure --prefix=/opt/willow |
| 31 | + $(MAKE) all |
| 32 | + mkdir stage-install |
| 33 | + $(MAKE) install ALTROOT=`pwd`/stage-install |
| 34 | + cp COPYRIGHT svr4/copyright |
| 35 | + cd svr4 && \ |
| 36 | + (find ../stage-install | pkgproto ../stage-install=/ ; cat proto.suffix) >prototype && \ |
| 37 | + pkgmk -o && \ |
| 38 | + pkgtrans -s /var/spool/pkg `pwd`/../WMFwillow-@VERSION@.pkg WMFwillow |
| 39 | + |
Index: trunk/willow/configure.in |
— | — | @@ -308,6 +308,7 @@ |
309 | 309 | |
310 | 310 | AC_OUTPUT( |
311 | 311 | mk/prog.mk |
| 312 | + mk/lib.mk |
312 | 313 | mk/vars.mk |
313 | 314 | mk/rules.mk |
314 | 315 | mk/data.mk |
— | — | @@ -318,6 +319,11 @@ |
319 | 320 | mk/Makefile |
320 | 321 | Makefile |
321 | 322 | src/Makefile |
| 323 | + src/bin/Makefile |
| 324 | + src/bin/willow/Makefile |
| 325 | + src/lib/Makefile |
| 326 | + src/lib/wnet/Makefile |
| 327 | + src/lib/wlog/Makefile |
322 | 328 | errors/Makefile) |
323 | 329 | |
324 | 330 | if test x$epoll_in_kernel = xno; then |
Index: trunk/willow/mk/prog.mk.in |
— | — | @@ -2,8 +2,8 @@ |
3 | 3 | # |
4 | 4 | # Build a program. |
5 | 5 | |
6 | | -@include@ @q@@top_srcdir@/mk/vars.mk@q@ |
7 | | -@include@ @q@@top_srcdir@/mk/rules.mk@q@ |
| 6 | +@include@ @q@@abs_top_srcdir@/mk/vars.mk@q@ |
| 7 | +@include@ @q@@abs_top_srcdir@/mk/rules.mk@q@ |
8 | 8 | |
9 | 9 | default: all |
10 | 10 | |
— | — | @@ -39,4 +39,4 @@ |
40 | 40 | _MYDISTFILES=$(SRCS) $(EXTRA_DIST) |
41 | 41 | _extradist: |
42 | 42 | |
43 | | -@include@ @q@@top_srcdir@/mk/depend.@dependstyle@.mk@q@ |
| 43 | +@include@ @q@@abs_top_srcdir@/mk/depend.@dependstyle@.mk@q@ |
Index: trunk/willow/mk/subdir.mk.in |
— | — | @@ -11,9 +11,9 @@ |
12 | 12 | |
13 | 13 | all install lint clean depend _extradist: |
14 | 14 | @for dir in $(SUBDIRS); do \ |
15 | | - echo "$@ ==> $$dir" ;\ |
16 | | - cd $$dir && $(MAKE) `echo $@ | sed -e s/_extradist/_dist/` _DISTPATH="$(_DISTPATH)/$$dir" || exit 1 ;\ |
17 | | - echo "$@ <== $$dir" ;\ |
| 15 | + echo "$@ ==> $(_DISTPATH)$$dir" ;\ |
| 16 | + cd $$dir && $(MAKE) `echo $@ | sed -e s/_extradist/_dist/` _DISTPATH="$(_DISTPATH)$$dir/" || exit 1 ;\ |
| 17 | + echo "$@ <== $(_DISTPATH)$$dir" ;\ |
18 | 18 | cd .. ;\ |
19 | 19 | done |
20 | 20 | |
Index: trunk/willow/mk/vars.mk.in |
— | — | @@ -1,6 +1,9 @@ |
2 | 2 | # @(#) $Header$ |
3 | 3 | # |
4 | 4 | # Standard variables. |
| 5 | +# |
| 6 | +# Warning! don't use top_srcdir in this file, use abs_top_srcdir (or, better, |
| 7 | +# use $(SRCROOT).) |
5 | 8 | |
6 | 9 | PACKAGE= willow |
7 | 10 | VERSION= @VERSION@ |
— | — | @@ -9,19 +12,28 @@ |
10 | 13 | _YACC= @YACC@ |
11 | 14 | |
12 | 15 | CC= @CC@ |
13 | | -_CPPFLAGS= -I@top_srcdir@ -I. @CPPFLAGS@ |
| 16 | +_CPPFLAGS= -I@abs_top_srcdir@ -I. -I@abs_top_srcdir@/src/include @CPPFLAGS@ |
14 | 17 | _CFLAGS= @CFLAGS@ |
15 | 18 | _LDFLAGS= @LDFLAGS@ @LIBS@ |
16 | 19 | |
17 | | -_LINK=$(CC) $(_CFLAGS) $(CFLAGS) $(_LDFLAGS) $(LDFLAG) $(OBJS) |
18 | | -_COMPILE=$(CC) $(_CPPFLAGS) $(CPPFLAGS) $(_CFLAGS) $(CFLAGS) |
19 | | -_RMF=rm -f |
20 | | -_INSTALL=@INSTALL@ |
21 | | -_INSTALLPROG=$(_INSTALL) -m 0755 |
22 | | -_INSTALLDATA=$(_INSTALL) -m 0644 |
23 | | -_MKDIR=$(_INSTALL) -m 0755 -d |
| 20 | +SRCROOT= @abs_top_srcdir@ |
24 | 21 | |
25 | | -_BINDIR=@prefix@@bindir@ |
26 | | -_DATADIR=@prefix@@datadir@ |
| 22 | +_LINK= $(CC) $(_CFLAGS) $(CFLAGS) $(_LDFLAGS) $(OBJS) $(LDFLAGS) |
| 23 | +_COMPILE= $(CC) $(_CPPFLAGS) $(CPPFLAGS) $(_CFLAGS) $(CFLAGS) |
| 24 | +_RMF= rm -f |
| 25 | +_AR= ar |
| 26 | +_RANLIB= ranlib |
27 | 27 | |
| 28 | +# autoconf will replace this with "../install-sh", which breaks when this file is included |
| 29 | +# from a directory 2 level deep. use the distributed install-sh program instead. |
| 30 | +#_INSTALL=@INSTALL@ |
| 31 | +_INSTALL= $(SRCROOT)/install-sh -c |
| 32 | +_INSTALLPROG= $(_INSTALL) -m 0755 |
| 33 | +_INSTALLDATA= $(_INSTALL) -m 0644 |
| 34 | +_MKDIR= $(_INSTALL) -m 0755 -d |
| 35 | + |
| 36 | +_BINDIR= $(ALTROOT)@prefix@@bindir@ |
| 37 | +_LIBDIR= $(ALTROOT)@prefix@@libdir@ |
| 38 | +_DATADIR= $(ALTROOT)@prefix@@datadir@ |
| 39 | + |
28 | 40 | DISTDEST= @abs_top_srcdir@/$(PACKAGE)-$(VERSION) |
Index: trunk/willow/src/strlcat.c |
— | — | @@ -1,65 +0,0 @@ |
2 | | -/* @(#)$Header$ */ |
3 | | -/* $NetBSD: strlcat.c,v 1.16 2003/10/27 00:12:42 lukem Exp $ */ |
4 | | -/* $OpenBSD: strlcat.c,v 1.10 2003/04/12 21:56:39 millert Exp $ */ |
5 | | - |
6 | | -/* |
7 | | - * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com> |
8 | | - * |
9 | | - * Permission to use, copy, modify, and distribute this software for any |
10 | | - * purpose with or without fee is hereby granted, provided that the above |
11 | | - * copyright notice and this permission notice appear in all copies. |
12 | | - * |
13 | | - * THE SOFTWARE IS PROVIDED "AS IS" AND TODD C. MILLER DISCLAIMS ALL |
14 | | - * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES |
15 | | - * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL TODD C. MILLER BE LIABLE |
16 | | - * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
17 | | - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION |
18 | | - * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN |
19 | | - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
20 | | - */ |
21 | | - |
22 | | -#if defined __SUNPRO_C || defined __DECC || defined __HP_cc |
23 | | -# pragma ident "@(#)$Header$" |
24 | | -#endif |
25 | | - |
26 | | -#include <sys/types.h> |
27 | | -#include <assert.h> |
28 | | -#include <string.h> |
29 | | - |
30 | | -/* |
31 | | - * Appends src to string dst of size siz (unlike strncat, siz is the |
32 | | - * full size of dst, not space left). At most siz-1 characters |
33 | | - * will be copied. Always NUL terminates (unless siz <= strlen(dst)). |
34 | | - * Returns strlen(src) + MIN(siz, strlen(initial dst)). |
35 | | - * If retval >= siz, truncation occurred. |
36 | | - */ |
37 | | -size_t |
38 | | -strlcat(dst, src, siz) |
39 | | - char *dst; |
40 | | - const char *src; |
41 | | - size_t siz; |
42 | | -{ |
43 | | - char *d = dst; |
44 | | - const char *s = src; |
45 | | - size_t n = siz; |
46 | | - size_t dlen; |
47 | | - |
48 | | - /* Find the end of dst and adjust bytes left but don't go past end */ |
49 | | - while (n-- != 0 && *d != '\0') |
50 | | - d++; |
51 | | - dlen = d - dst; |
52 | | - n = siz - dlen; |
53 | | - |
54 | | - if (n == 0) |
55 | | - return(dlen + strlen(s)); |
56 | | - while (*s != '\0') { |
57 | | - if (n != 1) { |
58 | | - *d++ = *s; |
59 | | - n--; |
60 | | - } |
61 | | - s++; |
62 | | - } |
63 | | - *d = '\0'; |
64 | | - |
65 | | - return(dlen + (s - src)); /* count does not include NUL */ |
66 | | -} |
Index: trunk/willow/src/willow.c |
— | — | @@ -1,406 +0,0 @@ |
2 | | -/* @(#) $Header$ */ |
3 | | -/* This source code is in the public domain. */ |
4 | | -/* |
5 | | - * Willow: Lightweight HTTP reverse-proxy. |
6 | | - */ |
7 | | - |
8 | | -#if defined __SUNPRO_C || defined __DECC || defined __HP_cc |
9 | | -# pragma ident "@(#)$Header$" |
10 | | -#endif |
11 | | - |
12 | | -#include <sys/mman.h> |
13 | | - |
14 | | -#include <stdio.h> |
15 | | -#include <stdlib.h> |
16 | | -#include <signal.h> |
17 | | -#include <stdarg.h> |
18 | | -#include <string.h> |
19 | | -#include <unistd.h> |
20 | | -#include <errno.h> |
21 | | - |
22 | | -#include "wlog.h" |
23 | | -#include "wnet.h" |
24 | | -#include "wconfig.h" |
25 | | -#include "willow.h" |
26 | | -#include "whttp.h" |
27 | | -#include "wcache.h" |
28 | | - |
29 | | -#ifdef WDEBUG_ALLOC |
30 | | -static void ae_checkleaks(void); |
31 | | -static void segv_action(int, siginfo_t *, void *); |
32 | | -#endif |
33 | | - |
34 | | -static const char *progname; |
35 | | - |
36 | | -#define min(x,y) ((x) < (y) ? (x) : (y)) |
37 | | - |
38 | | -/*ARGSUSED*/ |
39 | | -static void |
40 | | -sig_exit(s) |
41 | | - int s; |
42 | | -{ |
43 | | - wnet_exit = 1; |
44 | | -} |
45 | | - |
46 | | -static void |
47 | | -usage(void) |
48 | | -{ |
49 | | - (void)fprintf(stderr, "usage: %s [-fzv]\n" |
50 | | - "\t-f\trun in foreground (don't detach)\n" |
51 | | - "\t-z\tcreate cache directory structure and exit\n" |
52 | | - "\t-v\tprint version number and exit\n" |
53 | | - , progname); |
54 | | -} |
55 | | - |
56 | | -#ifdef __lint |
57 | | -# pragma error_messages(off, E_H_C_CHECK2) |
58 | | -#endif |
59 | | - |
60 | | -int |
61 | | -main(argc, argv) |
62 | | - char *argv[]; |
63 | | - int argc; |
64 | | -{ |
65 | | - int i; |
66 | | - int zflag = 0; |
67 | | - |
68 | | -#ifdef WDEBUG_ALLOC |
69 | | -struct sigaction segv_act; |
70 | | - bzero(&segv_act, sizeof(segv_act)); |
71 | | - segv_act.sa_sigaction = segv_action; |
72 | | - segv_act.sa_flags = SA_SIGINFO; |
73 | | - |
74 | | - sigaction(SIGSEGV, &segv_act, NULL); |
75 | | -#endif |
76 | | - |
77 | | - progname = argv[0]; |
78 | | - |
79 | | - while ((i = getopt(argc, argv, "fzv")) != -1) { |
80 | | - switch (i) { |
81 | | - case 'z': |
82 | | - zflag++; |
83 | | - /*FALLTHRU*/ |
84 | | - case 'f': |
85 | | - config.foreground = 1; |
86 | | - break; |
87 | | - case 'v': |
88 | | - (void)fprintf(stderr, "%s\n", PACKAGE_VERSION); |
89 | | - exit(0); |
90 | | - default: |
91 | | - usage(); |
92 | | - exit(8); |
93 | | - } |
94 | | - } |
95 | | - |
96 | | - argv += optind; |
97 | | - argc -= optind; |
98 | | - |
99 | | - if (argc) { |
100 | | - (void)fprintf(stderr, "%s: too many argments\n", progname); |
101 | | - usage(); |
102 | | - exit(8); |
103 | | - } |
104 | | - |
105 | | - wnet_set_time(); |
106 | | - |
107 | | - wconfig_init(NULL); |
108 | | - wlog_init(); |
109 | | - if (zflag) { |
110 | | - wcache_setupfs(); |
111 | | - exit(0); |
112 | | - } |
113 | | - wcache_init(1); |
114 | | - |
115 | | - /* |
116 | | - * HTTP should be initialised before the network so that |
117 | | - * the wlogwriter exits cleanly. |
118 | | - */ |
119 | | - whttp_init(); |
120 | | - wnet_init(); |
121 | | - |
122 | | - (void)signal(SIGINT, sig_exit); |
123 | | - (void)signal(SIGTERM, sig_exit); |
124 | | - |
125 | | - wlog(WLOG_NOTICE, "running"); |
126 | | - |
127 | | -#ifdef WDEBUG_ALLOC |
128 | | - (void)fprintf(stderr, "debug allocator enabled, assuming -f\n"); |
129 | | - config.foreground = 1; |
130 | | -#endif |
131 | | - |
132 | | - if (!config.foreground) |
133 | | - daemon(0, 0); |
134 | | - |
135 | | - wnet_run(); |
136 | | - wlog_close(); |
137 | | - wcache_shutdown(); |
138 | | - whttp_shutdown(); |
139 | | - |
140 | | -#ifdef WDEBUG_ALLOC |
141 | | - ae_checkleaks(); |
142 | | -#endif |
143 | | - return EXIT_SUCCESS; |
144 | | -} |
145 | | - |
146 | | -#ifdef __lint |
147 | | -# pragma error_messages(default, E_H_C_CHECK2) |
148 | | -#endif |
149 | | - |
150 | | -void |
151 | | -outofmemory(void) |
152 | | -{ |
153 | | - static int count; |
154 | | - |
155 | | - if (count++) |
156 | | - abort(); |
157 | | - |
158 | | - wlog(WLOG_ERROR, "fatal: out of memory. exiting."); |
159 | | - exit(8); |
160 | | -} |
161 | | - |
162 | | -void |
163 | | -realloc_addchar(sp, c) |
164 | | - char **sp; |
165 | | - int c; |
166 | | -{ |
167 | | - char *p; |
168 | | - |
169 | | - if ((*sp = wrealloc(*sp, strlen(*sp) + 2)) == NULL) |
170 | | - outofmemory(); |
171 | | - p = *sp + strlen(*sp); |
172 | | - *p++ = (char) c; |
173 | | - *p++ = '\0'; |
174 | | -} |
175 | | - |
176 | | -void |
177 | | -realloc_strcat(sp, s) |
178 | | - char **sp; |
179 | | - const char *s; |
180 | | -{ |
181 | | - if ((*sp = wrealloc(*sp, strlen(*sp) + strlen(s) + 1)) == NULL) |
182 | | - outofmemory(); |
183 | | - (void)strcat(*sp, s); |
184 | | -} |
185 | | - |
186 | | -#ifdef WDEBUG_ALLOC |
187 | | -# ifdef THREADED_IO |
188 | | -pthread_mutex_t ae_mtx = PTHREAD_MUTEX_INITIALIZER; |
189 | | -# define ALLOC_LOCK pthread_mutex_lock(&ae_mtx) |
190 | | -# define ALLOC_UNLOCK pthread_mutex_unlock(&ae_mtx) |
191 | | -# else |
192 | | -# define ALLOC_LOCK ((void)0) |
193 | | -# define ALLOC_UNLOCK ((void)0) |
194 | | -# endif |
195 | | - |
196 | | -struct alloc_entry { |
197 | | - char *ae_addr; |
198 | | - char *ae_mapping; |
199 | | - size_t ae_mapsize; |
200 | | - size_t ae_size; |
201 | | - int ae_freed; |
202 | | - const char *ae_freed_file; |
203 | | - int ae_freed_line; |
204 | | - const char *ae_alloced_file; |
205 | | - int ae_alloced_line; |
206 | | -struct alloc_entry *ae_next; |
207 | | -}; |
208 | | - |
209 | | -static struct alloc_entry allocs; |
210 | | -static int pgsize; |
211 | | - |
212 | | -static void |
213 | | -segv_action(sig, si, data) |
214 | | - int sig; |
215 | | - siginfo_t *si; |
216 | | - void *data; |
217 | | -{ |
218 | | -struct alloc_entry *ae; |
219 | | - |
220 | | - /* |
221 | | - * This is mostly non-standard, unportable and unreliable, but if the debug allocator |
222 | | - * is enabled, it's more important to produce useful errors than conform to the letter |
223 | | - * of the law. |
224 | | - */ |
225 | | - (void)fprintf(stderr, "SEGV at %p%s (pid %d)\n", si->si_addr, si->si_code == SI_NOINFO ? " [SI_NOINFO]" : "", |
226 | | - (int) getpid()); |
227 | | - for (ae = allocs.ae_next; ae; ae = ae->ae_next) |
228 | | - if (!ae->ae_freed && (char *)si->si_addr > ae->ae_mapping && |
229 | | - (char *)si->si_addr < ae->ae_mapping + ae->ae_mapsize) { |
230 | | - (void)fprintf(stderr, "\t%p [map @ %p size %d] from %s:%d\n", ae->ae_addr, ae->ae_mapping, |
231 | | - ae->ae_mapsize, ae->ae_alloced_file, ae->ae_alloced_line); |
232 | | - break; |
233 | | - } |
234 | | - if (ae == NULL) |
235 | | - (void)fprintf(stderr, "\tunknown address\n"); |
236 | | - abort(); |
237 | | - _exit(1); |
238 | | -} |
239 | | - |
240 | | -static void |
241 | | -ae_checkleaks(void) |
242 | | -{ |
243 | | -struct alloc_entry *ae; |
244 | | - |
245 | | - ALLOC_LOCK(); |
246 | | - for (ae = allocs.ae_next; ae; ae = ae->ae_next) |
247 | | - if (!ae->ae_freed) |
248 | | - (void)fprintf(stderr, "%p @ %s:%d\n", ae->ae_addr, ae->ae_alloced_file, ae->ae_alloced_line); |
249 | | - ALLOC_UNLOCK(); |
250 | | -} |
251 | | - |
252 | | -void * |
253 | | -internal_wmalloc(size, file, line) |
254 | | - size_t size; |
255 | | - const char *file; |
256 | | - int line; |
257 | | -{ |
258 | | - void *p; |
259 | | -struct alloc_entry *ae; |
260 | | - size_t mapsize; |
261 | | - |
262 | | - ALLOC_LOCK(); |
263 | | - |
264 | | - if (pgsize == 0) |
265 | | - pgsize = sysconf(_SC_PAGESIZE); |
266 | | - |
267 | | - mapsize = (size/pgsize + 2) * pgsize; |
268 | | - if ((p = mmap(NULL, mapsize, PROT_READ|PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0)) == (void *)-1) { |
269 | | - (void)fprintf(stderr, "mmap: %s\n", strerror(errno)); |
270 | | - ALLOC_UNLOCK(); |
271 | | - return NULL; |
272 | | - } |
273 | | - |
274 | | - for (ae = &allocs; ae->ae_next; ae = ae->ae_next) |
275 | | - if (ae->ae_next->ae_mapping == p) |
276 | | - break; |
277 | | - |
278 | | - if (!ae->ae_next) { |
279 | | - if ((ae->ae_next = malloc(sizeof(struct alloc_entry))) == NULL) { |
280 | | - (void)fputs("out of memory\n", stderr); |
281 | | - abort(); |
282 | | - } |
283 | | - bzero(ae->ae_next, sizeof(struct alloc_entry)); |
284 | | - } |
285 | | - |
286 | | - ae = ae->ae_next; |
287 | | - ae->ae_addr = ((char *)p + (mapsize - pgsize)) - size; |
288 | | - ae->ae_mapping = p; |
289 | | - ae->ae_mapsize = mapsize; |
290 | | - ae->ae_size = size; |
291 | | - ae->ae_freed = 0; |
292 | | - ae->ae_alloced_file = file; |
293 | | - ae->ae_alloced_line = line; |
294 | | - (void)fprintf(stderr, "alloc %d @ %p [map @ %p:%p, size %d] at %s:%d\n", size, ae->ae_addr, |
295 | | - ae->ae_mapping, ae->ae_mapping + ae->ae_mapsize, ae->ae_mapsize, file, line); |
296 | | - if (mprotect(ae->ae_addr + size, pgsize, PROT_NONE) < 0) { |
297 | | - (void)fprintf(stderr, "mprotect(0x%p, %d, PROT_NONE): %s\n", ae->ae_addr + size, pgsize, strerror(errno)); |
298 | | - exit(8); |
299 | | - } |
300 | | - |
301 | | - ALLOC_UNLOCK(); |
302 | | - return ae->ae_addr; |
303 | | -} |
304 | | - |
305 | | -void |
306 | | -internal_wfree(p, file, line) |
307 | | - void *p; |
308 | | - const char *file; |
309 | | - int line; |
310 | | -{ |
311 | | -struct alloc_entry *ae; |
312 | | - |
313 | | - ALLOC_LOCK(); |
314 | | - |
315 | | - (void)fprintf(stderr, "free %p @ %s:%d\n", p, file, line); |
316 | | - |
317 | | - for (ae = allocs.ae_next; ae; ae = ae->ae_next) { |
318 | | - if (ae->ae_addr == p) { |
319 | | - if (ae->ae_freed) { |
320 | | - (void)fprintf(stderr, "wfree: ptr %p already freed @ %s:%d! [alloced at %s:%d]\n", |
321 | | - p, ae->ae_freed_file, ae->ae_freed_line, |
322 | | - ae->ae_alloced_file, ae->ae_alloced_line); |
323 | | - ae_checkleaks(); |
324 | | - abort(); |
325 | | - } |
326 | | - ae->ae_freed = 1; |
327 | | - ae->ae_freed_file = file; |
328 | | - ae->ae_freed_line = line; |
329 | | - if (mprotect(ae->ae_addr + ae->ae_size, pgsize, PROT_READ | PROT_WRITE) < 0) { |
330 | | - (void)fprintf(stderr, "mprotect(0x%p, %d, PROT_READ | PROT_WRITE): %s\n", |
331 | | - ae->ae_addr + ae->ae_size, pgsize, strerror(errno)); |
332 | | - exit(8); |
333 | | - } |
334 | | - munmap(ae->ae_mapping, ae->ae_mapsize); |
335 | | - ALLOC_UNLOCK(); |
336 | | - return; |
337 | | - } |
338 | | - } |
339 | | - |
340 | | - (void)fprintf(stderr, "wfree: ptr %p never malloced!\n", p); |
341 | | - ae_checkleaks(); |
342 | | - abort(); |
343 | | -} |
344 | | - |
345 | | -char * |
346 | | -internal_wstrdup(s, file, line) |
347 | | - const char *s, *file; |
348 | | - int line; |
349 | | -{ |
350 | | - char *ret = internal_wmalloc(strlen(s) + 1, file, line); |
351 | | - (void)strcpy(ret, s); |
352 | | - return ret; |
353 | | -} |
354 | | - |
355 | | -void * |
356 | | -internal_wrealloc(p, size, file, line) |
357 | | - void *p; |
358 | | - const char *file; |
359 | | - int line; |
360 | | - size_t size; |
361 | | -{ |
362 | | - void *new; |
363 | | -struct alloc_entry *ae; |
364 | | - size_t osize = 0; |
365 | | - |
366 | | - if (!p) |
367 | | - return internal_wmalloc(size, file, line); |
368 | | - |
369 | | - ALLOC_LOCK(); |
370 | | - |
371 | | - for (ae = allocs.ae_next; ae; ae = ae->ae_next) |
372 | | - if (ae->ae_addr == p) { |
373 | | - osize = ae->ae_size; |
374 | | - break; |
375 | | - } |
376 | | - |
377 | | - if (osize == 0) { |
378 | | - (void)fprintf(stderr, "wrealloc: ptr %p never malloced!\n", p); |
379 | | - ae_checkleaks(); |
380 | | - abort(); |
381 | | - } |
382 | | - |
383 | | - ALLOC_UNLOCK(); |
384 | | - |
385 | | - new = internal_wmalloc(size, file, line); |
386 | | - bcopy(p, new, min(osize, size)); |
387 | | - internal_wfree(p, file, line); |
388 | | - |
389 | | - return new; |
390 | | -} |
391 | | - |
392 | | -void * |
393 | | -internal_wcalloc(num, size, file, line) |
394 | | - size_t num, size; |
395 | | - const char *file; |
396 | | - int line; |
397 | | -{ |
398 | | - size_t t = size * num; |
399 | | - void *p; |
400 | | - |
401 | | - if ((p = internal_wmalloc(t)) == NULL) |
402 | | - return NULL; |
403 | | - bzero(p, t); |
404 | | - return p; |
405 | | -} |
406 | | - |
407 | | -#endif |
Index: trunk/willow/src/wlog.h |
— | — | @@ -1,42 +0,0 @@ |
2 | | -/* @(#) $Header$ */ |
3 | | -/* This source code is in the public domain. */ |
4 | | -/* |
5 | | - * Willow: Lightweight HTTP reverse-proxy. |
6 | | - * wlog: logging. |
7 | | - */ |
8 | | - |
9 | | -#ifndef WLOG_H |
10 | | -#define WLOG_H |
11 | | - |
12 | | -#if defined __SUNPRO_C || defined __DECC || defined __HP_cc |
13 | | -# pragma ident "@(#)$Header$" |
14 | | -#endif |
15 | | - |
16 | | -#include "config.h" |
17 | | - |
18 | | -#define WLOG_DEBUG 0 |
19 | | -#define WLOG_NOTICE 1 |
20 | | -#define WLOG_WARNING 2 |
21 | | -#define WLOG_ERROR 3 |
22 | | -#define WLOG_MAX 3 |
23 | | - |
24 | | -extern struct log_variables { |
25 | | - char *file; |
26 | | - int level; |
27 | | - FILE *fp; |
28 | | - int syslog; |
29 | | - int facility; |
30 | | -} logging; |
31 | | - |
32 | | -void wlog_init(void); |
33 | | -/*PRINTFLIKE2*/ |
34 | | -void wlog(int, const char *, ...); |
35 | | -void wlog_close(void); |
36 | | - |
37 | | -#ifndef WILLOW_DEBUG |
38 | | -# define WDEBUG(x) ((void)0) |
39 | | -#else |
40 | | -# define WDEBUG(x) wlog x |
41 | | -#endif |
42 | | - |
43 | | -#endif |
Index: trunk/willow/src/wnet.c |
— | — | @@ -1,437 +0,0 @@ |
2 | | -/* @(#) $Header$ */ |
3 | | -/* This source code is in the public domain. */ |
4 | | -/* |
5 | | - * Willow: Lightweight HTTP reverse-proxy. |
6 | | - * wnet: Networking. |
7 | | - */ |
8 | | - |
9 | | -#if defined __SUNPRO_C || defined __DECC || defined __HP_cc |
10 | | -# pragma ident "@(#)$Header$" |
11 | | -#endif |
12 | | - |
13 | | -#include <sys/types.h> |
14 | | -#include <sys/socket.h> |
15 | | - |
16 | | -#include "config.h" |
17 | | -#ifdef HAVE_SYS_SENDFILE_H |
18 | | -# include <sys/sendfile.h> |
19 | | -#endif |
20 | | - |
21 | | -#include <arpa/inet.h> |
22 | | - |
23 | | -#include <stdio.h> |
24 | | -#include <string.h> |
25 | | -#include <stdlib.h> |
26 | | -#include <unistd.h> |
27 | | -#include <errno.h> |
28 | | -#include <fcntl.h> |
29 | | -#include <signal.h> |
30 | | -#include <assert.h> |
31 | | -#include <strings.h> |
32 | | - |
33 | | -#include "willow.h" |
34 | | -#include "wnet.h" |
35 | | -#include "wconfig.h" |
36 | | -#include "wlog.h" |
37 | | -#include "whttp.h" |
38 | | - |
39 | | -#define RDBUF_INC 8192 /* buffer in 8 KiB incrs */ |
40 | | - |
41 | | -struct wrtbuf { |
42 | | - /* for buffers only */ |
43 | | -const void *wb_buf; |
44 | | - /* for sendfile only */ |
45 | | - off_t wb_off; |
46 | | - int wb_source; |
47 | | - /* for buffers & sendfile */ |
48 | | - size_t wb_size; |
49 | | - int wb_done; |
50 | | - fdwcb wb_func; |
51 | | - void *wb_udata; |
52 | | -}; |
53 | | - |
54 | | -char current_time_str[30]; |
55 | | -char current_time_short[30]; |
56 | | -#ifdef __lint |
57 | | -# pragma error_messages(off, E_GLOBAL_COULD_BE_STATIC) |
58 | | -#endif |
59 | | -time_t current_time; |
60 | | -#ifdef __lint |
61 | | -# pragma error_messages(default, E_GLOBAL_COULD_BE_STATIC) |
62 | | -#endif |
63 | | - |
64 | | -static void init_fde(struct fde *); |
65 | | - |
66 | | -static void wnet_accept(struct fde *); |
67 | | -static void wnet_write_do(struct fde *); |
68 | | -static void wnet_sendfile_do(struct fde *); |
69 | | - |
70 | | -static void readbuf_reset(struct readbuf *); |
71 | | - |
72 | | -struct fde *fde_table; |
73 | | -int max_fd; |
74 | | - |
75 | | -int wnet_exit; |
76 | | - |
77 | | -void |
78 | | -wnet_init(void) |
79 | | -{ |
80 | | - int i; |
81 | | - |
82 | | - max_fd = getdtablesize(); |
83 | | - if ((fde_table = wcalloc(max_fd, sizeof(struct fde))) == NULL) |
84 | | - outofmemory(); |
85 | | - |
86 | | - wlog(WLOG_NOTICE, "maximum number of open files: %d", max_fd); |
87 | | - |
88 | | - (void)signal(SIGPIPE, SIG_IGN); |
89 | | - wnet_init_select(); |
90 | | - |
91 | | - for (i = 0; i < nlisteners; ++i) { |
92 | | - struct listener *lns = listeners[i]; |
93 | | - |
94 | | - int fd = wnet_open("listener"); |
95 | | - int one = 1; |
96 | | - if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) == -1) { |
97 | | - wlog(WLOG_ERROR, "setsockopt: %s: %s\n", lns->name, strerror(errno)); |
98 | | - exit(8); |
99 | | - } |
100 | | - if (bind(fd, (struct sockaddr *) &lns->addr, sizeof(lns->addr)) < 0) { |
101 | | - wlog(WLOG_ERROR, "bind: %s: %s\n", lns->name, strerror(errno)); |
102 | | - exit(8); |
103 | | - } |
104 | | - if (listen(fd, 10) < 0) { |
105 | | - wlog(WLOG_ERROR, "listen: %s: %s\n", lns->name, strerror(errno)); |
106 | | - exit(8); |
107 | | - } |
108 | | - wnet_register(fd, FDE_READ, wnet_accept, NULL); |
109 | | - wlog(WLOG_NOTICE, "listening on %s", lns->name); |
110 | | - } |
111 | | -} |
112 | | - |
113 | | -void |
114 | | -wnet_accept(e) |
115 | | - struct fde *e; |
116 | | -{ |
117 | | -struct client_data *cdata; |
118 | | -#ifdef __hpux |
119 | | - int addrlen; |
120 | | -#else |
121 | | - socklen_t addrlen; |
122 | | -#endif |
123 | | - int newfd, val; |
124 | | -struct fde *newe; |
125 | | - |
126 | | - if ((cdata = wcalloc(1, sizeof(*cdata))) == NULL) |
127 | | - outofmemory(); |
128 | | - |
129 | | - addrlen = sizeof(cdata->cdat_addr); |
130 | | - |
131 | | - if ((newfd = accept(e->fde_fd, (struct sockaddr *) &cdata->cdat_addr, &addrlen)) < 0) { |
132 | | - wlog(WLOG_NOTICE, "accept error: %s", strerror(errno)); |
133 | | - wfree(cdata); |
134 | | - return; |
135 | | - } |
136 | | - |
137 | | - if (newfd >= max_fd) { |
138 | | - wlog(WLOG_NOTICE, "out of file descriptors!"); |
139 | | - wfree(cdata); |
140 | | - (void)close(newfd); |
141 | | - return; |
142 | | - } |
143 | | - |
144 | | - val = fcntl(newfd, F_GETFL, 0); |
145 | | - if (val == -1 || fcntl(newfd, F_SETFL, val | O_NONBLOCK) == -1) { |
146 | | - wlog(WLOG_WARNING, "fcntl(%d) failed: %s", newfd, strerror(errno)); |
147 | | - wfree(cdata); |
148 | | - (void)close(newfd); |
149 | | - return; |
150 | | - } |
151 | | - |
152 | | - newe = &fde_table[newfd]; |
153 | | - init_fde(newe); |
154 | | - newe->fde_flags.open = 1; |
155 | | -#ifdef USE_POLL |
156 | | - if (newfd > highest_fd) |
157 | | - highest_fd = newfd; |
158 | | -#endif |
159 | | - newe->fde_fd = newfd; |
160 | | - newe->fde_cdata = cdata; |
161 | | - newe->fde_desc = "accept()ed fd"; |
162 | | - (void)inet_ntop(AF_INET, &cdata->cdat_addr.sin_addr.s_addr, newe->fde_straddr, sizeof(newe->fde_straddr)); |
163 | | - |
164 | | - WDEBUG((WLOG_DEBUG, "wnet_accept: new fd %d", newfd)); |
165 | | - http_new(newe); |
166 | | - return; |
167 | | -} |
168 | | - |
169 | | -static void |
170 | | -init_fde(fde) |
171 | | - struct fde *fde; |
172 | | -{ |
173 | | - fde->fde_fd = 0; |
174 | | - fde->fde_desc = "<unknown>"; |
175 | | - fde->fde_read_handler = NULL; |
176 | | - fde->fde_write_handler = NULL; |
177 | | - fde->fde_cdata = NULL; |
178 | | - fde->fde_rdata = fde->fde_wdata = NULL; |
179 | | - (void)strcpy(fde->fde_straddr, "NONE"); |
180 | | - fde->fde_epflags = 0; |
181 | | - bzero(&fde->fde_readbuf, sizeof(fde->fde_readbuf)); |
182 | | - fde->fde_flags.open = 0; |
183 | | -} |
184 | | - |
185 | | -int |
186 | | -wnet_open(desc) |
187 | | - const char *desc; |
188 | | -{ |
189 | | - int fd, val; |
190 | | - |
191 | | - if ((fd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { |
192 | | - wlog(WLOG_WARNING, "socket: %s", strerror(errno)); |
193 | | - return -1; |
194 | | - } |
195 | | - |
196 | | - val = fcntl(fd, F_GETFL, 0); |
197 | | - if (val == -1 || fcntl(fd, F_SETFL, val | O_NONBLOCK) == -1) { |
198 | | - wlog(WLOG_WARNING, "fcntl(%d) failed: %s", fd, strerror(errno)); |
199 | | - return -1; |
200 | | - } |
201 | | - |
202 | | - init_fde(&fde_table[fd]); |
203 | | - fde_table[fd].fde_fd = fd; |
204 | | - fde_table[fd].fde_desc = desc; |
205 | | - fde_table[fd].fde_flags.open = 1; |
206 | | -#ifdef USE_POLL |
207 | | - if (fd > highest_fd) |
208 | | - highest_fd = fd; |
209 | | -#endif |
210 | | - |
211 | | - return fd; |
212 | | -} |
213 | | - |
214 | | -void |
215 | | -wnet_close(fd) |
216 | | - int fd; |
217 | | -{ |
218 | | -struct fde *e = &fde_table[fd]; |
219 | | - |
220 | | - wnet_register(fd, FDE_READ | FDE_WRITE, NULL, NULL); |
221 | | - (void)close(e->fde_fd); |
222 | | - if (e->fde_cdata) |
223 | | - wfree(e->fde_cdata); |
224 | | - readbuf_free(&e->fde_readbuf); |
225 | | - e->fde_flags.open = 0; |
226 | | - e->fde_read_handler = NULL; |
227 | | - e->fde_write_handler = NULL; |
228 | | -#ifdef USE_POLL |
229 | | - if (fd == highest_fd) |
230 | | - --highest_fd; |
231 | | -#endif |
232 | | -} |
233 | | - |
234 | | -void |
235 | | -wnet_sendfile(fd, source, size, off, cb, data) |
236 | | - int fd, source; |
237 | | - size_t size; |
238 | | - off_t off; |
239 | | - fdwcb cb; |
240 | | - void *data; |
241 | | -{ |
242 | | -struct wrtbuf *wb; |
243 | | -struct fde *e = &fde_table[fd]; |
244 | | - |
245 | | - WDEBUG((WLOG_DEBUG, "wnet_sendfile: %d (+%ld) bytes from %d to %d [%s]", size, (long)off, source, fd, e->fde_desc)); |
246 | | - |
247 | | - if ((wb = wcalloc(1, sizeof(*wb))) == NULL) |
248 | | - outofmemory(); |
249 | | - |
250 | | - wb->wb_done = 0; |
251 | | - wb->wb_func = cb; |
252 | | - wb->wb_udata = data; |
253 | | - wb->wb_size = size; |
254 | | - wb->wb_source = source; |
255 | | - wb->wb_off = off; |
256 | | - |
257 | | - e->fde_wdata = wb; |
258 | | - wnet_register(e->fde_fd, FDE_WRITE, wnet_sendfile_do, e); |
259 | | - wnet_sendfile_do(e); |
260 | | -} |
261 | | - |
262 | | -void |
263 | | -wnet_write(fd, buf, bufsz, cb, data) |
264 | | - int fd; |
265 | | - const void *buf; |
266 | | - size_t bufsz; |
267 | | - fdwcb cb; |
268 | | - void *data; |
269 | | -{ |
270 | | -struct wrtbuf *wb; |
271 | | -struct fde *e = &fde_table[fd]; |
272 | | - |
273 | | - WDEBUG((WLOG_DEBUG, "wnet_write: %d bytes to %d [%s]", bufsz, e->fde_fd, e->fde_desc)); |
274 | | - |
275 | | - if ((wb = wmalloc(sizeof(*wb))) == NULL) |
276 | | - outofmemory(); |
277 | | - |
278 | | - wb->wb_buf = buf; |
279 | | - wb->wb_size = bufsz; |
280 | | - wb->wb_done = 0; |
281 | | - wb->wb_func = cb; |
282 | | - wb->wb_udata = data; |
283 | | - |
284 | | - e->fde_wdata = wb; |
285 | | - |
286 | | - wnet_register(e->fde_fd, FDE_WRITE, wnet_sendfile_do, e); |
287 | | - wnet_write_do(e); |
288 | | -} |
289 | | - |
290 | | -static void |
291 | | -wnet_write_do(e) |
292 | | - struct fde *e; |
293 | | -{ |
294 | | -struct wrtbuf *buf; |
295 | | - int i; |
296 | | -#ifdef WILLOW_DEBUG |
297 | | - char *p; |
298 | | -#endif |
299 | | - |
300 | | - buf = e->fde_wdata; |
301 | | - while ((i = write(e->fde_fd, (char *)buf->wb_buf + buf->wb_done, buf->wb_size - buf->wb_done)) > -1) { |
302 | | -#ifdef WILLOW_DEBUG |
303 | | - fprintf(stderr, "write buf: ["); |
304 | | - for (p = ((char *)buf->wb_buf + buf->wb_done); p < ((char *)buf->wb_buf + buf->wb_done + i); ++p) |
305 | | - fputc(*p, stderr); |
306 | | - fputs("]\n", stderr); |
307 | | -#endif |
308 | | - buf->wb_done += i; |
309 | | - WDEBUG((WLOG_DEBUG, "%d of %d done", buf->wb_done, buf->wb_size)); |
310 | | - if (buf->wb_done == buf->wb_size) { |
311 | | - wnet_register(e->fde_fd, FDE_WRITE, NULL, NULL); |
312 | | - buf->wb_func(e, buf->wb_udata, 0); |
313 | | - wfree(buf); |
314 | | - return; |
315 | | - } |
316 | | - } |
317 | | - |
318 | | - if (errno == EWOULDBLOCK) |
319 | | - return; |
320 | | - |
321 | | - wnet_register(e->fde_fd, FDE_WRITE, NULL, NULL); |
322 | | - buf->wb_func(e, buf->wb_udata, -1); |
323 | | - wfree(buf); |
324 | | -} |
325 | | - |
326 | | -static void |
327 | | -wnet_sendfile_do(e) |
328 | | - struct fde *e; |
329 | | -{ |
330 | | -struct wrtbuf *buf; |
331 | | - int i; |
332 | | - /*LINTED unused variable: freebsd-only*/ |
333 | | - off_t off, origoff; |
334 | | - |
335 | | - buf = e->fde_wdata; |
336 | | - origoff = buf->wb_off; |
337 | | - |
338 | | - WDEBUG((WLOG_DEBUG, "wnet_sendfile_do: for %d, off=%ld, size=%d", e->fde_fd, (long) buf->wb_off, buf->wb_size)); |
339 | | - /* |
340 | | - * On Solaris (sendfilev), FreeBSD, Tru64 UNIX and HP-UX (sendfile), we can write header data |
341 | | - * along with the sendfile, which improves performance and reduces syscall usage. |
342 | | - * At the moment this isn't supported, though... |
343 | | - * |
344 | | - * Linux sendfile() doesn't seem to have anything similar. |
345 | | - */ |
346 | | -#if defined __linux__ || defined __sun |
347 | | - i = sendfile(e->fde_fd, buf->wb_source, &buf->wb_off, buf->wb_size); |
348 | | -#elif defined __FreeBSD__ |
349 | | - i = sendfile(buf->wb_source, e->fde_fd, buf->wb_size, NULL, &off, 0); |
350 | | - buf->wb_off += off; |
351 | | - i = off; |
352 | | -#elif defined __hpux || (defined __digital__ && defined __unix__) |
353 | | - i = sendfile(e->fde_fd, buf->wb_source, buf->wb_off, buf->wb_size, NULL, 0); |
354 | | - buf->wb_off += i; |
355 | | -#else |
356 | | -# error i don't know how to invoke sendfile() on this system |
357 | | -#endif |
358 | | - buf->wb_size -= (buf->wb_off - origoff); |
359 | | - |
360 | | - if (buf->wb_size == 0) { |
361 | | - wnet_register(e->fde_fd, FDE_WRITE, NULL, NULL); |
362 | | - buf->wb_func(e, buf->wb_udata, 0); |
363 | | - wfree(buf); |
364 | | - return; |
365 | | - } |
366 | | - |
367 | | - if (i == -1 && errno != EWOULDBLOCK) { |
368 | | - wnet_register(e->fde_fd, FDE_WRITE, NULL, NULL); |
369 | | - buf->wb_func(e, buf->wb_udata, -1); |
370 | | - wfree(buf); |
371 | | - } |
372 | | - |
373 | | - WDEBUG((WLOG_DEBUG, "wnet_sendfile_do: sendfile failed %s", strerror(errno))); |
374 | | - |
375 | | - if (errno == EWOULDBLOCK) |
376 | | - return; |
377 | | - |
378 | | -} |
379 | | - |
380 | | -void |
381 | | -wnet_set_time(void) |
382 | | -{ |
383 | | -struct tm *now; |
384 | | - time_t old = current_time; |
385 | | - size_t n; |
386 | | - |
387 | | - current_time = time(NULL); |
388 | | - if (current_time == old) |
389 | | - return; |
390 | | - |
391 | | - now = gmtime(¤t_time); |
392 | | - |
393 | | - n = strftime(current_time_str, sizeof(current_time_str), "%a, %d %b %Y %H:%M:%S GMT", now); |
394 | | - assert(n); |
395 | | - n = strftime(current_time_short, sizeof(current_time_short), "%Y-%m-%d %H:%M:%S", now); |
396 | | - assert(n); |
397 | | -} |
398 | | - |
399 | | - |
400 | | -int |
401 | | -readbuf_getdata(fde) |
402 | | - struct fde *fde; |
403 | | -{ |
404 | | - int i; |
405 | | - |
406 | | - WDEBUG((WLOG_DEBUG, "readbuf_getdata: called")); |
407 | | - if (readbuf_data_left(&fde->fde_readbuf) == 0) |
408 | | - readbuf_reset(&fde->fde_readbuf); |
409 | | - |
410 | | - if (readbuf_spare_size(&fde->fde_readbuf) == 0) { |
411 | | - WDEBUG((WLOG_DEBUG, "readbuf_getdata: no space in buffer")); |
412 | | - fde->fde_readbuf.rb_size += RDBUF_INC; |
413 | | - fde->fde_readbuf.rb_p = realloc(fde->fde_readbuf.rb_p, fde->fde_readbuf.rb_size); |
414 | | - } |
415 | | - |
416 | | - if ((i = read(fde->fde_fd, readbuf_spare_start(&fde->fde_readbuf), readbuf_spare_size(&fde->fde_readbuf))) < 1) |
417 | | - return i; |
418 | | - fde->fde_readbuf.rb_dsize += i; |
419 | | - WDEBUG((WLOG_DEBUG, "readbuf_getdata: read %d bytes", i)); |
420 | | - |
421 | | - return i; |
422 | | -} |
423 | | - |
424 | | -void |
425 | | -readbuf_free(buffer) |
426 | | - struct readbuf *buffer; |
427 | | -{ |
428 | | - if (buffer->rb_p) |
429 | | - free(buffer->rb_p); |
430 | | - bzero(buffer, sizeof(*buffer)); |
431 | | -} |
432 | | - |
433 | | -static void |
434 | | -readbuf_reset(buffer) |
435 | | - struct readbuf *buffer; |
436 | | -{ |
437 | | - buffer->rb_dpos = buffer->rb_dsize = 0; |
438 | | -} |
Index: trunk/willow/src/wbackend.c |
— | — | @@ -1,164 +0,0 @@ |
2 | | -/* @(#) $Header$ */ |
3 | | -/* This source code is in the public domain. */ |
4 | | -/* |
5 | | - * Willow: Lightweight HTTP reverse-proxy. |
6 | | - * wbackend: HTTP backend handling. |
7 | | - */ |
8 | | - |
9 | | -#if defined __SUNPRO_C || defined __DECC || defined __HP_cc |
10 | | -# pragma ident "@(#)$Header$" |
11 | | -#endif |
12 | | - |
13 | | -#include <sys/types.h> |
14 | | -#include <sys/socket.h> |
15 | | - |
16 | | -#include <arpa/inet.h> |
17 | | - |
18 | | -#include <stdlib.h> |
19 | | -#include <stdio.h> |
20 | | -#include <string.h> |
21 | | -#include <errno.h> |
22 | | -#include <strings.h> |
23 | | - |
24 | | -#include "willow.h" |
25 | | -#include "wbackend.h" |
26 | | -#include "wnet.h" |
27 | | -#include "wlog.h" |
28 | | -#include "confparse.h" |
29 | | - |
30 | | -static struct backend **backends; |
31 | | -int nbackends; |
32 | | - |
33 | | -static struct backend *new_backend(const char *, int); |
34 | | -static void backend_read(struct fde *); |
35 | | -static struct backend *next_backend(void); |
36 | | - |
37 | | -struct backend_cb_data { |
38 | | -struct backend *bc_backend; |
39 | | - backend_cb bc_func; |
40 | | - void *bc_data; |
41 | | -}; |
42 | | - |
43 | | -static struct backend * |
44 | | -new_backend(addr, port) |
45 | | - const char *addr; |
46 | | - int port; |
47 | | -{ |
48 | | -struct backend *nb; |
49 | | - |
50 | | - if ((nb = wcalloc(1, sizeof(*nb))) == NULL) |
51 | | - outofmemory(); |
52 | | - |
53 | | - nb->be_port = port; |
54 | | - nb->be_name = wstrdup(addr); |
55 | | - nb->be_addr.sin_family = AF_INET; |
56 | | - nb->be_addr.sin_port = htons(nb->be_port); |
57 | | - nb->be_addr.sin_addr.s_addr = inet_addr(nb->be_name); |
58 | | - nb->be_okay = 1; |
59 | | - return nb; |
60 | | -} |
61 | | - |
62 | | -void |
63 | | -add_backend(addr, port) |
64 | | - const char *addr; |
65 | | - int port; |
66 | | -{ |
67 | | - if (port < 1 || port > 65535) { |
68 | | - conf_report_error("invalid backend port: %d", port); |
69 | | - nerrors++; |
70 | | - return; |
71 | | - } |
72 | | - |
73 | | - if ((backends = wrealloc(backends, sizeof(struct backend*) * ++nbackends)) == NULL) |
74 | | - outofmemory(); |
75 | | - backends[nbackends - 1] = new_backend(addr, port); |
76 | | - wlog(WLOG_NOTICE, "backend: %s:%d", addr, port); |
77 | | -} |
78 | | - |
79 | | -#if 0 |
80 | | -void |
81 | | -backend_file(file) |
82 | | - char *file; |
83 | | -{ |
84 | | - FILE *f; |
85 | | - char line[1024]; |
86 | | - |
87 | | - if ((f = fopen(file, "r")) == NULL) { |
88 | | - perror(file); |
89 | | - exit(8); |
90 | | - } |
91 | | - |
92 | | - while (fgets(line, sizeof line, f)) { |
93 | | - line[strlen(line) - 1] = '\0'; |
94 | | - add_backend(line); |
95 | | - } |
96 | | - |
97 | | - (void)fclose(f); |
98 | | -} |
99 | | -#endif |
100 | | - |
101 | | -int |
102 | | -get_backend(func, data) |
103 | | - backend_cb func; |
104 | | - void *data; |
105 | | -{ |
106 | | -struct backend_cb_data *cbd; |
107 | | - int s; |
108 | | - |
109 | | - WDEBUG((WLOG_DEBUG, "get_backend: called")); |
110 | | - |
111 | | - if ((cbd = wmalloc(sizeof(*cbd))) == NULL) |
112 | | - outofmemory(); |
113 | | - |
114 | | - cbd->bc_func = func; |
115 | | - cbd->bc_data = data; |
116 | | - cbd->bc_backend = next_backend(); |
117 | | - |
118 | | - if ((s = wnet_open("backend connection")) == -1) { |
119 | | - wlog(WLOG_WARNING, "opening backend socket: %s", strerror(errno)); |
120 | | - return -1; |
121 | | - } |
122 | | - |
123 | | - if (connect(s, (struct sockaddr *)&cbd->bc_backend->be_addr, sizeof(cbd->bc_backend->be_addr)) == 0) { |
124 | | - WDEBUG((WLOG_DEBUG, "get_backend: connection completed immediately")); |
125 | | - func(cbd->bc_backend, &fde_table[s], data); |
126 | | - wfree(cbd); |
127 | | - return 0; |
128 | | - } |
129 | | - |
130 | | - if (errno != EINPROGRESS) { |
131 | | - wlog(WLOG_WARNING, "%s: %s", cbd->bc_backend->be_name, strerror(errno)); |
132 | | - return -1; |
133 | | - } |
134 | | - |
135 | | - WDEBUG((WLOG_DEBUG, "get_backend: waiting for connection to complete")); |
136 | | - wnet_register(s, FDE_WRITE, backend_read, cbd); |
137 | | - return 0; |
138 | | -} |
139 | | - |
140 | | -static void |
141 | | -backend_read(e) |
142 | | - struct fde *e; |
143 | | -{ |
144 | | -struct backend_cb_data *cbd = e->fde_rdata; |
145 | | - |
146 | | - /* |
147 | | - * After handing the fd off to the caller, we don't care about it |
148 | | - * any more. |
149 | | - */ |
150 | | - wnet_register(e->fde_fd, FDE_WRITE, NULL, NULL); |
151 | | - |
152 | | - cbd->bc_func(cbd->bc_backend, e, cbd->bc_data); |
153 | | - wfree(cbd); |
154 | | -} |
155 | | - |
156 | | -static struct backend * |
157 | | -next_backend(void) |
158 | | -{ |
159 | | -static int cur = 0; |
160 | | - |
161 | | - if (cur >= nbackends) |
162 | | - cur = 0; |
163 | | - |
164 | | - return backends[cur++]; |
165 | | -} |
Index: trunk/willow/src/confparse.c |
— | — | @@ -1,458 +0,0 @@ |
2 | | -/* @(#) $Header$ */ |
3 | | -/* From ircd-ratbox: newconf.c,v 7.209 2005/04/05 01:22:57 leeh Exp */ |
4 | | -/* This source code is in the public domain. */ |
5 | | -/* |
6 | | - * Willow: Lightweight HTTP reverse-proxy. |
7 | | - * confparse: config parser implementation. |
8 | | - */ |
9 | | - |
10 | | -#if defined __SUNPRO_C || defined __DECC || defined __HP_cc |
11 | | -# pragma ident "@(#)$Header$" |
12 | | -#endif |
13 | | - |
14 | | -#include <stdarg.h> |
15 | | -#include <stdio.h> |
16 | | -#include <string.h> |
17 | | -#include <syslog.h> |
18 | | - |
19 | | -#include "willow.h" |
20 | | -#include "confparse.h" |
21 | | -#include "queue.h" |
22 | | -#include "wlog.h" |
23 | | -#include "wbackend.h" |
24 | | -#include "wconfig.h" |
25 | | - |
26 | | -#define CF_TYPE(x) ((x) & CF_MTYPE) |
27 | | - |
28 | | -int nerrors; |
29 | | -struct top_conf *conf_cur_block; |
30 | | -char *conf_cur_block_name; |
31 | | - |
32 | | -static LIST_HEAD(conf_items_head, top_conf) conf_items = |
33 | | - LIST_HEAD_INITIALIZER(conf_items); |
34 | | - |
35 | | -static struct conf_entry *find_conf_item(struct top_conf *top, const char *); |
36 | | -static void conf_set_generic_int(void *, void *); |
37 | | -static void conf_set_generic_string(void *, int, void *); |
38 | | -static void add_top_conf(const char *name, int (*) (struct top_conf *), |
39 | | - int (*) (struct top_conf *), struct conf_entry *); |
40 | | - |
41 | | -void |
42 | | -conf_report_error(const char *fmt, ...) |
43 | | -{ |
44 | | - char buf[1024]; |
45 | | - va_list ap; |
46 | | - |
47 | | - va_start(ap, fmt); |
48 | | - (void)vsnprintf(buf, 1024, fmt, ap); |
49 | | - va_end(ap); |
50 | | - |
51 | | - wlog(WLOG_ERROR, "\"%s\", line %d: %s", current_file, lineno, buf); |
52 | | -} |
53 | | - |
54 | | -void |
55 | | -yyerror(msg) |
56 | | - const char *msg; |
57 | | -{ |
58 | | - conf_report_error("%s", msg); |
59 | | -} |
60 | | - |
61 | | -static const char * |
62 | | -conf_strtype(type) |
63 | | - int type; |
64 | | -{ |
65 | | - switch (type & CF_MTYPE) |
66 | | - { |
67 | | - case CF_INT: |
68 | | - return "integer value"; |
69 | | - case CF_STRING: |
70 | | - return "unquoted string"; |
71 | | - case CF_YESNO: |
72 | | - return "yes/no value"; |
73 | | - case CF_QSTRING: |
74 | | - return "quoted string"; |
75 | | - case CF_TIME: |
76 | | - return "time/size value"; |
77 | | - default: |
78 | | - return "unknown type"; |
79 | | - } |
80 | | -} |
81 | | - |
82 | | -static void |
83 | | -add_top_conf(name, sfunc, efunc, items) |
84 | | - const char *name; |
85 | | - int (*sfunc) (struct top_conf *); |
86 | | - int (*efunc) (struct top_conf *); |
87 | | - struct conf_entry *items; |
88 | | -{ |
89 | | -struct top_conf *tc; |
90 | | - |
91 | | - tc = wmalloc(sizeof(struct top_conf)); |
92 | | - |
93 | | - tc->tc_name = wstrdup(name); |
94 | | - tc->tc_sfunc = sfunc; |
95 | | - tc->tc_efunc = efunc; |
96 | | - tc->tc_entries = items; |
97 | | - |
98 | | - LIST_INSERT_HEAD(&conf_items, tc, entries); |
99 | | -} |
100 | | - |
101 | | -static struct top_conf * |
102 | | -find_top_conf(name) |
103 | | - const char *name; |
104 | | -{ |
105 | | -struct top_conf *tc; |
106 | | - |
107 | | - LIST_FOREACH(tc, &conf_items, entries) { |
108 | | - if (!strcasecmp(tc->tc_name, name)) |
109 | | - return tc; |
110 | | - } |
111 | | - |
112 | | - return NULL; |
113 | | -} |
114 | | - |
115 | | -static struct conf_entry * |
116 | | -find_conf_item(top, name) |
117 | | - struct top_conf *top; |
118 | | - const char *name; |
119 | | -{ |
120 | | -struct conf_entry *cf; |
121 | | - |
122 | | - if (top->tc_entries) { |
123 | | - int i; |
124 | | - |
125 | | - for(i = 0; top->tc_entries[i].cf_type; i++) |
126 | | - { |
127 | | - cf = &top->tc_entries[i]; |
128 | | - |
129 | | - if(!strcasecmp(cf->cf_name, name)) |
130 | | - return cf; |
131 | | - } |
132 | | - } |
133 | | - |
134 | | - LIST_FOREACH(cf, &top->tc_items, entries) { |
135 | | - if(strcasecmp(cf->cf_name, name) == 0) |
136 | | - return cf; |
137 | | - } |
138 | | - |
139 | | - return NULL; |
140 | | -} |
141 | | - |
142 | | -int |
143 | | -conf_call_set(tc, item, value, type) |
144 | | - struct top_conf *tc; |
145 | | - char *item; |
146 | | - conf_parm_t *value; |
147 | | - int type; |
148 | | -{ |
149 | | -struct conf_entry *cf; |
150 | | - conf_parm_t *cp; |
151 | | - |
152 | | - if (!tc) |
153 | | - return -1; |
154 | | - |
155 | | - if ((cf = find_conf_item(tc, item)) == NULL) { |
156 | | - conf_report_error("Non-existant configuration setting %s::%s.", |
157 | | - tc->tc_name, (char *) item); |
158 | | - nerrors++; |
159 | | - return -1; |
160 | | - } |
161 | | - |
162 | | - /* |
163 | | - * If it takes one thing, make sure they only passed one thing, |
164 | | - * and handle as needed. |
165 | | - */ |
166 | | - if (value->type & CF_FLIST && !cf->cf_type & CF_FLIST) { |
167 | | - conf_report_error("Option %s::%s does not take a list of values.", |
168 | | - tc->tc_name, item); |
169 | | - nerrors++; |
170 | | - return -1; |
171 | | - } |
172 | | - |
173 | | - cp = value->v.list; |
174 | | - |
175 | | - if (CF_TYPE(value->v.list->type) != CF_TYPE(cf->cf_type)) { |
176 | | - /* |
177 | | - * If it expects a string value, but we got a yesno, |
178 | | - * convert it back |
179 | | - */ |
180 | | - if((CF_TYPE(value->v.list->type) == CF_YESNO) && |
181 | | - (CF_TYPE(cf->cf_type) == CF_STRING)) { |
182 | | - value->v.list->type = CF_STRING; |
183 | | - |
184 | | - if(cp->v.number == 1) |
185 | | - cp->v.string = wstrdup("yes"); |
186 | | - else |
187 | | - cp->v.string = wstrdup("no"); |
188 | | - } |
189 | | - |
190 | | - /* |
191 | | - * Maybe it's a CF_TIME and they passed CF_INT -- |
192 | | - * should still be valid. |
193 | | - */ |
194 | | - else if(!((CF_TYPE(value->v.list->type) == CF_INT) && |
195 | | - (CF_TYPE(cf->cf_type) == CF_TIME))) { |
196 | | - conf_report_error("Wrong type for %s::%s (expected %s, got %s)", |
197 | | - tc->tc_name, (char *) item, |
198 | | - conf_strtype(cf->cf_type), conf_strtype(value->v.list->type)); |
199 | | - nerrors++; |
200 | | - return -1; |
201 | | - } |
202 | | - } |
203 | | - |
204 | | - if (cf->cf_type & CF_FLIST) { |
205 | | - /* just pass it the extended argument list */ |
206 | | - cf->cf_func(value->v.list); |
207 | | - } else { |
208 | | - /* it's old-style, needs only one arg */ |
209 | | - switch (cf->cf_type) { |
210 | | - case CF_INT: |
211 | | - case CF_TIME: |
212 | | - case CF_YESNO: |
213 | | - if(cf->cf_arg) |
214 | | - conf_set_generic_int(&cp->v.number, cf->cf_arg); |
215 | | - else |
216 | | - cf->cf_func(&cp->v.number); |
217 | | - break; |
218 | | - case CF_STRING: |
219 | | - case CF_QSTRING: |
220 | | - if(!*cp->v.string) |
221 | | - conf_report_error("Ignoring %s::%s -- empty field", |
222 | | - tc->tc_name, item); |
223 | | - else if(cf->cf_arg) |
224 | | - conf_set_generic_string(cp->v.string, cf->cf_len, cf->cf_arg); |
225 | | - else |
226 | | - cf->cf_func(cp->v.string); |
227 | | - break; |
228 | | - } |
229 | | - } |
230 | | - |
231 | | - return 0; |
232 | | -} |
233 | | - |
234 | | -int |
235 | | -conf_start_block(block, name) |
236 | | - const char *block, *name; |
237 | | -{ |
238 | | - if ((conf_cur_block = find_top_conf(block)) == NULL) { |
239 | | - conf_report_error("Configuration block '%s' is not defined.", block); |
240 | | - nerrors++; |
241 | | - return -1; |
242 | | - } |
243 | | - |
244 | | - if (name) |
245 | | - conf_cur_block_name = wstrdup(name); |
246 | | - else |
247 | | - conf_cur_block_name = NULL; |
248 | | - |
249 | | - if (conf_cur_block->tc_sfunc) |
250 | | - if (conf_cur_block->tc_sfunc(conf_cur_block) < 0) |
251 | | - return -1; |
252 | | - |
253 | | - return 0; |
254 | | -} |
255 | | - |
256 | | -int |
257 | | -conf_end_block(tc) |
258 | | - struct top_conf *tc; |
259 | | -{ |
260 | | - if(tc->tc_efunc) |
261 | | - return tc->tc_efunc(tc); |
262 | | - |
263 | | - wfree(conf_cur_block_name); |
264 | | - return 0; |
265 | | -} |
266 | | - |
267 | | - |
268 | | -static void |
269 | | -conf_set_generic_int(data, location) |
270 | | - void *data, *location; |
271 | | -{ |
272 | | - *((int *) location) = *((unsigned int *) data); |
273 | | -} |
274 | | - |
275 | | -static void |
276 | | -conf_set_generic_string(data, len, location) |
277 | | - void *data, *location; |
278 | | - int len; |
279 | | -{ |
280 | | - char **loc = location; |
281 | | - char *input = data; |
282 | | - |
283 | | - if(len && strlen(input) > len) |
284 | | - input[len] = '\0'; |
285 | | - |
286 | | - wfree(*loc); |
287 | | - *loc = wstrdup(input); |
288 | | -} |
289 | | - |
290 | | -static int backend_port; |
291 | | - |
292 | | -static int |
293 | | -conf_begin_backend(tc) |
294 | | - struct top_conf *tc; |
295 | | -{ |
296 | | - if (conf_cur_block_name == NULL) { |
297 | | - conf_report_error("backend name not specified"); |
298 | | - nerrors++; |
299 | | - return -1; |
300 | | - } |
301 | | - |
302 | | - return 0; |
303 | | -} |
304 | | - |
305 | | -static int |
306 | | -conf_end_backend(tc) |
307 | | - struct top_conf *tc; |
308 | | -{ |
309 | | - add_backend(conf_cur_block_name, backend_port); |
310 | | - backend_port = 0; |
311 | | - |
312 | | - return 0; |
313 | | -} |
314 | | - |
315 | | -static int listen_port; |
316 | | - |
317 | | -static int |
318 | | -conf_begin_listen(tc) |
319 | | - struct top_conf *tc; |
320 | | -{ |
321 | | - if (conf_cur_block_name == NULL) { |
322 | | - conf_report_error("listener host not specified"); |
323 | | - nerrors++; |
324 | | - return -1; |
325 | | - } |
326 | | - |
327 | | - return 0; |
328 | | -} |
329 | | - |
330 | | -static int |
331 | | -conf_end_listen(tc) |
332 | | - struct top_conf *tc; |
333 | | -{ |
334 | | - add_listener(conf_cur_block_name, listen_port); |
335 | | - listen_port = 0; |
336 | | - |
337 | | - return 0; |
338 | | -} |
339 | | - |
340 | | -static int cachedir_size; |
341 | | - |
342 | | -static int |
343 | | -conf_begin_cachedir(tc) |
344 | | - struct top_conf *tc; |
345 | | -{ |
346 | | - if (conf_cur_block_name == NULL) { |
347 | | - conf_report_error("cache directory not specified"); |
348 | | - nerrors++; |
349 | | - return -1; |
350 | | - } |
351 | | - |
352 | | - return 0; |
353 | | -} |
354 | | - |
355 | | -static int |
356 | | -conf_end_cachedir(tc) |
357 | | - struct top_conf *tc; |
358 | | -{ |
359 | | - add_cachedir(conf_cur_block_name, cachedir_size); |
360 | | - cachedir_size = 0; |
361 | | - |
362 | | - return 0; |
363 | | -} |
364 | | - |
365 | | -static char *log_file, *log_syslog_facility, *log_access_log; |
366 | | -static int log_level, log_syslog; |
367 | | - |
368 | | -static struct syslog_facility { |
369 | | - char *name; |
370 | | - int fac; |
371 | | -} syslog_facilities[] = { |
372 | | - {"user", LOG_USER}, |
373 | | - {"mail", LOG_MAIL}, |
374 | | - {"daemon", LOG_DAEMON}, |
375 | | - {"auth", LOG_AUTH}, |
376 | | - {"lpr", LOG_LPR}, |
377 | | - {"news", LOG_NEWS}, |
378 | | - {"uucp", LOG_UUCP}, |
379 | | - {"cron", LOG_CRON}, |
380 | | -#ifdef LOG_AUDIT |
381 | | - {"audit", LOG_AUDIT}, |
382 | | -#endif |
383 | | - {"local0", LOG_LOCAL0}, |
384 | | - {"local1", LOG_LOCAL0}, |
385 | | - {"local2", LOG_LOCAL0}, |
386 | | - {"local3", LOG_LOCAL0}, |
387 | | - {"local4", LOG_LOCAL0}, |
388 | | - {"local5", LOG_LOCAL0}, |
389 | | - {"local6", LOG_LOCAL0}, |
390 | | - {"local7", LOG_LOCAL0}, |
391 | | - {NULL, 0}, |
392 | | -}; |
393 | | - |
394 | | -static int |
395 | | -conf_end_log(tc) |
396 | | - struct top_conf *tc; |
397 | | -{ |
398 | | - if (log_file) { |
399 | | - logging.file = wstrdup(log_file); |
400 | | - } |
401 | | - |
402 | | - if (log_syslog) { |
403 | | - struct syslog_facility *fac = syslog_facilities; |
404 | | - |
405 | | - logging.syslog = 1; |
406 | | - |
407 | | - if (log_syslog_facility) { |
408 | | - for (; fac->name; fac++) { |
409 | | - if (!strcmp(fac->name, log_syslog_facility)) { |
410 | | - logging.facility = fac->fac; |
411 | | - break; |
412 | | - } |
413 | | - } |
414 | | - if (!fac->name) { |
415 | | - conf_report_error("unrecognised syslog facility \"%s\"", log_syslog_facility); |
416 | | - nerrors++; |
417 | | - } |
418 | | - } else |
419 | | - logging.facility = LOG_DAEMON; |
420 | | - } |
421 | | - |
422 | | - logging.level = log_level; |
423 | | - if (log_access_log) |
424 | | - config.access_log = wstrdup(log_access_log); |
425 | | - return 0; |
426 | | -} |
427 | | - |
428 | | -static struct conf_entry conf_backend_table[] = { |
429 | | - { "port", CF_INT, NULL, 0, &backend_port }, |
430 | | - { NULL } |
431 | | -}; |
432 | | - |
433 | | -static struct conf_entry conf_listen_table[] = { |
434 | | - { "port", CF_INT, NULL, 0, &listen_port }, |
435 | | - { NULL } |
436 | | -}; |
437 | | - |
438 | | -static struct conf_entry conf_cachedir_table[] = { |
439 | | - { "size", CF_TIME, NULL, 0, &cachedir_size }, |
440 | | - { NULL } |
441 | | -}; |
442 | | - |
443 | | -static struct conf_entry conf_log_table[] = { |
444 | | - { "level", CF_INT, NULL, 0, &log_level }, |
445 | | - { "file", CF_QSTRING, NULL, 0, &log_file }, |
446 | | - { "syslog", CF_YESNO, NULL, 0, &log_syslog }, |
447 | | - { "facility", CF_STRING, NULL, 0, &log_syslog_facility }, |
448 | | - { "access-log", CF_QSTRING, NULL, 0, &log_access_log }, |
449 | | - { NULL } |
450 | | -}; |
451 | | - |
452 | | -void |
453 | | -newconf_init(void) |
454 | | -{ |
455 | | - add_top_conf("backend", conf_begin_backend, conf_end_backend, conf_backend_table); |
456 | | - add_top_conf("listen", conf_begin_listen, conf_end_listen, conf_listen_table); |
457 | | - add_top_conf("cache-dir", conf_begin_cachedir, conf_end_cachedir, conf_cachedir_table); |
458 | | - add_top_conf("log", NULL, conf_end_log, conf_log_table); |
459 | | -} |
Index: trunk/willow/src/parser.y |
— | — | @@ -1,317 +0,0 @@ |
2 | | -/* @(#) $Header$ */ |
3 | | -/* From: $Nightmare: nightmare/src/main/parser.y,v 1.2.2.1.2.1 2002/07/02 03:42:10 ejb Exp $ */ |
4 | | -/* From: ircd_parser.y,v 1.281 2005/03/22 16:27:48 androsyn Exp */ |
5 | | -/* This source code is in the public domain. */ |
6 | | -/* |
7 | | - * Willow: Lightweight HTTP reverse-proxy. |
8 | | - * parser: configuration file parser. |
9 | | - */ |
10 | | - |
11 | | -%{ |
12 | | -#if defined __SUNPRO_CC || defined __DECC || defined __HP_cc |
13 | | -# pragma ident "@(#)$Header$" |
14 | | -#endif |
15 | | - |
16 | | -#include <sys/types.h> |
17 | | -#include <sys/stat.h> |
18 | | - |
19 | | -#include <netinet/in.h> |
20 | | - |
21 | | -#include <string.h> |
22 | | -#include <stdlib.h> |
23 | | -#include <stdarg.h> |
24 | | -#include <stdio.h> |
25 | | - |
26 | | -#include "willow.h" |
27 | | -#include "confparse.h" |
28 | | - |
29 | | -#define YY_NO_UNPUT |
30 | | - |
31 | | -int yyparse(); |
32 | | -int yyerror(const char *); |
33 | | -int yylex(); |
34 | | - |
35 | | -static time_t conf_find_time(const char*); |
36 | | -static void add_cur_list(int, const char *, int); |
37 | | - |
38 | | -static struct { |
39 | | - const char * name; |
40 | | - const char * plural; |
41 | | - time_t val; |
42 | | -} conf_times[] = { |
43 | | - {"second", "seconds", 1}, |
44 | | - {"minute", "minutes", 60}, |
45 | | - {"hour", "hours", 60 * 60}, |
46 | | - {"day", "days", 60 * 60 * 24}, |
47 | | - {"week", "weeks", 60 * 60 * 24 * 7}, |
48 | | - {"fortnight", "fortnights", 60 * 60 * 24 * 14}, |
49 | | - {"month", "months", 60 * 60 * 24 * 7 * 4}, |
50 | | - {"year", "years", 60 * 60 * 24 * 365}, |
51 | | - /* ok-- we now do sizes here too. they aren't times, but |
52 | | - it's close enough */ |
53 | | - {"byte", "bytes", 1}, |
54 | | - {"kb", NULL, 1024}, |
55 | | - {"kbyte", "kbytes", 1024}, |
56 | | - {"kilobyte", "kilebytes", 1024}, |
57 | | - {"mb", NULL, 1024 * 1024}, |
58 | | - {"mbyte", "mbytes", 1024 * 1024}, |
59 | | - {"megabyte", "megabytes", 1024 * 1024}, |
60 | | - {NULL, NULL, 0}, |
61 | | -}; |
62 | | - |
63 | | -static time_t |
64 | | -conf_find_time(name) |
65 | | - const char *name; |
66 | | -{ |
67 | | - int i; |
68 | | - |
69 | | - for (i = 0; conf_times[i].name; ++i) { |
70 | | - if (!strcasecmp(conf_times[i].name, name) || |
71 | | - (conf_times[i].plural && !strcasecmp(conf_times[i].plural, name))) |
72 | | - return conf_times[i].val; |
73 | | - } |
74 | | - |
75 | | - return 0; |
76 | | -} |
77 | | - |
78 | | -static struct { |
79 | | -const char *word; |
80 | | - int yesno; |
81 | | -} yesno[] = { |
82 | | - {"yes", 1}, |
83 | | - {"no", 0}, |
84 | | - {"true", 1}, |
85 | | - {"false", 0}, |
86 | | - {"on", 1}, |
87 | | - {"off", 0}, |
88 | | - {NULL, 0} |
89 | | -}; |
90 | | - |
91 | | -static int |
92 | | -conf_get_yesno_value(str) |
93 | | - const char *str; |
94 | | -{ |
95 | | - int i; |
96 | | - |
97 | | - for (i = 0; yesno[i].word; i++) |
98 | | - if (!strcasecmp(str, yesno[i].word)) |
99 | | - return yesno[i].yesno; |
100 | | - |
101 | | - return -1; |
102 | | -} |
103 | | - |
104 | | -static void |
105 | | -free_cur_list(list) |
106 | | - conf_parm_t *list; |
107 | | -{ |
108 | | - switch (list->type & CF_MTYPE) { |
109 | | - case CF_STRING: |
110 | | - case CF_QSTRING: |
111 | | - wfree(list->v.string); |
112 | | - break; |
113 | | - case CF_LIST: |
114 | | - free_cur_list(list->v.list); |
115 | | - break; |
116 | | - default: break; |
117 | | - } |
118 | | - |
119 | | - if (list->next) |
120 | | - free_cur_list(list->next); |
121 | | -} |
122 | | - |
123 | | - |
124 | | -conf_parm_t * cur_list = NULL; |
125 | | - |
126 | | -static void |
127 | | -add_cur_list_cpt(new) |
128 | | - conf_parm_t *new; |
129 | | -{ |
130 | | - if (cur_list == NULL) { |
131 | | - cur_list = wcalloc(1, sizeof(conf_parm_t)); |
132 | | - cur_list->type |= CF_FLIST; |
133 | | - cur_list->v.list = new; |
134 | | - } else { |
135 | | - new->next = cur_list->v.list; |
136 | | - cur_list->v.list = new; |
137 | | - } |
138 | | -} |
139 | | - |
140 | | -static void |
141 | | -add_cur_list(type, str, number) |
142 | | - int type, number; |
143 | | - const char *str; |
144 | | -{ |
145 | | - conf_parm_t *new; |
146 | | - |
147 | | - new = wmalloc(sizeof(conf_parm_t)); |
148 | | - new->next = NULL; |
149 | | - new->type = type; |
150 | | - |
151 | | - switch(type) { |
152 | | - case CF_INT: |
153 | | - case CF_TIME: |
154 | | - case CF_YESNO: |
155 | | - new->v.number = number; |
156 | | - break; |
157 | | - case CF_STRING: |
158 | | - case CF_QSTRING: |
159 | | - new->v.string = wstrdup(str); |
160 | | - break; |
161 | | - } |
162 | | - |
163 | | - add_cur_list_cpt(new); |
164 | | -} |
165 | | - |
166 | | - |
167 | | -%} |
168 | | - |
169 | | -%union { |
170 | | - int number; |
171 | | - char *string; |
172 | | - conf_parm_t *conf_parm; |
173 | | -} |
174 | | - |
175 | | -%token TWODOTS |
176 | | - |
177 | | -%token <string> QSTRING STRING |
178 | | -%token <number> NUMBER |
179 | | - |
180 | | -%type <string> qstring string |
181 | | -%type <number> number timespec |
182 | | -%type <conf_parm> oneitem single itemlist |
183 | | - |
184 | | -%start conf |
185 | | - |
186 | | -%% |
187 | | - |
188 | | -conf: |
189 | | - | conf conf_item |
190 | | - | error |
191 | | - ; |
192 | | - |
193 | | -conf_item: block |
194 | | - ; |
195 | | - |
196 | | -block: string |
197 | | - { |
198 | | - conf_start_block($1, NULL); |
199 | | - wfree($1); |
200 | | - } |
201 | | - '{' block_items '}' ';' |
202 | | - { |
203 | | - if (conf_cur_block) |
204 | | - conf_end_block(conf_cur_block); |
205 | | - } |
206 | | - | string qstring |
207 | | - { |
208 | | - conf_start_block($1, $2); |
209 | | - wfree($1); |
210 | | - wfree($2); |
211 | | - } |
212 | | - '{' block_items '}' ';' |
213 | | - { |
214 | | - if (conf_cur_block) |
215 | | - conf_end_block(conf_cur_block); |
216 | | - } |
217 | | - ; |
218 | | - |
219 | | -block_items: block_items block_item |
220 | | - | block_item |
221 | | - ; |
222 | | - |
223 | | -block_item: string '=' itemlist ';' |
224 | | - { |
225 | | - conf_call_set(conf_cur_block, $1, cur_list, CF_LIST); |
226 | | - free_cur_list(cur_list); |
227 | | - cur_list = NULL; |
228 | | - wfree($1); |
229 | | - } |
230 | | - ; |
231 | | - |
232 | | -itemlist: itemlist ',' single |
233 | | - | single |
234 | | - ; |
235 | | - |
236 | | -single: oneitem |
237 | | - { |
238 | | - add_cur_list_cpt($1); |
239 | | - } |
240 | | - | oneitem TWODOTS oneitem |
241 | | - { |
242 | | - /* "1 .. 5" meaning 1,2,3,4,5 - only valid for integers */ |
243 | | - if (($1->type & CF_MTYPE) != CF_INT || |
244 | | - ($3->type & CF_MTYPE) != CF_INT) { |
245 | | - conf_report_error("Both arguments in '..' notation must be integers."); |
246 | | - break; |
247 | | - } else { |
248 | | - int i; |
249 | | - |
250 | | - for (i = $1->v.number; i <= $3->v.number; i++) { |
251 | | - add_cur_list(CF_INT, 0, i); |
252 | | - } |
253 | | - } |
254 | | - } |
255 | | - ; |
256 | | - |
257 | | -oneitem: qstring |
258 | | - { |
259 | | - $$ = wmalloc(sizeof(conf_parm_t)); |
260 | | - $$->type = CF_QSTRING; |
261 | | - $$->v.string = wstrdup($1); |
262 | | - wfree($1); |
263 | | - } |
264 | | - | timespec |
265 | | - { |
266 | | - $$ = wmalloc(sizeof(conf_parm_t)); |
267 | | - $$->type = CF_TIME; |
268 | | - $$->v.number = $1; |
269 | | - } |
270 | | - | number |
271 | | - { |
272 | | - $$ = wmalloc(sizeof(conf_parm_t)); |
273 | | - $$->type = CF_INT; |
274 | | - $$->v.number = $1; |
275 | | - } |
276 | | - | string |
277 | | - { |
278 | | - /* a 'string' could also be a yes/no value .. |
279 | | - so pass it as that, if so */ |
280 | | - int val = conf_get_yesno_value($1); |
281 | | - |
282 | | - $$ = wmalloc(sizeof(conf_parm_t)); |
283 | | - |
284 | | - if (val != -1) { |
285 | | - $$->type = CF_YESNO; |
286 | | - $$->v.number = val; |
287 | | - } else { |
288 | | - $$->type = CF_STRING; |
289 | | - $$->v.string = wstrdup($1); |
290 | | - } |
291 | | - wfree($1); |
292 | | - } |
293 | | - ; |
294 | | - |
295 | | -qstring: QSTRING { strcpy($$, $1); } ; |
296 | | -string: STRING { strcpy($$, $1); } ; |
297 | | -number: NUMBER { $$ = $1; } ; |
298 | | - |
299 | | -timespec: number string |
300 | | - { |
301 | | - time_t t; |
302 | | - |
303 | | - if ((t = conf_find_time($2)) == 0) { |
304 | | - conf_report_error("Unrecognised time type/size '%s'", $2); |
305 | | - t = 1; |
306 | | - } |
307 | | - |
308 | | - $$ = $1 * t; |
309 | | - } |
310 | | - | timespec timespec |
311 | | - { |
312 | | - $$ = $1 + $2; |
313 | | - } |
314 | | - | timespec number |
315 | | - { |
316 | | - $$ = $1 + $2; |
317 | | - } |
318 | | - ; |
Index: trunk/willow/src/willow.h |
— | — | @@ -1,57 +0,0 @@ |
2 | | -/* @(#) $Header$ */ |
3 | | -/* This source code is in the public domain. */ |
4 | | -/* |
5 | | - * Willow: Lightweight HTTP reverse-proxy. |
6 | | - * willow: General utility functions. |
7 | | - */ |
8 | | - |
9 | | -#ifndef WILLOW_H |
10 | | -#define WILLOW_H |
11 | | - |
12 | | -#if defined __SUNPRO_C || defined __DECC || defined __HP_cc |
13 | | -# pragma ident "@(#)$Header$" |
14 | | -#endif |
15 | | - |
16 | | -#include "config.h" |
17 | | - |
18 | | -#ifdef WDEBUG_ALLOC |
19 | | -void *internal_wmalloc(size_t, const char *, int); |
20 | | -void internal_wfree(void *, const char *, int); |
21 | | -char *internal_wstrdup(const char *, const char *, int); |
22 | | -void *internal_wrealloc(void *, size_t, const char *, int); |
23 | | -void *internal_wcalloc(size_t, size_t, const char *, int); |
24 | | -# define wmalloc(s) internal_wmalloc(s, __FILE__, __LINE__) |
25 | | -# define wfree(p) internal_wfree(p, __FILE__, __LINE__) |
26 | | -# define wstrdup(p) internal_wstrdup(p, __FILE__, __LINE__) |
27 | | -# define wrealloc(p,s) internal_wrealloc(p, s, __FILE__, __LINE__) |
28 | | -# define wcalloc(n,s) internal_wcalloc(n, s, __FILE__, __LINE)) |
29 | | -#else |
30 | | -# include <stdlib.h> |
31 | | - |
32 | | -# define wmalloc malloc |
33 | | -# define wfree free |
34 | | -# define wstrdup strdup |
35 | | -# define wrealloc realloc |
36 | | -# define wcalloc calloc |
37 | | -#endif |
38 | | - |
39 | | -void realloc_strcat(char **, const char *); |
40 | | -void realloc_addchar(char **, int); |
41 | | - |
42 | | -#ifndef HAVE_DAEMON |
43 | | -int daemon(int, int); |
44 | | -#endif |
45 | | - |
46 | | -#ifndef HAVE_SOCKLEN_T |
47 | | -typedef int socklen_t; |
48 | | -#endif |
49 | | - |
50 | | -void outofmemory(void); |
51 | | -#ifdef __SUNPRO_C |
52 | | -# pragma does_not_return(outofmemory) |
53 | | -#endif |
54 | | - |
55 | | -#define safe_snprintf(n,a) if (snprintf a > (n - 1)) abort(); |
56 | | -#define min(x,y) ((x) < (y) ? (x) : (y)) |
57 | | - |
58 | | -#endif |
Index: trunk/willow/src/wnet.h |
— | — | @@ -1,124 +0,0 @@ |
2 | | -/* @(#) $Header$ */ |
3 | | -/* This source code is in the public domain. */ |
4 | | -/* |
5 | | - * Willow: Lightweight HTTP reverse-proxy. |
6 | | - * wnet: Networking. |
7 | | - */ |
8 | | - |
9 | | -#ifndef WNET_H |
10 | | -#define WNET_H |
11 | | - |
12 | | -#if defined __SUNPRO_C || defined __DECC || defined __HP_cc |
13 | | -# pragma ident "@(#)$Header$" |
14 | | -#endif |
15 | | - |
16 | | -#if defined __digital__ && defined __unix__ |
17 | | -/* sendfile prototype is missing on Tru64 UNIX */ |
18 | | -# include <sys/uio.h> |
19 | | - |
20 | | -ssize_t sendfile(int, int, off_t, size_t, const struct iovec *, int); |
21 | | -#endif |
22 | | - |
23 | | -#include <sys/types.h> |
24 | | - |
25 | | -#include <netinet/in.h> |
26 | | - |
27 | | -#include "config.h" |
28 | | -#ifdef THREADED_IO |
29 | | -# include <pthread.h> |
30 | | -#endif |
31 | | - |
32 | | -#include "willow.h" |
33 | | - |
34 | | -struct fde; |
35 | | - |
36 | | -extern int max_fd; |
37 | | - |
38 | | -typedef void (*fdcb)(struct fde*); |
39 | | -typedef void (*fdwcb)(struct fde*, void*, int); |
40 | | - |
41 | | -struct client_data; |
42 | | - |
43 | | -#ifdef USE_POLL |
44 | | -extern int highest_fd; |
45 | | -#endif |
46 | | - |
47 | | -struct readbuf { |
48 | | - char *rb_p; /* start of allocated region */ |
49 | | - int rb_size; /* size of allocated region */ |
50 | | - int rb_dsize; /* [p,p+dsize) is valid data */ |
51 | | - int rb_dpos; /* current data position */ |
52 | | -}; |
53 | | -#define readbuf_spare_size(b) ((b)->rb_size - (b)->rb_dsize) |
54 | | -#define readbuf_spare_start(b) ((b)->rb_p + (b)->rb_dsize) |
55 | | -#define readbuf_data_left(b) ((b)->rb_dsize - (b)->rb_dpos) |
56 | | -#define readbuf_inc_data_pos(b, i) ((b)->rb_dpos += (i)) |
57 | | -#define readbuf_cur_pos(b) ((b)->rb_p + (b)->rb_dpos) |
58 | | - |
59 | | -struct fde { |
60 | | - int fde_fd; |
61 | | - const char *fde_desc; |
62 | | - fdcb fde_read_handler; |
63 | | - fdcb fde_write_handler; |
64 | | -struct client_data *fde_cdata; |
65 | | - void *fde_rdata; |
66 | | - void *fde_wdata; |
67 | | - char fde_straddr[16]; |
68 | | - int fde_epflags; |
69 | | -struct readbuf fde_readbuf; |
70 | | - struct { |
71 | | - int open:1; |
72 | | - } fde_flags; |
73 | | -#ifdef THREADED_IO |
74 | | - pthread_mutex_t fde_mtx; |
75 | | -#endif |
76 | | -}; |
77 | | -extern struct fde *fde_table; |
78 | | - |
79 | | -#ifdef THREADED_IO |
80 | | -# ifdef WILLOW_DEBUG |
81 | | -# define FDE_LOCK(e) do { \ |
82 | | - wlog(WLOG_DEBUG, "%u locks %d", pthread_self(), (e)->fde_fd); \ |
83 | | - (void)pthread_mutex_lock(&(e)->fde_mtx); \ |
84 | | -} while(0) |
85 | | -# define FDE_UNLOCK(e) do { \ |
86 | | - wlog(WLOG_DEBUG, "%u unlocks %d", pthread_self(), (e)->fde_fd); \ |
87 | | - (void)pthread_mutex_unlock(&(e)->fde_mtx); \ |
88 | | -} while(0) |
89 | | -# else |
90 | | -# define FDE_LOCK(e) (void)pthread_mutex_lock(&(e)->fde_mtx) |
91 | | -# define FDE_UNLOCK(e) (void)pthread_mutex_unlock(&(e)->fde_mtx) |
92 | | -# endif |
93 | | -#else |
94 | | -# define FDE_LOCK(e) |
95 | | -# define FDE_UNLOCK(e) |
96 | | -#endif |
97 | | - |
98 | | -struct client_data { |
99 | | -struct sockaddr_in cdat_addr; |
100 | | -}; |
101 | | - |
102 | | -extern char current_time_str[]; |
103 | | -extern char current_time_short[]; |
104 | | -extern time_t current_time; |
105 | | -extern int wnet_exit; |
106 | | - |
107 | | -#define FDE_READ 0x1 |
108 | | -#define FDE_WRITE 0x2 |
109 | | - |
110 | | -void wnet_init(void); |
111 | | -void wnet_run(void); |
112 | | - |
113 | | -void wnet_register(int, int, fdcb, void *); |
114 | | -int wnet_open(const char *desc); |
115 | | -void wnet_close(int); |
116 | | -void wnet_write(int, const void *, size_t, fdwcb, void *); |
117 | | -void wnet_sendfile(int, int, size_t, off_t, fdwcb, void *); |
118 | | - |
119 | | -void wnet_set_time(void); |
120 | | -void wnet_init_select(void); |
121 | | - |
122 | | -int readbuf_getdata(struct fde *); |
123 | | -void readbuf_free(struct readbuf *); |
124 | | - |
125 | | -#endif |
Index: trunk/willow/src/wbackend.h |
— | — | @@ -1,37 +0,0 @@ |
2 | | -/* @(#) $Header$ */ |
3 | | -/* This source code is in the public domain. */ |
4 | | -/* |
5 | | - * Willow: Lightweight HTTP reverse-proxy. |
6 | | - * wbackend: HTTP backend handling. |
7 | | - */ |
8 | | - |
9 | | -#ifndef WBACKEND_H |
10 | | -#define WBACKEND_H |
11 | | - |
12 | | -#if defined __SUNPRO_C || defined __DECC || defined __HP_cc |
13 | | -# pragma ident "@(#)$Header$" |
14 | | -#endif |
15 | | - |
16 | | -#include <sys/types.h> |
17 | | - |
18 | | -#include <netinet/in.h> |
19 | | - |
20 | | -struct fde; |
21 | | - |
22 | | -struct backend { |
23 | | - char *be_name; /* IP as specified in config */ |
24 | | - int be_port; /* port number */ |
25 | | -struct sockaddr_in be_addr; /* socket address */ |
26 | | - int be_okay; /* 1 if okay, 0 if unavailable */ |
27 | | -}; |
28 | | - |
29 | | -typedef void (*backend_cb)(struct backend *, struct fde *, void *); |
30 | | - |
31 | | -void add_backend(const char *, int); |
32 | | -void backend_file(char *); |
33 | | - |
34 | | -int get_backend(backend_cb, void *); |
35 | | - |
36 | | -extern int nbackends; |
37 | | - |
38 | | -#endif |
Index: trunk/willow/src/confparse.h |
— | — | @@ -1,78 +0,0 @@ |
2 | | -/* @(#) $Header$ */ |
3 | | -/* From: $Nightmare: nightmare/include/config.h,v 1.32.2.2.2.2 2002/07/02 03:41:28 ejb Exp $ */ |
4 | | -/* From: newconf.h,v 7.36 2005/03/21 22:42:10 leeh Exp */ |
5 | | -/* This source code is in the public domain. */ |
6 | | -/* |
7 | | - * Willow: Lightweight HTTP reverse-proxy. |
8 | | - * confparse: configuration parser. |
9 | | - */ |
10 | | - |
11 | | -#ifndef CONFPARSE_H |
12 | | -#define CONFPARSE_H |
13 | | - |
14 | | -#if defined __SUNPRO_C || defined __DECC || defined __HP_cc |
15 | | -# pragma ident "@(#)$Header$" |
16 | | -#endif |
17 | | - |
18 | | -#include "queue.h" |
19 | | - |
20 | | -struct conf_entry { |
21 | | -const char *cf_name; |
22 | | - int cf_type; |
23 | | - void (*cf_func) (void *); |
24 | | - int cf_len; |
25 | | - void *cf_arg; |
26 | | - LIST_ENTRY(conf_entry) entries; |
27 | | -}; |
28 | | - |
29 | | -struct top_conf { |
30 | | - char *tc_name; |
31 | | - int (*tc_sfunc) (struct top_conf *); |
32 | | - int (*tc_efunc) (struct top_conf *); |
33 | | - LIST_HEAD(tc_items_head, conf_entry) tc_items; |
34 | | - struct conf_entry *tc_entries; |
35 | | - LIST_ENTRY(top_conf) entries; |
36 | | -}; |
37 | | - |
38 | | -#define CF_QSTRING 0x01 |
39 | | -#define CF_INT 0x02 |
40 | | -#define CF_STRING 0x03 |
41 | | -#define CF_TIME 0x04 |
42 | | -#define CF_YESNO 0x05 |
43 | | -#define CF_LIST 0x06 |
44 | | -#define CF_ONE 0x07 |
45 | | - |
46 | | -#define CF_MTYPE 0xFF |
47 | | - |
48 | | -#define CF_FLIST 0x1000 |
49 | | -#define CF_MFLAG 0xFF00 |
50 | | - |
51 | | -typedef struct conf_parm_t_stru |
52 | | -{ |
53 | | -struct conf_parm_t_stru *next; |
54 | | - int type; |
55 | | - union { |
56 | | - char *string; |
57 | | - int number; |
58 | | - struct conf_parm_t_stru *list; |
59 | | - } v; |
60 | | -} conf_parm_t; |
61 | | - |
62 | | -extern struct top_conf *conf_cur_block; |
63 | | - |
64 | | -extern const char *current_file; |
65 | | -extern int lineno; |
66 | | -extern int nerrors; |
67 | | - |
68 | | -int read_config(char *); |
69 | | -int conf_start_block(const char *, const char *); |
70 | | -int conf_end_block(struct top_conf *); |
71 | | -int conf_call_set(struct top_conf *, char *, conf_parm_t *, int); |
72 | | -void conf_report_error(const char *, ...); |
73 | | -void newconf_init(void); |
74 | | -extern char *conf_cur_block_name; |
75 | | -int add_conf_item(const char *topconf, const char *name, int type, void (*func) (void *)); |
76 | | -int remove_conf_item(const char *topconf, const char *name); |
77 | | - |
78 | | - |
79 | | -#endif |
Index: trunk/willow/src/lexer.l |
— | — | @@ -1,66 +0,0 @@ |
2 | | -%{ |
3 | | -/* @(#) $Header$ */ |
4 | | -/* This source code is in the public domain. */ |
5 | | -/* |
6 | | - * Willow: Lightweight HTTP reverse-proxy. |
7 | | - * lexer: configuration file lexer. |
8 | | - */ |
9 | | - |
10 | | -#if defined __SUNPRO_C || defined __DECC || defined __HP_cc |
11 | | -# pragma ident "@(#)$Header$" |
12 | | -#endif |
13 | | - |
14 | | -#include <string.h> |
15 | | -#include <errno.h> |
16 | | - |
17 | | -#include "willow.h" |
18 | | -#include "confparse.h" |
19 | | -#include "y.tab.h" |
20 | | - |
21 | | -int lineno = 1; |
22 | | - |
23 | | -int |
24 | | -yywrap(void) |
25 | | -{ |
26 | | - return 1; |
27 | | -} |
28 | | -%} |
29 | | - |
30 | | -%x COMMENT |
31 | | - |
32 | | -ws [ \t]* |
33 | | -number [0-9][0-9]* |
34 | | -comment #.* |
35 | | -qstring \"[^\"\n]*[\"] |
36 | | -string [a-zA-Z_\~][a-zA-Z0-9_-]* |
37 | | - |
38 | | -%% |
39 | | - |
40 | | -^[ \t]*"/*" { BEGIN COMMENT; } |
41 | | -^[ \t]*"/*".*"*/"[ \t]*\n { lineno++; } |
42 | | - |
43 | | -<COMMENT>"*/"[ \t]*\n { BEGIN 0; lineno++; break; } |
44 | | -<COMMENT>"*/" { BEGIN 0; break; } |
45 | | -<COMMENT>\n { lineno++; break; } |
46 | | -<COMMENT>.\n { lineno++; break; } |
47 | | -<COMMENT>. { break; } |
48 | | -\n { lineno++; } |
49 | | -{ws} ; |
50 | | -{comment} ; |
51 | | -{number} { char *s; |
52 | | - yylval.number = strtol(yytext, &s, 0); |
53 | | - if (*s) { |
54 | | - conf_report_error("invalid number '%s': %s", yytext, strerror(errno)); |
55 | | - break; |
56 | | - } |
57 | | - return NUMBER; |
58 | | - } |
59 | | -{string} { yylval.string = wstrdup(yytext); |
60 | | - return STRING; |
61 | | - } |
62 | | -{qstring} { yylval.string = wstrdup(yytext + 1); |
63 | | - yylval.string[yyleng - 2] = '\0'; |
64 | | - return QSTRING; |
65 | | - } |
66 | | -. { return yytext[0]; |
67 | | - } |
Index: trunk/willow/src/queue.h |
— | — | @@ -1,517 +0,0 @@ |
2 | | -/* @(#) $Header$ */ |
3 | | -/* From: @(#)queue.h 8.5 (Berkeley) 8/20/94 */ |
4 | | -/* From: $FreeBSD: src/sys/sys/queue.h,v 1.58 2004/04/07 04:19:49 imp Exp $ */ |
5 | | - |
6 | | -/* |
7 | | - * Copyright (c) 1991, 1993 |
8 | | - * The Regents of the University of California. All rights reserved. |
9 | | - * |
10 | | - * Redistribution and use in source and binary forms, with or without |
11 | | - * modification, are permitted provided that the following conditions |
12 | | - * are met: |
13 | | - * 1. Redistributions of source code must retain the above copyright |
14 | | - * notice, this list of conditions and the following disclaimer. |
15 | | - * 2. Redistributions in binary form must reproduce the above copyright |
16 | | - * notice, this list of conditions and the following disclaimer in the |
17 | | - * documentation and/or other materials provided with the distribution. |
18 | | - * 4. Neither the name of the University nor the names of its contributors |
19 | | - * may be used to endorse or promote products derived from this software |
20 | | - * without specific prior written permission. |
21 | | - * |
22 | | - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
23 | | - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
24 | | - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
25 | | - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
26 | | - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
27 | | - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
28 | | - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
29 | | - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
30 | | - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
31 | | - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
32 | | - * SUCH DAMAGE. |
33 | | - * |
34 | | - */ |
35 | | - |
36 | | -#ifndef QUEUE_H |
37 | | -#define QUEUE_H |
38 | | - |
39 | | -#if defined __SUNPRO_C || defined __DECC || defined __HP_cc |
40 | | -# pragma ident "@(#)$Header$" |
41 | | -#endif |
42 | | - |
43 | | -#include "config.h" |
44 | | -#ifdef HAVE_SYS_QUEUE_H |
45 | | -# include <sys/queue.h> |
46 | | -#else |
47 | | - |
48 | | -/* |
49 | | - * This file defines four types of data structures: singly-linked lists, |
50 | | - * singly-linked tail queues, lists and tail queues. |
51 | | - * |
52 | | - * A singly-linked list is headed by a single forward pointer. The elements |
53 | | - * are singly linked for minimum space and pointer manipulation overhead at |
54 | | - * the expense of O(n) removal for arbitrary elements. New elements can be |
55 | | - * added to the list after an existing element or at the head of the list. |
56 | | - * Elements being removed from the head of the list should use the explicit |
57 | | - * macro for this purpose for optimum efficiency. A singly-linked list may |
58 | | - * only be traversed in the forward direction. Singly-linked lists are ideal |
59 | | - * for applications with large datasets and few or no removals or for |
60 | | - * implementing a LIFO queue. |
61 | | - * |
62 | | - * A singly-linked tail queue is headed by a pair of pointers, one to the |
63 | | - * head of the list and the other to the tail of the list. The elements are |
64 | | - * singly linked for minimum space and pointer manipulation overhead at the |
65 | | - * expense of O(n) removal for arbitrary elements. New elements can be added |
66 | | - * to the list after an existing element, at the head of the list, or at the |
67 | | - * end of the list. Elements being removed from the head of the tail queue |
68 | | - * should use the explicit macro for this purpose for optimum efficiency. |
69 | | - * A singly-linked tail queue may only be traversed in the forward direction. |
70 | | - * Singly-linked tail queues are ideal for applications with large datasets |
71 | | - * and few or no removals or for implementing a FIFO queue. |
72 | | - * |
73 | | - * A list is headed by a single forward pointer (or an array of forward |
74 | | - * pointers for a hash table header). The elements are doubly linked |
75 | | - * so that an arbitrary element can be removed without a need to |
76 | | - * traverse the list. New elements can be added to the list before |
77 | | - * or after an existing element or at the head of the list. A list |
78 | | - * may only be traversed in the forward direction. |
79 | | - * |
80 | | - * A tail queue is headed by a pair of pointers, one to the head of the |
81 | | - * list and the other to the tail of the list. The elements are doubly |
82 | | - * linked so that an arbitrary element can be removed without a need to |
83 | | - * traverse the list. New elements can be added to the list before or |
84 | | - * after an existing element, at the head of the list, or at the end of |
85 | | - * the list. A tail queue may be traversed in either direction. |
86 | | - * |
87 | | - * For details on the use of these macros, see the queue(3) manual page. |
88 | | - * |
89 | | - * |
90 | | - * SLIST LIST STAILQ TAILQ |
91 | | - * _HEAD + + + + |
92 | | - * _HEAD_INITIALIZER + + + + |
93 | | - * _ENTRY + + + + |
94 | | - * _INIT + + + + |
95 | | - * _EMPTY + + + + |
96 | | - * _FIRST + + + + |
97 | | - * _NEXT + + + + |
98 | | - * _PREV - - - + |
99 | | - * _LAST - - + + |
100 | | - * _FOREACH + + + + |
101 | | - * _FOREACH_SAFE + + + + |
102 | | - * _FOREACH_REVERSE - - - + |
103 | | - * _FOREACH_REVERSE_SAFE - - - + |
104 | | - * _INSERT_HEAD + + + + |
105 | | - * _INSERT_BEFORE - + - + |
106 | | - * _INSERT_AFTER + + + + |
107 | | - * _INSERT_TAIL - - + + |
108 | | - * _CONCAT - - + + |
109 | | - * _REMOVE_HEAD + - + - |
110 | | - * _REMOVE + + + + |
111 | | - * |
112 | | - */ |
113 | | -#define QUEUE_MACRO_DEBUG 0 |
114 | | -#if QUEUE_MACRO_DEBUG |
115 | | -/* Store the last 2 places the queue element or head was altered */ |
116 | | -struct qm_trace { |
117 | | - char * lastfile; |
118 | | - int lastline; |
119 | | - char * prevfile; |
120 | | - int prevline; |
121 | | -}; |
122 | | - |
123 | | -#define TRACEBUF struct qm_trace trace; |
124 | | -#define TRASHIT(x) do {(x) = (void *)-1;} while (0) |
125 | | - |
126 | | -#define QMD_TRACE_HEAD(head) do { \ |
127 | | - (head)->trace.prevline = (head)->trace.lastline; \ |
128 | | - (head)->trace.prevfile = (head)->trace.lastfile; \ |
129 | | - (head)->trace.lastline = __LINE__; \ |
130 | | - (head)->trace.lastfile = __FILE__; \ |
131 | | -} while (0) |
132 | | - |
133 | | -#define QMD_TRACE_ELEM(elem) do { \ |
134 | | - (elem)->trace.prevline = (elem)->trace.lastline; \ |
135 | | - (elem)->trace.prevfile = (elem)->trace.lastfile; \ |
136 | | - (elem)->trace.lastline = __LINE__; \ |
137 | | - (elem)->trace.lastfile = __FILE__; \ |
138 | | -} while (0) |
139 | | - |
140 | | -#else |
141 | | -#define QMD_TRACE_ELEM(elem) |
142 | | -#define QMD_TRACE_HEAD(head) |
143 | | -#define TRACEBUF |
144 | | -#define TRASHIT(x) |
145 | | -#endif /* QUEUE_MACRO_DEBUG */ |
146 | | - |
147 | | -/* |
148 | | - * Singly-linked List declarations. |
149 | | - */ |
150 | | -#define SLIST_HEAD(name, type) \ |
151 | | -struct name { \ |
152 | | - struct type *slh_first; /* first element */ \ |
153 | | -} |
154 | | - |
155 | | -#define SLIST_HEAD_INITIALIZER(head) \ |
156 | | - { NULL } |
157 | | - |
158 | | -#define SLIST_ENTRY(type) \ |
159 | | -struct { \ |
160 | | - struct type *sle_next; /* next element */ \ |
161 | | -} |
162 | | - |
163 | | -/* |
164 | | - * Singly-linked List functions. |
165 | | - */ |
166 | | -#define SLIST_EMPTY(head) ((head)->slh_first == NULL) |
167 | | - |
168 | | -#define SLIST_FIRST(head) ((head)->slh_first) |
169 | | - |
170 | | -#define SLIST_FOREACH(var, head, field) \ |
171 | | - for ((var) = SLIST_FIRST((head)); \ |
172 | | - (var); \ |
173 | | - (var) = SLIST_NEXT((var), field)) |
174 | | - |
175 | | -#define SLIST_FOREACH_SAFE(var, head, field, tvar) \ |
176 | | - for ((var) = SLIST_FIRST((head)); \ |
177 | | - (var) && ((tvar) = SLIST_NEXT((var), field), 1); \ |
178 | | - (var) = (tvar)) |
179 | | - |
180 | | -#define SLIST_FOREACH_PREVPTR(var, varp, head, field) \ |
181 | | - for ((varp) = &SLIST_FIRST((head)); \ |
182 | | - ((var) = *(varp)) != NULL; \ |
183 | | - (varp) = &SLIST_NEXT((var), field)) |
184 | | - |
185 | | -#define SLIST_INIT(head) do { \ |
186 | | - SLIST_FIRST((head)) = NULL; \ |
187 | | -} while (0) |
188 | | - |
189 | | -#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \ |
190 | | - SLIST_NEXT((elm), field) = SLIST_NEXT((slistelm), field); \ |
191 | | - SLIST_NEXT((slistelm), field) = (elm); \ |
192 | | -} while (0) |
193 | | - |
194 | | -#define SLIST_INSERT_HEAD(head, elm, field) do { \ |
195 | | - SLIST_NEXT((elm), field) = SLIST_FIRST((head)); \ |
196 | | - SLIST_FIRST((head)) = (elm); \ |
197 | | -} while (0) |
198 | | - |
199 | | -#define SLIST_NEXT(elm, field) ((elm)->field.sle_next) |
200 | | - |
201 | | -#define SLIST_REMOVE(head, elm, type, field) do { \ |
202 | | - if (SLIST_FIRST((head)) == (elm)) { \ |
203 | | - SLIST_REMOVE_HEAD((head), field); \ |
204 | | - } \ |
205 | | - else { \ |
206 | | - struct type *curelm = SLIST_FIRST((head)); \ |
207 | | - while (SLIST_NEXT(curelm, field) != (elm)) \ |
208 | | - curelm = SLIST_NEXT(curelm, field); \ |
209 | | - SLIST_NEXT(curelm, field) = \ |
210 | | - SLIST_NEXT(SLIST_NEXT(curelm, field), field); \ |
211 | | - } \ |
212 | | -} while (0) |
213 | | - |
214 | | -#define SLIST_REMOVE_HEAD(head, field) do { \ |
215 | | - SLIST_FIRST((head)) = SLIST_NEXT(SLIST_FIRST((head)), field); \ |
216 | | -} while (0) |
217 | | - |
218 | | -/* |
219 | | - * Singly-linked Tail queue declarations. |
220 | | - */ |
221 | | -#define STAILQ_HEAD(name, type) \ |
222 | | -struct name { \ |
223 | | - struct type *stqh_first;/* first element */ \ |
224 | | - struct type **stqh_last;/* addr of last next element */ \ |
225 | | -} |
226 | | - |
227 | | -#define STAILQ_HEAD_INITIALIZER(head) \ |
228 | | - { NULL, &(head).stqh_first } |
229 | | - |
230 | | -#define STAILQ_ENTRY(type) \ |
231 | | -struct { \ |
232 | | - struct type *stqe_next; /* next element */ \ |
233 | | -} |
234 | | - |
235 | | -/* |
236 | | - * Singly-linked Tail queue functions. |
237 | | - */ |
238 | | -#define STAILQ_CONCAT(head1, head2) do { \ |
239 | | - if (!STAILQ_EMPTY((head2))) { \ |
240 | | - *(head1)->stqh_last = (head2)->stqh_first; \ |
241 | | - (head1)->stqh_last = (head2)->stqh_last; \ |
242 | | - STAILQ_INIT((head2)); \ |
243 | | - } \ |
244 | | -} while (0) |
245 | | - |
246 | | -#define STAILQ_EMPTY(head) ((head)->stqh_first == NULL) |
247 | | - |
248 | | -#define STAILQ_FIRST(head) ((head)->stqh_first) |
249 | | - |
250 | | -#define STAILQ_FOREACH(var, head, field) \ |
251 | | - for((var) = STAILQ_FIRST((head)); \ |
252 | | - (var); \ |
253 | | - (var) = STAILQ_NEXT((var), field)) |
254 | | - |
255 | | - |
256 | | -#define STAILQ_FOREACH_SAFE(var, head, field, tvar) \ |
257 | | - for ((var) = STAILQ_FIRST((head)); \ |
258 | | - (var) && ((tvar) = STAILQ_NEXT((var), field), 1); \ |
259 | | - (var) = (tvar)) |
260 | | - |
261 | | -#define STAILQ_INIT(head) do { \ |
262 | | - STAILQ_FIRST((head)) = NULL; \ |
263 | | - (head)->stqh_last = &STAILQ_FIRST((head)); \ |
264 | | -} while (0) |
265 | | - |
266 | | -#define STAILQ_INSERT_AFTER(head, tqelm, elm, field) do { \ |
267 | | - if ((STAILQ_NEXT((elm), field) = STAILQ_NEXT((tqelm), field)) == NULL)\ |
268 | | - (head)->stqh_last = &STAILQ_NEXT((elm), field); \ |
269 | | - STAILQ_NEXT((tqelm), field) = (elm); \ |
270 | | -} while (0) |
271 | | - |
272 | | -#define STAILQ_INSERT_HEAD(head, elm, field) do { \ |
273 | | - if ((STAILQ_NEXT((elm), field) = STAILQ_FIRST((head))) == NULL) \ |
274 | | - (head)->stqh_last = &STAILQ_NEXT((elm), field); \ |
275 | | - STAILQ_FIRST((head)) = (elm); \ |
276 | | -} while (0) |
277 | | - |
278 | | -#define STAILQ_INSERT_TAIL(head, elm, field) do { \ |
279 | | - STAILQ_NEXT((elm), field) = NULL; \ |
280 | | - *(head)->stqh_last = (elm); \ |
281 | | - (head)->stqh_last = &STAILQ_NEXT((elm), field); \ |
282 | | -} while (0) |
283 | | - |
284 | | -#define STAILQ_LAST(head, type, field) \ |
285 | | - (STAILQ_EMPTY((head)) ? \ |
286 | | - NULL : \ |
287 | | - ((struct type *) \ |
288 | | - ((char *)((head)->stqh_last) - __offsetof(struct type, field)))) |
289 | | - |
290 | | -#define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next) |
291 | | - |
292 | | -#define STAILQ_REMOVE(head, elm, type, field) do { \ |
293 | | - if (STAILQ_FIRST((head)) == (elm)) { \ |
294 | | - STAILQ_REMOVE_HEAD((head), field); \ |
295 | | - } \ |
296 | | - else { \ |
297 | | - struct type *curelm = STAILQ_FIRST((head)); \ |
298 | | - while (STAILQ_NEXT(curelm, field) != (elm)) \ |
299 | | - curelm = STAILQ_NEXT(curelm, field); \ |
300 | | - if ((STAILQ_NEXT(curelm, field) = \ |
301 | | - STAILQ_NEXT(STAILQ_NEXT(curelm, field), field)) == NULL)\ |
302 | | - (head)->stqh_last = &STAILQ_NEXT((curelm), field);\ |
303 | | - } \ |
304 | | -} while (0) |
305 | | - |
306 | | -#define STAILQ_REMOVE_HEAD(head, field) do { \ |
307 | | - if ((STAILQ_FIRST((head)) = \ |
308 | | - STAILQ_NEXT(STAILQ_FIRST((head)), field)) == NULL) \ |
309 | | - (head)->stqh_last = &STAILQ_FIRST((head)); \ |
310 | | -} while (0) |
311 | | - |
312 | | -#define STAILQ_REMOVE_HEAD_UNTIL(head, elm, field) do { \ |
313 | | - if ((STAILQ_FIRST((head)) = STAILQ_NEXT((elm), field)) == NULL) \ |
314 | | - (head)->stqh_last = &STAILQ_FIRST((head)); \ |
315 | | -} while (0) |
316 | | - |
317 | | -/* |
318 | | - * List declarations. |
319 | | - */ |
320 | | -#define LIST_HEAD(name, type) \ |
321 | | -struct name { \ |
322 | | - struct type *lh_first; /* first element */ \ |
323 | | -} |
324 | | - |
325 | | -#define LIST_HEAD_INITIALIZER(head) \ |
326 | | - { NULL } |
327 | | - |
328 | | -#define LIST_ENTRY(type) \ |
329 | | -struct { \ |
330 | | - struct type *le_next; /* next element */ \ |
331 | | - struct type **le_prev; /* address of previous next element */ \ |
332 | | -} |
333 | | - |
334 | | -/* |
335 | | - * List functions. |
336 | | - */ |
337 | | - |
338 | | -#define LIST_EMPTY(head) ((head)->lh_first == NULL) |
339 | | - |
340 | | -#define LIST_FIRST(head) ((head)->lh_first) |
341 | | - |
342 | | -#define LIST_FOREACH(var, head, field) \ |
343 | | - for ((var) = LIST_FIRST((head)); \ |
344 | | - (var); \ |
345 | | - (var) = LIST_NEXT((var), field)) |
346 | | - |
347 | | -#define LIST_FOREACH_SAFE(var, head, field, tvar) \ |
348 | | - for ((var) = LIST_FIRST((head)); \ |
349 | | - (var) && ((tvar) = LIST_NEXT((var), field), 1); \ |
350 | | - (var) = (tvar)) |
351 | | - |
352 | | -#define LIST_INIT(head) do { \ |
353 | | - LIST_FIRST((head)) = NULL; \ |
354 | | -} while (0) |
355 | | - |
356 | | -#define LIST_INSERT_AFTER(listelm, elm, field) do { \ |
357 | | - if ((LIST_NEXT((elm), field) = LIST_NEXT((listelm), field)) != NULL)\ |
358 | | - LIST_NEXT((listelm), field)->field.le_prev = \ |
359 | | - &LIST_NEXT((elm), field); \ |
360 | | - LIST_NEXT((listelm), field) = (elm); \ |
361 | | - (elm)->field.le_prev = &LIST_NEXT((listelm), field); \ |
362 | | -} while (0) |
363 | | - |
364 | | -#define LIST_INSERT_BEFORE(listelm, elm, field) do { \ |
365 | | - (elm)->field.le_prev = (listelm)->field.le_prev; \ |
366 | | - LIST_NEXT((elm), field) = (listelm); \ |
367 | | - *(listelm)->field.le_prev = (elm); \ |
368 | | - (listelm)->field.le_prev = &LIST_NEXT((elm), field); \ |
369 | | -} while (0) |
370 | | - |
371 | | -#define LIST_INSERT_HEAD(head, elm, field) do { \ |
372 | | - if ((LIST_NEXT((elm), field) = LIST_FIRST((head))) != NULL) \ |
373 | | - LIST_FIRST((head))->field.le_prev = &LIST_NEXT((elm), field);\ |
374 | | - LIST_FIRST((head)) = (elm); \ |
375 | | - (elm)->field.le_prev = &LIST_FIRST((head)); \ |
376 | | -} while (0) |
377 | | - |
378 | | -#define LIST_NEXT(elm, field) ((elm)->field.le_next) |
379 | | - |
380 | | -#define LIST_REMOVE(elm, field) do { \ |
381 | | - if (LIST_NEXT((elm), field) != NULL) \ |
382 | | - LIST_NEXT((elm), field)->field.le_prev = \ |
383 | | - (elm)->field.le_prev; \ |
384 | | - *(elm)->field.le_prev = LIST_NEXT((elm), field); \ |
385 | | -} while (0) |
386 | | - |
387 | | -/* |
388 | | - * Tail queue declarations. |
389 | | - */ |
390 | | -#define TAILQ_HEAD(name, type) \ |
391 | | -struct name { \ |
392 | | - struct type *tqh_first; /* first element */ \ |
393 | | - struct type **tqh_last; /* addr of last next element */ \ |
394 | | - TRACEBUF \ |
395 | | -} |
396 | | - |
397 | | -#define TAILQ_HEAD_INITIALIZER(head) \ |
398 | | - { NULL, &(head).tqh_first } |
399 | | - |
400 | | -#define TAILQ_ENTRY(type) \ |
401 | | -struct { \ |
402 | | - struct type *tqe_next; /* next element */ \ |
403 | | - struct type **tqe_prev; /* address of previous next element */ \ |
404 | | - TRACEBUF \ |
405 | | -} |
406 | | - |
407 | | -/* |
408 | | - * Tail queue functions. |
409 | | - */ |
410 | | -#define TAILQ_CONCAT(head1, head2, field) do { \ |
411 | | - if (!TAILQ_EMPTY(head2)) { \ |
412 | | - *(head1)->tqh_last = (head2)->tqh_first; \ |
413 | | - (head2)->tqh_first->field.tqe_prev = (head1)->tqh_last; \ |
414 | | - (head1)->tqh_last = (head2)->tqh_last; \ |
415 | | - TAILQ_INIT((head2)); \ |
416 | | - QMD_TRACE_HEAD(head); \ |
417 | | - QMD_TRACE_HEAD(head2); \ |
418 | | - } \ |
419 | | -} while (0) |
420 | | - |
421 | | -#define TAILQ_EMPTY(head) ((head)->tqh_first == NULL) |
422 | | - |
423 | | -#define TAILQ_FIRST(head) ((head)->tqh_first) |
424 | | - |
425 | | -#define TAILQ_FOREACH(var, head, field) \ |
426 | | - for ((var) = TAILQ_FIRST((head)); \ |
427 | | - (var); \ |
428 | | - (var) = TAILQ_NEXT((var), field)) |
429 | | - |
430 | | -#define TAILQ_FOREACH_SAFE(var, head, field, tvar) \ |
431 | | - for ((var) = TAILQ_FIRST((head)); \ |
432 | | - (var) && ((tvar) = TAILQ_NEXT((var), field), 1); \ |
433 | | - (var) = (tvar)) |
434 | | - |
435 | | -#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \ |
436 | | - for ((var) = TAILQ_LAST((head), headname); \ |
437 | | - (var); \ |
438 | | - (var) = TAILQ_PREV((var), headname, field)) |
439 | | - |
440 | | -#define TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \ |
441 | | - for ((var) = TAILQ_LAST((head), headname); \ |
442 | | - (var) && ((tvar) = TAILQ_PREV((var), headname, field), 1); \ |
443 | | - (var) = (tvar)) |
444 | | - |
445 | | -#define TAILQ_INIT(head) do { \ |
446 | | - TAILQ_FIRST((head)) = NULL; \ |
447 | | - (head)->tqh_last = &TAILQ_FIRST((head)); \ |
448 | | - QMD_TRACE_HEAD(head); \ |
449 | | -} while (0) |
450 | | - |
451 | | -#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ |
452 | | - if ((TAILQ_NEXT((elm), field) = TAILQ_NEXT((listelm), field)) != NULL)\ |
453 | | - TAILQ_NEXT((elm), field)->field.tqe_prev = \ |
454 | | - &TAILQ_NEXT((elm), field); \ |
455 | | - else { \ |
456 | | - (head)->tqh_last = &TAILQ_NEXT((elm), field); \ |
457 | | - QMD_TRACE_HEAD(head); \ |
458 | | - } \ |
459 | | - TAILQ_NEXT((listelm), field) = (elm); \ |
460 | | - (elm)->field.tqe_prev = &TAILQ_NEXT((listelm), field); \ |
461 | | - QMD_TRACE_ELEM(&(elm)->field); \ |
462 | | - QMD_TRACE_ELEM(&listelm->field); \ |
463 | | -} while (0) |
464 | | - |
465 | | -#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ |
466 | | - (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ |
467 | | - TAILQ_NEXT((elm), field) = (listelm); \ |
468 | | - *(listelm)->field.tqe_prev = (elm); \ |
469 | | - (listelm)->field.tqe_prev = &TAILQ_NEXT((elm), field); \ |
470 | | - QMD_TRACE_ELEM(&(elm)->field); \ |
471 | | - QMD_TRACE_ELEM(&listelm->field); \ |
472 | | -} while (0) |
473 | | - |
474 | | -#define TAILQ_INSERT_HEAD(head, elm, field) do { \ |
475 | | - if ((TAILQ_NEXT((elm), field) = TAILQ_FIRST((head))) != NULL) \ |
476 | | - TAILQ_FIRST((head))->field.tqe_prev = \ |
477 | | - &TAILQ_NEXT((elm), field); \ |
478 | | - else \ |
479 | | - (head)->tqh_last = &TAILQ_NEXT((elm), field); \ |
480 | | - TAILQ_FIRST((head)) = (elm); \ |
481 | | - (elm)->field.tqe_prev = &TAILQ_FIRST((head)); \ |
482 | | - QMD_TRACE_HEAD(head); \ |
483 | | - QMD_TRACE_ELEM(&(elm)->field); \ |
484 | | -} while (0) |
485 | | - |
486 | | -#define TAILQ_INSERT_TAIL(head, elm, field) do { \ |
487 | | - TAILQ_NEXT((elm), field) = NULL; \ |
488 | | - (elm)->field.tqe_prev = (head)->tqh_last; \ |
489 | | - *(head)->tqh_last = (elm); \ |
490 | | - (head)->tqh_last = &TAILQ_NEXT((elm), field); \ |
491 | | - QMD_TRACE_HEAD(head); \ |
492 | | - QMD_TRACE_ELEM(&(elm)->field); \ |
493 | | -} while (0) |
494 | | - |
495 | | -#define TAILQ_LAST(head, headname) \ |
496 | | - (*(((struct headname *)((head)->tqh_last))->tqh_last)) |
497 | | - |
498 | | -#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) |
499 | | - |
500 | | -#define TAILQ_PREV(elm, headname, field) \ |
501 | | - (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) |
502 | | - |
503 | | -#define TAILQ_REMOVE(head, elm, field) do { \ |
504 | | - if ((TAILQ_NEXT((elm), field)) != NULL) \ |
505 | | - TAILQ_NEXT((elm), field)->field.tqe_prev = \ |
506 | | - (elm)->field.tqe_prev; \ |
507 | | - else { \ |
508 | | - (head)->tqh_last = (elm)->field.tqe_prev; \ |
509 | | - QMD_TRACE_HEAD(head); \ |
510 | | - } \ |
511 | | - *(elm)->field.tqe_prev = TAILQ_NEXT((elm), field); \ |
512 | | - TRASHIT((elm)->field.tqe_next); \ |
513 | | - TRASHIT((elm)->field.tqe_prev); \ |
514 | | - QMD_TRACE_ELEM(&(elm)->field); \ |
515 | | -} while (0) |
516 | | - |
517 | | -#endif /* !HAVE_SYS_QUEUE_H */ |
518 | | -#endif /* !QUEUE_H */ |
Index: trunk/willow/src/wcache.c |
— | — | @@ -1,466 +0,0 @@ |
2 | | -/* @(#) $Header$ */ |
3 | | -/* This source code is in the public domain. */ |
4 | | -/* |
5 | | - * Willow: Lightweight HTTP reverse-proxy. |
6 | | - * wcache: entity caching. |
7 | | - */ |
8 | | - |
9 | | -#if defined __SUNPRO_C || defined __DECC || defined __HP_cc |
10 | | -# pragma ident "@(#)$Header$" |
11 | | -#endif |
12 | | - |
13 | | -/* |
14 | | - * Cache metadata is stored in a BerkeleyDB database, along with a key which |
15 | | - * represents the filename. The objects themselves are stored on a filesystem, |
16 | | - * using the key and a path constructed from the key's prefix; for example, |
17 | | - * the key "123456" would be stored as "1/2/3/123456". |
18 | | - * |
19 | | - * This is rather flawed, because if two people try to start caching the same |
20 | | - * object at the same time, duplicate files are created in the cache, and |
21 | | - * won't ever be deleted. What should happen is that finding or creating |
22 | | - * a cached object is a single atomic operation. |
23 | | - */ |
24 | | - |
25 | | -#include <sys/types.h> |
26 | | -#include <sys/stat.h> |
27 | | - |
28 | | -#include <string.h> |
29 | | -#include <errno.h> |
30 | | -#include <stdlib.h> |
31 | | -#include <math.h> |
32 | | -#include <strings.h> |
33 | | -#include <limits.h> |
34 | | -#include <assert.h> |
35 | | - |
36 | | -#include <db.h> |
37 | | - |
38 | | -#include "wcache.h" |
39 | | -#include "wlog.h" |
40 | | -#include "wconfig.h" |
41 | | -#include "willow.h" |
42 | | - |
43 | | -static DB_ENV *cacheenv; |
44 | | -static DB *cacheobjs; |
45 | | - |
46 | | -#define CACHEDIR "__objects__" |
47 | | - |
48 | | -static void dberror(const char *, int); |
49 | | -static void cache_writestate(struct cache_state *, DB_TXN *); |
50 | | -static int cache_getstate(struct cache_state *, DB_TXN *); |
51 | | -static int cache_next_id(void); |
52 | | - |
53 | | -static struct cache_state state; |
54 | | -static int int_max_len; |
55 | | - |
56 | | -static void dberror(txt, err) |
57 | | - const char *txt; |
58 | | - int err; |
59 | | -{ |
60 | | - wlog(WLOG_ERROR, "fatal database error: %s: %s", txt, db_strerror(err)); |
61 | | - wcache_shutdown(); |
62 | | - exit(8); |
63 | | -} |
64 | | - |
65 | | -void |
66 | | -wcache_setupfs(void) |
67 | | -{ |
68 | | - int i, j, k; |
69 | | -struct cachedir *cd; |
70 | | -struct cache_state state; |
71 | | - DB_TXN *txn; |
72 | | - |
73 | | - for (cd = config.caches; cd < config.caches + config.ncaches; ++cd) { |
74 | | - size_t len, dlen; |
75 | | - char *dir, *env; |
76 | | - |
77 | | - dlen = strlen(cd->dir) + sizeof(CACHEDIR) + 1 + 6 /* 0/1/2/ */; |
78 | | - if ((dir = wmalloc(dlen)) == NULL) |
79 | | - outofmemory(); |
80 | | - |
81 | | - safe_snprintf(dlen, (dir, dlen, "%s/%s", cd->dir, CACHEDIR)); |
82 | | - |
83 | | - len = strlen(cd->dir) + sizeof("/__env__") + 1; |
84 | | - if ((env = wmalloc(len)) == NULL) |
85 | | - outofmemory(); |
86 | | - |
87 | | - safe_snprintf(len, (env, len, "%s/__env__", cd->dir)); |
88 | | - |
89 | | - /* create base directory if it doesn't exist */ |
90 | | - /*LINTED unsafe mkdir*/ |
91 | | - if (mkdir(cd->dir, 0700) < 0 || mkdir(dir, 0700) < 0 || mkdir(env, 0700)) { |
92 | | - wlog(WLOG_ERROR, "%s: mkdir: %s", cd->dir, strerror(errno)); |
93 | | - exit(8); |
94 | | - } |
95 | | - |
96 | | - for (i = 0; i < 10; ++i) { |
97 | | - safe_snprintf(dlen, (dir, dlen, "%s/%s/%d", cd->dir, CACHEDIR, i)); |
98 | | - |
99 | | - /*LINTED unsafe mkdir*/ |
100 | | - if (mkdir(dir, 0700) < 0) { |
101 | | - wlog(WLOG_ERROR, "%s: mkdir: %s", dir, strerror(errno)); |
102 | | - exit(8); |
103 | | - } |
104 | | - |
105 | | - for (j = 0; j < 10; ++j) { |
106 | | - safe_snprintf(dlen, (dir, dlen, "%s/%s/%d/%d", cd->dir, CACHEDIR, i, j)); |
107 | | - /*LINTED unsafe mkdir*/ |
108 | | - if (mkdir(dir, 0700) < 0) { |
109 | | - wlog(WLOG_ERROR, "%s: mkdir: %s", dir, strerror(errno)); |
110 | | - exit(8); |
111 | | - } |
112 | | - for (k = 0; k < 10; ++k) { |
113 | | - safe_snprintf(dlen, (dir, dlen, "%s/%s/%d/%d/%d", cd->dir, CACHEDIR, i, j, k)); |
114 | | - /*LINTED unsafe mkdir*/ |
115 | | - if (mkdir(dir, 0700) < 0) { |
116 | | - wlog(WLOG_ERROR, "%s: mkdir: %s", dir, strerror(errno)); |
117 | | - exit(8); |
118 | | - } |
119 | | - } |
120 | | - } |
121 | | - } |
122 | | - wfree(dir); |
123 | | - wfree(env); |
124 | | - wlog(WLOG_NOTICE, "created cache directory structure for %s", cd->dir); |
125 | | - } |
126 | | - wcache_init(0); |
127 | | - |
128 | | - bzero(&state, sizeof(state)); |
129 | | - state.cs_id = 1000; |
130 | | - if (i = cacheenv->txn_begin(cacheenv, NULL, &txn, 0)) |
131 | | - dberror("setupfs: txn_begin", i); |
132 | | - |
133 | | - cache_writestate(&state, txn); |
134 | | - |
135 | | - if (i = txn->commit(txn, 0)) |
136 | | - dberror("setupfs: commit", i); |
137 | | - |
138 | | - wlog(WLOG_NOTICE, "wrote initial cache state"); |
139 | | - wcache_shutdown(); |
140 | | -} |
141 | | - |
142 | | -void |
143 | | -wcache_shutdown(void) |
144 | | -{ |
145 | | - int i; |
146 | | - |
147 | | - /* don't use dberror() here because it calls us */ |
148 | | - /*LINTED =/==*/ |
149 | | - if ((i = cacheobjs->close(cacheobjs, 0)) || (i = cacheenv->close(cacheenv, 0))) { |
150 | | - wlog(WLOG_ERROR, "error closing database: %s", db_strerror(i)); |
151 | | - exit(8); |
152 | | - } |
153 | | -} |
154 | | - |
155 | | -void |
156 | | -wcache_init(readstate) |
157 | | - int readstate; |
158 | | -{ |
159 | | -struct cachedir *cd; |
160 | | - int i; |
161 | | - DB_TXN *txn; |
162 | | - |
163 | | - wlog(WLOG_NOTICE, "using bdb: %s", DB_VERSION_STRING); |
164 | | - |
165 | | - if (config.ncaches == 0) { |
166 | | - wlog(WLOG_WARNING, "no cache directories specified"); |
167 | | - return; |
168 | | - } |
169 | | - |
170 | | - /* only one cache dir supported for now... */ |
171 | | - for (cd = config.caches; cd < config.caches + config.ncaches; ++cd) { |
172 | | - size_t len; |
173 | | - char *dir; |
174 | | - |
175 | | - len = strlen(cd->dir) + sizeof("/__env__"); |
176 | | - if ((dir = wmalloc(len)) == NULL) |
177 | | - outofmemory(); |
178 | | - |
179 | | - safe_snprintf(len, (dir, len, "%s/__env__", cd->dir)); |
180 | | - |
181 | | - if (i = db_env_create(&cacheenv, 0)) |
182 | | - dberror("init: env_create", i); |
183 | | - |
184 | | - cacheenv->set_errfile(cacheenv, stderr); |
185 | | - cacheenv->set_errpfx(cacheenv, "willow"); |
186 | | - |
187 | | - if (i = cacheenv->open(cacheenv, dir, DB_CREATE | DB_INIT_TXN | DB_INIT_LOCK | |
188 | | - DB_INIT_MPOOL | DB_PRIVATE |
189 | | -#ifdef THREADED_IO |
190 | | - | DB_THREAD |
191 | | -#endif |
192 | | - , 0)) |
193 | | - dberror("init: env open", i); |
194 | | - |
195 | | - if (i = db_create(&cacheobjs, cacheenv, 0)) |
196 | | - dberror("init: db_create", i); |
197 | | - |
198 | | - if (i = cacheenv->txn_begin(cacheenv, NULL, &txn, 0)) |
199 | | - dberror("init: open txn_begin", i); |
200 | | - |
201 | | - if (i = cacheobjs->open(cacheobjs, txn, "cacheobjs.db", NULL, DB_HASH, |
202 | | - DB_CREATE, 0600)) |
203 | | - dberror("init: db open", i); |
204 | | - |
205 | | - if (i = txn->commit(txn, 0)) |
206 | | - dberror("init: open commit", i); |
207 | | - |
208 | | - wfree(dir); |
209 | | - } |
210 | | - |
211 | | - if (readstate) { |
212 | | - if (i = cacheenv->txn_begin(cacheenv, NULL, &txn, 0)) |
213 | | - dberror("init: state txn_begin", i); |
214 | | - if (cache_getstate(&state, txn) == -1) { |
215 | | - wlog(WLOG_ERROR, "cache state unavailable"); |
216 | | - exit(8); |
217 | | - } |
218 | | - if (i = txn->commit(txn, 0)) |
219 | | - dberror("init: state commit", i); |
220 | | - } |
221 | | - |
222 | | - int_max_len = log10(INT_MAX) + 1; |
223 | | -} |
224 | | - |
225 | | -static char * |
226 | | -make_keybuf(key) |
227 | | - struct cache_key *key; |
228 | | -{ |
229 | | - char *buf; |
230 | | - |
231 | | - if ((buf = wmalloc(key->ck_len + 1)) == NULL) |
232 | | - outofmemory(); |
233 | | - bcopy(key->ck_key, buf, key->ck_len + 1); |
234 | | - return buf; |
235 | | -} |
236 | | - |
237 | | -static char * |
238 | | -make_databuf(obj) |
239 | | - struct cache_object *obj; |
240 | | -{ |
241 | | - char *buf; |
242 | | - |
243 | | - if ((buf = wmalloc(sizeof(struct cache_object) + obj->co_plen + 1)) == NULL) |
244 | | - outofmemory(); |
245 | | - |
246 | | - bcopy(obj, buf, sizeof(struct cache_object)); |
247 | | - bcopy(obj->co_path, buf + sizeof(struct cache_object), obj->co_plen + 1); |
248 | | - return buf; |
249 | | -} |
250 | | - |
251 | | -struct cache_object * |
252 | | -wcache_find_object(key) |
253 | | - struct cache_key *key; |
254 | | -{ |
255 | | - DBT keyt, datat; |
256 | | - DB_TXN *txn; |
257 | | -struct cache_object *data; |
258 | | - int i, j; |
259 | | - char *keybuf; |
260 | | - |
261 | | - WDEBUG((WLOG_DEBUG, "wcache_find_object: looking for %s %d", key->ck_key, key->ck_len)); |
262 | | - if (cacheobjs == NULL) |
263 | | - return NULL; |
264 | | - |
265 | | - keybuf = make_keybuf(key); |
266 | | - |
267 | | - bzero(&keyt, sizeof(keyt)); |
268 | | - bzero(&datat, sizeof(datat)); |
269 | | - |
270 | | - keyt.data = keybuf; |
271 | | - keyt.size = key->ck_len + 1; |
272 | | - |
273 | | - datat.flags = DB_DBT_MALLOC; |
274 | | - |
275 | | - if (i = cacheenv->txn_begin(cacheenv, NULL, &txn, 0)) |
276 | | - dberror("find_object: txn_begin", i); |
277 | | - |
278 | | - if (i = cacheobjs->get(cacheobjs, txn, &keyt, &datat, 0)) { |
279 | | - wfree(keybuf); |
280 | | - if (j = txn->abort(txn)) |
281 | | - dberror("find_object: abort", j); |
282 | | - if (i != DB_NOTFOUND) |
283 | | - dberror("find_object: get", i); |
284 | | - return NULL; |
285 | | - } |
286 | | - if (i = txn->commit(txn, 0)) |
287 | | - dberror("find_object: commit", i); |
288 | | - |
289 | | - wfree(keybuf); |
290 | | - |
291 | | - data = datat.data; |
292 | | - data->co_path = (char *)data + sizeof(*data); |
293 | | - WDEBUG((WLOG_DEBUG, "found %s, path=[%s]", key->ck_key, data->co_path)); |
294 | | - data->co_flags &= ~WCACHE_FREE; |
295 | | - return data; |
296 | | -} |
297 | | - |
298 | | -int |
299 | | -wcache_store_object(key, obj) |
300 | | - struct cache_key *key; |
301 | | - struct cache_object *obj; |
302 | | -{ |
303 | | - DBT keyt, datat; |
304 | | - DB_TXN *txn; |
305 | | - char *keybuf; |
306 | | - int i, ret = 0; |
307 | | - |
308 | | - WDEBUG((WLOG_DEBUG, "storing %s %d in cache, path %s", key->ck_key, key->ck_len, obj->co_path)); |
309 | | - |
310 | | - bzero(&keyt, sizeof(keyt)); |
311 | | - bzero(&datat, sizeof(datat)); |
312 | | - keybuf = make_keybuf(key); |
313 | | - |
314 | | - keyt.data = keybuf; |
315 | | - keyt.size = key->ck_len + 1; |
316 | | - |
317 | | - datat.data = make_databuf(obj); |
318 | | - datat.size = sizeof(struct cache_object) + obj->co_plen + 1; |
319 | | - |
320 | | - if (i = cacheenv->txn_begin(cacheenv, NULL, &txn, 0)) |
321 | | - dberror("store_object: txn_begin", i); |
322 | | - if (cacheobjs->put(cacheobjs, txn, &keyt, &datat, DB_NOOVERWRITE)) |
323 | | - ret = -1; |
324 | | - if (i = txn->commit(txn, 0)) |
325 | | - dberror("store_object: commit", i); |
326 | | - |
327 | | - wfree(keybuf); |
328 | | - wfree(datat.data); |
329 | | - |
330 | | - return ret; |
331 | | -} |
332 | | - |
333 | | -struct cache_key * |
334 | | -wcache_make_key(host, path) |
335 | | - const char *host, *path; |
336 | | -{ |
337 | | -struct cache_key *ret; |
338 | | - |
339 | | - if ((ret = wmalloc(sizeof(*ret))) == NULL) |
340 | | - outofmemory(); |
341 | | - |
342 | | - ret->ck_len = strlen(host) + strlen(path); |
343 | | - ret->ck_key = wmalloc(ret->ck_len + 1); |
344 | | - safe_snprintf(ret->ck_len, (ret->ck_key, ret->ck_len, "%s%s", host, path)); |
345 | | - return ret; |
346 | | -} |
347 | | - |
348 | | -void |
349 | | -wcache_free_key(key) |
350 | | - struct cache_key *key; |
351 | | -{ |
352 | | - wfree(key->ck_key); |
353 | | - wfree(key); |
354 | | -} |
355 | | - |
356 | | -void |
357 | | -wcache_free_object(obj) |
358 | | - struct cache_object *obj; |
359 | | -{ |
360 | | - if (obj->co_flags & WCACHE_FREE) { |
361 | | - wfree(obj->co_path); |
362 | | - wfree(obj); |
363 | | - } else { |
364 | | - free(obj); |
365 | | - } |
366 | | -} |
367 | | - |
368 | | -static void |
369 | | -cache_writestate(state, txn) |
370 | | - struct cache_state *state; |
371 | | - DB_TXN *txn; |
372 | | -{ |
373 | | - DBT keyt, datat; |
374 | | - int i; |
375 | | - |
376 | | - WDEBUG((WLOG_DEBUG, "writing cache state")); |
377 | | - |
378 | | - bzero(&keyt, sizeof(keyt)); |
379 | | - bzero(&datat, sizeof(datat)); |
380 | | - |
381 | | - keyt.size = 5; |
382 | | - keyt.data = "STATE"; |
383 | | - |
384 | | - datat.size = sizeof(*state); |
385 | | - datat.data = state; |
386 | | - |
387 | | - if (i = cacheobjs->put(cacheobjs, txn, &keyt, &datat, 0)) |
388 | | - dberror("writestate: put", i); |
389 | | -} |
390 | | - |
391 | | -static int |
392 | | -cache_getstate(state, txn) |
393 | | - struct cache_state *state; |
394 | | - DB_TXN *txn; |
395 | | -{ |
396 | | - DBT keyt, datat; |
397 | | - int i; |
398 | | - |
399 | | - WDEBUG((WLOG_DEBUG, "reading cache state")); |
400 | | - |
401 | | - bzero(&keyt, sizeof(keyt)); |
402 | | - bzero(&datat, sizeof(datat)); |
403 | | - |
404 | | - keyt.size = 5; |
405 | | - keyt.data = "STATE"; |
406 | | - |
407 | | - datat.ulen = sizeof(*state); |
408 | | - datat.data = state; |
409 | | - datat.flags = DB_DBT_USERMEM; |
410 | | - |
411 | | - if (i = cacheobjs->get(cacheobjs, txn, &keyt, &datat, 0)) |
412 | | - dberror("getstate: get", i); |
413 | | - |
414 | | - WDEBUG((WLOG_DEBUG, "cs_id = %d", state->cs_id)); |
415 | | - return 0; |
416 | | -} |
417 | | - |
418 | | -static int |
419 | | -cache_next_id(void) |
420 | | -{ |
421 | | - DB_TXN *txn; |
422 | | - int i; |
423 | | - |
424 | | - if (i = cacheenv->txn_begin(cacheenv, NULL, &txn, 0)) |
425 | | - dberror("next_id: txn_begin", i); |
426 | | - |
427 | | - state.cs_id++; |
428 | | - cache_writestate(&state, txn); |
429 | | - |
430 | | - if (i = txn->commit(txn, 0)) |
431 | | - dberror("next_id: commit", i); |
432 | | - |
433 | | - return state.cs_id; |
434 | | -} |
435 | | - |
436 | | -struct cache_object * |
437 | | -wcache_new_object(void) |
438 | | -{ |
439 | | -struct cache_object *ret; |
440 | | - int i; |
441 | | - char *p, *s, a[11]; |
442 | | - |
443 | | - if ((ret = wcalloc(1, sizeof(*ret))) == NULL) |
444 | | - outofmemory(); |
445 | | - |
446 | | - ret->co_id = cache_next_id(); |
447 | | - |
448 | | - assert(ret->co_id > 999); |
449 | | - ret->co_plen = int_max_len + 6; |
450 | | - if ((ret->co_path = wmalloc(ret->co_plen + 1)) == NULL) |
451 | | - outofmemory(); |
452 | | - p = ret->co_path; |
453 | | - safe_snprintf(10, (a, 10, "%d", ret->co_id)); |
454 | | - s = a + strlen(a) - 1; |
455 | | - WDEBUG((WLOG_DEBUG, "id=%d a=%s", ret->co_id, a)); |
456 | | - |
457 | | - for (i = 0; i < 3; ++i) { |
458 | | - *p++ = *s--; |
459 | | - *p++ = '/'; |
460 | | - } |
461 | | - *p = '\0'; |
462 | | - if (strlcat(ret->co_path, a, ret->co_plen + 1) >= ret->co_plen + 1) |
463 | | - abort(); |
464 | | - ret->co_flags |= WCACHE_FREE; |
465 | | - WDEBUG((WLOG_DEBUG, "new object path is [%s], len %d", ret->co_path, ret->co_plen)); |
466 | | - return ret; |
467 | | -} |
Index: trunk/willow/src/wconfig.c |
— | — | @@ -1,128 +0,0 @@ |
2 | | -/* @(#) $Header$ */ |
3 | | -/* This source code is in the public domain. */ |
4 | | -/* |
5 | | - * Willow: Lightweight HTTP reverse-proxy. |
6 | | - * wconfig: configuration. |
7 | | - */ |
8 | | - |
9 | | -#if defined __SUNPRO_C || defined __DECC || defined __HP_cc |
10 | | -# pragma ident "@(#)$Header$" |
11 | | -#endif |
12 | | - |
13 | | -#include <sys/types.h> |
14 | | -#include <sys/socket.h> |
15 | | - |
16 | | -#include <netinet/in.h> |
17 | | - |
18 | | -#include <arpa/inet.h> |
19 | | - |
20 | | -#include <stdlib.h> |
21 | | -#include <stdio.h> |
22 | | -#include <string.h> |
23 | | -#include <syslog.h> |
24 | | -#include <errno.h> |
25 | | -#include <strings.h> |
26 | | - |
27 | | -#include "willow.h" |
28 | | -#include "wconfig.h" |
29 | | -#include "wbackend.h" |
30 | | -#include "wlog.h" |
31 | | -#include "confparse.h" |
32 | | - |
33 | | -#define CONFIGFILE "./willow.conf" |
34 | | - |
35 | | -int yyparse(); |
36 | | - |
37 | | -struct listener **listeners; |
38 | | -int nlisteners; |
39 | | -struct configuration config; |
40 | | - |
41 | | -const char *current_file; |
42 | | - |
43 | | -void |
44 | | -wconfig_init(const char *file) |
45 | | -{ |
46 | | - FILE *cfg; |
47 | | -extern FILE *yyin; |
48 | | - |
49 | | - if (file == NULL) |
50 | | - file = CONFIGFILE; |
51 | | - current_file = file; |
52 | | - |
53 | | - if ((cfg = fopen(file, "r")) == NULL) { |
54 | | - perror(file); |
55 | | - exit(8); |
56 | | - } |
57 | | - wlog(WLOG_NOTICE, "loading configuration from %s", current_file); |
58 | | - yyin = cfg; |
59 | | - newconf_init(); |
60 | | - |
61 | | - if (yyparse()) { |
62 | | - wlog(WLOG_ERROR, "could not parse configuration file"); |
63 | | - nerrors++; |
64 | | - } |
65 | | - if (!nlisteners) { |
66 | | - wlog(WLOG_ERROR, "no listeners defined"); |
67 | | - nerrors++; |
68 | | - } |
69 | | - if (!nbackends) { |
70 | | - wlog(WLOG_ERROR, "no backends defined"); |
71 | | - nerrors++; |
72 | | - } |
73 | | - if (nerrors) { |
74 | | - wlog(WLOG_ERROR, "%d error(s) in configuration file. cannot continue.", nerrors); |
75 | | - exit(8); |
76 | | - } |
77 | | - |
78 | | - (void)fclose(cfg); |
79 | | -} |
80 | | - |
81 | | -int |
82 | | -add_listener(addr, port) |
83 | | - const char *addr; |
84 | | - int port; |
85 | | -{ |
86 | | -struct listener *nl; |
87 | | - |
88 | | - if (port < 0 || port > 65535) { |
89 | | - conf_report_error("invalid listener port %d", port); |
90 | | - nerrors++; |
91 | | - return -1; |
92 | | - } |
93 | | - |
94 | | - if ((nl = wcalloc(1, sizeof(*nl))) == NULL) |
95 | | - outofmemory(); |
96 | | - |
97 | | - if ((listeners = wrealloc(listeners, sizeof(struct listener *) * ++nlisteners)) == NULL) |
98 | | - outofmemory(); |
99 | | - |
100 | | - nl->port = port; |
101 | | - nl->name = wstrdup(addr); |
102 | | - nl->addr.sin_family = AF_INET; |
103 | | - nl->addr.sin_port = htons(nl->port); |
104 | | - nl->addr.sin_addr.s_addr = inet_addr(nl->name); |
105 | | - listeners[nlisteners - 1] = nl; |
106 | | - wlog(WLOG_NOTICE, "listening on %s:%d", addr, port); |
107 | | - return 0; |
108 | | -} |
109 | | - |
110 | | -int |
111 | | -add_cachedir(dir, size) |
112 | | - const char *dir; |
113 | | - int size; |
114 | | -{ |
115 | | - if (size < 1) { |
116 | | - conf_report_error("invalid cache size %d\n", size); |
117 | | - nerrors++; |
118 | | - return -1; |
119 | | - } |
120 | | - |
121 | | - config.caches = wrealloc(config.caches, sizeof(*config.caches) * (config.ncaches + 1)); |
122 | | - config.caches[config.ncaches].dir = wstrdup(dir); |
123 | | - config.caches[config.ncaches].maxsize = size; |
124 | | - wlog(WLOG_NOTICE, "cache dir \"%s\", size %d bytes", |
125 | | - config.caches[config.ncaches].dir, |
126 | | - config.caches[config.ncaches].maxsize); |
127 | | - config.ncaches++; |
128 | | - return 0; |
129 | | -} |
Index: trunk/willow/src/wnet_kqueue.c |
— | — | @@ -1,143 +0,0 @@ |
2 | | -/* @(#) $Header$ */ |
3 | | -/* This source code is in the public domain. */ |
4 | | -/* |
5 | | - * Willow: Lightweight HTTP reverse-proxy. |
6 | | - * wnet_kqueue: FreeBSD kqueue-specific networking. |
7 | | - */ |
8 | | - |
9 | | -#if defined __SUNPRO_C || defined __DECC || defined __HP_cc |
10 | | -# pragma ident "@(#)$Header$" |
11 | | -#endif |
12 | | - |
13 | | -#include <sys/types.h> |
14 | | -#include <sys/socket.h> |
15 | | -#include <sys/event.h> |
16 | | -#include <sys/time.h> |
17 | | - |
18 | | -#include <arpa/inet.h> |
19 | | - |
20 | | -#include <stdio.h> |
21 | | -#include <string.h> |
22 | | -#include <stdlib.h> |
23 | | -#include <unistd.h> |
24 | | -#include <errno.h> |
25 | | -#include <assert.h> |
26 | | -#include <fcntl.h> |
27 | | -#include <signal.h> |
28 | | - |
29 | | -#include "willow.h" |
30 | | -#include "wnet.h" |
31 | | -#include "wconfig.h" |
32 | | -#include "wlog.h" |
33 | | -#include "whttp.h" |
34 | | - |
35 | | -static void kq_update_event(int, int, u_int); |
36 | | -static void kq_update_immediate(int, int, u_int); |
37 | | - |
38 | | -static int kq; |
39 | | -struct timespec zero_timespec; |
40 | | -#define GETN 256 |
41 | | -static struct kevent kqlst[GETN], kqchg[GETN]; |
42 | | -static int kqoff; |
43 | | - |
44 | | -void |
45 | | -wnet_init_select(void) |
46 | | -{ |
47 | | - if ((kq = kqueue()) < 0) { |
48 | | - perror("kqueue"); |
49 | | - exit(8); |
50 | | - } |
51 | | -} |
52 | | - |
53 | | -void |
54 | | -wnet_run(void) |
55 | | -{ |
56 | | - int i; |
57 | | - int nget; |
58 | | - |
59 | | - while ((nget = kevent(kq, kqchg, kqoff, kqlst, GETN, NULL)) > -1) { |
60 | | - wnet_set_time(); |
61 | | - |
62 | | - kqoff = 0; |
63 | | - for (i = 0; i < nget; ++i) { |
64 | | - struct fde *e = &fde_table[kqlst[i].ident]; |
65 | | - assert(kqlst[i].ident < MAX_FD); |
66 | | - |
67 | | - if (kqlst[i].flags & EV_ERROR) { |
68 | | - (void)fprintf(stderr, "error for %d (%s): %s\n", |
69 | | - kqlst[i].ident, e->fde_desc, strerror(kqlst[i].data)); |
70 | | - exit(8); |
71 | | - } |
72 | | - |
73 | | - if ((kqlst[i].filter == EVFILT_READ) && e->fde_read_handler) { |
74 | | - int ret = e->fde_read_handler(e); |
75 | | - if (ret == 0) |
76 | | - wnet_register(kqlst[i].ident, FDE_READ, e->fde_read_handler, NULL); |
77 | | - } |
78 | | - if ((kqlst[i].filter == EVFILT_WRITE) && e->fde_write_handler) { |
79 | | - int ret = e->fde_write_handler(e); |
80 | | - if (ret == 0) |
81 | | - wnet_register(kqlst[i].ident, FDE_WRITE, e->fde_write_handler, NULL); |
82 | | - } |
83 | | - } |
84 | | - } |
85 | | - perror("wnet_run/kevent"); |
86 | | -} |
87 | | - |
88 | | -void |
89 | | -wnet_register(fd, what, handler, data) |
90 | | - fdcb handler; |
91 | | - void *data; |
92 | | -{ |
93 | | -struct fde *e = &fde_table[fd]; |
94 | | - u_int flags; |
95 | | - |
96 | | - assert(fd < MAX_FD); |
97 | | - |
98 | | - if (handler == NULL) { |
99 | | - kq_update_immediate(fd, EVFILT_READ, EV_DELETE); |
100 | | - kq_update_immediate(fd, EVFILT_WRITE, EV_DELETE); |
101 | | - return; |
102 | | - } |
103 | | - |
104 | | - flags = EV_ADD | EV_ONESHOT; |
105 | | - |
106 | | - e->fde_fd = fd; |
107 | | - if (what & FDE_READ) { |
108 | | - e->fde_read_handler = handler; |
109 | | - kq_update_event(fd, EVFILT_READ, flags); |
110 | | - } |
111 | | - if (what & FDE_WRITE) { |
112 | | - e->fde_write_handler = handler; |
113 | | - kq_update_event(fd, EVFILT_WRITE, flags); |
114 | | - } |
115 | | - |
116 | | - if (data) |
117 | | - e->fde_rdata = data; |
118 | | -} |
119 | | - |
120 | | -static void |
121 | | -kq_update_event(fd, filter, flags) |
122 | | - u_int flags; |
123 | | -{ |
124 | | - EV_SET(&kqchg[kqoff], fd, filter, flags, 0, 0, NULL); |
125 | | - if (++kqoff == GETN) { |
126 | | - if (kevent(kq, kqchg, kqoff, NULL, 0, &zero_timespec) < 0) { |
127 | | - perror("kevent"); |
128 | | - exit(8); |
129 | | - } |
130 | | - kqoff = 0; |
131 | | - } |
132 | | -} |
133 | | - |
134 | | -static void |
135 | | -kq_update_immediate(fd, filter, flags) |
136 | | - u_int flags; |
137 | | -{ |
138 | | -struct kevent ke; |
139 | | - |
140 | | - EV_SET(&ke, fd, filter, flags, 0, 0, NULL); |
141 | | - kevent(kq, &ke, 1, NULL, 0, &zero_timespec); |
142 | | -} |
143 | | - |
144 | | - |
Index: trunk/willow/src/wcache.h |
— | — | @@ -1,51 +0,0 @@ |
2 | | -/* @(#) $Header$ */ |
3 | | -/* This source code is in the public domain. */ |
4 | | -/* |
5 | | - * Willow: Lightweight HTTP reverse-proxy. |
6 | | - * wcache: entity caching. |
7 | | - */ |
8 | | - |
9 | | -#ifndef WCACHE_H |
10 | | -#define WCACHE_H |
11 | | - |
12 | | -#if defined __SUNPRO_C || defined __DECC || defined __HP_cc |
13 | | -# pragma ident "@(#)$Header$" |
14 | | -#endif |
15 | | - |
16 | | -#define WCACHE_FREE 1 |
17 | | - |
18 | | -/* |
19 | | - * Information about the current cache state, stored in the null key |
20 | | - * (length 0). |
21 | | - */ |
22 | | -struct cache_state { |
23 | | - int cs_id; |
24 | | -}; |
25 | | - |
26 | | -struct cache_key { |
27 | | - int ck_len; |
28 | | - char *ck_key; |
29 | | -}; |
30 | | - |
31 | | -struct cache_object { |
32 | | - int co_flags; |
33 | | - time_t co_expires; /* Expires: header or -1 */ |
34 | | - time_t co_time; /* Last-Modified / retrieval time */ |
35 | | - int co_id; /* Object id */ |
36 | | - int co_plen; /* Size of cache object */ |
37 | | - char *co_path; /* Object data location */ |
38 | | -}; |
39 | | - |
40 | | -void wcache_init(int); |
41 | | -void wcache_setupfs(void); |
42 | | -void wcache_shutdown(void); |
43 | | - |
44 | | -struct cache_key *wcache_make_key(const char *host, const char *path); |
45 | | -void wcache_free_key(struct cache_key *); |
46 | | - |
47 | | -struct cache_object *wcache_find_object(struct cache_key *); |
48 | | -struct cache_object *wcache_new_object(void); |
49 | | -int wcache_store_object(struct cache_key *, struct cache_object *); |
50 | | -void wcache_free_object(struct cache_object *); |
51 | | - |
52 | | -#endif |
Index: trunk/willow/src/strlcpy.c |
— | — | @@ -1,61 +0,0 @@ |
2 | | -/* @(#) $Header$ */ |
3 | | -/* $NetBSD: strlcpy.c,v 1.14 2003/10/27 00:12:42 lukem Exp $ */ |
4 | | -/* $OpenBSD: strlcpy.c,v 1.7 2003/04/12 21:56:39 millert Exp $ */ |
5 | | - |
6 | | -/* |
7 | | - * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com> |
8 | | - * |
9 | | - * Permission to use, copy, modify, and distribute this software for any |
10 | | - * purpose with or without fee is hereby granted, provided that the above |
11 | | - * copyright notice and this permission notice appear in all copies. |
12 | | - * |
13 | | - * THE SOFTWARE IS PROVIDED "AS IS" AND TODD C. MILLER DISCLAIMS ALL |
14 | | - * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES |
15 | | - * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL TODD C. MILLER BE LIABLE |
16 | | - * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
17 | | - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION |
18 | | - * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN |
19 | | - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
20 | | - */ |
21 | | - |
22 | | -#if defined __SUNPRO_C || defined __DECC || defined __HP_cc |
23 | | -# pragma ident "@(#) $Header$" |
24 | | -#endif |
25 | | - |
26 | | -#include <sys/types.h> |
27 | | -#include <assert.h> |
28 | | -#include <string.h> |
29 | | - |
30 | | -/* |
31 | | - * Copy src to string dst of size siz. At most siz-1 characters |
32 | | - * will be copied. Always NUL terminates (unless siz == 0). |
33 | | - * Returns strlen(src); if retval >= siz, truncation occurred. |
34 | | - */ |
35 | | -size_t |
36 | | -strlcpy(dst, src, siz) |
37 | | - char *dst; |
38 | | - const char *src; |
39 | | - size_t siz; |
40 | | -{ |
41 | | - char *d = dst; |
42 | | - const char *s = src; |
43 | | - size_t n = siz; |
44 | | - |
45 | | - /* Copy as many bytes as will fit */ |
46 | | - if (n != 0 && --n != 0) { |
47 | | - do { |
48 | | - if ((*d++ = *s++) == 0) |
49 | | - break; |
50 | | - } while (--n != 0); |
51 | | - } |
52 | | - |
53 | | - /* Not enough room in dst, add NUL and traverse rest of src */ |
54 | | - if (n == 0) { |
55 | | - if (siz != 0) |
56 | | - *d = '\0'; /* NUL-terminate dst */ |
57 | | - while (*s++) |
58 | | - ; |
59 | | - } |
60 | | - |
61 | | - return(s - src - 1); /* count does not include NUL */ |
62 | | -} |
Index: trunk/willow/src/wconfig.h |
— | — | @@ -1,44 +0,0 @@ |
2 | | -/* @(#) $Header$ */ |
3 | | -/* This source code is in the public domain. */ |
4 | | -/* |
5 | | - * Willow: Lightweight HTTP reverse-proxy. |
6 | | - * wconfig: configuration. |
7 | | - */ |
8 | | - |
9 | | -#ifndef WCONFIG_H |
10 | | -#define WCONFIG_H |
11 | | - |
12 | | -#if defined __SUNPRO_C || defined __DECC || defined __HP_cc |
13 | | -# pragma ident "@(#)$Header$" |
14 | | -#endif |
15 | | - |
16 | | -#include <sys/types.h> |
17 | | -#include <netinet/in.h> |
18 | | - |
19 | | -struct listener { |
20 | | - char *name; |
21 | | - char *host; |
22 | | - int port; |
23 | | -struct sockaddr_in addr; |
24 | | -}; |
25 | | -extern int nlisteners; |
26 | | -extern struct listener **listeners; |
27 | | - |
28 | | -struct cachedir { |
29 | | - char *dir; |
30 | | - size_t maxsize; |
31 | | -}; |
32 | | - |
33 | | -extern struct configuration { |
34 | | - int foreground; |
35 | | -const char *access_log; |
36 | | -struct cachedir *caches; |
37 | | - int ncaches; |
38 | | -} config; |
39 | | - |
40 | | -void wconfig_init(const char *); |
41 | | - |
42 | | -int add_listener(const char *, int); |
43 | | -int add_cachedir(const char *, int); |
44 | | - |
45 | | -#endif |
Index: trunk/willow/src/wnet_devpoll.c |
— | — | @@ -1,128 +0,0 @@ |
2 | | -/* @(#) $Header$ */ |
3 | | -/* This source code is in the public domain. */ |
4 | | -/* |
5 | | - * Willow: Lightweight HTTP reverse-proxy. |
6 | | - * wnet_ports: Solaris /dev/poll-specific networking |
7 | | - */ |
8 | | - |
9 | | -#if defined __SUNPRO_C || defined __DECC || defined __HP_cc |
10 | | -# pragma ident "@(#)$Header$" |
11 | | -#endif |
12 | | - |
13 | | -#include <sys/types.h> |
14 | | -#include <sys/socket.h> |
15 | | -#include <sys/devpoll.h> |
16 | | - |
17 | | -#include <arpa/inet.h> |
18 | | - |
19 | | -#include <stdio.h> |
20 | | -#include <string.h> |
21 | | -#include <stdlib.h> |
22 | | -#include <unistd.h> |
23 | | -#include <errno.h> |
24 | | -#include <assert.h> |
25 | | -#include <fcntl.h> |
26 | | -#include <signal.h> |
27 | | -#include <poll.h> |
28 | | - |
29 | | -#include "willow.h" |
30 | | -#include "wnet.h" |
31 | | -#include "wconfig.h" |
32 | | -#include "wlog.h" |
33 | | -#include "whttp.h" |
34 | | - |
35 | | -static int polldev; |
36 | | -struct dvpoll dvp; |
37 | | -#define GETN 64 |
38 | | -struct pollfd pollfds[GETN]; |
39 | | - |
40 | | -void |
41 | | -wnet_init_select(void) |
42 | | -{ |
43 | | - if ((polldev = open("/dev/poll", O_RDWR)) < 0) { |
44 | | - perror("/dev/poll"); |
45 | | - exit(8); |
46 | | - } |
47 | | -} |
48 | | - |
49 | | -void |
50 | | -wnet_run(void) |
51 | | -{ |
52 | | - int i, n; |
53 | | - |
54 | | - for (;;) { |
55 | | - dvp.dp_fds = pollfds; |
56 | | - dvp.dp_nfds = GETN; |
57 | | - dvp.dp_timeout = -1; |
58 | | - |
59 | | - if ((n = ioctl(polldev, DP_POLL, &dvp)) < 0) |
60 | | - break; |
61 | | - |
62 | | - wnet_set_time(); |
63 | | - |
64 | | - for (i = 0; i < n; ++i) { |
65 | | - struct fde *e = &fde_table[pollfds[i].fd]; |
66 | | - |
67 | | - if ((pollfds[i].revents & POLLRDNORM) && e->fde_read_handler) { |
68 | | - e->fde_read_handler(e); |
69 | | - } |
70 | | - if ((pollfds[i].revents & POLLWRNORM) && e->fde_write_handler) { |
71 | | - e->fde_write_handler(e); |
72 | | - } |
73 | | - } |
74 | | - } |
75 | | - perror("/dev/poll"); |
76 | | -} |
77 | | - |
78 | | -void |
79 | | -wnet_register(fd, what, handler, data) |
80 | | - fdcb handler; |
81 | | - void *data; |
82 | | -{ |
83 | | -struct fde *e = &fde_table[fd]; |
84 | | -struct pollfd pfd; |
85 | | - |
86 | | - bzero(&pfd, sizeof(pfd)); |
87 | | - pfd.fd = fd; |
88 | | - |
89 | | - /* |
90 | | - * Always remove it first, or we just make a no-op when trying to remove flags. |
91 | | - */ |
92 | | - pfd.events = POLLREMOVE; |
93 | | - if (e->fde_epflags && write(polldev, &pfd, sizeof(pfd)) < 0) { |
94 | | - perror("/dev/poll"); |
95 | | - exit(8); |
96 | | - } |
97 | | - |
98 | | - pfd.events = e->fde_epflags; |
99 | | - |
100 | | - e->fde_fd = fd; |
101 | | - if (handler == NULL) { |
102 | | - if (what & FDE_READ) |
103 | | - e->fde_epflags &= ~POLLRDNORM; |
104 | | - if (what & FDE_WRITE) |
105 | | - e->fde_epflags &= ~POLLWRNORM; |
106 | | - } else { |
107 | | - if (what & FDE_READ) { |
108 | | - e->fde_read_handler = handler; |
109 | | - e->fde_epflags |= POLLRDNORM; |
110 | | - } |
111 | | - if (what & FDE_WRITE) { |
112 | | - e->fde_write_handler = handler; |
113 | | - e->fde_epflags |= POLLWRNORM; |
114 | | - } |
115 | | - } |
116 | | - |
117 | | - if (!e->fde_epflags) |
118 | | - return; |
119 | | - |
120 | | - pfd.events = e->fde_epflags; |
121 | | - |
122 | | - if (data) |
123 | | - e->fde_rdata = data; |
124 | | - |
125 | | - if (write(polldev, &pfd, sizeof(pfd)) < 0) { |
126 | | - perror("write(/dev/poll)"); |
127 | | - exit(8); |
128 | | - } |
129 | | -} |
Index: trunk/willow/src/whttp_entity.c |
— | — | @@ -1,791 +0,0 @@ |
2 | | -/* @(#) $Header$ */ |
3 | | -/* This source code is in the public domain. */ |
4 | | -/* |
5 | | - * Willow: Lightweight HTTP reverse-proxy. |
6 | | - * whttp_entity: HTTP entity handling. |
7 | | - */ |
8 | | - |
9 | | -#if defined __SUNPRO_C || defined __DECC || defined __HP_cc |
10 | | -# pragma ident "@(#)$Header$" |
11 | | -#endif |
12 | | - |
13 | | -/* How does this work? |
14 | | - * |
15 | | - * Each HTTP request can be divided into two entities: the request and the |
16 | | - * response. The client sends the request, i.e. the headers and possibly |
17 | | - * a body, to the server, which considers it and sends a reply. |
18 | | - * |
19 | | - * Internally, we read the request headers and ignore the |
20 | | - * body [entity_read_headers]. We then examine the headers |
21 | | - * [whttp:client_read_done] and decide if it has a body. We modify |
22 | | - * the entry slightly, and send it to the backend with either no source |
23 | | - * or, if it had a body, the client's FDE as the source [entity_send]. |
24 | | - * We then wait for the server to reply with its header. When it does |
25 | | - * [whttp:backend_headers_done], we send the request to the client, using |
26 | | - * the backend's FDE as the body, if it has one, and close it. |
27 | | - * |
28 | | - * See "Entity sending" below for a detailed description of how entity |
29 | | - * sending works. |
30 | | - * |
31 | | - * TODO: We don't have to buffer the headers, _but_ it makes things easier |
32 | | - * for now and doesn't cost much. if we start not buffering we need to |
33 | | - * decide what to do when the client goes away unexpectedly. probably it's |
34 | | - * easiest to just drop the backend connection (this is wasteful of backends |
35 | | - * but we don't cache them at the moment anyway). what do we do when the |
36 | | - * client sends "Foo: bar\r\n baz\r\n" and we decide after baz that we |
37 | | - * shouldn't send that header after all? |
38 | | - * |
39 | | - * There is a trade-off in some places between excessive copying and |
40 | | - * excessive syscalls. In some cases we copy data (headers) when we could |
41 | | - * undo the parser mangling and send them as-is. IMO this is not likely |
42 | | - * to be a worthwhile optimisation, needs profiling. |
43 | | - * |
44 | | - * As for FDE backending, Unix sucks: |
45 | | - * |
46 | | - * The sendfile() function copies data from in_fd to out_fd starting |
47 | | - * at offset off and of length len bytes. The in_fd argument should |
48 | | - * be a file descriptor to a regular file opened for reading. |
49 | | - */ |
50 | | - |
51 | | -#include <sys/uio.h> |
52 | | - |
53 | | -#include <unistd.h> |
54 | | -#include <errno.h> |
55 | | -#include <string.h> |
56 | | -#include <stdlib.h> |
57 | | -#include <stdio.h> |
58 | | -#include <assert.h> |
59 | | -/*LINTED*/ |
60 | | -#include <fcntl.h> |
61 | | -#include <strings.h> |
62 | | - |
63 | | -#include "willow.h" |
64 | | -#include "whttp.h" |
65 | | -#include "whttp_entity.h" |
66 | | -#include "wnet.h" |
67 | | -#include "wlog.h" |
68 | | - |
69 | | -#define ENTITY_STATE_START 0 |
70 | | -#define ENTITY_STATE_CR 1 |
71 | | -#define ENTITY_STATE_NL 2 |
72 | | -#define ENTITY_STATE_HDR 3 |
73 | | -#define ENTITY_STATE_COLON 4 |
74 | | -#define ENTITY_STATE_SPACE 5 |
75 | | -#define ENTITY_STATE_VALUE 6 |
76 | | -#define ENTITY_STATE_CREMPTY 7 |
77 | | -#define ENTITY_STATE_DONE 8 |
78 | | -#define ENTITY_STATE_BODY 9 |
79 | | - |
80 | | -static void entity_read_callback(struct fde *); |
81 | | -static int parse_headers(struct http_entity *); |
82 | | -static int parse_reqtype(struct http_entity *); |
83 | | - |
84 | | -static void entity_send_headers_done(struct fde *, void *, int); |
85 | | -static void entity_send_fde_write_done(struct fde *, void *, int); |
86 | | -static void entity_send_buf_done(struct fde *, void *, int); |
87 | | -static void entity_send_fde_read(struct fde *); |
88 | | -static void entity_send_file_done(struct fde *, void *, int); |
89 | | - |
90 | | -void |
91 | | -entity_free(entity) |
92 | | - struct http_entity *entity; |
93 | | -{ |
94 | | - if (!entity->he_flags.response) |
95 | | - if (entity->he_rdata.request.path) |
96 | | - wfree(entity->he_rdata.request.path); |
97 | | - header_free(&entity->he_headers); |
98 | | -} |
99 | | - |
100 | | -void |
101 | | -entity_read_headers(entity, func, udata) |
102 | | - struct http_entity *entity; |
103 | | - header_cb func; |
104 | | - void *udata; |
105 | | -{ |
106 | | - entity->_he_cbdata = udata; |
107 | | - entity->_he_func = func; |
108 | | - |
109 | | - WDEBUG((WLOG_DEBUG, "entity_read_headers: starting")); |
110 | | - /* XXX source for an entity header read is _always_ an fde */ |
111 | | - wnet_register(entity->he_source.fde.fde->fde_fd, FDE_READ, entity_read_callback, entity); |
112 | | - //entity_read_callback(entity->he_source.fde); |
113 | | -} |
114 | | - |
115 | | -static void |
116 | | -entity_read_callback(fde) |
117 | | - struct fde *fde; |
118 | | -{ |
119 | | -struct http_entity *entity = fde->fde_rdata; |
120 | | - |
121 | | - WDEBUG((WLOG_DEBUG, "entity_read_callback: called, source %d, left=%d", |
122 | | - entity->he_source.fde.fde->fde_fd, |
123 | | - readbuf_data_left(&entity->he_source.fde.fde->fde_readbuf))); |
124 | | - |
125 | | - if (readbuf_data_left(&entity->he_source.fde.fde->fde_readbuf) == 0) { |
126 | | - switch (readbuf_getdata(entity->he_source.fde.fde)) { |
127 | | - case -1: |
128 | | - WDEBUG((WLOG_DEBUG, "entity_read_callback: readbuf_getdata returned -1, errno=%d %s", |
129 | | - errno, strerror(errno))); |
130 | | - if (errno == EWOULDBLOCK) |
131 | | - return; |
132 | | - /*FALLTHRU*/ |
133 | | - case 0: |
134 | | - WDEBUG((WLOG_DEBUG, "entity_read_callback: readbuf_getdata returned 0")); |
135 | | - wnet_register(entity->he_source.fde.fde->fde_fd, FDE_READ, NULL, NULL); |
136 | | - entity->he_flags.error = 1; |
137 | | - entity->_he_func(entity, entity->_he_cbdata, -1); |
138 | | - return; |
139 | | - } |
140 | | - } |
141 | | - |
142 | | - WDEBUG((WLOG_DEBUG, "entity_read_callback: running header parse, %d left in buffer", |
143 | | - readbuf_data_left(&entity->he_source.fde.fde->fde_readbuf))); |
144 | | - if (parse_headers(entity) == -1) { |
145 | | - WDEBUG((WLOG_DEBUG, "entity_read_callback: parse_headers returned -1")); |
146 | | - wnet_register(entity->he_source.fde.fde->fde_fd, FDE_READ, NULL, NULL); |
147 | | - entity->he_flags.error = 1; |
148 | | - entity->_he_func(entity, entity->_he_cbdata, -1); |
149 | | - return; |
150 | | - } |
151 | | - |
152 | | - if (entity->_he_state == ENTITY_STATE_DONE) { |
153 | | - WDEBUG((WLOG_DEBUG, "entity_read_callback: client is ENTITY_STATE_DONE")); |
154 | | - wnet_register(entity->he_source.fde.fde->fde_fd, FDE_READ, NULL, NULL); |
155 | | - entity->_he_func(entity, entity->_he_cbdata, 01); |
156 | | - return; |
157 | | - } |
158 | | - |
159 | | - return; |
160 | | -} |
161 | | - |
162 | | -/* |
163 | | - * I don't like this. There should be an easier/faster way to do it, but this |
164 | | - * is the most understandable form for me... |
165 | | - * |
166 | | - * TODO: handle headers of the form "Name: value\r\n more value\r\n". |
167 | | - * |
168 | | - * This is more strict than it needs to be in some places, e.g. enforcement of |
169 | | - * \r\n over \n. |
170 | | - */ |
171 | | -static int |
172 | | -parse_headers(entity) |
173 | | - struct http_entity *entity; |
174 | | -{ |
175 | | - assert(entity->he_source_type == ENT_SOURCE_FDE); |
176 | | - |
177 | | - while (readbuf_data_left(&entity->he_source.fde.fde->fde_readbuf) > 0) { |
178 | | - char c = *readbuf_cur_pos(&entity->he_source.fde.fde->fde_readbuf); |
179 | | - |
180 | | - switch(entity->_he_state) { |
181 | | - case ENTITY_STATE_START: |
182 | | - /* should be reading a request type */ |
183 | | - switch(c) { |
184 | | - case '\r': |
185 | | - *readbuf_cur_pos(&entity->he_source.fde.fde->fde_readbuf) = '\0'; |
186 | | - if (parse_reqtype(entity) == -1) |
187 | | - return -1; |
188 | | - entity->_he_state = ENTITY_STATE_CR; |
189 | | - break; |
190 | | - case '\n': |
191 | | - return -1; |
192 | | - default: |
193 | | - break; |
194 | | - } |
195 | | - break; |
196 | | - case ENTITY_STATE_CR: |
197 | | - switch(c) { |
198 | | - case '\n': |
199 | | - entity->_he_state = ENTITY_STATE_NL; |
200 | | - break; |
201 | | - default: |
202 | | - return -1; |
203 | | - } |
204 | | - break; |
205 | | - case ENTITY_STATE_NL: |
206 | | - switch(c) { |
207 | | - case '\r': |
208 | | - entity->_he_state = ENTITY_STATE_CREMPTY; |
209 | | - break; |
210 | | - case '\n': case ' ': case ':': |
211 | | - return -1; |
212 | | - default: /* header name */ |
213 | | - entity->_he_state = ENTITY_STATE_HDR; |
214 | | - entity->_he_hdrbuf = entity->he_source.fde.fde->fde_readbuf.rb_p |
215 | | - + entity->he_source.fde.fde->fde_readbuf.rb_dpos; |
216 | | - entity->_he_lastname = entity->_he_hdrbuf; |
217 | | - break; |
218 | | - } |
219 | | - break; |
220 | | - case ENTITY_STATE_HDR: |
221 | | - switch(c) { |
222 | | - case ':': |
223 | | - entity->_he_state = ENTITY_STATE_COLON; |
224 | | - *readbuf_cur_pos(&entity->he_source.fde.fde->fde_readbuf) = '\0'; |
225 | | - break; |
226 | | - case ' ': case '\r': case '\n': |
227 | | - return -1; |
228 | | - default: |
229 | | - break; |
230 | | - } |
231 | | - break; |
232 | | - case ENTITY_STATE_COLON: |
233 | | - switch(c) { |
234 | | - case ' ': |
235 | | - entity->_he_state = ENTITY_STATE_SPACE; |
236 | | - break; |
237 | | - default: |
238 | | - return -1; |
239 | | - } |
240 | | - break; |
241 | | - case ENTITY_STATE_SPACE: |
242 | | - switch(c) { |
243 | | - case '\r': case '\n': case ':': case ' ': |
244 | | - return -1; |
245 | | - default: |
246 | | - entity->_he_valstart = entity->he_source.fde.fde->fde_readbuf.rb_p + |
247 | | - entity->he_source.fde.fde->fde_readbuf.rb_dpos; |
248 | | - entity->_he_state = ENTITY_STATE_VALUE; |
249 | | - break; |
250 | | - } |
251 | | - break; |
252 | | - case ENTITY_STATE_VALUE: |
253 | | - switch(c) { |
254 | | - case '\r': |
255 | | - *readbuf_cur_pos(&entity->he_source.fde.fde->fde_readbuf) = '\0'; |
256 | | - /* |
257 | | - * Check for "interesting" headers that we want to do |
258 | | - * extra processing on. |
259 | | - */ |
260 | | - if (entity->he_headers.hl_num++ > MAX_HEADERS) |
261 | | - return -1; |
262 | | - header_add(&entity->he_headers, entity->_he_lastname, entity->_he_valstart); |
263 | | - if (!strcmp(entity->_he_lastname, "Host")) |
264 | | - entity->he_rdata.request.host = entity->_he_valstart; |
265 | | - else if (!strcmp(entity->_he_lastname, "Content-Length")) { |
266 | | - char *cl = entity->_he_valstart; |
267 | | - entity->he_rdata.request.contlen = atoi(cl); |
268 | | - WDEBUG((WLOG_DEBUG, "got content-length: %d [%s]", |
269 | | - entity->he_rdata.request.contlen, cl)); |
270 | | - } |
271 | | - entity->_he_state = ENTITY_STATE_CR; |
272 | | - break; |
273 | | - case '\n': |
274 | | - return -1; |
275 | | - default: |
276 | | - break; |
277 | | - } |
278 | | - break; |
279 | | - case ENTITY_STATE_CREMPTY: |
280 | | - switch(c) { |
281 | | - case '\n': |
282 | | - entity->_he_state = ENTITY_STATE_DONE; |
283 | | - readbuf_inc_data_pos(&entity->he_source.fde.fde->fde_readbuf, 1); |
284 | | - return 0; |
285 | | - default: |
286 | | - return -1; |
287 | | - } |
288 | | - case ENTITY_STATE_DONE: |
289 | | - /* |
290 | | - * We're done parsing headers on this client, but they |
291 | | - * sent more data. Shouldn't ever happen, but kill |
292 | | - * them if it does. |
293 | | - */ |
294 | | - return -1; |
295 | | - default: |
296 | | - abort(); /* ??? This should be handled above for |
297 | | - * consistency (ENTITY_STATE_BODY) but i |
298 | | - * don't know which is correct. |
299 | | - */ |
300 | | - } |
301 | | - readbuf_inc_data_pos(&entity->he_source.fde.fde->fde_readbuf, 1); |
302 | | - } |
303 | | - return 0; |
304 | | -} |
305 | | - |
306 | | -static int |
307 | | -parse_reqtype(entity) |
308 | | - struct http_entity *entity; |
309 | | -{ |
310 | | - char *p, *s; |
311 | | - char *request = entity->he_source.fde.fde->fde_readbuf.rb_p; |
312 | | - int i; |
313 | | - |
314 | | - WDEBUG((WLOG_DEBUG, "parse_reqtype: called, response=%d", (int)entity->he_flags.response)); |
315 | | - |
316 | | - /* |
317 | | - * These probably shouldn't be handled in the same function. |
318 | | - */ |
319 | | - if (entity->he_flags.response) { |
320 | | - /* |
321 | | - * HTTP/1.0 |
322 | | - */ |
323 | | - if ((p = strchr(request, ' ')) == NULL) |
324 | | - return -1; |
325 | | - *p++ = '\0'; |
326 | | - |
327 | | - /* 200 */ |
328 | | - if ((s = strchr(p, ' ')) == NULL) |
329 | | - return -1; |
330 | | - *s++ = '\0'; |
331 | | - entity->he_rdata.response.status = atoi(p); |
332 | | - |
333 | | - /* OK */ |
334 | | - entity->he_rdata.response.status_str = s; |
335 | | - |
336 | | - WDEBUG((WLOG_DEBUG, "parse_reqtype: \"%s\" \"%d\" \"%s\"", |
337 | | - request, entity->he_rdata.response.status, |
338 | | - entity->he_rdata.response.status_str)); |
339 | | - return 0; |
340 | | - } |
341 | | - |
342 | | - /* GET */ |
343 | | - if ((p = strchr(request, ' ')) == NULL) |
344 | | - return -1; |
345 | | - |
346 | | - *p++ = '\0'; |
347 | | - |
348 | | - for (i = 0; supported_reqtypes[i].name; i++) |
349 | | - if (!strcmp(request, supported_reqtypes[i].name)) |
350 | | - break; |
351 | | - |
352 | | - entity->he_rdata.request.reqtype = supported_reqtypes[i].type; |
353 | | - if (entity->he_rdata.request.reqtype == REQTYPE_INVALID) |
354 | | - return -1; |
355 | | - |
356 | | - /* /path/to/file */ |
357 | | - if ((s = strchr(p, ' ')) == NULL) |
358 | | - return -1; |
359 | | - |
360 | | - *s++ = '\0'; |
361 | | - |
362 | | - entity->he_rdata.request.path = wstrdup(p); |
363 | | - |
364 | | - /* HTTP/1.0 */ |
365 | | - /* |
366 | | - * Ignore this for now... |
367 | | - */ |
368 | | - return 0; |
369 | | -} |
370 | | - |
371 | | -#ifdef __lint |
372 | | -# pragma error_messages(off, E_GLOBAL_COULD_BE_STATIC) |
373 | | -#endif |
374 | | -/* |
375 | | - * Header handling. |
376 | | - */ |
377 | | -void |
378 | | -header_free(head) |
379 | | - struct header_list *head; |
380 | | -{ |
381 | | -struct header_list *next = head->hl_next; |
382 | | - |
383 | | - while (next) { |
384 | | - struct header_list *this = next; |
385 | | - next = this->hl_next; |
386 | | - if (this->hl_flags & HDR_ALLOCED) |
387 | | - wfree((char *)this->hl_name); |
388 | | - wfree(this); |
389 | | - } |
390 | | - |
391 | | - bzero(head, sizeof(*head)); |
392 | | -} |
393 | | -#ifdef __lint |
394 | | -# pragma error_messages(default, E_GLOBAL_COULD_BE_STATIC) |
395 | | -#endif |
396 | | - |
397 | | -void |
398 | | -header_add(head, name, value) |
399 | | - struct header_list *head; |
400 | | - const char *name, *value; |
401 | | -{ |
402 | | -struct header_list *new = head; |
403 | | - |
404 | | - head->hl_num++; |
405 | | - |
406 | | - if (head->hl_tail) |
407 | | - new = head->hl_tail; |
408 | | - else |
409 | | - while (new->hl_next) |
410 | | - new = new->hl_next; |
411 | | - new->hl_next = wmalloc(sizeof(*head->hl_next)); |
412 | | - head->hl_tail = new->hl_next; |
413 | | - head->hl_len += strlen(name) + strlen(value) + 4; |
414 | | - new = new->hl_next; |
415 | | - new->hl_name = name; |
416 | | - new->hl_value = value; |
417 | | - new->hl_next = new->hl_tail = NULL; |
418 | | - new->hl_flags = 0; |
419 | | -} |
420 | | - |
421 | | -void |
422 | | -header_remove(head, it) |
423 | | - struct header_list *head, *it; |
424 | | -{ |
425 | | -struct header_list *jt; |
426 | | - |
427 | | - jt = head; |
428 | | - while (jt->hl_next && jt->hl_next != it) |
429 | | - jt = jt->hl_next; |
430 | | - jt->hl_next = jt->hl_next->hl_next; |
431 | | - if (it == head->hl_tail) |
432 | | - head->hl_tail = jt; |
433 | | - wfree(it); |
434 | | -} |
435 | | - |
436 | | -#ifdef __lint |
437 | | -# pragma error_messages(off, E_GLOBAL_COULD_BE_STATIC) |
438 | | -#endif |
439 | | -char * |
440 | | -header_build(head) |
441 | | - struct header_list *head; |
442 | | -{ |
443 | | - char *buf; |
444 | | - size_t bufsz; |
445 | | - size_t buflen = 0; |
446 | | - |
447 | | - bufsz = head->hl_len + 3; |
448 | | - if ((buf = wmalloc(bufsz)) == NULL) |
449 | | - outofmemory(); |
450 | | - |
451 | | - *buf = '\0'; |
452 | | - while (head->hl_next) { |
453 | | - head = head->hl_next; |
454 | | - buflen += snprintf(buf + buflen, bufsz - buflen - 1, "%s: %s\r\n", head->hl_name, head->hl_value); |
455 | | - } |
456 | | - if (strlcat(buf, "\r\n", bufsz) >= bufsz ) |
457 | | - abort(); |
458 | | - |
459 | | - return buf; |
460 | | -} |
461 | | -#ifdef __lint |
462 | | -# pragma error_messages(default, E_GLOBAL_COULD_BE_STATIC) |
463 | | -#endif |
464 | | - |
465 | | -void |
466 | | -header_dump(head, fd) |
467 | | - struct header_list *head; |
468 | | - int fd; |
469 | | -{ |
470 | | - int i = 0; |
471 | | -struct header_list *h; |
472 | | - |
473 | | - h = head->hl_next; |
474 | | - while (h) { |
475 | | - h = h->hl_next; |
476 | | - ++i; |
477 | | - } |
478 | | - |
479 | | - write(fd, &i, sizeof(i)); |
480 | | - |
481 | | - while (head->hl_next) { |
482 | | - int i, j; |
483 | | - head = head->hl_next; |
484 | | - i = strlen(head->hl_name); |
485 | | - write(fd, &i, sizeof(i)); |
486 | | - j = strlen(head->hl_value); |
487 | | - write(fd, &j, sizeof(j)); |
488 | | - write(fd, head->hl_name, i); |
489 | | - write(fd, head->hl_value, j); |
490 | | - } |
491 | | -} |
492 | | - |
493 | | -int |
494 | | -header_undump(head, fd, len) |
495 | | - struct header_list *head; |
496 | | - int fd; |
497 | | - off_t *len; |
498 | | -{ |
499 | | - int i = 0, j = 0, n = 0; |
500 | | -struct header_list *it = head; |
501 | | - ssize_t r; |
502 | | - |
503 | | - *len = 0; |
504 | | - bzero(head, sizeof(*head)); |
505 | | - head->hl_flags |= HDR_ALLOCED; |
506 | | - if ((r = read(fd, &n, sizeof(n))) < 0) { |
507 | | - wlog(WLOG_WARNING, "reading cache file: %s", strerror(errno)); |
508 | | - return -1; /* XXX */ |
509 | | - } |
510 | | - |
511 | | - *len += r; |
512 | | - WDEBUG((WLOG_DEBUG, "header_undump: %d entries", n)); |
513 | | - |
514 | | - while (n--) { |
515 | | - char *n, *v, *s; |
516 | | - int k; |
517 | | - |
518 | | - if ((it->hl_next = wcalloc(1, sizeof(struct header_list))) == NULL) |
519 | | - outofmemory(); |
520 | | - it = it->hl_next; |
521 | | - *len += read(fd, &i, sizeof(i)); |
522 | | - *len += read(fd, &j, sizeof(j)); |
523 | | - WDEBUG((WLOG_DEBUG, "header_undump: i=%d j=%d", i, j)); |
524 | | - n = wmalloc(i + j + 2); |
525 | | - i = read(fd, n, i); |
526 | | - *len += i; |
527 | | - s = n + i; |
528 | | - *s++ = '\0'; |
529 | | - v = s; |
530 | | - k = read(fd, s, j); |
531 | | - *len += k; |
532 | | - s += k; |
533 | | - *s = '\0'; |
534 | | - it->hl_name = n; |
535 | | - it->hl_value = v; |
536 | | - it->hl_flags = HDR_ALLOCED; |
537 | | - head->hl_len += i + j + 4; |
538 | | - } |
539 | | - |
540 | | - head->hl_tail = it; |
541 | | - return 0; |
542 | | -} |
543 | | - |
544 | | -/* |
545 | | - * Entity sending. This is not pretty. |
546 | | - * |
547 | | - * The entry point is entity_send(). This writes the request [XXX: this should |
548 | | - * be done async. I'm pretty certain it'll never block, but we can't guarantee |
549 | | - * that], builds a string from the headers, and wnet_writes it with |
550 | | - * entity_send_headers_done as the callback. |
551 | | - * |
552 | | - * entity_send_headers_done decides what to do next: |
553 | | - * NO BODY -> call user's callback immediately. |
554 | | - * FDE BODY -> entity_send_start_proxy |
555 | | - * BUF BODY -> entity_send_from_buf |
556 | | - * |
557 | | - * entity_send_start_proxy: |
558 | | - * registers a read callback for the source FDE with entity_send_source_read |
559 | | - * as the callback. entity_send_source_read reads the available data, then |
560 | | - * writes it with entity_send_source_write as the callback. _write CALLS |
561 | | - * SOURCE_READ AGAIN. this is important because otherwise we run into bad |
562 | | - * interactions with the edge-triggered wnet [? i don't think this is |
563 | | - * actually true but it's what the old code did and it's simpler than |
564 | | - * registering in two places]. source_read handles EAGAIN and wnet_register |
565 | | - * itself. |
566 | | - * |
567 | | - * entity_send_from_buf: |
568 | | - * calls wnet_write on the buffer with entity_send_buf_done as the callback. |
569 | | - * entity_send_buf_done calls the user's callback and returns. |
570 | | - * |
571 | | - * WARNING: if wnet_write completes immediately, i.e. does not block, it will |
572 | | - * call your callback before it returns. after this, the entity may no longer |
573 | | - * exist. wnet_write should generally be the last thing a function does |
574 | | - * before it returns. |
575 | | - */ |
576 | | - |
577 | | -void |
578 | | -entity_send(fde, entity, cb, data) |
579 | | - struct fde *fde; |
580 | | - struct http_entity *entity; |
581 | | - header_cb cb; |
582 | | - void *data; |
583 | | -{ |
584 | | - char status[4]; |
585 | | - |
586 | | - entity->_he_func = cb; |
587 | | - entity->_he_cbdata = data; |
588 | | - |
589 | | - WDEBUG((WLOG_DEBUG, "entity_send: writing to %d [%s]", fde->fde_fd, fde->fde_desc)); |
590 | | - |
591 | | - if (entity->he_flags.response) { |
592 | | - struct iovec vec[5]; |
593 | | - |
594 | | - safe_snprintf(4, (status, 4, "%d", entity->he_rdata.response.status)); |
595 | | - vec[0].iov_base = "HTTP/1.0 "; |
596 | | - vec[0].iov_len = 9; |
597 | | - vec[1].iov_base = status; |
598 | | - vec[1].iov_len = strlen(status); |
599 | | - vec[2].iov_base = " "; |
600 | | - vec[2].iov_len = 1; |
601 | | - vec[3].iov_base = (void *)entity->he_rdata.response.status_str; |
602 | | - vec[3].iov_len = strlen(entity->he_rdata.response.status_str); |
603 | | - vec[4].iov_base = "\r\n"; |
604 | | - vec[4].iov_len = 2; |
605 | | - writev(fde->fde_fd, vec, 5); |
606 | | - } else { |
607 | | - struct iovec vec[4]; |
608 | | - |
609 | | - vec[0].iov_base = (void *)request_string[entity->he_rdata.request.reqtype]; |
610 | | - vec[0].iov_len = strlen(request_string[entity->he_rdata.request.reqtype]); |
611 | | - vec[1].iov_base = " "; |
612 | | - vec[1].iov_len = 1; |
613 | | - vec[2].iov_base = entity->he_rdata.request.path; |
614 | | - vec[2].iov_len = strlen(entity->he_rdata.request.path); |
615 | | - vec[3].iov_base = " HTTP/1.0\r\n"; |
616 | | - vec[3].iov_len = 11; |
617 | | - writev(fde->fde_fd, vec, 4); |
618 | | - } |
619 | | - |
620 | | - entity->_he_target = fde; |
621 | | - |
622 | | - entity->_he_hdrbuf = header_build(&entity->he_headers); |
623 | | - wnet_write(fde->fde_fd, entity->_he_hdrbuf, strlen(entity->_he_hdrbuf), |
624 | | - entity_send_headers_done, entity); |
625 | | -} |
626 | | - |
627 | | -/*ARGSUSED*/ |
628 | | -static void |
629 | | -entity_send_headers_done(fde, data, res) |
630 | | - struct fde *fde; |
631 | | - void *data; |
632 | | - int res; |
633 | | -{ |
634 | | -struct http_entity *entity = data; |
635 | | - |
636 | | - wfree(entity->_he_hdrbuf); |
637 | | - |
638 | | - WDEBUG((WLOG_DEBUG, "entity_send_headers_done: called for %d [%s], res=%d", fde->fde_fd, fde->fde_desc, res)); |
639 | | - |
640 | | - if (res == -1) { |
641 | | - entity->_he_func(entity, entity->_he_cbdata, -1); |
642 | | - return; |
643 | | - } |
644 | | - |
645 | | - if (entity->he_source_type == ENT_SOURCE_NONE) { |
646 | | - /* no body for this request */ |
647 | | - WDEBUG((WLOG_DEBUG, "entity_send_headers_done: no body, return immediately")); |
648 | | - entity->_he_func(entity, entity->_he_cbdata, 0); |
649 | | - return; |
650 | | - } |
651 | | - |
652 | | - if (entity->he_source_type == ENT_SOURCE_BUFFER) { |
653 | | - /* write buffer, callback when done */ |
654 | | - WDEBUG((WLOG_DEBUG, "entity_send_headers_done: source is buffer, %d bytes", |
655 | | - entity->he_source.buffer.len)); |
656 | | - wnet_write(fde->fde_fd, entity->he_source.buffer.addr, |
657 | | - entity->he_source.buffer.len, entity_send_buf_done, entity); |
658 | | - return; |
659 | | - } |
660 | | - |
661 | | - if (entity->he_source_type == ENT_SOURCE_FILE) { |
662 | | - /* write file */ |
663 | | - wnet_sendfile(fde->fde_fd, entity->he_source.fd.fd, |
664 | | - entity->he_source.fd.size - entity->he_source.fd.off, |
665 | | - entity->he_source.fd.off, entity_send_file_done, entity); |
666 | | - return; |
667 | | - } |
668 | | - |
669 | | - /* FDE backended write */ |
670 | | - /* |
671 | | - * fde_read reads some amount of data (not necessarily all of it), and |
672 | | - * then calls wnet_write to write it. it then unregisters the fd as |
673 | | - * readable. when wnet_write completes and calls fde_write_done, it |
674 | | - * registers the fd as readable again.. |
675 | | - */ |
676 | | - WDEBUG((WLOG_DEBUG, "entity_send_headers_done: source is FDE")); |
677 | | - entity->he_source.fde._wrt = entity->he_source.fde.len; |
678 | | - wnet_register(entity->he_source.fde.fde->fde_fd, FDE_READ, entity_send_fde_read, entity); |
679 | | - entity_send_fde_read(entity->he_source.fde.fde); |
680 | | -} |
681 | | - |
682 | | -static void |
683 | | -entity_send_fde_read(fde) |
684 | | - struct fde *fde; |
685 | | -{ |
686 | | -struct http_entity *entity = fde->fde_rdata; |
687 | | - ssize_t len; |
688 | | - size_t wrt; |
689 | | - void *cur_pos; |
690 | | - |
691 | | - WDEBUG((WLOG_DEBUG, "entity_send_fde_read: called for %d [%s]", fde->fde_fd, fde->fde_desc)); |
692 | | - WDEBUG((WLOG_DEBUG, "entity_send_fde_read: %d bytes left in readbuf", |
693 | | - readbuf_data_left(&entity->he_source.fde.fde->fde_readbuf))); |
694 | | - |
695 | | - if (entity->he_source.fde._wrt == 0) { |
696 | | - entity->_he_func(entity, entity->_he_cbdata, 0); |
697 | | - return; |
698 | | - } |
699 | | - |
700 | | - if (readbuf_data_left(&entity->he_source.fde.fde->fde_readbuf) == 0) { |
701 | | - len = readbuf_getdata(fde); |
702 | | - } else |
703 | | - len = readbuf_data_left(&entity->he_source.fde.fde->fde_readbuf); |
704 | | - |
705 | | - WDEBUG((WLOG_DEBUG, "entity_send_fde_read: read %d bytes", len)); |
706 | | - |
707 | | - if (len == 0) { |
708 | | - /* remote closed */ |
709 | | - entity->_he_func(entity, entity->_he_cbdata, 0); |
710 | | - return; |
711 | | - } |
712 | | - |
713 | | - if (len == -1) { |
714 | | - if (errno == EAGAIN) { |
715 | | - return; |
716 | | - } |
717 | | - |
718 | | - entity->_he_func(entity, entity->_he_cbdata, -1); |
719 | | - return; |
720 | | - } |
721 | | - |
722 | | - if (entity->he_cache_callback) { |
723 | | - entity->he_cache_callback(readbuf_cur_pos(&entity->he_source.fde.fde->fde_readbuf), |
724 | | - readbuf_data_left(&entity->he_source.fde.fde->fde_readbuf), |
725 | | - entity->he_cache_callback_data); |
726 | | - } |
727 | | - |
728 | | - if (entity->he_source.fde._wrt == -1) |
729 | | - wrt = readbuf_data_left(&entity->he_source.fde.fde->fde_readbuf); |
730 | | - else { |
731 | | - wrt = min(readbuf_data_left(&entity->he_source.fde.fde->fde_readbuf), |
732 | | - entity->he_source.fde._wrt); |
733 | | - entity->he_source.fde._wrt -= wrt; |
734 | | - } |
735 | | - |
736 | | - WDEBUG((WLOG_DEBUG, "_wrt=%d, writing %d", entity->he_source.fde._wrt, wrt)); |
737 | | - cur_pos = readbuf_cur_pos(&entity->he_source.fde.fde->fde_readbuf); |
738 | | - readbuf_inc_data_pos(&entity->he_source.fde.fde->fde_readbuf, wrt); |
739 | | - wnet_write(entity->_he_target->fde_fd, cur_pos, |
740 | | - wrt, entity_send_fde_write_done, entity); |
741 | | -} |
742 | | - |
743 | | -/*ARGSUSED*/ |
744 | | -static void |
745 | | -entity_send_fde_write_done(fde, data, res) |
746 | | - struct fde *fde; |
747 | | - void *data; |
748 | | - int res; |
749 | | -{ |
750 | | -struct http_entity *entity = data; |
751 | | - |
752 | | - WDEBUG((WLOG_DEBUG, "entity_send_fde_write_done: called")); |
753 | | - |
754 | | - if (entity->he_source.fde._wrt == 0) { |
755 | | - wnet_register(entity->he_source.fde.fde->fde_fd, FDE_READ, NULL, NULL); |
756 | | - WDEBUG((WLOG_DEBUG, "entity_send_fde_write_done: _wrt = 0, fd=%d, target=%d", |
757 | | - entity->he_source.fde.fde->fde_fd, entity->_he_target->fde_fd)); |
758 | | - readbuf_free(&entity->_he_target->fde_readbuf); |
759 | | - entity->_he_func(entity, entity->_he_cbdata, 0); |
760 | | - return; |
761 | | - } |
762 | | - |
763 | | - wnet_register(entity->he_source.fde.fde->fde_fd, FDE_READ, entity_send_fde_read, entity); |
764 | | -} |
765 | | - |
766 | | -/*ARGSUSED*/ |
767 | | -static void |
768 | | -entity_send_buf_done(fde, data, res) |
769 | | - struct fde *fde; |
770 | | - void *data; |
771 | | - int res; |
772 | | -{ |
773 | | -struct http_entity *entity = data; |
774 | | - |
775 | | - WDEBUG((WLOG_DEBUG, "entity_send_buf_done: called for %d [%s], res=%d", fde->fde_fd, fde->fde_desc, res)); |
776 | | - entity->_he_func(entity, entity->_he_cbdata, res); |
777 | | - return; |
778 | | -} |
779 | | - |
780 | | -/*ARGSUSED*/ |
781 | | -static void |
782 | | -entity_send_file_done(fde, data, res) |
783 | | - struct fde *fde; |
784 | | - void *data; |
785 | | - int res; |
786 | | -{ |
787 | | -struct http_entity *entity = data; |
788 | | - |
789 | | - WDEBUG((WLOG_DEBUG, "entity_send_file_done: called for %d [%s], res=%d", fde->fde_fd, fde->fde_desc, res)); |
790 | | - entity->_he_func(entity, entity->_he_cbdata, res); |
791 | | - return; |
792 | | -} |
Index: trunk/willow/src/wnet_poll.c |
— | — | @@ -1,113 +0,0 @@ |
2 | | -/* @(#) $Header$ */ |
3 | | -/* This source code is in the public domain. */ |
4 | | -/* |
5 | | - * Willow: Lightweight HTTP reverse-proxy. |
6 | | - * wnet_poll: poll()-specific networking. |
7 | | - */ |
8 | | - |
9 | | -#if defined __SUNPRO_C || defined __DECC || defined __HP_cc |
10 | | -# pragma ident "@(#)$Header$" |
11 | | -#endif |
12 | | - |
13 | | -#include <sys/types.h> |
14 | | -#include <sys/socket.h> |
15 | | - |
16 | | -#include <arpa/inet.h> |
17 | | - |
18 | | -#include <stdio.h> |
19 | | -#include <string.h> |
20 | | -#include <stdlib.h> |
21 | | -#include <unistd.h> |
22 | | -#include <errno.h> |
23 | | -#include <assert.h> |
24 | | -#include <fcntl.h> |
25 | | -#include <signal.h> |
26 | | -#include <poll.h> |
27 | | - |
28 | | -#include "willow.h" |
29 | | -#include "wnet.h" |
30 | | -#include "wconfig.h" |
31 | | -#include "wlog.h" |
32 | | -#include "whttp.h" |
33 | | - |
34 | | -/* May not have X/Open macros */ |
35 | | - |
36 | | -#ifndef POLLRDNORM |
37 | | -# define POLLRDNORM POLLIN |
38 | | -#endif |
39 | | - |
40 | | -#ifndef POLLWRNORM |
41 | | -# define POLLWRNORM POLLOUT |
42 | | -#endif |
43 | | - |
44 | | -static struct pollfd *pfds; |
45 | | -int highest_fd; |
46 | | - |
47 | | -void |
48 | | -wnet_init_select(void) |
49 | | -{ |
50 | | - int i; |
51 | | - |
52 | | - pfds = wmalloc(sizeof(*pfds) * getdtablesize()); |
53 | | - bzero(pfds, sizeof(*pfds) * getdtablesize()); |
54 | | -} |
55 | | - |
56 | | -void |
57 | | -wnet_run(void) |
58 | | -{ |
59 | | - int n = 0, i; |
60 | | - |
61 | | - for (;;) { |
62 | | - if ((i = poll(pfds, highest_fd + 1, -1)) == -1) |
63 | | - break; |
64 | | - wnet_set_time(); |
65 | | - |
66 | | - for (n = 0; n < highest_fd + 1; ++n) { |
67 | | - struct fde *e = &fde_table[pfds[n].fd]; |
68 | | - |
69 | | - if ((pfds[n].revents & POLLRDNORM) && e->fde_read_handler) { |
70 | | - e->fde_read_handler(e); |
71 | | - } |
72 | | - |
73 | | - if ((pfds[n].revents & POLLWRNORM) && e->fde_write_handler) { |
74 | | - e->fde_write_handler(e); |
75 | | - } |
76 | | - } |
77 | | - } |
78 | | - perror("poll"); |
79 | | -} |
80 | | - |
81 | | -void |
82 | | -wnet_register(fd, what, handler, data) |
83 | | - int fd, what; |
84 | | - fdcb handler; |
85 | | - void *data; |
86 | | -{ |
87 | | -struct fde *e = &fde_table[fd]; |
88 | | - int flags = e->fde_epflags; |
89 | | - |
90 | | - assert(fd < max_fd); |
91 | | - |
92 | | - if (handler == NULL) { |
93 | | - e->fde_epflags = 0; |
94 | | - pfds[fd].fd = -1; |
95 | | - pfds[fd].events = 0; |
96 | | - return; |
97 | | - } |
98 | | - |
99 | | - e->fde_fd = fd; |
100 | | - if (what & FDE_READ) { |
101 | | - e->fde_read_handler = handler; |
102 | | - e->fde_epflags |= POLLRDNORM; |
103 | | - } |
104 | | - if (what & FDE_WRITE) { |
105 | | - e->fde_write_handler = handler; |
106 | | - e->fde_epflags |= POLLWRNORM; |
107 | | - } |
108 | | - |
109 | | - pfds[fd].fd = fd; |
110 | | - pfds[fd].events = e->fde_epflags; |
111 | | - |
112 | | - if (data) |
113 | | - e->fde_rdata = data; |
114 | | -} |
Index: trunk/willow/src/daemon.c |
— | — | @@ -1,71 +0,0 @@ |
2 | | -/* $Header$ */ |
3 | | -/* $NetBSD: daemon.c,v 1.9 2003/08/07 16:42:46 agc Exp $ */ |
4 | | - |
5 | | -/*- |
6 | | - * Copyright (c) 1990, 1993 |
7 | | - * The Regents of the University of California. All rights reserved. |
8 | | - * |
9 | | - * Redistribution and use in source and binary forms, with or without |
10 | | - * modification, are permitted provided that the following conditions |
11 | | - * are met: |
12 | | - * 1. Redistributions of source code must retain the above copyright |
13 | | - * notice, this list of conditions and the following disclaimer. |
14 | | - * 2. Redistributions in binary form must reproduce the above copyright |
15 | | - * notice, this list of conditions and the following disclaimer in the |
16 | | - * documentation and/or other materials provided with the distribution. |
17 | | - * 3. Neither the name of the University nor the names of its contributors |
18 | | - * may be used to endorse or promote products derived from this software |
19 | | - * without specific prior written permission. |
20 | | - * |
21 | | - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
22 | | - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
23 | | - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
24 | | - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
25 | | - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
26 | | - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
27 | | - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
28 | | - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
29 | | - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
30 | | - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
31 | | - * SUCH DAMAGE. |
32 | | - */ |
33 | | - |
34 | | -#if defined __SUNPRO_C || defined __DECC || defined __HP_cc |
35 | | -# pragma ident "@(#)$Header$" |
36 | | -# pragma ident "$NetBSD: daemon.c,v 1.9 2003/08/07 16:42:46 agc Exp $" |
37 | | -#endif |
38 | | - |
39 | | -#include <fcntl.h> |
40 | | -#include <stdlib.h> |
41 | | -#include <unistd.h> |
42 | | - |
43 | | -int |
44 | | -daemon(nochdir, noclose) |
45 | | - int nochdir, noclose; |
46 | | -{ |
47 | | - int fd; |
48 | | - |
49 | | - switch (fork()) { |
50 | | - case -1: |
51 | | - return (-1); |
52 | | - case 0: |
53 | | - break; |
54 | | - default: |
55 | | - _exit(0); |
56 | | - } |
57 | | - |
58 | | - if (setsid() == -1) |
59 | | - return (-1); |
60 | | - |
61 | | - if (!nochdir) |
62 | | - (void)chdir("/"); |
63 | | - |
64 | | - if (!noclose && (fd = open("/dev/null", O_RDWR, 0)) != -1) { |
65 | | - (void)dup2(fd, STDIN_FILENO); |
66 | | - (void)dup2(fd, STDOUT_FILENO); |
67 | | - (void)dup2(fd, STDERR_FILENO); |
68 | | - if (fd > STDERR_FILENO) |
69 | | - (void)close(fd); |
70 | | - } |
71 | | - return (0); |
72 | | -} |
Index: trunk/willow/src/wnet_ports.c |
— | — | @@ -1,245 +0,0 @@ |
2 | | -/* @(#) $Header$ */ |
3 | | -/* This source code is in the public domain. */ |
4 | | -/* |
5 | | - * Willow: Lightweight HTTP reverse-proxy. |
6 | | - * wnet_ports: Solaris event ports-specific networking |
7 | | - */ |
8 | | - |
9 | | -#if defined __SUNPRO_C || defined __DECC || defined __HP_cc |
10 | | -# pragma ident "@(#)$Header$" |
11 | | -#endif |
12 | | - |
13 | | -#include <sys/types.h> |
14 | | -#include <sys/socket.h> |
15 | | - |
16 | | -#include <stdio.h> |
17 | | -#include <stdlib.h> |
18 | | -#include <assert.h> |
19 | | -#include <fcntl.h> |
20 | | -#include <port.h> |
21 | | -#include <errno.h> |
22 | | -#include <string.h> |
23 | | -#include <unistd.h> |
24 | | - |
25 | | -#include "config.h" |
26 | | - |
27 | | -#ifdef THREADED_IO |
28 | | -# include <pthread.h> |
29 | | -#endif |
30 | | - |
31 | | -#include "wnet.h" |
32 | | -#include "wlog.h" |
33 | | - |
34 | | -#define READABLE POLLRDNORM |
35 | | - |
36 | | -static void run_event(struct fde *, int); |
37 | | - |
38 | | -static int port; |
39 | | -#define GETN 256 |
40 | | -static port_event_t pe[GETN]; |
41 | | - |
42 | | -#ifdef THREADED_IO |
43 | | -# define NTHREADS 20 |
44 | | -static pthread_t thread_ids[NTHREADS]; |
45 | | -struct { |
46 | | - int fd; |
47 | | - int flags; |
48 | | -} t_event; |
49 | | - |
50 | | -pthread_cond_t t_cond = PTHREAD_COND_INITIALIZER; |
51 | | -pthread_mutex_t t_mtx = PTHREAD_MUTEX_INITIALIZER; |
52 | | - |
53 | | -static void * |
54 | | -thread_event_wait(data) |
55 | | - void *data; |
56 | | -{ |
57 | | - int fd, flags; |
58 | | - port_event_t pe; |
59 | | - |
60 | | - WDEBUG((WLOG_DEBUG, "[%u] starting", pthread_self())); |
61 | | - |
62 | | - for (;;) { |
63 | | - int i; |
64 | | - |
65 | | - WDEBUG((WLOG_DEBUG, "[%u] waiting", pthread_self())); |
66 | | - |
67 | | - i = port_get(port, &pe, NULL); |
68 | | - if (i == -1) { |
69 | | - wlog(WLOG_WARNING, "port_get: %s", strerror(errno)); |
70 | | - break; |
71 | | - } |
72 | | - |
73 | | - WDEBUG((WLOG_DEBUG, "[%u] activity on %d", pthread_self(), (int)pe.portev_object)); |
74 | | - wnet_set_time(); |
75 | | - |
76 | | - fd = pe.portev_object; |
77 | | - FDE_LOCK(&fde_table[fd]); |
78 | | - run_event(&fde_table[fd], pe.portev_events); |
79 | | - FDE_UNLOCK(&fde_table[fd]); |
80 | | - } |
81 | | - /*NOTREACHED*/ |
82 | | -} |
83 | | -#endif |
84 | | - |
85 | | -static void |
86 | | -run_event(fde, events) |
87 | | - struct fde *fde; |
88 | | - int events; |
89 | | -{ |
90 | | - int hadread, hadwrite; |
91 | | - |
92 | | - hadread = fde->fde_epflags & READABLE; |
93 | | - hadwrite = fde->fde_epflags & POLLWRNORM; |
94 | | - |
95 | | - /* |
96 | | - * Immediately re-associate. If the caller doesn't want it, |
97 | | - * they'll dissociate it themselves. This could be optimised |
98 | | - * a little to save 2 syscalls in some cases... |
99 | | - */ |
100 | | - |
101 | | - if ((events & READABLE) && fde->fde_read_handler) { |
102 | | - WDEBUG((WLOG_DEBUG, "\tread")); |
103 | | - fde->fde_read_handler(fde); |
104 | | - if (hadread && (fde->fde_epflags & READABLE)) |
105 | | - if (port_associate(port, PORT_SOURCE_FD, fde->fde_fd, READABLE, NULL) == -1) { |
106 | | - wlog(WLOG_ERROR, "port_associate: %s", strerror(errno)); |
107 | | - exit(8); |
108 | | - } |
109 | | - } |
110 | | - |
111 | | - if ((events & (POLLWRNORM | POLLERR)) && fde->fde_write_handler) { |
112 | | - WDEBUG((WLOG_DEBUG, "\twrite")); |
113 | | - fde->fde_write_handler(fde); |
114 | | - if (hadwrite && (fde->fde_epflags & POLLWRNORM)) |
115 | | - if (port_associate(port, PORT_SOURCE_FD, fde->fde_fd, POLLWRNORM, NULL) == -1) { |
116 | | - wlog(WLOG_ERROR, "port_associate: %s", strerror(errno)); |
117 | | - exit(8); |
118 | | - } |
119 | | - } |
120 | | -} |
121 | | - |
122 | | -void |
123 | | -wnet_init_select(void) |
124 | | -{ |
125 | | - int i; |
126 | | - |
127 | | - if ((port = port_create()) < 0) { |
128 | | - perror("port_create"); |
129 | | - exit(8); |
130 | | - } |
131 | | - |
132 | | -#ifdef THREADED_IO |
133 | | - WDEBUG((WLOG_DEBUG, "wnet_init_select: thread startup")); |
134 | | - |
135 | | - (void) pthread_mutex_lock(&t_mtx); |
136 | | - |
137 | | - for (i = 0; i < NTHREADS; ++i) { |
138 | | - pthread_attr_t attr; |
139 | | - pthread_attr_init(&attr); |
140 | | - //pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM); |
141 | | - if (pthread_create(&thread_ids[i], &attr, thread_event_wait, NULL) != 0) { |
142 | | - perror("pthread_create"); |
143 | | - exit(8); |
144 | | - } |
145 | | - } |
146 | | - for (i = 0; i < getdtablesize(); ++i) { |
147 | | - pthread_mutexattr_t attr; |
148 | | - if (pthread_mutexattr_init(&attr) != 0) { |
149 | | - perror("pthread_mutexattr_init"); |
150 | | - exit(8); |
151 | | - } |
152 | | - if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE) != 0) { |
153 | | - perror("pthread_mutexattr_settype"); |
154 | | - exit(8); |
155 | | - } |
156 | | - if (pthread_mutex_init(&fde_table[i].fde_mtx, &attr) != 0) { |
157 | | - perror("pthread_mutex_init"); |
158 | | - exit(8); |
159 | | - } |
160 | | - } |
161 | | -#endif |
162 | | -} |
163 | | - |
164 | | -void |
165 | | -wnet_run(void) |
166 | | -{ |
167 | | - uint nget = 1; |
168 | | - |
169 | | -#ifdef THREADED_IO |
170 | | - thread_event_wait(NULL); |
171 | | -#else |
172 | | - int i; |
173 | | - for (;;) { |
174 | | - i = port_getn(port, pe, GETN, &nget, NULL); |
175 | | - |
176 | | - if (i == -1) { |
177 | | - if (errno == EINTR) { |
178 | | - if (wnet_exit) |
179 | | - return; |
180 | | - continue; |
181 | | - } |
182 | | - break; |
183 | | - } |
184 | | - |
185 | | - wnet_set_time(); |
186 | | - |
187 | | - for (i = 0; i < nget; ++i) { |
188 | | - struct fde *e = &fde_table[pe[i].portev_object]; |
189 | | - |
190 | | - WDEBUG((WLOG_DEBUG, "activity on fd %d [%s]", e->fde_fd, e->fde_desc)); |
191 | | - |
192 | | - run_event(e, pe[i].portev_events); |
193 | | - } |
194 | | - nget = 1; |
195 | | - } |
196 | | -#endif |
197 | | -} |
198 | | - |
199 | | -void |
200 | | -wnet_register(fd, what, handler, data) |
201 | | - int fd, what; |
202 | | - fdcb handler; |
203 | | - void *data; |
204 | | -{ |
205 | | -struct fde *e = &fde_table[fd]; |
206 | | - int oldflags = e->fde_epflags; |
207 | | - |
208 | | - WDEBUG((WLOG_DEBUG, "wnet_register: %d [%s] for %d %p", fd, e->fde_desc, what, (void *)handler)); |
209 | | - |
210 | | - FDE_LOCK(e); |
211 | | - |
212 | | - if (what & FDE_READ) { |
213 | | - e->fde_read_handler = handler; |
214 | | - if (handler) |
215 | | - e->fde_epflags |= READABLE; |
216 | | - else |
217 | | - e->fde_epflags &= ~READABLE; |
218 | | - } |
219 | | - if (what & FDE_WRITE) { |
220 | | - e->fde_write_handler = handler; |
221 | | - if (handler) |
222 | | - e->fde_epflags |= POLLWRNORM; |
223 | | - else |
224 | | - e->fde_epflags &= ~POLLWRNORM; |
225 | | - } |
226 | | - |
227 | | - if (data) |
228 | | - e->fde_rdata = data; |
229 | | - |
230 | | - if (oldflags == e->fde_epflags) { |
231 | | - /* no change */ |
232 | | - FDE_UNLOCK(e); |
233 | | - return; |
234 | | - } |
235 | | - |
236 | | - if (e->fde_epflags) { |
237 | | - if (port_associate(port, PORT_SOURCE_FD, fd, e->fde_epflags, NULL) < 0) { |
238 | | - perror("port_associate"); |
239 | | - abort(); |
240 | | - } |
241 | | - } else { |
242 | | - (void)port_dissociate(port, PORT_SOURCE_FD, fd); |
243 | | - } |
244 | | - |
245 | | - FDE_UNLOCK(e); |
246 | | -} |
Index: trunk/willow/src/whttp.c |
— | — | @@ -1,649 +0,0 @@ |
2 | | -/* @(#) $Header$ */ |
3 | | -/* This source code is in the public domain. */ |
4 | | -/* |
5 | | - * Willow: Lightweight HTTP reverse-proxy. |
6 | | - * whttp: HTTP implementation. |
7 | | - */ |
8 | | - |
9 | | -#if defined __SUNPRO_C || defined __DECC || defined __HP_cc |
10 | | -# pragma ident "@(#)$Header$" |
11 | | -#endif |
12 | | - |
13 | | -/* |
14 | | - * The logic of whttp is explained in whttp_entity.c |
15 | | - */ |
16 | | - |
17 | | -#include <sys/types.h> |
18 | | -#include <sys/stat.h> |
19 | | -#include <sys/param.h> |
20 | | - |
21 | | -#include <stdlib.h> |
22 | | -#include <stdio.h> |
23 | | -#include <string.h> |
24 | | -#include <unistd.h> |
25 | | -#include <errno.h> |
26 | | -#include <netdb.h> |
27 | | -#include <fcntl.h> |
28 | | -#include <strings.h> |
29 | | - |
30 | | -#include "willow.h" |
31 | | -#include "whttp.h" |
32 | | -#include "wnet.h" |
33 | | -#include "wbackend.h" |
34 | | -#include "wconfig.h" |
35 | | -#include "wlogwriter.h" |
36 | | -#include "whttp_entity.h" |
37 | | -#include "wlog.h" |
38 | | -#include "wcache.h" |
39 | | - |
40 | | -#ifndef MAXHOSTNAMELEN |
41 | | -# define MAXHOSTNAMELEN HOST_NAME_MAX /* SysV / BSD disagreement */ |
42 | | -#endif |
43 | | - |
44 | | -/* |
45 | | - * Error handling. |
46 | | - */ |
47 | | -#define ERR_GENERAL 0 |
48 | | -#define ERR_BADREQUEST 1 |
49 | | -#define ERR_BADRESPONSE 2 |
50 | | -#define ERR_CACHE_IO 3 |
51 | | - |
52 | | -static const char *error_files[] = { |
53 | | - /* ERR_GENERAL */ DATADIR "/errors/ERR_GENERAL", |
54 | | - /* ERR_BADREQUEST */ DATADIR "/errors/ERR_BADREQUEST", |
55 | | - /* ERR_BADRESPONSE */ DATADIR "/errors/ERR_BADRESPONSE", |
56 | | - /* ERR_CACHE_IO */ DATADIR "/errors/ERR_CACHE_IO", |
57 | | -}; |
58 | | - |
59 | | -const char *request_string[] = { |
60 | | - "GET", |
61 | | - "POST", |
62 | | - "HEAD", |
63 | | - "TRACE", |
64 | | - "OPTIONS", |
65 | | -}; |
66 | | - |
67 | | -struct request_type supported_reqtypes[] = { |
68 | | - { "GET", 3, REQTYPE_GET }, |
69 | | - { "POST", 4, REQTYPE_POST }, |
70 | | - { "HEAD", 4, REQTYPE_HEAD }, |
71 | | - { "TRACE", 5, REQTYPE_TRACE }, |
72 | | - { "OPTIONS", 7, REQTYPE_OPTIONS }, |
73 | | - { NULL, 0, REQTYPE_INVALID } |
74 | | -}; |
75 | | - |
76 | | -struct http_client { |
77 | | -struct fde *cl_fde; /* backref to fd */ |
78 | | - int cl_reqtype; /* request type or 0 */ |
79 | | - char *cl_path; /* path they want */ |
80 | | - char *cl_wrtbuf; /* write buf (either to client or be) */ |
81 | | -struct backend *cl_backend; /* backend servicing this client */ |
82 | | -struct fde *cl_backendfde; /* fde for backend */ |
83 | | -struct http_entity cl_entity; /* reply to send back */ |
84 | | - |
85 | | - /* Cache-related data */ |
86 | | - int cl_cfd; /* FD of cache file for writing, or 0 */ |
87 | | -struct cache_key cl_key; /* Cache key */ |
88 | | -struct cache_object *cl_co; /* Cache object */ |
89 | | - struct { |
90 | | - int f_cached:1; |
91 | | - } cl_flags; |
92 | | - |
93 | | -struct http_client *fe_next; /* freelist */ |
94 | | -}; |
95 | | - |
96 | | -static struct http_client freelist; |
97 | | - |
98 | | -static void client_close(struct http_client *); |
99 | | -static void proxy_start_backend(struct backend *, struct fde *, void *); |
100 | | -static void client_read_done(struct http_entity *, void *, int); |
101 | | -static void client_response_done(struct http_entity *, void *, int); |
102 | | -static void backend_headers_done(struct http_entity *, void *, int); |
103 | | -static void client_headers_done(struct http_entity *, void *, int); |
104 | | -static void client_write_cached(struct http_client *); |
105 | | - |
106 | | -static void client_send_error(struct http_client *, int, const char *); |
107 | | -static void client_log_request(struct http_client *); |
108 | | - |
109 | | -static void do_cache_write(const char *, size_t, void *); |
110 | | - |
111 | | -static char via_hdr[1024]; |
112 | | -static char *cache_hit_hdr; |
113 | | -static char *cache_miss_hdr; |
114 | | - |
115 | | -static char my_hostname[MAXHOSTNAMELEN + 1]; |
116 | | -static char my_version[64]; |
117 | | -static int logwr_pipe[2]; |
118 | | -static FILE *alf; |
119 | | - |
120 | | -/* |
121 | | - * Initialize whttp, start loggers. |
122 | | - */ |
123 | | -void |
124 | | -whttp_init(void) |
125 | | -{ |
126 | | - size_t hsize; |
127 | | - |
128 | | - if (gethostname(my_hostname, MAXHOSTNAMELEN) < 0) { |
129 | | - perror("gethostname"); |
130 | | - exit(8); |
131 | | - } |
132 | | - |
133 | | - (void)strlcpy(my_version, "Willow/" PACKAGE_VERSION, 64); |
134 | | - safe_snprintf(1023, (via_hdr, 1023, "1.0 %s (%s)", my_hostname, my_version)); |
135 | | - |
136 | | - hsize = sizeof("MISS from ") + strlen(my_hostname); |
137 | | - cache_hit_hdr = wmalloc(hsize + 1); |
138 | | - cache_miss_hdr = wmalloc(hsize + 1); |
139 | | - |
140 | | - if (cache_hit_hdr == NULL || cache_miss_hdr == NULL) |
141 | | - outofmemory(); |
142 | | - |
143 | | - safe_snprintf(hsize, (cache_hit_hdr, hsize, "HIT from %s", my_hostname)); |
144 | | - safe_snprintf(hsize, (cache_miss_hdr, hsize, "MISS from %s", my_hostname)); |
145 | | - |
146 | | - /* |
147 | | - * Fork the logwriter. |
148 | | - */ |
149 | | - if (config.access_log) { |
150 | | - if (pipe(logwr_pipe) < 0) { |
151 | | - perror("pipe"); |
152 | | - exit(8); |
153 | | - } |
154 | | - wlogwriter_start(logwr_pipe); |
155 | | - if ((alf = fdopen(logwr_pipe[0], "w")) == NULL) { |
156 | | - perror("fdopen"); |
157 | | - exit(8); |
158 | | - } |
159 | | - } |
160 | | -} |
161 | | - |
162 | | -void |
163 | | -whttp_shutdown(void) |
164 | | -{ |
165 | | - wfree(cache_hit_hdr); |
166 | | - wfree(cache_miss_hdr); |
167 | | -} |
168 | | - |
169 | | -/* |
170 | | - * Create a new client associated with the FDE 'e'. |
171 | | - */ |
172 | | -static struct http_client * |
173 | | -new_client(e) |
174 | | - struct fde *e; |
175 | | -{ |
176 | | -struct http_client *cl; |
177 | | - |
178 | | - if (freelist.fe_next) { |
179 | | - cl = freelist.fe_next; |
180 | | - freelist.fe_next = cl->fe_next; |
181 | | - bzero(cl, sizeof(*cl)); |
182 | | - } else { |
183 | | - if ((cl = wcalloc(1, sizeof(*cl))) == NULL) |
184 | | - outofmemory(); |
185 | | - } |
186 | | - |
187 | | - cl->cl_fde = e; |
188 | | - return cl; |
189 | | -} |
190 | | - |
191 | | -/* |
192 | | - * Called by wnet_accept to regiister a new client. Reads the request headers |
193 | | - * from the client. |
194 | | - */ |
195 | | -void |
196 | | -http_new(e) |
197 | | - struct fde *e; |
198 | | -{ |
199 | | -struct http_client *cl; |
200 | | - |
201 | | - cl = new_client(e); |
202 | | - cl->cl_entity.he_source_type = ENT_SOURCE_FDE; |
203 | | - cl->cl_entity.he_source.fde.fde = e; |
204 | | - cl->cl_entity.he_rdata.request.contlen = -1; |
205 | | - |
206 | | - WDEBUG((WLOG_DEBUG, "http_new: starting header read for %d", cl->cl_fde->fde_fd)); |
207 | | - entity_read_headers(&cl->cl_entity, client_read_done, cl); |
208 | | -} |
209 | | - |
210 | | -/* |
211 | | - * Called when the initial request has been read. Checks if the object is |
212 | | - * cached, and starts a backend request if not. If it it, sends the cached |
213 | | - * object to the client. |
214 | | - */ |
215 | | -/*ARGSUSED*/ |
216 | | -static void |
217 | | -client_read_done(entity, data, res) |
218 | | - struct http_entity *entity; |
219 | | - void *data; |
220 | | - int res; |
221 | | -{ |
222 | | -struct http_client *client = data; |
223 | | -struct cache_key ckey; |
224 | | -struct cache_object *cobj; |
225 | | - |
226 | | - WDEBUG((WLOG_DEBUG, "client_read_done: called")); |
227 | | - |
228 | | - if (res == -1) { |
229 | | - client_close(client); |
230 | | - return; |
231 | | - } |
232 | | - |
233 | | - if (client->cl_entity.he_rdata.request.host == NULL) |
234 | | - client->cl_path = wstrdup(client->cl_entity.he_rdata.request.path); |
235 | | - else { |
236 | | - size_t len; |
237 | | - |
238 | | - len = strlen(client->cl_entity.he_rdata.request.host) + |
239 | | - strlen(client->cl_entity.he_rdata.request.path) + 7; |
240 | | - |
241 | | - client->cl_path = wmalloc(len + 1); |
242 | | - if (client->cl_path == NULL) |
243 | | - outofmemory(); |
244 | | - safe_snprintf(len + 1, (client->cl_path, len + 1, "http://%s%s", client->cl_entity.he_rdata.request.host, |
245 | | - client->cl_entity.he_rdata.request.path)); |
246 | | - } |
247 | | - |
248 | | - client->cl_reqtype = client->cl_entity.he_rdata.request.reqtype; |
249 | | - |
250 | | - /* |
251 | | - * Check for cached object. |
252 | | - */ |
253 | | - if (client->cl_reqtype == REQTYPE_GET) { |
254 | | - ckey.ck_len = strlen(client->cl_path); |
255 | | - ckey.ck_key = client->cl_path; |
256 | | - cobj = wcache_find_object(&ckey); |
257 | | - if (cobj != NULL) { |
258 | | - client->cl_co = cobj; |
259 | | - WDEBUG((WLOG_DEBUG, "client_read_done: object %s cached", client->cl_path)); |
260 | | - client_write_cached(client); |
261 | | - return; |
262 | | - } |
263 | | - } |
264 | | - |
265 | | - /* |
266 | | - * Not cached. Find a backend. |
267 | | - */ |
268 | | - if (get_backend(proxy_start_backend, client) == -1) { |
269 | | - client_send_error(client, ERR_GENERAL, strerror(errno)); |
270 | | - return; |
271 | | - } |
272 | | -} |
273 | | - |
274 | | -/* |
275 | | - * Called when backend is ready. backend==NULL if none was found. |
276 | | - */ |
277 | | -static void |
278 | | -proxy_start_backend(backend, e, data) |
279 | | - struct backend *backend; |
280 | | - struct fde *e; |
281 | | - void *data; |
282 | | -{ |
283 | | -struct http_client *client = data; |
284 | | -struct header_list *it; |
285 | | - |
286 | | - WDEBUG((WLOG_DEBUG, "proxy_start_backend: called")); |
287 | | - |
288 | | - if (backend == NULL) { |
289 | | - client_send_error(client, ERR_GENERAL, strerror(errno)); |
290 | | - return; |
291 | | - } |
292 | | - |
293 | | - client->cl_backend = backend; |
294 | | - client->cl_backendfde = e; |
295 | | - |
296 | | - for (it = client->cl_entity.he_headers.hl_next; it; it = it->hl_next) { |
297 | | - if (!strcmp(it->hl_name, "Connection")) { |
298 | | - header_remove(&client->cl_entity.he_headers, it); |
299 | | - it = client->cl_entity.he_headers.hl_next; |
300 | | - continue; |
301 | | - } |
302 | | - } |
303 | | - |
304 | | - header_add(&client->cl_entity.he_headers, "X-Forwarded-For", client->cl_fde->fde_straddr); |
305 | | - /* |
306 | | - * POST requests require Content-Length. |
307 | | - */ |
308 | | - if (client->cl_reqtype == REQTYPE_POST) { |
309 | | - if (client->cl_entity.he_rdata.request.contlen == -1) { |
310 | | - client_send_error(client, ERR_BADREQUEST, "POST request without Content-Length"); |
311 | | - return; |
312 | | - } |
313 | | - |
314 | | - WDEBUG((WLOG_DEBUG, "client content-length=%d", client->cl_entity.he_rdata.request.contlen)); |
315 | | - client->cl_entity.he_source_type = ENT_SOURCE_FDE; |
316 | | - client->cl_entity.he_source.fde.fde = client->cl_fde; |
317 | | - client->cl_entity.he_source.fde.len = client->cl_entity.he_rdata.request.contlen; |
318 | | - } else |
319 | | - client->cl_entity.he_source_type = ENT_SOURCE_NONE; |
320 | | - |
321 | | - entity_send(e, &client->cl_entity, backend_headers_done, client); |
322 | | -} |
323 | | - |
324 | | -/* |
325 | | - * Called when clients request was written to the backend. |
326 | | - */ |
327 | | -/*ARGSUSED*/ |
328 | | -static void |
329 | | -backend_headers_done(entity, data, res) |
330 | | - struct http_entity *entity; |
331 | | - void *data; |
332 | | - int res; |
333 | | -{ |
334 | | -struct http_client *client = data; |
335 | | - |
336 | | - WDEBUG((WLOG_DEBUG, "backend_headers_done: called")); |
337 | | - if (res == -1) { |
338 | | - client_send_error(client, ERR_GENERAL, strerror(errno)); |
339 | | - return; |
340 | | - } |
341 | | - |
342 | | - entity_free(&client->cl_entity); |
343 | | - bzero(&client->cl_entity, sizeof(client->cl_entity)); |
344 | | - client->cl_entity.he_source_type = ENT_SOURCE_FDE; |
345 | | - client->cl_entity.he_source.fde.fde = client->cl_backendfde; |
346 | | - client->cl_entity.he_source.fde.len = -1; |
347 | | - |
348 | | - client->cl_entity.he_flags.response = 1; |
349 | | - |
350 | | - /* |
351 | | - * This should probably be handled somewhere inside |
352 | | - * whttp_entity.c ... |
353 | | - */ |
354 | | - entity_read_headers(&client->cl_entity, client_headers_done, client); |
355 | | -} |
356 | | - |
357 | | -/* |
358 | | - * Called when backend's headers are finished reading. |
359 | | - */ |
360 | | -static void |
361 | | -client_headers_done(entity, data, res) |
362 | | - struct http_entity *entity; |
363 | | - void *data; |
364 | | - int res; |
365 | | -{ |
366 | | -struct http_client *client = data; |
367 | | - char *cache_path; |
368 | | - size_t plen; |
369 | | - |
370 | | - WDEBUG((WLOG_DEBUG, "client_headers_done: called")); |
371 | | - |
372 | | - if (res == -1) { |
373 | | - client_close(client); |
374 | | - return; |
375 | | - } |
376 | | - |
377 | | - /* |
378 | | - * If cachable, open the cache file and write data. |
379 | | - * |
380 | | - * Don't cache responses to non-GET requests, or non-200 replies. |
381 | | - */ |
382 | | - if (client->cl_reqtype == REQTYPE_GET && entity->he_rdata.response.status == 200 |
383 | | - && config.ncaches) { |
384 | | - client->cl_key.ck_len = strlen(client->cl_path); |
385 | | - client->cl_key.ck_key = client->cl_path; |
386 | | - client->cl_co = wcache_new_object(); |
387 | | - plen = strlen(config.caches[0].dir) + client->cl_co->co_plen + 12 + 2; |
388 | | - if ((cache_path = wcalloc(1, plen + 1)) == NULL) |
389 | | - outofmemory(); |
390 | | - safe_snprintf(plen, (cache_path, plen, "%s/__objects__/%s", config.caches[0].dir, client->cl_co->co_path)); |
391 | | - WDEBUG((WLOG_DEBUG, "caching %s at %s", client->cl_path, cache_path)); |
392 | | - if ((client->cl_cfd = open(cache_path, O_WRONLY | O_CREAT | O_EXCL, 0600)) == -1) { |
393 | | - wlog(WLOG_WARNING, "opening cache file %s: %s", cache_path, strerror(errno)); |
394 | | - client->cl_cfd = 0; |
395 | | - } else { |
396 | | - entity->he_cache_callback = do_cache_write; |
397 | | - entity->he_cache_callback_data = client; |
398 | | - header_dump(&client->cl_entity.he_headers, client->cl_cfd); |
399 | | - } |
400 | | - wfree(cache_path); |
401 | | - } |
402 | | - |
403 | | - header_add(&client->cl_entity.he_headers, "Via", via_hdr); |
404 | | - header_add(&client->cl_entity.he_headers, "X-Cache", cache_miss_hdr); |
405 | | - client->cl_entity.he_source.fde.len = -1; |
406 | | - entity_send(client->cl_fde, &client->cl_entity, client_response_done, client); |
407 | | -} |
408 | | - |
409 | | -/* |
410 | | - * Write a cached object to the client. |
411 | | - */ |
412 | | -static void |
413 | | -client_write_cached(client) |
414 | | - struct http_client *client; |
415 | | -{ |
416 | | - size_t plen; |
417 | | - char *cache_path; |
418 | | -struct stat sb; |
419 | | - |
420 | | - plen = strlen(config.caches[0].dir) + client->cl_co->co_plen + 12 + 2; |
421 | | - if ((cache_path = wcalloc(1, plen + 1)) == NULL) |
422 | | - outofmemory(); |
423 | | - safe_snprintf(plen, (cache_path, plen, "%s/__objects__/%s", config.caches[0].dir, client->cl_co->co_path)); |
424 | | - WDEBUG((WLOG_DEBUG, "serving %s from cache at %s [path %s]", client->cl_path, cache_path, client->cl_co->co_path)); |
425 | | - |
426 | | - if ((client->cl_cfd = open(cache_path, O_RDONLY)) == -1) { |
427 | | - wlog(WLOG_WARNING, "opening cache file %s: %s", cache_path, strerror(errno)); |
428 | | - client_send_error(client, ERR_CACHE_IO, strerror(errno)); |
429 | | - wfree(cache_path); |
430 | | - return; |
431 | | - } |
432 | | - |
433 | | - if (fstat(client->cl_cfd, &sb) < 0) { |
434 | | - wlog(WLOG_WARNING, "stat(%s): %s", cache_path, strerror(errno)); |
435 | | - client_send_error(client, ERR_CACHE_IO, strerror(errno)); |
436 | | - wfree(cache_path); |
437 | | - return; |
438 | | - } |
439 | | - |
440 | | - wfree(cache_path); |
441 | | - |
442 | | - entity_free(&client->cl_entity); |
443 | | - bzero(&client->cl_entity, sizeof(client->cl_entity)); |
444 | | - header_undump(&client->cl_entity.he_headers, client->cl_cfd, &client->cl_entity.he_source.fd.off); |
445 | | - header_add(&client->cl_entity.he_headers, "Via", via_hdr); |
446 | | - header_add(&client->cl_entity.he_headers, "X-Cache", cache_hit_hdr); |
447 | | - |
448 | | - client->cl_entity.he_flags.response = 1; |
449 | | - client->cl_entity.he_rdata.response.status = 200; |
450 | | - client->cl_entity.he_rdata.response.status_str = "OK"; |
451 | | - |
452 | | - client->cl_entity.he_source.fd.fd = client->cl_cfd; |
453 | | - client->cl_entity.he_source.fd.size = sb.st_size; |
454 | | - |
455 | | - client->cl_entity.he_source_type = ENT_SOURCE_FILE; |
456 | | - |
457 | | - client->cl_flags.f_cached = 1; |
458 | | - entity_send(client->cl_fde, &client->cl_entity, client_response_done, client); |
459 | | -} |
460 | | - |
461 | | -/* |
462 | | - * Called when response was finished writing to the client. |
463 | | - */ |
464 | | -/*ARGSUSED*/ |
465 | | -static void |
466 | | -client_response_done(entity, data, res) |
467 | | - struct http_entity *entity; |
468 | | - void *data; |
469 | | - int res; |
470 | | -{ |
471 | | -struct http_client *client = data; |
472 | | - |
473 | | - WDEBUG((WLOG_DEBUG, "client_response_done: called")); |
474 | | - |
475 | | - if (client->cl_cfd) { |
476 | | - if (close(client->cl_cfd) < 0) { |
477 | | - wlog(WLOG_WARNING, "writing cache file: %s\n", strerror(errno)); |
478 | | - } |
479 | | - } |
480 | | - |
481 | | - if (client->cl_co) { |
482 | | - if (res != -1) { |
483 | | - if (!client->cl_flags.f_cached) { |
484 | | - if (wcache_store_object(&client->cl_key, client->cl_co) == -1) { |
485 | | - /* normally, this means someone else cached it before us */ |
486 | | - wlog(WLOG_WARNING, "object cache store failed"); |
487 | | - } |
488 | | - } |
489 | | - } else { |
490 | | - wlog(WLOG_WARNING, "writing cached file: %s", strerror(errno)); |
491 | | - /* XXX should unlink cached file */ |
492 | | - } |
493 | | - wcache_free_object(client->cl_co); |
494 | | - } |
495 | | - |
496 | | - client_log_request(client); |
497 | | - client_close(client); |
498 | | -} |
499 | | - |
500 | | -static void |
501 | | -client_close(client) |
502 | | - struct http_client *client; |
503 | | -{ |
504 | | - WDEBUG((WLOG_DEBUG, "close client %d", client->cl_fde->fde_fd)); |
505 | | - if (client->cl_wrtbuf) |
506 | | - wfree(client->cl_wrtbuf); |
507 | | - if (client->cl_path) |
508 | | - wfree(client->cl_path); |
509 | | - wnet_close(client->cl_fde->fde_fd); |
510 | | - if (client->cl_backendfde) |
511 | | - wnet_close(client->cl_backendfde->fde_fd); |
512 | | - entity_free(&client->cl_entity); |
513 | | - |
514 | | - client->fe_next = freelist.fe_next; |
515 | | - freelist.fe_next = client; |
516 | | -} |
517 | | - |
518 | | -static void |
519 | | -client_send_error(client, errnum, errdata) |
520 | | - struct http_client *client; |
521 | | - int errnum; |
522 | | - const char *errdata; |
523 | | -{ |
524 | | - FILE *errfile; |
525 | | - char errbuf[8192]; |
526 | | - char *p = errbuf, *u; |
527 | | - ssize_t size; |
528 | | - |
529 | | - if ((errfile = fopen(error_files[errnum], "r")) == NULL) { |
530 | | - client_close(client); |
531 | | - return; |
532 | | - } |
533 | | - |
534 | | - if ((size = fread(errbuf, 1, sizeof(errbuf) - 1, errfile)) < 0) { |
535 | | - (void)fclose(errfile); |
536 | | - client_close(client); |
537 | | - return; |
538 | | - } |
539 | | - |
540 | | - (void)fclose(errfile); |
541 | | - errbuf[size] = '\0'; |
542 | | - |
543 | | - if (!errdata) |
544 | | - errdata = "Unknown error"; |
545 | | - if (!client->cl_path) |
546 | | - client->cl_path = wstrdup("NONE"); |
547 | | - |
548 | | - u = NULL; |
549 | | - |
550 | | - while (*p) { |
551 | | - switch(*p) { |
552 | | - case '%': |
553 | | - switch (*++p) { |
554 | | - case 'U': |
555 | | - realloc_strcat(&u, client->cl_path); |
556 | | - break; |
557 | | - case 'D': |
558 | | - realloc_strcat(&u, current_time_str); |
559 | | - break; |
560 | | - case 'H': |
561 | | - realloc_strcat(&u, my_hostname); |
562 | | - break; |
563 | | - case 'E': |
564 | | - realloc_strcat(&u, errdata); |
565 | | - break; |
566 | | - case 'V': |
567 | | - realloc_strcat(&u, my_version); |
568 | | - break; |
569 | | - default: |
570 | | - break; |
571 | | - } |
572 | | - p++; |
573 | | - continue; |
574 | | - default: |
575 | | - realloc_addchar(&u, *p); |
576 | | - break; |
577 | | - } |
578 | | - ++p; |
579 | | - } |
580 | | - |
581 | | - client->cl_wrtbuf = u; |
582 | | - |
583 | | - bzero(&client->cl_entity.he_headers, sizeof(client->cl_entity.he_headers)); |
584 | | - header_add(&client->cl_entity.he_headers, "Date", current_time_str); |
585 | | - header_add(&client->cl_entity.he_headers, "Expires", current_time_str); |
586 | | - header_add(&client->cl_entity.he_headers, "Server", my_version); |
587 | | - header_add(&client->cl_entity.he_headers, "Content-Type", "text/html"); |
588 | | - header_add(&client->cl_entity.he_headers, "Connection", "close"); |
589 | | - |
590 | | - client->cl_entity.he_flags.response = 1; |
591 | | - client->cl_entity.he_rdata.response.status = 503; |
592 | | - client->cl_entity.he_rdata.response.status_str = "Service unavailable"; |
593 | | - client->cl_entity.he_source_type = ENT_SOURCE_BUFFER; |
594 | | - client->cl_entity.he_source.buffer.addr = client->cl_wrtbuf; |
595 | | - client->cl_entity.he_source.buffer.len = strlen(client->cl_wrtbuf); |
596 | | - |
597 | | - client->cl_entity.he_flags.cachable = 0; |
598 | | - entity_send(client->cl_fde, &client->cl_entity, client_response_done, client); |
599 | | -} |
600 | | - |
601 | | -static void |
602 | | -client_log_request(client) |
603 | | - struct http_client *client; |
604 | | -{ |
605 | | -#ifdef THREADED_IO |
606 | | -static pthread_mutex_t mtx; |
607 | | -#endif |
608 | | - |
609 | | - int i; |
610 | | - |
611 | | - if (!config.access_log) |
612 | | - return; |
613 | | - |
614 | | -#ifdef THREADED_IO |
615 | | - (void)pthread_mutex_lock(&mtx); |
616 | | -#endif |
617 | | - i = fprintf(alf, "[%s] %s %s \"%s\" %d %s %s\n", |
618 | | - current_time_short, client->cl_fde->fde_straddr, |
619 | | - request_string[client->cl_reqtype], |
620 | | - client->cl_path, client->cl_entity.he_rdata.response.status, |
621 | | - client->cl_backend ? client->cl_backend->be_name : "-", |
622 | | - client->cl_flags.f_cached ? "HIT" : "MISS"); |
623 | | - if (i < 0) { |
624 | | - wlog(WLOG_ERROR, "writing logfile: %s", strerror(errno)); |
625 | | - exit(8); |
626 | | - } |
627 | | - |
628 | | - if (fflush(alf) == EOF) { |
629 | | - wlog(WLOG_ERROR, "flushing logfile: %s", strerror(errno)); |
630 | | - exit(8); |
631 | | - } |
632 | | -#ifdef THREADED_IO |
633 | | - (void)pthread_mutex_unlock(&mtx); |
634 | | -#endif |
635 | | -} |
636 | | - |
637 | | -static void |
638 | | -do_cache_write(buf, len, data) |
639 | | - const char *buf; |
640 | | - size_t len; |
641 | | - void *data; |
642 | | -{ |
643 | | -struct http_client *client = data; |
644 | | - |
645 | | - if (write(client->cl_cfd, buf, len) < 0) { |
646 | | - /*EMPTY*/ |
647 | | - WDEBUG((WLOG_WARNING, "writing cached data: %s", strerror(errno))); |
648 | | - } |
649 | | -} |
650 | | - |
Index: trunk/willow/src/whttp_entity.h |
— | — | @@ -1,135 +0,0 @@ |
2 | | -/* @(#) $Header$ */ |
3 | | -/* This source code is in the public domain. */ |
4 | | -/* |
5 | | - * Willow: Lightweight HTTP reverse-proxy. |
6 | | - * whttp_entity: HTTP entity handling. |
7 | | - */ |
8 | | - |
9 | | -#ifndef WHTTP_ENTITY |
10 | | -#define WHTTP_ENTITY |
11 | | - |
12 | | -#if defined __SUNPRO_C || defined __DECC || defined __HP_cc |
13 | | -# pragma ident "@(#)$Header$" |
14 | | -#endif |
15 | | - |
16 | | -#ifdef THREADED_IO |
17 | | -# include <pthread.h> |
18 | | -#endif |
19 | | - |
20 | | -#include "whttp.h" |
21 | | - |
22 | | -#define ENT_SOURCE_BUFFER 1 |
23 | | -#define ENT_SOURCE_FDE 2 |
24 | | -#define ENT_SOURCE_NONE 3 |
25 | | -#define ENT_SOURCE_FILE 4 |
26 | | - |
27 | | -#define REQTYPE_GET 0 |
28 | | -#define REQTYPE_POST 1 |
29 | | -#define REQTYPE_HEAD 2 |
30 | | -#define REQTYPE_TRACE 3 |
31 | | -#define REQTYPE_OPTIONS 4 |
32 | | -#define REQTYPE_INVALID -1 |
33 | | - |
34 | | -#define MAX_HEADERS 64 /* maximum # of headers to allow */ |
35 | | - |
36 | | -struct http_entity; |
37 | | -struct http_client; |
38 | | - |
39 | | -typedef void (*header_cb)(struct http_entity *, void *, int); |
40 | | -typedef void (*cache_callback)(const char *, size_t, void *); |
41 | | - |
42 | | -#define HDR_ALLOCED 1 |
43 | | - |
44 | | -struct header_list { |
45 | | -const char *hl_name; |
46 | | -const char *hl_value; |
47 | | -struct header_list *hl_next; |
48 | | -struct header_list *hl_tail; |
49 | | - int hl_len; |
50 | | - int hl_num; |
51 | | - int hl_flags; |
52 | | -}; |
53 | | - |
54 | | -struct http_entity { |
55 | | - union { |
56 | | - /* response-only data */ |
57 | | - struct { |
58 | | - int status; |
59 | | - const char *status_str; |
60 | | - } response; |
61 | | - /* request-only data */ |
62 | | - struct { |
63 | | - int reqtype; |
64 | | - char *path; |
65 | | - /* |
66 | | - * Interesting headers. |
67 | | - */ |
68 | | - char *host; /* Host */ |
69 | | - int contlen; /* Content-Length */ |
70 | | - } request; |
71 | | - } he_rdata; |
72 | | - |
73 | | -struct header_list he_headers; |
74 | | - int he_source_type; |
75 | | - |
76 | | - union { |
77 | | - /* buffer data */ |
78 | | - struct { |
79 | | - const char *addr; |
80 | | - int len; |
81 | | - } buffer; |
82 | | - /* sendfile data */ |
83 | | - struct { |
84 | | - int fd; |
85 | | - size_t size; |
86 | | - off_t off; |
87 | | - } fd; |
88 | | - /* fde data */ |
89 | | - struct { |
90 | | - struct fde *fde; |
91 | | - int len; /* or -1 */ |
92 | | - int _wrt; /* amount left to write */ |
93 | | - } fde; |
94 | | - } he_source; |
95 | | - |
96 | | - struct { |
97 | | - int cachable:1; |
98 | | - int response:1; |
99 | | - int error:1; |
100 | | - } he_flags; |
101 | | - |
102 | | - /* |
103 | | - * If you want a callback when each piece of data is written, set this. |
104 | | - * This only works when sending from an FDE, not when using a buffer |
105 | | - * (if you use a buffer, you already have the data...) |
106 | | - */ |
107 | | - cache_callback he_cache_callback; |
108 | | - void *he_cache_callback_data; |
109 | | - |
110 | | - /* |
111 | | - * This is internal to whttp_entity. Don't touch it. |
112 | | - */ |
113 | | - void *_he_cbdata; |
114 | | - header_cb _he_func; |
115 | | - char *_he_hdrbuf; |
116 | | - char _he_rdbuf[8192]; /* does this really need to be here? */ |
117 | | -struct fde *_he_target; |
118 | | - int _he_state; |
119 | | - pthread_t _he_thread; |
120 | | - char *_he_lastname; |
121 | | - char *_he_valstart; |
122 | | -}; |
123 | | - |
124 | | -void entity_read_headers(struct http_entity *, header_cb, void *); |
125 | | -void entity_send(struct fde *, struct http_entity *, header_cb, void *); |
126 | | -void entity_free(struct http_entity *); |
127 | | - |
128 | | -void header_add(struct header_list *, const char *, const char *); |
129 | | - |
130 | | -void header_free(struct header_list *); |
131 | | -char *header_build(struct header_list *); |
132 | | -void header_remove(struct header_list *, struct header_list *); |
133 | | -void header_dump(struct header_list *, int); |
134 | | -int header_undump(struct header_list *, int, off_t *); |
135 | | - |
136 | | -#endif |
Index: trunk/willow/src/wnet_epoll.c |
— | — | @@ -1,136 +0,0 @@ |
2 | | -/* @(#) $Header$ */ |
3 | | -/* This source code is in the public domain. */ |
4 | | -/* |
5 | | - * Willow: Lightweight HTTP reverse-proxy. |
6 | | - * wnet: Networking. |
7 | | - */ |
8 | | - |
9 | | -#if defined __SUNPRO_C || defined __DECC || defined __HP_cc |
10 | | -# pragma ident "@(#)$Header$" |
11 | | -#endif |
12 | | - |
13 | | -#include <sys/types.h> |
14 | | -#include <sys/socket.h> |
15 | | - |
16 | | -#include <arpa/inet.h> |
17 | | - |
18 | | -#include <stdio.h> |
19 | | -#include <string.h> |
20 | | -#include <stdlib.h> |
21 | | -#include <unistd.h> |
22 | | -#include <errno.h> |
23 | | -#include <assert.h> |
24 | | -#include <fcntl.h> |
25 | | -#include <signal.h> |
26 | | -#include <sys/epoll.h> |
27 | | - |
28 | | -#include "willow.h" |
29 | | -#include "wnet.h" |
30 | | -#include "wconfig.h" |
31 | | -#include "wlog.h" |
32 | | -#include "whttp.h" |
33 | | - |
34 | | -static int epfd; |
35 | | - |
36 | | -void |
37 | | -wnet_init_select(void) |
38 | | -{ |
39 | | - int i; |
40 | | - |
41 | | - signal(SIGPIPE, SIG_IGN); |
42 | | - |
43 | | - if ((epfd = epoll_create(MAX_FD)) < 0) { |
44 | | - perror("epoll_create"); |
45 | | - exit(8); |
46 | | - } |
47 | | -} |
48 | | - |
49 | | -void |
50 | | -wnet_run(void) |
51 | | -{ |
52 | | - int i, n; |
53 | | -struct epoll_event events[256]; |
54 | | - |
55 | | - while ((i = epoll_wait(epfd, events, 256, -1)) != -1) { |
56 | | - wnet_set_time(); |
57 | | - |
58 | | - for (n = 0; n < i; ++n) { |
59 | | - struct fde *e = &fde_table[events[n].data.fd]; |
60 | | - struct epoll_event ev; |
61 | | - assert(events[n].data.fd < MAX_FD); |
62 | | - |
63 | | - e->fde_epflags &= ~events[n].events; |
64 | | - ev.events = e->fde_epflags; |
65 | | - ev.data.fd = e->fde_fd; |
66 | | - if (e->fde_epflags == 0) { |
67 | | - if (epoll_ctl(epfd, EPOLL_CTL_DEL, e->fde_fd, NULL) < 0) { |
68 | | - perror("epoll_ctl(DEL)"); |
69 | | - exit(8); |
70 | | - } |
71 | | - } else { |
72 | | - if (epoll_ctl(epfd, EPOLL_CTL_MOD, e->fde_fd, &ev) < 0) { |
73 | | - perror("epoll_ctl(MOD)"); |
74 | | - exit(8); |
75 | | - } |
76 | | - } |
77 | | - |
78 | | - if ((events[n].events & EPOLLIN) && e->fde_read_handler) { |
79 | | - int ret = e->fde_read_handler(e); |
80 | | - if (ret == 0) |
81 | | - wnet_register(e->fde_fd, FDE_READ, e->fde_read_handler, NULL); |
82 | | - } |
83 | | - |
84 | | - if ((events[n].events & EPOLLOUT) && e->fde_write_handler) { |
85 | | - int ret = e->fde_write_handler(e); |
86 | | - if (ret == 0) |
87 | | - wnet_register(e->fde_fd, FDE_WRITE, e->fde_write_handler, NULL); |
88 | | - } |
89 | | - } |
90 | | - } |
91 | | - perror("epoll_wait"); |
92 | | -} |
93 | | - |
94 | | -void |
95 | | -wnet_register(fd, what, handler, data) |
96 | | - fdcb handler; |
97 | | - void *data; |
98 | | -{ |
99 | | -struct fde *e = &fde_table[fd]; |
100 | | - int flags = e->fde_epflags, mod = flags; |
101 | | -struct epoll_event ev; |
102 | | - |
103 | | - assert(fd < MAX_FD); |
104 | | - |
105 | | - if (handler == NULL) { |
106 | | - epoll_ctl(epfd, EPOLL_CTL_DEL, fd, NULL); |
107 | | - return; |
108 | | - } |
109 | | - |
110 | | - e->fde_fd = fd; |
111 | | - if (what & FDE_READ) { |
112 | | - e->fde_read_handler = handler; |
113 | | - e->fde_epflags |= EPOLLIN; |
114 | | - } |
115 | | - if (what & FDE_WRITE) { |
116 | | - e->fde_write_handler = handler; |
117 | | - e->fde_epflags |= EPOLLOUT; |
118 | | - } |
119 | | - |
120 | | - if (data) |
121 | | - e->fde_rdata = data; |
122 | | - |
123 | | - bzero(&ev, sizeof(ev)); |
124 | | - ev.events = e->fde_epflags; |
125 | | - ev.data.fd = fd; |
126 | | - if (mod) { |
127 | | - if (epoll_ctl(epfd, EPOLL_CTL_MOD, fd, &ev) < 0) { |
128 | | - perror("epoll_ctl"); |
129 | | - exit(8); |
130 | | - } |
131 | | - } else { |
132 | | - if (epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev) < 0) { |
133 | | - perror("epoll_ctl"); |
134 | | - exit(8); |
135 | | - } |
136 | | - } |
137 | | -} |
Index: trunk/willow/src/wlog.c |
— | — | @@ -1,116 +0,0 @@ |
2 | | -/* @(#) $Header$ */ |
3 | | -/* This source code is in the public domain. */ |
4 | | -/* |
5 | | - * Willow: Lightweight HTTP reverse-proxy. |
6 | | - * wlog: logging. |
7 | | - */ |
8 | | - |
9 | | -#if defined __SUNPRO_C || defined __DECC || defined __HP_cc |
10 | | -# pragma ident "@(#)$Header$" |
11 | | -#endif |
12 | | - |
13 | | -#include <stdio.h> |
14 | | -#include <stdarg.h> |
15 | | -#include <stdlib.h> |
16 | | -#include <stdarg.h> |
17 | | -#include <string.h> |
18 | | -#include <syslog.h> |
19 | | -#include <errno.h> |
20 | | - |
21 | | -#include "config.h" |
22 | | -#ifdef THREADED_IO |
23 | | -# include <pthread.h> |
24 | | -#endif |
25 | | - |
26 | | -#include "wlog.h" |
27 | | -#include "wnet.h" |
28 | | -#include "wconfig.h" |
29 | | - |
30 | | -#ifdef THREADED_IO |
31 | | -static pthread_mutex_t wlog_mtx = PTHREAD_MUTEX_INITIALIZER; |
32 | | -# define WLOG_LOCK() pthread_mutex_lock(&wlog_mtx) |
33 | | -# define WLOG_UNLOCK() pthread_mutex_unlock(&wlog_mtx) |
34 | | -#else |
35 | | -# define WLOG_LOCK() |
36 | | -# define WLOG_UNLOCK() |
37 | | -#endif |
38 | | - |
39 | | -struct log_variables logging; |
40 | | - |
41 | | -static const char *sev_names[] = { |
42 | | - "Debug", |
43 | | - "Notice", |
44 | | - "Warning", |
45 | | - "Error", |
46 | | -}; |
47 | | - |
48 | | -static const int syslog_pri[] = { |
49 | | - LOG_INFO, |
50 | | - LOG_WARNING, |
51 | | - LOG_ERR, |
52 | | -}; |
53 | | - |
54 | | -void |
55 | | -wlog_init(void) |
56 | | -{ |
57 | | - if (logging.syslog) |
58 | | - openlog("willow", LOG_PID, logging.facility); |
59 | | - |
60 | | - if (!logging.file) |
61 | | - return; |
62 | | - |
63 | | - /*LINTED unsafe fopen*/ |
64 | | - logging.fp = fopen(logging.file, "a"); |
65 | | - if (logging.fp == NULL) { |
66 | | - perror(logging.file); |
67 | | - exit(8); |
68 | | - } |
69 | | -} |
70 | | - |
71 | | -void |
72 | | -wlog(int sev, const char *fmt, ...) |
73 | | -{ |
74 | | - char s[1024]; |
75 | | - va_list ap; |
76 | | - int i; |
77 | | - |
78 | | - if (sev > WLOG_MAX) |
79 | | - sev = WLOG_NOTICE; |
80 | | - if (sev < logging.level) |
81 | | - return; |
82 | | - va_start(ap, fmt); |
83 | | - i = snprintf(s, 1024, "%s| %s: ", current_time_short, sev_names[sev]); |
84 | | - if (i > 1023) |
85 | | - abort(); |
86 | | - if (vsnprintf(s + i, 1023 - i, fmt, ap) > (1023 - i - 1)) |
87 | | - abort(); |
88 | | - |
89 | | - WLOG_LOCK(); |
90 | | - if (logging.syslog) |
91 | | - syslog(syslog_pri[sev], "%s", s + i); |
92 | | - if (logging.fp) { |
93 | | - if (fprintf(logging.fp, "%s\n", s) < 0) { |
94 | | - (void)fclose(logging.fp); |
95 | | - logging.fp = NULL; |
96 | | - wlog(WLOG_ERROR, "writing to logfile: %s", strerror(errno)); |
97 | | - exit(8); |
98 | | - } |
99 | | - } |
100 | | - |
101 | | - if (config.foreground) |
102 | | - (void)fprintf(stderr, "%s\n", s); |
103 | | - WLOG_UNLOCK(); |
104 | | - va_end(ap); |
105 | | -} |
106 | | - |
107 | | -void |
108 | | -wlog_close(void) |
109 | | -{ |
110 | | - if (fclose(logging.fp) == EOF) { |
111 | | - logging.fp = NULL; |
112 | | - wlog(WLOG_WARNING, "closing logfile: %s", strerror(errno)); |
113 | | - } |
114 | | - |
115 | | - if (logging.syslog) |
116 | | - closelog(); |
117 | | -} |
Index: trunk/willow/src/wlogwriter.h |
— | — | @@ -1,17 +0,0 @@ |
2 | | -/* @(#) $Header$ */ |
3 | | -/* This source code is in the public domain. */ |
4 | | -/* |
5 | | - * Willow: Lightweight HTTP reverse-proxy. |
6 | | - * wlogwriter: child process for log writing. |
7 | | - */ |
8 | | - |
9 | | -#ifndef WLOGWRITER_H |
10 | | -#define WLOGWRITER_H |
11 | | - |
12 | | -#if defined __SUNPRO_C || defined __DECC || defined __HP_cc |
13 | | -# pragma ident "@(#)$Header$" |
14 | | -#endif |
15 | | - |
16 | | -void wlogwriter_start(int *); |
17 | | - |
18 | | -#endif |
Index: trunk/willow/src/include/whttp_entity.h |
— | — | @@ -0,0 +1,135 @@ |
| 2 | +/* @(#) $Header$ */ |
| 3 | +/* This source code is in the public domain. */ |
| 4 | +/* |
| 5 | + * Willow: Lightweight HTTP reverse-proxy. |
| 6 | + * whttp_entity: HTTP entity handling. |
| 7 | + */ |
| 8 | + |
| 9 | +#ifndef WHTTP_ENTITY |
| 10 | +#define WHTTP_ENTITY |
| 11 | + |
| 12 | +#if defined __SUNPRO_C || defined __DECC || defined __HP_cc |
| 13 | +# pragma ident "@(#)$Header$" |
| 14 | +#endif |
| 15 | + |
| 16 | +#ifdef THREADED_IO |
| 17 | +# include <pthread.h> |
| 18 | +#endif |
| 19 | + |
| 20 | +#include "whttp.h" |
| 21 | + |
| 22 | +#define ENT_SOURCE_BUFFER 1 |
| 23 | +#define ENT_SOURCE_FDE 2 |
| 24 | +#define ENT_SOURCE_NONE 3 |
| 25 | +#define ENT_SOURCE_FILE 4 |
| 26 | + |
| 27 | +#define REQTYPE_GET 0 |
| 28 | +#define REQTYPE_POST 1 |
| 29 | +#define REQTYPE_HEAD 2 |
| 30 | +#define REQTYPE_TRACE 3 |
| 31 | +#define REQTYPE_OPTIONS 4 |
| 32 | +#define REQTYPE_INVALID -1 |
| 33 | + |
| 34 | +#define MAX_HEADERS 64 /* maximum # of headers to allow */ |
| 35 | + |
| 36 | +struct http_entity; |
| 37 | +struct http_client; |
| 38 | + |
| 39 | +typedef void (*header_cb)(struct http_entity *, void *, int); |
| 40 | +typedef void (*cache_callback)(const char *, size_t, void *); |
| 41 | + |
| 42 | +#define HDR_ALLOCED 1 |
| 43 | + |
| 44 | +struct header_list { |
| 45 | +const char *hl_name; |
| 46 | +const char *hl_value; |
| 47 | +struct header_list *hl_next; |
| 48 | +struct header_list *hl_tail; |
| 49 | + int hl_len; |
| 50 | + int hl_num; |
| 51 | + int hl_flags; |
| 52 | +}; |
| 53 | + |
| 54 | +struct http_entity { |
| 55 | + union { |
| 56 | + /* response-only data */ |
| 57 | + struct { |
| 58 | + int status; |
| 59 | + const char *status_str; |
| 60 | + } response; |
| 61 | + /* request-only data */ |
| 62 | + struct { |
| 63 | + int reqtype; |
| 64 | + char *path; |
| 65 | + /* |
| 66 | + * Interesting headers. |
| 67 | + */ |
| 68 | + char *host; /* Host */ |
| 69 | + int contlen; /* Content-Length */ |
| 70 | + } request; |
| 71 | + } he_rdata; |
| 72 | + |
| 73 | +struct header_list he_headers; |
| 74 | + int he_source_type; |
| 75 | + |
| 76 | + union { |
| 77 | + /* buffer data */ |
| 78 | + struct { |
| 79 | + const char *addr; |
| 80 | + int len; |
| 81 | + } buffer; |
| 82 | + /* sendfile data */ |
| 83 | + struct { |
| 84 | + int fd; |
| 85 | + size_t size; |
| 86 | + off_t off; |
| 87 | + } fd; |
| 88 | + /* fde data */ |
| 89 | + struct { |
| 90 | + struct fde *fde; |
| 91 | + int len; /* or -1 */ |
| 92 | + int _wrt; /* amount left to write */ |
| 93 | + } fde; |
| 94 | + } he_source; |
| 95 | + |
| 96 | + struct { |
| 97 | + int cachable:1; |
| 98 | + int response:1; |
| 99 | + int error:1; |
| 100 | + } he_flags; |
| 101 | + |
| 102 | + /* |
| 103 | + * If you want a callback when each piece of data is written, set this. |
| 104 | + * This only works when sending from an FDE, not when using a buffer |
| 105 | + * (if you use a buffer, you already have the data...) |
| 106 | + */ |
| 107 | + cache_callback he_cache_callback; |
| 108 | + void *he_cache_callback_data; |
| 109 | + |
| 110 | + /* |
| 111 | + * This is internal to whttp_entity. Don't touch it. |
| 112 | + */ |
| 113 | + void *_he_cbdata; |
| 114 | + header_cb _he_func; |
| 115 | + char *_he_hdrbuf; |
| 116 | + char _he_rdbuf[8192]; /* does this really need to be here? */ |
| 117 | +struct fde *_he_target; |
| 118 | + int _he_state; |
| 119 | + pthread_t _he_thread; |
| 120 | + char *_he_lastname; |
| 121 | + char *_he_valstart; |
| 122 | +}; |
| 123 | + |
| 124 | +void entity_read_headers(struct http_entity *, header_cb, void *); |
| 125 | +void entity_send(struct fde *, struct http_entity *, header_cb, void *); |
| 126 | +void entity_free(struct http_entity *); |
| 127 | + |
| 128 | +void header_add(struct header_list *, const char *, const char *); |
| 129 | + |
| 130 | +void header_free(struct header_list *); |
| 131 | +char *header_build(struct header_list *); |
| 132 | +void header_remove(struct header_list *, struct header_list *); |
| 133 | +void header_dump(struct header_list *, int); |
| 134 | +int header_undump(struct header_list *, int, off_t *); |
| 135 | + |
| 136 | +#endif |
Property changes on: trunk/willow/src/include/whttp_entity.h |
___________________________________________________________________ |
Added: svn:keywords |
1 | 137 | + Author Date Id Revision |
Added: svn:eol-style |
2 | 138 | + native |
Index: trunk/willow/src/include/queue.h |
— | — | @@ -0,0 +1,517 @@ |
| 2 | +/* @(#) $Header$ */ |
| 3 | +/* From: @(#)queue.h 8.5 (Berkeley) 8/20/94 */ |
| 4 | +/* From: $FreeBSD: src/sys/sys/queue.h,v 1.58 2004/04/07 04:19:49 imp Exp $ */ |
| 5 | + |
| 6 | +/* |
| 7 | + * Copyright (c) 1991, 1993 |
| 8 | + * The Regents of the University of California. All rights reserved. |
| 9 | + * |
| 10 | + * Redistribution and use in source and binary forms, with or without |
| 11 | + * modification, are permitted provided that the following conditions |
| 12 | + * are met: |
| 13 | + * 1. Redistributions of source code must retain the above copyright |
| 14 | + * notice, this list of conditions and the following disclaimer. |
| 15 | + * 2. Redistributions in binary form must reproduce the above copyright |
| 16 | + * notice, this list of conditions and the following disclaimer in the |
| 17 | + * documentation and/or other materials provided with the distribution. |
| 18 | + * 4. Neither the name of the University nor the names of its contributors |
| 19 | + * may be used to endorse or promote products derived from this software |
| 20 | + * without specific prior written permission. |
| 21 | + * |
| 22 | + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
| 23 | + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| 24 | + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| 25 | + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
| 26 | + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
| 27 | + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
| 28 | + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
| 29 | + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
| 30 | + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
| 31 | + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
| 32 | + * SUCH DAMAGE. |
| 33 | + * |
| 34 | + */ |
| 35 | + |
| 36 | +#ifndef QUEUE_H |
| 37 | +#define QUEUE_H |
| 38 | + |
| 39 | +#if defined __SUNPRO_C || defined __DECC || defined __HP_cc |
| 40 | +# pragma ident "@(#)$Header$" |
| 41 | +#endif |
| 42 | + |
| 43 | +#include "config.h" |
| 44 | +#ifdef HAVE_SYS_QUEUE_H |
| 45 | +# include <sys/queue.h> |
| 46 | +#else |
| 47 | + |
| 48 | +/* |
| 49 | + * This file defines four types of data structures: singly-linked lists, |
| 50 | + * singly-linked tail queues, lists and tail queues. |
| 51 | + * |
| 52 | + * A singly-linked list is headed by a single forward pointer. The elements |
| 53 | + * are singly linked for minimum space and pointer manipulation overhead at |
| 54 | + * the expense of O(n) removal for arbitrary elements. New elements can be |
| 55 | + * added to the list after an existing element or at the head of the list. |
| 56 | + * Elements being removed from the head of the list should use the explicit |
| 57 | + * macro for this purpose for optimum efficiency. A singly-linked list may |
| 58 | + * only be traversed in the forward direction. Singly-linked lists are ideal |
| 59 | + * for applications with large datasets and few or no removals or for |
| 60 | + * implementing a LIFO queue. |
| 61 | + * |
| 62 | + * A singly-linked tail queue is headed by a pair of pointers, one to the |
| 63 | + * head of the list and the other to the tail of the list. The elements are |
| 64 | + * singly linked for minimum space and pointer manipulation overhead at the |
| 65 | + * expense of O(n) removal for arbitrary elements. New elements can be added |
| 66 | + * to the list after an existing element, at the head of the list, or at the |
| 67 | + * end of the list. Elements being removed from the head of the tail queue |
| 68 | + * should use the explicit macro for this purpose for optimum efficiency. |
| 69 | + * A singly-linked tail queue may only be traversed in the forward direction. |
| 70 | + * Singly-linked tail queues are ideal for applications with large datasets |
| 71 | + * and few or no removals or for implementing a FIFO queue. |
| 72 | + * |
| 73 | + * A list is headed by a single forward pointer (or an array of forward |
| 74 | + * pointers for a hash table header). The elements are doubly linked |
| 75 | + * so that an arbitrary element can be removed without a need to |
| 76 | + * traverse the list. New elements can be added to the list before |
| 77 | + * or after an existing element or at the head of the list. A list |
| 78 | + * may only be traversed in the forward direction. |
| 79 | + * |
| 80 | + * A tail queue is headed by a pair of pointers, one to the head of the |
| 81 | + * list and the other to the tail of the list. The elements are doubly |
| 82 | + * linked so that an arbitrary element can be removed without a need to |
| 83 | + * traverse the list. New elements can be added to the list before or |
| 84 | + * after an existing element, at the head of the list, or at the end of |
| 85 | + * the list. A tail queue may be traversed in either direction. |
| 86 | + * |
| 87 | + * For details on the use of these macros, see the queue(3) manual page. |
| 88 | + * |
| 89 | + * |
| 90 | + * SLIST LIST STAILQ TAILQ |
| 91 | + * _HEAD + + + + |
| 92 | + * _HEAD_INITIALIZER + + + + |
| 93 | + * _ENTRY + + + + |
| 94 | + * _INIT + + + + |
| 95 | + * _EMPTY + + + + |
| 96 | + * _FIRST + + + + |
| 97 | + * _NEXT + + + + |
| 98 | + * _PREV - - - + |
| 99 | + * _LAST - - + + |
| 100 | + * _FOREACH + + + + |
| 101 | + * _FOREACH_SAFE + + + + |
| 102 | + * _FOREACH_REVERSE - - - + |
| 103 | + * _FOREACH_REVERSE_SAFE - - - + |
| 104 | + * _INSERT_HEAD + + + + |
| 105 | + * _INSERT_BEFORE - + - + |
| 106 | + * _INSERT_AFTER + + + + |
| 107 | + * _INSERT_TAIL - - + + |
| 108 | + * _CONCAT - - + + |
| 109 | + * _REMOVE_HEAD + - + - |
| 110 | + * _REMOVE + + + + |
| 111 | + * |
| 112 | + */ |
| 113 | +#define QUEUE_MACRO_DEBUG 0 |
| 114 | +#if QUEUE_MACRO_DEBUG |
| 115 | +/* Store the last 2 places the queue element or head was altered */ |
| 116 | +struct qm_trace { |
| 117 | + char * lastfile; |
| 118 | + int lastline; |
| 119 | + char * prevfile; |
| 120 | + int prevline; |
| 121 | +}; |
| 122 | + |
| 123 | +#define TRACEBUF struct qm_trace trace; |
| 124 | +#define TRASHIT(x) do {(x) = (void *)-1;} while (0) |
| 125 | + |
| 126 | +#define QMD_TRACE_HEAD(head) do { \ |
| 127 | + (head)->trace.prevline = (head)->trace.lastline; \ |
| 128 | + (head)->trace.prevfile = (head)->trace.lastfile; \ |
| 129 | + (head)->trace.lastline = __LINE__; \ |
| 130 | + (head)->trace.lastfile = __FILE__; \ |
| 131 | +} while (0) |
| 132 | + |
| 133 | +#define QMD_TRACE_ELEM(elem) do { \ |
| 134 | + (elem)->trace.prevline = (elem)->trace.lastline; \ |
| 135 | + (elem)->trace.prevfile = (elem)->trace.lastfile; \ |
| 136 | + (elem)->trace.lastline = __LINE__; \ |
| 137 | + (elem)->trace.lastfile = __FILE__; \ |
| 138 | +} while (0) |
| 139 | + |
| 140 | +#else |
| 141 | +#define QMD_TRACE_ELEM(elem) |
| 142 | +#define QMD_TRACE_HEAD(head) |
| 143 | +#define TRACEBUF |
| 144 | +#define TRASHIT(x) |
| 145 | +#endif /* QUEUE_MACRO_DEBUG */ |
| 146 | + |
| 147 | +/* |
| 148 | + * Singly-linked List declarations. |
| 149 | + */ |
| 150 | +#define SLIST_HEAD(name, type) \ |
| 151 | +struct name { \ |
| 152 | + struct type *slh_first; /* first element */ \ |
| 153 | +} |
| 154 | + |
| 155 | +#define SLIST_HEAD_INITIALIZER(head) \ |
| 156 | + { NULL } |
| 157 | + |
| 158 | +#define SLIST_ENTRY(type) \ |
| 159 | +struct { \ |
| 160 | + struct type *sle_next; /* next element */ \ |
| 161 | +} |
| 162 | + |
| 163 | +/* |
| 164 | + * Singly-linked List functions. |
| 165 | + */ |
| 166 | +#define SLIST_EMPTY(head) ((head)->slh_first == NULL) |
| 167 | + |
| 168 | +#define SLIST_FIRST(head) ((head)->slh_first) |
| 169 | + |
| 170 | +#define SLIST_FOREACH(var, head, field) \ |
| 171 | + for ((var) = SLIST_FIRST((head)); \ |
| 172 | + (var); \ |
| 173 | + (var) = SLIST_NEXT((var), field)) |
| 174 | + |
| 175 | +#define SLIST_FOREACH_SAFE(var, head, field, tvar) \ |
| 176 | + for ((var) = SLIST_FIRST((head)); \ |
| 177 | + (var) && ((tvar) = SLIST_NEXT((var), field), 1); \ |
| 178 | + (var) = (tvar)) |
| 179 | + |
| 180 | +#define SLIST_FOREACH_PREVPTR(var, varp, head, field) \ |
| 181 | + for ((varp) = &SLIST_FIRST((head)); \ |
| 182 | + ((var) = *(varp)) != NULL; \ |
| 183 | + (varp) = &SLIST_NEXT((var), field)) |
| 184 | + |
| 185 | +#define SLIST_INIT(head) do { \ |
| 186 | + SLIST_FIRST((head)) = NULL; \ |
| 187 | +} while (0) |
| 188 | + |
| 189 | +#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \ |
| 190 | + SLIST_NEXT((elm), field) = SLIST_NEXT((slistelm), field); \ |
| 191 | + SLIST_NEXT((slistelm), field) = (elm); \ |
| 192 | +} while (0) |
| 193 | + |
| 194 | +#define SLIST_INSERT_HEAD(head, elm, field) do { \ |
| 195 | + SLIST_NEXT((elm), field) = SLIST_FIRST((head)); \ |
| 196 | + SLIST_FIRST((head)) = (elm); \ |
| 197 | +} while (0) |
| 198 | + |
| 199 | +#define SLIST_NEXT(elm, field) ((elm)->field.sle_next) |
| 200 | + |
| 201 | +#define SLIST_REMOVE(head, elm, type, field) do { \ |
| 202 | + if (SLIST_FIRST((head)) == (elm)) { \ |
| 203 | + SLIST_REMOVE_HEAD((head), field); \ |
| 204 | + } \ |
| 205 | + else { \ |
| 206 | + struct type *curelm = SLIST_FIRST((head)); \ |
| 207 | + while (SLIST_NEXT(curelm, field) != (elm)) \ |
| 208 | + curelm = SLIST_NEXT(curelm, field); \ |
| 209 | + SLIST_NEXT(curelm, field) = \ |
| 210 | + SLIST_NEXT(SLIST_NEXT(curelm, field), field); \ |
| 211 | + } \ |
| 212 | +} while (0) |
| 213 | + |
| 214 | +#define SLIST_REMOVE_HEAD(head, field) do { \ |
| 215 | + SLIST_FIRST((head)) = SLIST_NEXT(SLIST_FIRST((head)), field); \ |
| 216 | +} while (0) |
| 217 | + |
| 218 | +/* |
| 219 | + * Singly-linked Tail queue declarations. |
| 220 | + */ |
| 221 | +#define STAILQ_HEAD(name, type) \ |
| 222 | +struct name { \ |
| 223 | + struct type *stqh_first;/* first element */ \ |
| 224 | + struct type **stqh_last;/* addr of last next element */ \ |
| 225 | +} |
| 226 | + |
| 227 | +#define STAILQ_HEAD_INITIALIZER(head) \ |
| 228 | + { NULL, &(head).stqh_first } |
| 229 | + |
| 230 | +#define STAILQ_ENTRY(type) \ |
| 231 | +struct { \ |
| 232 | + struct type *stqe_next; /* next element */ \ |
| 233 | +} |
| 234 | + |
| 235 | +/* |
| 236 | + * Singly-linked Tail queue functions. |
| 237 | + */ |
| 238 | +#define STAILQ_CONCAT(head1, head2) do { \ |
| 239 | + if (!STAILQ_EMPTY((head2))) { \ |
| 240 | + *(head1)->stqh_last = (head2)->stqh_first; \ |
| 241 | + (head1)->stqh_last = (head2)->stqh_last; \ |
| 242 | + STAILQ_INIT((head2)); \ |
| 243 | + } \ |
| 244 | +} while (0) |
| 245 | + |
| 246 | +#define STAILQ_EMPTY(head) ((head)->stqh_first == NULL) |
| 247 | + |
| 248 | +#define STAILQ_FIRST(head) ((head)->stqh_first) |
| 249 | + |
| 250 | +#define STAILQ_FOREACH(var, head, field) \ |
| 251 | + for((var) = STAILQ_FIRST((head)); \ |
| 252 | + (var); \ |
| 253 | + (var) = STAILQ_NEXT((var), field)) |
| 254 | + |
| 255 | + |
| 256 | +#define STAILQ_FOREACH_SAFE(var, head, field, tvar) \ |
| 257 | + for ((var) = STAILQ_FIRST((head)); \ |
| 258 | + (var) && ((tvar) = STAILQ_NEXT((var), field), 1); \ |
| 259 | + (var) = (tvar)) |
| 260 | + |
| 261 | +#define STAILQ_INIT(head) do { \ |
| 262 | + STAILQ_FIRST((head)) = NULL; \ |
| 263 | + (head)->stqh_last = &STAILQ_FIRST((head)); \ |
| 264 | +} while (0) |
| 265 | + |
| 266 | +#define STAILQ_INSERT_AFTER(head, tqelm, elm, field) do { \ |
| 267 | + if ((STAILQ_NEXT((elm), field) = STAILQ_NEXT((tqelm), field)) == NULL)\ |
| 268 | + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ |
| 269 | + STAILQ_NEXT((tqelm), field) = (elm); \ |
| 270 | +} while (0) |
| 271 | + |
| 272 | +#define STAILQ_INSERT_HEAD(head, elm, field) do { \ |
| 273 | + if ((STAILQ_NEXT((elm), field) = STAILQ_FIRST((head))) == NULL) \ |
| 274 | + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ |
| 275 | + STAILQ_FIRST((head)) = (elm); \ |
| 276 | +} while (0) |
| 277 | + |
| 278 | +#define STAILQ_INSERT_TAIL(head, elm, field) do { \ |
| 279 | + STAILQ_NEXT((elm), field) = NULL; \ |
| 280 | + *(head)->stqh_last = (elm); \ |
| 281 | + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ |
| 282 | +} while (0) |
| 283 | + |
| 284 | +#define STAILQ_LAST(head, type, field) \ |
| 285 | + (STAILQ_EMPTY((head)) ? \ |
| 286 | + NULL : \ |
| 287 | + ((struct type *) \ |
| 288 | + ((char *)((head)->stqh_last) - __offsetof(struct type, field)))) |
| 289 | + |
| 290 | +#define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next) |
| 291 | + |
| 292 | +#define STAILQ_REMOVE(head, elm, type, field) do { \ |
| 293 | + if (STAILQ_FIRST((head)) == (elm)) { \ |
| 294 | + STAILQ_REMOVE_HEAD((head), field); \ |
| 295 | + } \ |
| 296 | + else { \ |
| 297 | + struct type *curelm = STAILQ_FIRST((head)); \ |
| 298 | + while (STAILQ_NEXT(curelm, field) != (elm)) \ |
| 299 | + curelm = STAILQ_NEXT(curelm, field); \ |
| 300 | + if ((STAILQ_NEXT(curelm, field) = \ |
| 301 | + STAILQ_NEXT(STAILQ_NEXT(curelm, field), field)) == NULL)\ |
| 302 | + (head)->stqh_last = &STAILQ_NEXT((curelm), field);\ |
| 303 | + } \ |
| 304 | +} while (0) |
| 305 | + |
| 306 | +#define STAILQ_REMOVE_HEAD(head, field) do { \ |
| 307 | + if ((STAILQ_FIRST((head)) = \ |
| 308 | + STAILQ_NEXT(STAILQ_FIRST((head)), field)) == NULL) \ |
| 309 | + (head)->stqh_last = &STAILQ_FIRST((head)); \ |
| 310 | +} while (0) |
| 311 | + |
| 312 | +#define STAILQ_REMOVE_HEAD_UNTIL(head, elm, field) do { \ |
| 313 | + if ((STAILQ_FIRST((head)) = STAILQ_NEXT((elm), field)) == NULL) \ |
| 314 | + (head)->stqh_last = &STAILQ_FIRST((head)); \ |
| 315 | +} while (0) |
| 316 | + |
| 317 | +/* |
| 318 | + * List declarations. |
| 319 | + */ |
| 320 | +#define LIST_HEAD(name, type) \ |
| 321 | +struct name { \ |
| 322 | + struct type *lh_first; /* first element */ \ |
| 323 | +} |
| 324 | + |
| 325 | +#define LIST_HEAD_INITIALIZER(head) \ |
| 326 | + { NULL } |
| 327 | + |
| 328 | +#define LIST_ENTRY(type) \ |
| 329 | +struct { \ |
| 330 | + struct type *le_next; /* next element */ \ |
| 331 | + struct type **le_prev; /* address of previous next element */ \ |
| 332 | +} |
| 333 | + |
| 334 | +/* |
| 335 | + * List functions. |
| 336 | + */ |
| 337 | + |
| 338 | +#define LIST_EMPTY(head) ((head)->lh_first == NULL) |
| 339 | + |
| 340 | +#define LIST_FIRST(head) ((head)->lh_first) |
| 341 | + |
| 342 | +#define LIST_FOREACH(var, head, field) \ |
| 343 | + for ((var) = LIST_FIRST((head)); \ |
| 344 | + (var); \ |
| 345 | + (var) = LIST_NEXT((var), field)) |
| 346 | + |
| 347 | +#define LIST_FOREACH_SAFE(var, head, field, tvar) \ |
| 348 | + for ((var) = LIST_FIRST((head)); \ |
| 349 | + (var) && ((tvar) = LIST_NEXT((var), field), 1); \ |
| 350 | + (var) = (tvar)) |
| 351 | + |
| 352 | +#define LIST_INIT(head) do { \ |
| 353 | + LIST_FIRST((head)) = NULL; \ |
| 354 | +} while (0) |
| 355 | + |
| 356 | +#define LIST_INSERT_AFTER(listelm, elm, field) do { \ |
| 357 | + if ((LIST_NEXT((elm), field) = LIST_NEXT((listelm), field)) != NULL)\ |
| 358 | + LIST_NEXT((listelm), field)->field.le_prev = \ |
| 359 | + &LIST_NEXT((elm), field); \ |
| 360 | + LIST_NEXT((listelm), field) = (elm); \ |
| 361 | + (elm)->field.le_prev = &LIST_NEXT((listelm), field); \ |
| 362 | +} while (0) |
| 363 | + |
| 364 | +#define LIST_INSERT_BEFORE(listelm, elm, field) do { \ |
| 365 | + (elm)->field.le_prev = (listelm)->field.le_prev; \ |
| 366 | + LIST_NEXT((elm), field) = (listelm); \ |
| 367 | + *(listelm)->field.le_prev = (elm); \ |
| 368 | + (listelm)->field.le_prev = &LIST_NEXT((elm), field); \ |
| 369 | +} while (0) |
| 370 | + |
| 371 | +#define LIST_INSERT_HEAD(head, elm, field) do { \ |
| 372 | + if ((LIST_NEXT((elm), field) = LIST_FIRST((head))) != NULL) \ |
| 373 | + LIST_FIRST((head))->field.le_prev = &LIST_NEXT((elm), field);\ |
| 374 | + LIST_FIRST((head)) = (elm); \ |
| 375 | + (elm)->field.le_prev = &LIST_FIRST((head)); \ |
| 376 | +} while (0) |
| 377 | + |
| 378 | +#define LIST_NEXT(elm, field) ((elm)->field.le_next) |
| 379 | + |
| 380 | +#define LIST_REMOVE(elm, field) do { \ |
| 381 | + if (LIST_NEXT((elm), field) != NULL) \ |
| 382 | + LIST_NEXT((elm), field)->field.le_prev = \ |
| 383 | + (elm)->field.le_prev; \ |
| 384 | + *(elm)->field.le_prev = LIST_NEXT((elm), field); \ |
| 385 | +} while (0) |
| 386 | + |
| 387 | +/* |
| 388 | + * Tail queue declarations. |
| 389 | + */ |
| 390 | +#define TAILQ_HEAD(name, type) \ |
| 391 | +struct name { \ |
| 392 | + struct type *tqh_first; /* first element */ \ |
| 393 | + struct type **tqh_last; /* addr of last next element */ \ |
| 394 | + TRACEBUF \ |
| 395 | +} |
| 396 | + |
| 397 | +#define TAILQ_HEAD_INITIALIZER(head) \ |
| 398 | + { NULL, &(head).tqh_first } |
| 399 | + |
| 400 | +#define TAILQ_ENTRY(type) \ |
| 401 | +struct { \ |
| 402 | + struct type *tqe_next; /* next element */ \ |
| 403 | + struct type **tqe_prev; /* address of previous next element */ \ |
| 404 | + TRACEBUF \ |
| 405 | +} |
| 406 | + |
| 407 | +/* |
| 408 | + * Tail queue functions. |
| 409 | + */ |
| 410 | +#define TAILQ_CONCAT(head1, head2, field) do { \ |
| 411 | + if (!TAILQ_EMPTY(head2)) { \ |
| 412 | + *(head1)->tqh_last = (head2)->tqh_first; \ |
| 413 | + (head2)->tqh_first->field.tqe_prev = (head1)->tqh_last; \ |
| 414 | + (head1)->tqh_last = (head2)->tqh_last; \ |
| 415 | + TAILQ_INIT((head2)); \ |
| 416 | + QMD_TRACE_HEAD(head); \ |
| 417 | + QMD_TRACE_HEAD(head2); \ |
| 418 | + } \ |
| 419 | +} while (0) |
| 420 | + |
| 421 | +#define TAILQ_EMPTY(head) ((head)->tqh_first == NULL) |
| 422 | + |
| 423 | +#define TAILQ_FIRST(head) ((head)->tqh_first) |
| 424 | + |
| 425 | +#define TAILQ_FOREACH(var, head, field) \ |
| 426 | + for ((var) = TAILQ_FIRST((head)); \ |
| 427 | + (var); \ |
| 428 | + (var) = TAILQ_NEXT((var), field)) |
| 429 | + |
| 430 | +#define TAILQ_FOREACH_SAFE(var, head, field, tvar) \ |
| 431 | + for ((var) = TAILQ_FIRST((head)); \ |
| 432 | + (var) && ((tvar) = TAILQ_NEXT((var), field), 1); \ |
| 433 | + (var) = (tvar)) |
| 434 | + |
| 435 | +#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \ |
| 436 | + for ((var) = TAILQ_LAST((head), headname); \ |
| 437 | + (var); \ |
| 438 | + (var) = TAILQ_PREV((var), headname, field)) |
| 439 | + |
| 440 | +#define TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \ |
| 441 | + for ((var) = TAILQ_LAST((head), headname); \ |
| 442 | + (var) && ((tvar) = TAILQ_PREV((var), headname, field), 1); \ |
| 443 | + (var) = (tvar)) |
| 444 | + |
| 445 | +#define TAILQ_INIT(head) do { \ |
| 446 | + TAILQ_FIRST((head)) = NULL; \ |
| 447 | + (head)->tqh_last = &TAILQ_FIRST((head)); \ |
| 448 | + QMD_TRACE_HEAD(head); \ |
| 449 | +} while (0) |
| 450 | + |
| 451 | +#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ |
| 452 | + if ((TAILQ_NEXT((elm), field) = TAILQ_NEXT((listelm), field)) != NULL)\ |
| 453 | + TAILQ_NEXT((elm), field)->field.tqe_prev = \ |
| 454 | + &TAILQ_NEXT((elm), field); \ |
| 455 | + else { \ |
| 456 | + (head)->tqh_last = &TAILQ_NEXT((elm), field); \ |
| 457 | + QMD_TRACE_HEAD(head); \ |
| 458 | + } \ |
| 459 | + TAILQ_NEXT((listelm), field) = (elm); \ |
| 460 | + (elm)->field.tqe_prev = &TAILQ_NEXT((listelm), field); \ |
| 461 | + QMD_TRACE_ELEM(&(elm)->field); \ |
| 462 | + QMD_TRACE_ELEM(&listelm->field); \ |
| 463 | +} while (0) |
| 464 | + |
| 465 | +#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ |
| 466 | + (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ |
| 467 | + TAILQ_NEXT((elm), field) = (listelm); \ |
| 468 | + *(listelm)->field.tqe_prev = (elm); \ |
| 469 | + (listelm)->field.tqe_prev = &TAILQ_NEXT((elm), field); \ |
| 470 | + QMD_TRACE_ELEM(&(elm)->field); \ |
| 471 | + QMD_TRACE_ELEM(&listelm->field); \ |
| 472 | +} while (0) |
| 473 | + |
| 474 | +#define TAILQ_INSERT_HEAD(head, elm, field) do { \ |
| 475 | + if ((TAILQ_NEXT((elm), field) = TAILQ_FIRST((head))) != NULL) \ |
| 476 | + TAILQ_FIRST((head))->field.tqe_prev = \ |
| 477 | + &TAILQ_NEXT((elm), field); \ |
| 478 | + else \ |
| 479 | + (head)->tqh_last = &TAILQ_NEXT((elm), field); \ |
| 480 | + TAILQ_FIRST((head)) = (elm); \ |
| 481 | + (elm)->field.tqe_prev = &TAILQ_FIRST((head)); \ |
| 482 | + QMD_TRACE_HEAD(head); \ |
| 483 | + QMD_TRACE_ELEM(&(elm)->field); \ |
| 484 | +} while (0) |
| 485 | + |
| 486 | +#define TAILQ_INSERT_TAIL(head, elm, field) do { \ |
| 487 | + TAILQ_NEXT((elm), field) = NULL; \ |
| 488 | + (elm)->field.tqe_prev = (head)->tqh_last; \ |
| 489 | + *(head)->tqh_last = (elm); \ |
| 490 | + (head)->tqh_last = &TAILQ_NEXT((elm), field); \ |
| 491 | + QMD_TRACE_HEAD(head); \ |
| 492 | + QMD_TRACE_ELEM(&(elm)->field); \ |
| 493 | +} while (0) |
| 494 | + |
| 495 | +#define TAILQ_LAST(head, headname) \ |
| 496 | + (*(((struct headname *)((head)->tqh_last))->tqh_last)) |
| 497 | + |
| 498 | +#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) |
| 499 | + |
| 500 | +#define TAILQ_PREV(elm, headname, field) \ |
| 501 | + (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) |
| 502 | + |
| 503 | +#define TAILQ_REMOVE(head, elm, field) do { \ |
| 504 | + if ((TAILQ_NEXT((elm), field)) != NULL) \ |
| 505 | + TAILQ_NEXT((elm), field)->field.tqe_prev = \ |
| 506 | + (elm)->field.tqe_prev; \ |
| 507 | + else { \ |
| 508 | + (head)->tqh_last = (elm)->field.tqe_prev; \ |
| 509 | + QMD_TRACE_HEAD(head); \ |
| 510 | + } \ |
| 511 | + *(elm)->field.tqe_prev = TAILQ_NEXT((elm), field); \ |
| 512 | + TRASHIT((elm)->field.tqe_next); \ |
| 513 | + TRASHIT((elm)->field.tqe_prev); \ |
| 514 | + QMD_TRACE_ELEM(&(elm)->field); \ |
| 515 | +} while (0) |
| 516 | + |
| 517 | +#endif /* !HAVE_SYS_QUEUE_H */ |
| 518 | +#endif /* !QUEUE_H */ |
Property changes on: trunk/willow/src/include/queue.h |
___________________________________________________________________ |
Added: svn:keywords |
1 | 519 | + Author Date Id Revision |
Added: svn:eol-style |
2 | 520 | + native |
Index: trunk/willow/src/include/wlogwriter.h |
— | — | @@ -0,0 +1,17 @@ |
| 2 | +/* @(#) $Header$ */ |
| 3 | +/* This source code is in the public domain. */ |
| 4 | +/* |
| 5 | + * Willow: Lightweight HTTP reverse-proxy. |
| 6 | + * wlogwriter: child process for log writing. |
| 7 | + */ |
| 8 | + |
| 9 | +#ifndef WLOGWRITER_H |
| 10 | +#define WLOGWRITER_H |
| 11 | + |
| 12 | +#if defined __SUNPRO_C || defined __DECC || defined __HP_cc |
| 13 | +# pragma ident "@(#)$Header$" |
| 14 | +#endif |
| 15 | + |
| 16 | +void wlogwriter_start(int *); |
| 17 | + |
| 18 | +#endif |
Property changes on: trunk/willow/src/include/wlogwriter.h |
___________________________________________________________________ |
Added: svn:keywords |
1 | 19 | + Author Date Id Revision |
Added: svn:eol-style |
2 | 20 | + native |
Index: trunk/willow/src/include/whttp.h |
— | — | @@ -0,0 +1,28 @@ |
| 2 | +/* @(#) $Header$ */ |
| 3 | +/* This source code is in the public domain. */ |
| 4 | +/* |
| 5 | + * Willow: Lightweight HTTP reverse-proxy. |
| 6 | + * whttp: HTTP implementation. |
| 7 | + */ |
| 8 | + |
| 9 | +#ifndef WHTTP_H |
| 10 | +#define WHTTP_H |
| 11 | + |
| 12 | +#if defined __SUNPRO_C || defined __DECC || defined __HP_cc |
| 13 | +# pragma ident "@(#)$Header$" |
| 14 | +#endif |
| 15 | + |
| 16 | +struct fde; |
| 17 | + |
| 18 | +void http_new(struct fde *); |
| 19 | +void whttp_init(void); |
| 20 | +void whttp_shutdown(void); |
| 21 | + |
| 22 | +extern const char *request_string[]; |
| 23 | + |
| 24 | +extern struct request_type { |
| 25 | + const char *name; |
| 26 | + int len; |
| 27 | + int type; |
| 28 | +} supported_reqtypes[]; |
| 29 | +#endif |
Property changes on: trunk/willow/src/include/whttp.h |
___________________________________________________________________ |
Added: svn:keywords |
1 | 30 | + Author Date Id Revision |
Added: svn:eol-style |
2 | 31 | + native |
Index: trunk/willow/src/include/wlog.h |
— | — | @@ -0,0 +1,42 @@ |
| 2 | +/* @(#) $Header$ */ |
| 3 | +/* This source code is in the public domain. */ |
| 4 | +/* |
| 5 | + * Willow: Lightweight HTTP reverse-proxy. |
| 6 | + * wlog: logging. |
| 7 | + */ |
| 8 | + |
| 9 | +#ifndef WLOG_H |
| 10 | +#define WLOG_H |
| 11 | + |
| 12 | +#if defined __SUNPRO_C || defined __DECC || defined __HP_cc |
| 13 | +# pragma ident "@(#)$Header$" |
| 14 | +#endif |
| 15 | + |
| 16 | +#include "config.h" |
| 17 | + |
| 18 | +#define WLOG_DEBUG 0 |
| 19 | +#define WLOG_NOTICE 1 |
| 20 | +#define WLOG_WARNING 2 |
| 21 | +#define WLOG_ERROR 3 |
| 22 | +#define WLOG_MAX 3 |
| 23 | + |
| 24 | +extern struct log_variables { |
| 25 | + char *file; |
| 26 | + int level; |
| 27 | + FILE *fp; |
| 28 | + int syslog; |
| 29 | + int facility; |
| 30 | +} logging; |
| 31 | + |
| 32 | +void wlog_init(void); |
| 33 | +/*PRINTFLIKE2*/ |
| 34 | +void wlog(int, const char *, ...); |
| 35 | +void wlog_close(void); |
| 36 | + |
| 37 | +#ifndef WILLOW_DEBUG |
| 38 | +# define WDEBUG(x) ((void)0) |
| 39 | +#else |
| 40 | +# define WDEBUG(x) wlog x |
| 41 | +#endif |
| 42 | + |
| 43 | +#endif |
Property changes on: trunk/willow/src/include/wlog.h |
___________________________________________________________________ |
Added: svn:keywords |
1 | 44 | + Author Date Id Revision |
Added: svn:eol-style |
2 | 45 | + native |
Index: trunk/willow/src/include/wcache.h |
— | — | @@ -0,0 +1,51 @@ |
| 2 | +/* @(#) $Header$ */ |
| 3 | +/* This source code is in the public domain. */ |
| 4 | +/* |
| 5 | + * Willow: Lightweight HTTP reverse-proxy. |
| 6 | + * wcache: entity caching. |
| 7 | + */ |
| 8 | + |
| 9 | +#ifndef WCACHE_H |
| 10 | +#define WCACHE_H |
| 11 | + |
| 12 | +#if defined __SUNPRO_C || defined __DECC || defined __HP_cc |
| 13 | +# pragma ident "@(#)$Header$" |
| 14 | +#endif |
| 15 | + |
| 16 | +#define WCACHE_FREE 1 |
| 17 | + |
| 18 | +/* |
| 19 | + * Information about the current cache state, stored in the null key |
| 20 | + * (length 0). |
| 21 | + */ |
| 22 | +struct cache_state { |
| 23 | + int cs_id; |
| 24 | +}; |
| 25 | + |
| 26 | +struct cache_key { |
| 27 | + int ck_len; |
| 28 | + char *ck_key; |
| 29 | +}; |
| 30 | + |
| 31 | +struct cache_object { |
| 32 | + int co_flags; |
| 33 | + time_t co_expires; /* Expires: header or -1 */ |
| 34 | + time_t co_time; /* Last-Modified / retrieval time */ |
| 35 | + int co_id; /* Object id */ |
| 36 | + int co_plen; /* Size of cache object */ |
| 37 | + char *co_path; /* Object data location */ |
| 38 | +}; |
| 39 | + |
| 40 | +void wcache_init(int); |
| 41 | +void wcache_setupfs(void); |
| 42 | +void wcache_shutdown(void); |
| 43 | + |
| 44 | +struct cache_key *wcache_make_key(const char *host, const char *path); |
| 45 | +void wcache_free_key(struct cache_key *); |
| 46 | + |
| 47 | +struct cache_object *wcache_find_object(struct cache_key *); |
| 48 | +struct cache_object *wcache_new_object(void); |
| 49 | +int wcache_store_object(struct cache_key *, struct cache_object *); |
| 50 | +void wcache_free_object(struct cache_object *); |
| 51 | + |
| 52 | +#endif |
Property changes on: trunk/willow/src/include/wcache.h |
___________________________________________________________________ |
Added: svn:keywords |
1 | 53 | + Author Date Id Revision |
Added: svn:eol-style |
2 | 54 | + native |
Index: trunk/willow/src/include/wconfig.h |
— | — | @@ -0,0 +1,44 @@ |
| 2 | +/* @(#) $Header$ */ |
| 3 | +/* This source code is in the public domain. */ |
| 4 | +/* |
| 5 | + * Willow: Lightweight HTTP reverse-proxy. |
| 6 | + * wconfig: configuration. |
| 7 | + */ |
| 8 | + |
| 9 | +#ifndef WCONFIG_H |
| 10 | +#define WCONFIG_H |
| 11 | + |
| 12 | +#if defined __SUNPRO_C || defined __DECC || defined __HP_cc |
| 13 | +# pragma ident "@(#)$Header$" |
| 14 | +#endif |
| 15 | + |
| 16 | +#include <sys/types.h> |
| 17 | +#include <netinet/in.h> |
| 18 | + |
| 19 | +struct listener { |
| 20 | + char *name; |
| 21 | + char *host; |
| 22 | + int port; |
| 23 | +struct sockaddr_in addr; |
| 24 | +}; |
| 25 | +extern int nlisteners; |
| 26 | +extern struct listener **listeners; |
| 27 | + |
| 28 | +struct cachedir { |
| 29 | + char *dir; |
| 30 | + size_t maxsize; |
| 31 | +}; |
| 32 | + |
| 33 | +extern struct configuration { |
| 34 | + int foreground; |
| 35 | +const char *access_log; |
| 36 | +struct cachedir *caches; |
| 37 | + int ncaches; |
| 38 | +} config; |
| 39 | + |
| 40 | +void wconfig_init(const char *); |
| 41 | + |
| 42 | +int add_listener(const char *, int); |
| 43 | +int add_cachedir(const char *, int); |
| 44 | + |
| 45 | +#endif |
Property changes on: trunk/willow/src/include/wconfig.h |
___________________________________________________________________ |
Added: svn:keywords |
1 | 46 | + Author Date Id Revision |
Added: svn:eol-style |
2 | 47 | + native |
Index: trunk/willow/src/include/willow.h |
— | — | @@ -0,0 +1,57 @@ |
| 2 | +/* @(#) $Header$ */ |
| 3 | +/* This source code is in the public domain. */ |
| 4 | +/* |
| 5 | + * Willow: Lightweight HTTP reverse-proxy. |
| 6 | + * willow: General utility functions. |
| 7 | + */ |
| 8 | + |
| 9 | +#ifndef WILLOW_H |
| 10 | +#define WILLOW_H |
| 11 | + |
| 12 | +#if defined __SUNPRO_C || defined __DECC || defined __HP_cc |
| 13 | +# pragma ident "@(#)$Header$" |
| 14 | +#endif |
| 15 | + |
| 16 | +#include "config.h" |
| 17 | + |
| 18 | +#ifdef WDEBUG_ALLOC |
| 19 | +void *internal_wmalloc(size_t, const char *, int); |
| 20 | +void internal_wfree(void *, const char *, int); |
| 21 | +char *internal_wstrdup(const char *, const char *, int); |
| 22 | +void *internal_wrealloc(void *, size_t, const char *, int); |
| 23 | +void *internal_wcalloc(size_t, size_t, const char *, int); |
| 24 | +# define wmalloc(s) internal_wmalloc(s, __FILE__, __LINE__) |
| 25 | +# define wfree(p) internal_wfree(p, __FILE__, __LINE__) |
| 26 | +# define wstrdup(p) internal_wstrdup(p, __FILE__, __LINE__) |
| 27 | +# define wrealloc(p,s) internal_wrealloc(p, s, __FILE__, __LINE__) |
| 28 | +# define wcalloc(n,s) internal_wcalloc(n, s, __FILE__, __LINE)) |
| 29 | +#else |
| 30 | +# include <stdlib.h> |
| 31 | + |
| 32 | +# define wmalloc malloc |
| 33 | +# define wfree free |
| 34 | +# define wstrdup strdup |
| 35 | +# define wrealloc realloc |
| 36 | +# define wcalloc calloc |
| 37 | +#endif |
| 38 | + |
| 39 | +void realloc_strcat(char **, const char *); |
| 40 | +void realloc_addchar(char **, int); |
| 41 | + |
| 42 | +#ifndef HAVE_DAEMON |
| 43 | +int daemon(int, int); |
| 44 | +#endif |
| 45 | + |
| 46 | +#ifndef HAVE_SOCKLEN_T |
| 47 | +typedef int socklen_t; |
| 48 | +#endif |
| 49 | + |
| 50 | +void outofmemory(void); |
| 51 | +#ifdef __SUNPRO_C |
| 52 | +# pragma does_not_return(outofmemory) |
| 53 | +#endif |
| 54 | + |
| 55 | +#define safe_snprintf(n,a) if (snprintf a > (n - 1)) abort(); |
| 56 | +#define min(x,y) ((x) < (y) ? (x) : (y)) |
| 57 | + |
| 58 | +#endif |
Property changes on: trunk/willow/src/include/willow.h |
___________________________________________________________________ |
Added: svn:keywords |
1 | 59 | + Author Date Id Revision |
Added: svn:eol-style |
2 | 60 | + native |
Index: trunk/willow/src/include/wnet.h |
— | — | @@ -0,0 +1,124 @@ |
| 2 | +/* @(#) $Header$ */ |
| 3 | +/* This source code is in the public domain. */ |
| 4 | +/* |
| 5 | + * Willow: Lightweight HTTP reverse-proxy. |
| 6 | + * wnet: Networking. |
| 7 | + */ |
| 8 | + |
| 9 | +#ifndef WNET_H |
| 10 | +#define WNET_H |
| 11 | + |
| 12 | +#if defined __SUNPRO_C || defined __DECC || defined __HP_cc |
| 13 | +# pragma ident "@(#)$Header$" |
| 14 | +#endif |
| 15 | + |
| 16 | +#if defined __digital__ && defined __unix__ |
| 17 | +/* sendfile prototype is missing on Tru64 UNIX */ |
| 18 | +# include <sys/uio.h> |
| 19 | + |
| 20 | +ssize_t sendfile(int, int, off_t, size_t, const struct iovec *, int); |
| 21 | +#endif |
| 22 | + |
| 23 | +#include <sys/types.h> |
| 24 | + |
| 25 | +#include <netinet/in.h> |
| 26 | + |
| 27 | +#include "config.h" |
| 28 | +#ifdef THREADED_IO |
| 29 | +# include <pthread.h> |
| 30 | +#endif |
| 31 | + |
| 32 | +#include "willow.h" |
| 33 | + |
| 34 | +struct fde; |
| 35 | + |
| 36 | +extern int max_fd; |
| 37 | + |
| 38 | +typedef void (*fdcb)(struct fde*); |
| 39 | +typedef void (*fdwcb)(struct fde*, void*, int); |
| 40 | + |
| 41 | +struct client_data; |
| 42 | + |
| 43 | +#ifdef USE_POLL |
| 44 | +extern int highest_fd; |
| 45 | +#endif |
| 46 | + |
| 47 | +struct readbuf { |
| 48 | + char *rb_p; /* start of allocated region */ |
| 49 | + int rb_size; /* size of allocated region */ |
| 50 | + int rb_dsize; /* [p,p+dsize) is valid data */ |
| 51 | + int rb_dpos; /* current data position */ |
| 52 | +}; |
| 53 | +#define readbuf_spare_size(b) ((b)->rb_size - (b)->rb_dsize) |
| 54 | +#define readbuf_spare_start(b) ((b)->rb_p + (b)->rb_dsize) |
| 55 | +#define readbuf_data_left(b) ((b)->rb_dsize - (b)->rb_dpos) |
| 56 | +#define readbuf_inc_data_pos(b, i) ((b)->rb_dpos += (i)) |
| 57 | +#define readbuf_cur_pos(b) ((b)->rb_p + (b)->rb_dpos) |
| 58 | + |
| 59 | +struct fde { |
| 60 | + int fde_fd; |
| 61 | + const char *fde_desc; |
| 62 | + fdcb fde_read_handler; |
| 63 | + fdcb fde_write_handler; |
| 64 | +struct client_data *fde_cdata; |
| 65 | + void *fde_rdata; |
| 66 | + void *fde_wdata; |
| 67 | + char fde_straddr[16]; |
| 68 | + int fde_epflags; |
| 69 | +struct readbuf fde_readbuf; |
| 70 | + struct { |
| 71 | + int open:1; |
| 72 | + } fde_flags; |
| 73 | +#ifdef THREADED_IO |
| 74 | + pthread_mutex_t fde_mtx; |
| 75 | +#endif |
| 76 | +}; |
| 77 | +extern struct fde *fde_table; |
| 78 | + |
| 79 | +#ifdef THREADED_IO |
| 80 | +# ifdef WILLOW_DEBUG |
| 81 | +# define FDE_LOCK(e) do { \ |
| 82 | + wlog(WLOG_DEBUG, "%u locks %d", pthread_self(), (e)->fde_fd); \ |
| 83 | + (void)pthread_mutex_lock(&(e)->fde_mtx); \ |
| 84 | +} while(0) |
| 85 | +# define FDE_UNLOCK(e) do { \ |
| 86 | + wlog(WLOG_DEBUG, "%u unlocks %d", pthread_self(), (e)->fde_fd); \ |
| 87 | + (void)pthread_mutex_unlock(&(e)->fde_mtx); \ |
| 88 | +} while(0) |
| 89 | +# else |
| 90 | +# define FDE_LOCK(e) (void)pthread_mutex_lock(&(e)->fde_mtx) |
| 91 | +# define FDE_UNLOCK(e) (void)pthread_mutex_unlock(&(e)->fde_mtx) |
| 92 | +# endif |
| 93 | +#else |
| 94 | +# define FDE_LOCK(e) |
| 95 | +# define FDE_UNLOCK(e) |
| 96 | +#endif |
| 97 | + |
| 98 | +struct client_data { |
| 99 | +struct sockaddr_in cdat_addr; |
| 100 | +}; |
| 101 | + |
| 102 | +extern char current_time_str[]; |
| 103 | +extern char current_time_short[]; |
| 104 | +extern time_t current_time; |
| 105 | +extern int wnet_exit; |
| 106 | + |
| 107 | +#define FDE_READ 0x1 |
| 108 | +#define FDE_WRITE 0x2 |
| 109 | + |
| 110 | +void wnet_init(void); |
| 111 | +void wnet_run(void); |
| 112 | + |
| 113 | +void wnet_register(int, int, fdcb, void *); |
| 114 | +int wnet_open(const char *desc); |
| 115 | +void wnet_close(int); |
| 116 | +void wnet_write(int, const void *, size_t, fdwcb, void *); |
| 117 | +void wnet_sendfile(int, int, size_t, off_t, fdwcb, void *); |
| 118 | + |
| 119 | +void wnet_set_time(void); |
| 120 | +void wnet_init_select(void); |
| 121 | + |
| 122 | +int readbuf_getdata(struct fde *); |
| 123 | +void readbuf_free(struct readbuf *); |
| 124 | + |
| 125 | +#endif |
Property changes on: trunk/willow/src/include/wnet.h |
___________________________________________________________________ |
Added: svn:keywords |
1 | 126 | + Author Date Id Revision |
Added: svn:eol-style |
2 | 127 | + native |
Index: trunk/willow/src/include/wbackend.h |
— | — | @@ -0,0 +1,37 @@ |
| 2 | +/* @(#) $Header$ */ |
| 3 | +/* This source code is in the public domain. */ |
| 4 | +/* |
| 5 | + * Willow: Lightweight HTTP reverse-proxy. |
| 6 | + * wbackend: HTTP backend handling. |
| 7 | + */ |
| 8 | + |
| 9 | +#ifndef WBACKEND_H |
| 10 | +#define WBACKEND_H |
| 11 | + |
| 12 | +#if defined __SUNPRO_C || defined __DECC || defined __HP_cc |
| 13 | +# pragma ident "@(#)$Header$" |
| 14 | +#endif |
| 15 | + |
| 16 | +#include <sys/types.h> |
| 17 | + |
| 18 | +#include <netinet/in.h> |
| 19 | + |
| 20 | +struct fde; |
| 21 | + |
| 22 | +struct backend { |
| 23 | + char *be_name; /* IP as specified in config */ |
| 24 | + int be_port; /* port number */ |
| 25 | +struct sockaddr_in be_addr; /* socket address */ |
| 26 | + int be_okay; /* 1 if okay, 0 if unavailable */ |
| 27 | +}; |
| 28 | + |
| 29 | +typedef void (*backend_cb)(struct backend *, struct fde *, void *); |
| 30 | + |
| 31 | +void add_backend(const char *, int); |
| 32 | +void backend_file(char *); |
| 33 | + |
| 34 | +int get_backend(backend_cb, void *); |
| 35 | + |
| 36 | +extern int nbackends; |
| 37 | + |
| 38 | +#endif |
Property changes on: trunk/willow/src/include/wbackend.h |
___________________________________________________________________ |
Added: svn:keywords |
1 | 39 | + Author Date Id Revision |
Added: svn:eol-style |
2 | 40 | + native |
Index: trunk/willow/src/include/confparse.h |
— | — | @@ -0,0 +1,78 @@ |
| 2 | +/* @(#) $Header$ */ |
| 3 | +/* From: $Nightmare: nightmare/include/config.h,v 1.32.2.2.2.2 2002/07/02 03:41:28 ejb Exp $ */ |
| 4 | +/* From: newconf.h,v 7.36 2005/03/21 22:42:10 leeh Exp */ |
| 5 | +/* This source code is in the public domain. */ |
| 6 | +/* |
| 7 | + * Willow: Lightweight HTTP reverse-proxy. |
| 8 | + * confparse: configuration parser. |
| 9 | + */ |
| 10 | + |
| 11 | +#ifndef CONFPARSE_H |
| 12 | +#define CONFPARSE_H |
| 13 | + |
| 14 | +#if defined __SUNPRO_C || defined __DECC || defined __HP_cc |
| 15 | +# pragma ident "@(#)$Header$" |
| 16 | +#endif |
| 17 | + |
| 18 | +#include "queue.h" |
| 19 | + |
| 20 | +struct conf_entry { |
| 21 | +const char *cf_name; |
| 22 | + int cf_type; |
| 23 | + void (*cf_func) (void *); |
| 24 | + int cf_len; |
| 25 | + void *cf_arg; |
| 26 | + LIST_ENTRY(conf_entry) entries; |
| 27 | +}; |
| 28 | + |
| 29 | +struct top_conf { |
| 30 | + char *tc_name; |
| 31 | + int (*tc_sfunc) (struct top_conf *); |
| 32 | + int (*tc_efunc) (struct top_conf *); |
| 33 | + LIST_HEAD(tc_items_head, conf_entry) tc_items; |
| 34 | + struct conf_entry *tc_entries; |
| 35 | + LIST_ENTRY(top_conf) entries; |
| 36 | +}; |
| 37 | + |
| 38 | +#define CF_QSTRING 0x01 |
| 39 | +#define CF_INT 0x02 |
| 40 | +#define CF_STRING 0x03 |
| 41 | +#define CF_TIME 0x04 |
| 42 | +#define CF_YESNO 0x05 |
| 43 | +#define CF_LIST 0x06 |
| 44 | +#define CF_ONE 0x07 |
| 45 | + |
| 46 | +#define CF_MTYPE 0xFF |
| 47 | + |
| 48 | +#define CF_FLIST 0x1000 |
| 49 | +#define CF_MFLAG 0xFF00 |
| 50 | + |
| 51 | +typedef struct conf_parm_t_stru |
| 52 | +{ |
| 53 | +struct conf_parm_t_stru *next; |
| 54 | + int type; |
| 55 | + union { |
| 56 | + char *string; |
| 57 | + int number; |
| 58 | + struct conf_parm_t_stru *list; |
| 59 | + } v; |
| 60 | +} conf_parm_t; |
| 61 | + |
| 62 | +extern struct top_conf *conf_cur_block; |
| 63 | + |
| 64 | +extern const char *current_file; |
| 65 | +extern int lineno; |
| 66 | +extern int nerrors; |
| 67 | + |
| 68 | +int read_config(char *); |
| 69 | +int conf_start_block(const char *, const char *); |
| 70 | +int conf_end_block(struct top_conf *); |
| 71 | +int conf_call_set(struct top_conf *, char *, conf_parm_t *, int); |
| 72 | +void conf_report_error(const char *, ...); |
| 73 | +void newconf_init(void); |
| 74 | +extern char *conf_cur_block_name; |
| 75 | +int add_conf_item(const char *topconf, const char *name, int type, void (*func) (void *)); |
| 76 | +int remove_conf_item(const char *topconf, const char *name); |
| 77 | + |
| 78 | + |
| 79 | +#endif |
Property changes on: trunk/willow/src/include/confparse.h |
___________________________________________________________________ |
Added: svn:keywords |
1 | 80 | + Author Date Id Revision |
Added: svn:eol-style |
2 | 81 | + native |
Index: trunk/willow/src/lib/wnet/Makefile.in |
— | — | @@ -0,0 +1,13 @@ |
| 2 | +LIB = willownet |
| 3 | + |
| 4 | +selectsrc=wnet_@SELECTTYPE@.c |
| 5 | + |
| 6 | +CPPFLAGS = -DDATADIR=\"$(_DATADIR)\" |
| 7 | +SRCS = wnet.c ${selectsrc} |
| 8 | + |
| 9 | +EXTRA_DIST=wnet_poll.c wnet_ports.c wnet_kqueue.c wnet_epoll.c wnet_devpoll.c \ |
| 10 | + Makefile.in |
| 11 | + |
| 12 | +LDFLAGS = $(LIBOBJS) |
| 13 | + |
| 14 | +@include@ @q@@top_srcdir@/mk/lib.mk@q@ |
Property changes on: trunk/willow/src/lib/wnet/Makefile.in |
___________________________________________________________________ |
Added: svn:keywords |
1 | 15 | + Author Date Id Revision |
Added: svn:eol-style |
2 | 16 | + native |
Index: trunk/willow/src/lib/wnet/wnet_devpoll.c |
— | — | @@ -0,0 +1,128 @@ |
| 2 | +/* @(#) $Header$ */ |
| 3 | +/* This source code is in the public domain. */ |
| 4 | +/* |
| 5 | + * Willow: Lightweight HTTP reverse-proxy. |
| 6 | + * wnet_ports: Solaris /dev/poll-specific networking |
| 7 | + */ |
| 8 | + |
| 9 | +#if defined __SUNPRO_C || defined __DECC || defined __HP_cc |
| 10 | +# pragma ident "@(#)$Header$" |
| 11 | +#endif |
| 12 | + |
| 13 | +#include <sys/types.h> |
| 14 | +#include <sys/socket.h> |
| 15 | +#include <sys/devpoll.h> |
| 16 | + |
| 17 | +#include <arpa/inet.h> |
| 18 | + |
| 19 | +#include <stdio.h> |
| 20 | +#include <string.h> |
| 21 | +#include <stdlib.h> |
| 22 | +#include <unistd.h> |
| 23 | +#include <errno.h> |
| 24 | +#include <assert.h> |
| 25 | +#include <fcntl.h> |
| 26 | +#include <signal.h> |
| 27 | +#include <poll.h> |
| 28 | + |
| 29 | +#include "willow.h" |
| 30 | +#include "wnet.h" |
| 31 | +#include "wconfig.h" |
| 32 | +#include "wlog.h" |
| 33 | +#include "whttp.h" |
| 34 | + |
| 35 | +static int polldev; |
| 36 | +struct dvpoll dvp; |
| 37 | +#define GETN 64 |
| 38 | +struct pollfd pollfds[GETN]; |
| 39 | + |
| 40 | +void |
| 41 | +wnet_init_select(void) |
| 42 | +{ |
| 43 | + if ((polldev = open("/dev/poll", O_RDWR)) < 0) { |
| 44 | + perror("/dev/poll"); |
| 45 | + exit(8); |
| 46 | + } |
| 47 | +} |
| 48 | + |
| 49 | +void |
| 50 | +wnet_run(void) |
| 51 | +{ |
| 52 | + int i, n; |
| 53 | + |
| 54 | + for (;;) { |
| 55 | + dvp.dp_fds = pollfds; |
| 56 | + dvp.dp_nfds = GETN; |
| 57 | + dvp.dp_timeout = -1; |
| 58 | + |
| 59 | + if ((n = ioctl(polldev, DP_POLL, &dvp)) < 0) |
| 60 | + break; |
| 61 | + |
| 62 | + wnet_set_time(); |
| 63 | + |
| 64 | + for (i = 0; i < n; ++i) { |
| 65 | + struct fde *e = &fde_table[pollfds[i].fd]; |
| 66 | + |
| 67 | + if ((pollfds[i].revents & POLLRDNORM) && e->fde_read_handler) { |
| 68 | + e->fde_read_handler(e); |
| 69 | + } |
| 70 | + if ((pollfds[i].revents & POLLWRNORM) && e->fde_write_handler) { |
| 71 | + e->fde_write_handler(e); |
| 72 | + } |
| 73 | + } |
| 74 | + } |
| 75 | + perror("/dev/poll"); |
| 76 | +} |
| 77 | + |
| 78 | +void |
| 79 | +wnet_register(fd, what, handler, data) |
| 80 | + fdcb handler; |
| 81 | + void *data; |
| 82 | +{ |
| 83 | +struct fde *e = &fde_table[fd]; |
| 84 | +struct pollfd pfd; |
| 85 | + |
| 86 | + bzero(&pfd, sizeof(pfd)); |
| 87 | + pfd.fd = fd; |
| 88 | + |
| 89 | + /* |
| 90 | + * Always remove it first, or we just make a no-op when trying to remove flags. |
| 91 | + */ |
| 92 | + pfd.events = POLLREMOVE; |
| 93 | + if (e->fde_epflags && write(polldev, &pfd, sizeof(pfd)) < 0) { |
| 94 | + perror("/dev/poll"); |
| 95 | + exit(8); |
| 96 | + } |
| 97 | + |
| 98 | + pfd.events = e->fde_epflags; |
| 99 | + |
| 100 | + e->fde_fd = fd; |
| 101 | + if (handler == NULL) { |
| 102 | + if (what & FDE_READ) |
| 103 | + e->fde_epflags &= ~POLLRDNORM; |
| 104 | + if (what & FDE_WRITE) |
| 105 | + e->fde_epflags &= ~POLLWRNORM; |
| 106 | + } else { |
| 107 | + if (what & FDE_READ) { |
| 108 | + e->fde_read_handler = handler; |
| 109 | + e->fde_epflags |= POLLRDNORM; |
| 110 | + } |
| 111 | + if (what & FDE_WRITE) { |
| 112 | + e->fde_write_handler = handler; |
| 113 | + e->fde_epflags |= POLLWRNORM; |
| 114 | + } |
| 115 | + } |
| 116 | + |
| 117 | + if (!e->fde_epflags) |
| 118 | + return; |
| 119 | + |
| 120 | + pfd.events = e->fde_epflags; |
| 121 | + |
| 122 | + if (data) |
| 123 | + e->fde_rdata = data; |
| 124 | + |
| 125 | + if (write(polldev, &pfd, sizeof(pfd)) < 0) { |
| 126 | + perror("write(/dev/poll)"); |
| 127 | + exit(8); |
| 128 | + } |
| 129 | +} |
Property changes on: trunk/willow/src/lib/wnet/wnet_devpoll.c |
___________________________________________________________________ |
Added: svn:keywords |
1 | 130 | + Author Date Id Revision |
Added: svn:eol-style |
2 | 131 | + native |
Index: trunk/willow/src/lib/wnet/wnet_poll.c |
— | — | @@ -0,0 +1,113 @@ |
| 2 | +/* @(#) $Header$ */ |
| 3 | +/* This source code is in the public domain. */ |
| 4 | +/* |
| 5 | + * Willow: Lightweight HTTP reverse-proxy. |
| 6 | + * wnet_poll: poll()-specific networking. |
| 7 | + */ |
| 8 | + |
| 9 | +#if defined __SUNPRO_C || defined __DECC || defined __HP_cc |
| 10 | +# pragma ident "@(#)$Header$" |
| 11 | +#endif |
| 12 | + |
| 13 | +#include <sys/types.h> |
| 14 | +#include <sys/socket.h> |
| 15 | + |
| 16 | +#include <arpa/inet.h> |
| 17 | + |
| 18 | +#include <stdio.h> |
| 19 | +#include <string.h> |
| 20 | +#include <stdlib.h> |
| 21 | +#include <unistd.h> |
| 22 | +#include <errno.h> |
| 23 | +#include <assert.h> |
| 24 | +#include <fcntl.h> |
| 25 | +#include <signal.h> |
| 26 | +#include <poll.h> |
| 27 | + |
| 28 | +#include "willow.h" |
| 29 | +#include "wnet.h" |
| 30 | +#include "wconfig.h" |
| 31 | +#include "wlog.h" |
| 32 | +#include "whttp.h" |
| 33 | + |
| 34 | +/* May not have X/Open macros */ |
| 35 | + |
| 36 | +#ifndef POLLRDNORM |
| 37 | +# define POLLRDNORM POLLIN |
| 38 | +#endif |
| 39 | + |
| 40 | +#ifndef POLLWRNORM |
| 41 | +# define POLLWRNORM POLLOUT |
| 42 | +#endif |
| 43 | + |
| 44 | +static struct pollfd *pfds; |
| 45 | +int highest_fd; |
| 46 | + |
| 47 | +void |
| 48 | +wnet_init_select(void) |
| 49 | +{ |
| 50 | + int i; |
| 51 | + |
| 52 | + pfds = wmalloc(sizeof(*pfds) * getdtablesize()); |
| 53 | + bzero(pfds, sizeof(*pfds) * getdtablesize()); |
| 54 | +} |
| 55 | + |
| 56 | +void |
| 57 | +wnet_run(void) |
| 58 | +{ |
| 59 | + int n = 0, i; |
| 60 | + |
| 61 | + for (;;) { |
| 62 | + if ((i = poll(pfds, highest_fd + 1, -1)) == -1) |
| 63 | + break; |
| 64 | + wnet_set_time(); |
| 65 | + |
| 66 | + for (n = 0; n < highest_fd + 1; ++n) { |
| 67 | + struct fde *e = &fde_table[pfds[n].fd]; |
| 68 | + |
| 69 | + if ((pfds[n].revents & POLLRDNORM) && e->fde_read_handler) { |
| 70 | + e->fde_read_handler(e); |
| 71 | + } |
| 72 | + |
| 73 | + if ((pfds[n].revents & POLLWRNORM) && e->fde_write_handler) { |
| 74 | + e->fde_write_handler(e); |
| 75 | + } |
| 76 | + } |
| 77 | + } |
| 78 | + perror("poll"); |
| 79 | +} |
| 80 | + |
| 81 | +void |
| 82 | +wnet_register(fd, what, handler, data) |
| 83 | + int fd, what; |
| 84 | + fdcb handler; |
| 85 | + void *data; |
| 86 | +{ |
| 87 | +struct fde *e = &fde_table[fd]; |
| 88 | + int flags = e->fde_epflags; |
| 89 | + |
| 90 | + assert(fd < max_fd); |
| 91 | + |
| 92 | + if (handler == NULL) { |
| 93 | + e->fde_epflags = 0; |
| 94 | + pfds[fd].fd = -1; |
| 95 | + pfds[fd].events = 0; |
| 96 | + return; |
| 97 | + } |
| 98 | + |
| 99 | + e->fde_fd = fd; |
| 100 | + if (what & FDE_READ) { |
| 101 | + e->fde_read_handler = handler; |
| 102 | + e->fde_epflags |= POLLRDNORM; |
| 103 | + } |
| 104 | + if (what & FDE_WRITE) { |
| 105 | + e->fde_write_handler = handler; |
| 106 | + e->fde_epflags |= POLLWRNORM; |
| 107 | + } |
| 108 | + |
| 109 | + pfds[fd].fd = fd; |
| 110 | + pfds[fd].events = e->fde_epflags; |
| 111 | + |
| 112 | + if (data) |
| 113 | + e->fde_rdata = data; |
| 114 | +} |
Property changes on: trunk/willow/src/lib/wnet/wnet_poll.c |
___________________________________________________________________ |
Added: svn:keywords |
1 | 115 | + Author Date Id Revision |
Added: svn:eol-style |
2 | 116 | + native |
Index: trunk/willow/src/lib/wnet/wnet_ports.c |
— | — | @@ -0,0 +1,245 @@ |
| 2 | +/* @(#) $Header$ */ |
| 3 | +/* This source code is in the public domain. */ |
| 4 | +/* |
| 5 | + * Willow: Lightweight HTTP reverse-proxy. |
| 6 | + * wnet_ports: Solaris event ports-specific networking |
| 7 | + */ |
| 8 | + |
| 9 | +#if defined __SUNPRO_C || defined __DECC || defined __HP_cc |
| 10 | +# pragma ident "@(#)$Header$" |
| 11 | +#endif |
| 12 | + |
| 13 | +#include <sys/types.h> |
| 14 | +#include <sys/socket.h> |
| 15 | + |
| 16 | +#include <stdio.h> |
| 17 | +#include <stdlib.h> |
| 18 | +#include <assert.h> |
| 19 | +#include <fcntl.h> |
| 20 | +#include <port.h> |
| 21 | +#include <errno.h> |
| 22 | +#include <string.h> |
| 23 | +#include <unistd.h> |
| 24 | + |
| 25 | +#include "config.h" |
| 26 | + |
| 27 | +#ifdef THREADED_IO |
| 28 | +# include <pthread.h> |
| 29 | +#endif |
| 30 | + |
| 31 | +#include "wnet.h" |
| 32 | +#include "wlog.h" |
| 33 | + |
| 34 | +#define READABLE POLLRDNORM |
| 35 | + |
| 36 | +static void run_event(struct fde *, int); |
| 37 | + |
| 38 | +static int port; |
| 39 | +#define GETN 256 |
| 40 | +static port_event_t pe[GETN]; |
| 41 | + |
| 42 | +#ifdef THREADED_IO |
| 43 | +# define NTHREADS 20 |
| 44 | +static pthread_t thread_ids[NTHREADS]; |
| 45 | +struct { |
| 46 | + int fd; |
| 47 | + int flags; |
| 48 | +} t_event; |
| 49 | + |
| 50 | +pthread_cond_t t_cond = PTHREAD_COND_INITIALIZER; |
| 51 | +pthread_mutex_t t_mtx = PTHREAD_MUTEX_INITIALIZER; |
| 52 | + |
| 53 | +static void * |
| 54 | +thread_event_wait(data) |
| 55 | + void *data; |
| 56 | +{ |
| 57 | + int fd, flags; |
| 58 | + port_event_t pe; |
| 59 | + |
| 60 | + WDEBUG((WLOG_DEBUG, "[%u] starting", pthread_self())); |
| 61 | + |
| 62 | + for (;;) { |
| 63 | + int i; |
| 64 | + |
| 65 | + WDEBUG((WLOG_DEBUG, "[%u] waiting", pthread_self())); |
| 66 | + |
| 67 | + i = port_get(port, &pe, NULL); |
| 68 | + if (i == -1) { |
| 69 | + wlog(WLOG_WARNING, "port_get: %s", strerror(errno)); |
| 70 | + break; |
| 71 | + } |
| 72 | + |
| 73 | + WDEBUG((WLOG_DEBUG, "[%u] activity on %d", pthread_self(), (int)pe.portev_object)); |
| 74 | + wnet_set_time(); |
| 75 | + |
| 76 | + fd = pe.portev_object; |
| 77 | + FDE_LOCK(&fde_table[fd]); |
| 78 | + run_event(&fde_table[fd], pe.portev_events); |
| 79 | + FDE_UNLOCK(&fde_table[fd]); |
| 80 | + } |
| 81 | + /*NOTREACHED*/ |
| 82 | +} |
| 83 | +#endif |
| 84 | + |
| 85 | +static void |
| 86 | +run_event(fde, events) |
| 87 | + struct fde *fde; |
| 88 | + int events; |
| 89 | +{ |
| 90 | + int hadread, hadwrite; |
| 91 | + |
| 92 | + hadread = fde->fde_epflags & READABLE; |
| 93 | + hadwrite = fde->fde_epflags & POLLWRNORM; |
| 94 | + |
| 95 | + /* |
| 96 | + * Immediately re-associate. If the caller doesn't want it, |
| 97 | + * they'll dissociate it themselves. This could be optimised |
| 98 | + * a little to save 2 syscalls in some cases... |
| 99 | + */ |
| 100 | + |
| 101 | + if ((events & READABLE) && fde->fde_read_handler) { |
| 102 | + WDEBUG((WLOG_DEBUG, "\tread")); |
| 103 | + fde->fde_read_handler(fde); |
| 104 | + if (hadread && (fde->fde_epflags & READABLE)) |
| 105 | + if (port_associate(port, PORT_SOURCE_FD, fde->fde_fd, READABLE, NULL) == -1) { |
| 106 | + wlog(WLOG_ERROR, "port_associate: %s", strerror(errno)); |
| 107 | + exit(8); |
| 108 | + } |
| 109 | + } |
| 110 | + |
| 111 | + if ((events & (POLLWRNORM | POLLERR)) && fde->fde_write_handler) { |
| 112 | + WDEBUG((WLOG_DEBUG, "\twrite")); |
| 113 | + fde->fde_write_handler(fde); |
| 114 | + if (hadwrite && (fde->fde_epflags & POLLWRNORM)) |
| 115 | + if (port_associate(port, PORT_SOURCE_FD, fde->fde_fd, POLLWRNORM, NULL) == -1) { |
| 116 | + wlog(WLOG_ERROR, "port_associate: %s", strerror(errno)); |
| 117 | + exit(8); |
| 118 | + } |
| 119 | + } |
| 120 | +} |
| 121 | + |
| 122 | +void |
| 123 | +wnet_init_select(void) |
| 124 | +{ |
| 125 | + int i; |
| 126 | + |
| 127 | + if ((port = port_create()) < 0) { |
| 128 | + perror("port_create"); |
| 129 | + exit(8); |
| 130 | + } |
| 131 | + |
| 132 | +#ifdef THREADED_IO |
| 133 | + WDEBUG((WLOG_DEBUG, "wnet_init_select: thread startup")); |
| 134 | + |
| 135 | + (void) pthread_mutex_lock(&t_mtx); |
| 136 | + |
| 137 | + for (i = 0; i < NTHREADS; ++i) { |
| 138 | + pthread_attr_t attr; |
| 139 | + pthread_attr_init(&attr); |
| 140 | + //pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM); |
| 141 | + if (pthread_create(&thread_ids[i], &attr, thread_event_wait, NULL) != 0) { |
| 142 | + perror("pthread_create"); |
| 143 | + exit(8); |
| 144 | + } |
| 145 | + } |
| 146 | + for (i = 0; i < getdtablesize(); ++i) { |
| 147 | + pthread_mutexattr_t attr; |
| 148 | + if (pthread_mutexattr_init(&attr) != 0) { |
| 149 | + perror("pthread_mutexattr_init"); |
| 150 | + exit(8); |
| 151 | + } |
| 152 | + if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE) != 0) { |
| 153 | + perror("pthread_mutexattr_settype"); |
| 154 | + exit(8); |
| 155 | + } |
| 156 | + if (pthread_mutex_init(&fde_table[i].fde_mtx, &attr) != 0) { |
| 157 | + perror("pthread_mutex_init"); |
| 158 | + exit(8); |
| 159 | + } |
| 160 | + } |
| 161 | +#endif |
| 162 | +} |
| 163 | + |
| 164 | +void |
| 165 | +wnet_run(void) |
| 166 | +{ |
| 167 | + uint nget = 1; |
| 168 | + |
| 169 | +#ifdef THREADED_IO |
| 170 | + thread_event_wait(NULL); |
| 171 | +#else |
| 172 | + int i; |
| 173 | + for (;;) { |
| 174 | + i = port_getn(port, pe, GETN, &nget, NULL); |
| 175 | + |
| 176 | + if (i == -1) { |
| 177 | + if (errno == EINTR) { |
| 178 | + if (wnet_exit) |
| 179 | + return; |
| 180 | + continue; |
| 181 | + } |
| 182 | + break; |
| 183 | + } |
| 184 | + |
| 185 | + wnet_set_time(); |
| 186 | + |
| 187 | + for (i = 0; i < nget; ++i) { |
| 188 | + struct fde *e = &fde_table[pe[i].portev_object]; |
| 189 | + |
| 190 | + WDEBUG((WLOG_DEBUG, "activity on fd %d [%s]", e->fde_fd, e->fde_desc)); |
| 191 | + |
| 192 | + run_event(e, pe[i].portev_events); |
| 193 | + } |
| 194 | + nget = 1; |
| 195 | + } |
| 196 | +#endif |
| 197 | +} |
| 198 | + |
| 199 | +void |
| 200 | +wnet_register(fd, what, handler, data) |
| 201 | + int fd, what; |
| 202 | + fdcb handler; |
| 203 | + void *data; |
| 204 | +{ |
| 205 | +struct fde *e = &fde_table[fd]; |
| 206 | + int oldflags = e->fde_epflags; |
| 207 | + |
| 208 | + WDEBUG((WLOG_DEBUG, "wnet_register: %d [%s] for %d %p", fd, e->fde_desc, what, (void *)handler)); |
| 209 | + |
| 210 | + FDE_LOCK(e); |
| 211 | + |
| 212 | + if (what & FDE_READ) { |
| 213 | + e->fde_read_handler = handler; |
| 214 | + if (handler) |
| 215 | + e->fde_epflags |= READABLE; |
| 216 | + else |
| 217 | + e->fde_epflags &= ~READABLE; |
| 218 | + } |
| 219 | + if (what & FDE_WRITE) { |
| 220 | + e->fde_write_handler = handler; |
| 221 | + if (handler) |
| 222 | + e->fde_epflags |= POLLWRNORM; |
| 223 | + else |
| 224 | + e->fde_epflags &= ~POLLWRNORM; |
| 225 | + } |
| 226 | + |
| 227 | + if (data) |
| 228 | + e->fde_rdata = data; |
| 229 | + |
| 230 | + if (oldflags == e->fde_epflags) { |
| 231 | + /* no change */ |
| 232 | + FDE_UNLOCK(e); |
| 233 | + return; |
| 234 | + } |
| 235 | + |
| 236 | + if (e->fde_epflags) { |
| 237 | + if (port_associate(port, PORT_SOURCE_FD, fd, e->fde_epflags, NULL) < 0) { |
| 238 | + perror("port_associate"); |
| 239 | + abort(); |
| 240 | + } |
| 241 | + } else { |
| 242 | + (void)port_dissociate(port, PORT_SOURCE_FD, fd); |
| 243 | + } |
| 244 | + |
| 245 | + FDE_UNLOCK(e); |
| 246 | +} |
Property changes on: trunk/willow/src/lib/wnet/wnet_ports.c |
___________________________________________________________________ |
Added: svn:keywords |
1 | 247 | + Author Date Id Revision |
Added: svn:eol-style |
2 | 248 | + native |
Index: trunk/willow/src/lib/wnet/wnet_epoll.c |
— | — | @@ -0,0 +1,136 @@ |
| 2 | +/* @(#) $Header$ */ |
| 3 | +/* This source code is in the public domain. */ |
| 4 | +/* |
| 5 | + * Willow: Lightweight HTTP reverse-proxy. |
| 6 | + * wnet: Networking. |
| 7 | + */ |
| 8 | + |
| 9 | +#if defined __SUNPRO_C || defined __DECC || defined __HP_cc |
| 10 | +# pragma ident "@(#)$Header$" |
| 11 | +#endif |
| 12 | + |
| 13 | +#include <sys/types.h> |
| 14 | +#include <sys/socket.h> |
| 15 | + |
| 16 | +#include <arpa/inet.h> |
| 17 | + |
| 18 | +#include <stdio.h> |
| 19 | +#include <string.h> |
| 20 | +#include <stdlib.h> |
| 21 | +#include <unistd.h> |
| 22 | +#include <errno.h> |
| 23 | +#include <assert.h> |
| 24 | +#include <fcntl.h> |
| 25 | +#include <signal.h> |
| 26 | +#include <sys/epoll.h> |
| 27 | + |
| 28 | +#include "willow.h" |
| 29 | +#include "wnet.h" |
| 30 | +#include "wconfig.h" |
| 31 | +#include "wlog.h" |
| 32 | +#include "whttp.h" |
| 33 | + |
| 34 | +static int epfd; |
| 35 | + |
| 36 | +void |
| 37 | +wnet_init_select(void) |
| 38 | +{ |
| 39 | + int i; |
| 40 | + |
| 41 | + signal(SIGPIPE, SIG_IGN); |
| 42 | + |
| 43 | + if ((epfd = epoll_create(MAX_FD)) < 0) { |
| 44 | + perror("epoll_create"); |
| 45 | + exit(8); |
| 46 | + } |
| 47 | +} |
| 48 | + |
| 49 | +void |
| 50 | +wnet_run(void) |
| 51 | +{ |
| 52 | + int i, n; |
| 53 | +struct epoll_event events[256]; |
| 54 | + |
| 55 | + while ((i = epoll_wait(epfd, events, 256, -1)) != -1) { |
| 56 | + wnet_set_time(); |
| 57 | + |
| 58 | + for (n = 0; n < i; ++n) { |
| 59 | + struct fde *e = &fde_table[events[n].data.fd]; |
| 60 | + struct epoll_event ev; |
| 61 | + assert(events[n].data.fd < MAX_FD); |
| 62 | + |
| 63 | + e->fde_epflags &= ~events[n].events; |
| 64 | + ev.events = e->fde_epflags; |
| 65 | + ev.data.fd = e->fde_fd; |
| 66 | + if (e->fde_epflags == 0) { |
| 67 | + if (epoll_ctl(epfd, EPOLL_CTL_DEL, e->fde_fd, NULL) < 0) { |
| 68 | + perror("epoll_ctl(DEL)"); |
| 69 | + exit(8); |
| 70 | + } |
| 71 | + } else { |
| 72 | + if (epoll_ctl(epfd, EPOLL_CTL_MOD, e->fde_fd, &ev) < 0) { |
| 73 | + perror("epoll_ctl(MOD)"); |
| 74 | + exit(8); |
| 75 | + } |
| 76 | + } |
| 77 | + |
| 78 | + if ((events[n].events & EPOLLIN) && e->fde_read_handler) { |
| 79 | + int ret = e->fde_read_handler(e); |
| 80 | + if (ret == 0) |
| 81 | + wnet_register(e->fde_fd, FDE_READ, e->fde_read_handler, NULL); |
| 82 | + } |
| 83 | + |
| 84 | + if ((events[n].events & EPOLLOUT) && e->fde_write_handler) { |
| 85 | + int ret = e->fde_write_handler(e); |
| 86 | + if (ret == 0) |
| 87 | + wnet_register(e->fde_fd, FDE_WRITE, e->fde_write_handler, NULL); |
| 88 | + } |
| 89 | + } |
| 90 | + } |
| 91 | + perror("epoll_wait"); |
| 92 | +} |
| 93 | + |
| 94 | +void |
| 95 | +wnet_register(fd, what, handler, data) |
| 96 | + fdcb handler; |
| 97 | + void *data; |
| 98 | +{ |
| 99 | +struct fde *e = &fde_table[fd]; |
| 100 | + int flags = e->fde_epflags, mod = flags; |
| 101 | +struct epoll_event ev; |
| 102 | + |
| 103 | + assert(fd < MAX_FD); |
| 104 | + |
| 105 | + if (handler == NULL) { |
| 106 | + epoll_ctl(epfd, EPOLL_CTL_DEL, fd, NULL); |
| 107 | + return; |
| 108 | + } |
| 109 | + |
| 110 | + e->fde_fd = fd; |
| 111 | + if (what & FDE_READ) { |
| 112 | + e->fde_read_handler = handler; |
| 113 | + e->fde_epflags |= EPOLLIN; |
| 114 | + } |
| 115 | + if (what & FDE_WRITE) { |
| 116 | + e->fde_write_handler = handler; |
| 117 | + e->fde_epflags |= EPOLLOUT; |
| 118 | + } |
| 119 | + |
| 120 | + if (data) |
| 121 | + e->fde_rdata = data; |
| 122 | + |
| 123 | + bzero(&ev, sizeof(ev)); |
| 124 | + ev.events = e->fde_epflags; |
| 125 | + ev.data.fd = fd; |
| 126 | + if (mod) { |
| 127 | + if (epoll_ctl(epfd, EPOLL_CTL_MOD, fd, &ev) < 0) { |
| 128 | + perror("epoll_ctl"); |
| 129 | + exit(8); |
| 130 | + } |
| 131 | + } else { |
| 132 | + if (epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev) < 0) { |
| 133 | + perror("epoll_ctl"); |
| 134 | + exit(8); |
| 135 | + } |
| 136 | + } |
| 137 | +} |
Property changes on: trunk/willow/src/lib/wnet/wnet_epoll.c |
___________________________________________________________________ |
Added: svn:keywords |
1 | 138 | + Author Date Id Revision |
Added: svn:eol-style |
2 | 139 | + native |
Index: trunk/willow/src/lib/wnet/wnet_kqueue.c |
— | — | @@ -0,0 +1,143 @@ |
| 2 | +/* @(#) $Header$ */ |
| 3 | +/* This source code is in the public domain. */ |
| 4 | +/* |
| 5 | + * Willow: Lightweight HTTP reverse-proxy. |
| 6 | + * wnet_kqueue: FreeBSD kqueue-specific networking. |
| 7 | + */ |
| 8 | + |
| 9 | +#if defined __SUNPRO_C || defined __DECC || defined __HP_cc |
| 10 | +# pragma ident "@(#)$Header$" |
| 11 | +#endif |
| 12 | + |
| 13 | +#include <sys/types.h> |
| 14 | +#include <sys/socket.h> |
| 15 | +#include <sys/event.h> |
| 16 | +#include <sys/time.h> |
| 17 | + |
| 18 | +#include <arpa/inet.h> |
| 19 | + |
| 20 | +#include <stdio.h> |
| 21 | +#include <string.h> |
| 22 | +#include <stdlib.h> |
| 23 | +#include <unistd.h> |
| 24 | +#include <errno.h> |
| 25 | +#include <assert.h> |
| 26 | +#include <fcntl.h> |
| 27 | +#include <signal.h> |
| 28 | + |
| 29 | +#include "willow.h" |
| 30 | +#include "wnet.h" |
| 31 | +#include "wconfig.h" |
| 32 | +#include "wlog.h" |
| 33 | +#include "whttp.h" |
| 34 | + |
| 35 | +static void kq_update_event(int, int, u_int); |
| 36 | +static void kq_update_immediate(int, int, u_int); |
| 37 | + |
| 38 | +static int kq; |
| 39 | +struct timespec zero_timespec; |
| 40 | +#define GETN 256 |
| 41 | +static struct kevent kqlst[GETN], kqchg[GETN]; |
| 42 | +static int kqoff; |
| 43 | + |
| 44 | +void |
| 45 | +wnet_init_select(void) |
| 46 | +{ |
| 47 | + if ((kq = kqueue()) < 0) { |
| 48 | + perror("kqueue"); |
| 49 | + exit(8); |
| 50 | + } |
| 51 | +} |
| 52 | + |
| 53 | +void |
| 54 | +wnet_run(void) |
| 55 | +{ |
| 56 | + int i; |
| 57 | + int nget; |
| 58 | + |
| 59 | + while ((nget = kevent(kq, kqchg, kqoff, kqlst, GETN, NULL)) > -1) { |
| 60 | + wnet_set_time(); |
| 61 | + |
| 62 | + kqoff = 0; |
| 63 | + for (i = 0; i < nget; ++i) { |
| 64 | + struct fde *e = &fde_table[kqlst[i].ident]; |
| 65 | + assert(kqlst[i].ident < MAX_FD); |
| 66 | + |
| 67 | + if (kqlst[i].flags & EV_ERROR) { |
| 68 | + (void)fprintf(stderr, "error for %d (%s): %s\n", |
| 69 | + kqlst[i].ident, e->fde_desc, strerror(kqlst[i].data)); |
| 70 | + exit(8); |
| 71 | + } |
| 72 | + |
| 73 | + if ((kqlst[i].filter == EVFILT_READ) && e->fde_read_handler) { |
| 74 | + int ret = e->fde_read_handler(e); |
| 75 | + if (ret == 0) |
| 76 | + wnet_register(kqlst[i].ident, FDE_READ, e->fde_read_handler, NULL); |
| 77 | + } |
| 78 | + if ((kqlst[i].filter == EVFILT_WRITE) && e->fde_write_handler) { |
| 79 | + int ret = e->fde_write_handler(e); |
| 80 | + if (ret == 0) |
| 81 | + wnet_register(kqlst[i].ident, FDE_WRITE, e->fde_write_handler, NULL); |
| 82 | + } |
| 83 | + } |
| 84 | + } |
| 85 | + perror("wnet_run/kevent"); |
| 86 | +} |
| 87 | + |
| 88 | +void |
| 89 | +wnet_register(fd, what, handler, data) |
| 90 | + fdcb handler; |
| 91 | + void *data; |
| 92 | +{ |
| 93 | +struct fde *e = &fde_table[fd]; |
| 94 | + u_int flags; |
| 95 | + |
| 96 | + assert(fd < MAX_FD); |
| 97 | + |
| 98 | + if (handler == NULL) { |
| 99 | + kq_update_immediate(fd, EVFILT_READ, EV_DELETE); |
| 100 | + kq_update_immediate(fd, EVFILT_WRITE, EV_DELETE); |
| 101 | + return; |
| 102 | + } |
| 103 | + |
| 104 | + flags = EV_ADD | EV_ONESHOT; |
| 105 | + |
| 106 | + e->fde_fd = fd; |
| 107 | + if (what & FDE_READ) { |
| 108 | + e->fde_read_handler = handler; |
| 109 | + kq_update_event(fd, EVFILT_READ, flags); |
| 110 | + } |
| 111 | + if (what & FDE_WRITE) { |
| 112 | + e->fde_write_handler = handler; |
| 113 | + kq_update_event(fd, EVFILT_WRITE, flags); |
| 114 | + } |
| 115 | + |
| 116 | + if (data) |
| 117 | + e->fde_rdata = data; |
| 118 | +} |
| 119 | + |
| 120 | +static void |
| 121 | +kq_update_event(fd, filter, flags) |
| 122 | + u_int flags; |
| 123 | +{ |
| 124 | + EV_SET(&kqchg[kqoff], fd, filter, flags, 0, 0, NULL); |
| 125 | + if (++kqoff == GETN) { |
| 126 | + if (kevent(kq, kqchg, kqoff, NULL, 0, &zero_timespec) < 0) { |
| 127 | + perror("kevent"); |
| 128 | + exit(8); |
| 129 | + } |
| 130 | + kqoff = 0; |
| 131 | + } |
| 132 | +} |
| 133 | + |
| 134 | +static void |
| 135 | +kq_update_immediate(fd, filter, flags) |
| 136 | + u_int flags; |
| 137 | +{ |
| 138 | +struct kevent ke; |
| 139 | + |
| 140 | + EV_SET(&ke, fd, filter, flags, 0, 0, NULL); |
| 141 | + kevent(kq, &ke, 1, NULL, 0, &zero_timespec); |
| 142 | +} |
| 143 | + |
| 144 | + |
Property changes on: trunk/willow/src/lib/wnet/wnet_kqueue.c |
___________________________________________________________________ |
Added: svn:keywords |
1 | 145 | + Author Date Id Revision |
Added: svn:eol-style |
2 | 146 | + native |
Index: trunk/willow/src/lib/wnet/wnet.c |
— | — | @@ -0,0 +1,437 @@ |
| 2 | +/* @(#) $Header$ */ |
| 3 | +/* This source code is in the public domain. */ |
| 4 | +/* |
| 5 | + * Willow: Lightweight HTTP reverse-proxy. |
| 6 | + * wnet: Networking. |
| 7 | + */ |
| 8 | + |
| 9 | +#if defined __SUNPRO_C || defined __DECC || defined __HP_cc |
| 10 | +# pragma ident "@(#)$Header$" |
| 11 | +#endif |
| 12 | + |
| 13 | +#include <sys/types.h> |
| 14 | +#include <sys/socket.h> |
| 15 | + |
| 16 | +#include "config.h" |
| 17 | +#ifdef HAVE_SYS_SENDFILE_H |
| 18 | +# include <sys/sendfile.h> |
| 19 | +#endif |
| 20 | + |
| 21 | +#include <arpa/inet.h> |
| 22 | + |
| 23 | +#include <stdio.h> |
| 24 | +#include <string.h> |
| 25 | +#include <stdlib.h> |
| 26 | +#include <unistd.h> |
| 27 | +#include <errno.h> |
| 28 | +#include <fcntl.h> |
| 29 | +#include <signal.h> |
| 30 | +#include <assert.h> |
| 31 | +#include <strings.h> |
| 32 | + |
| 33 | +#include "willow.h" |
| 34 | +#include "wnet.h" |
| 35 | +#include "wconfig.h" |
| 36 | +#include "wlog.h" |
| 37 | +#include "whttp.h" |
| 38 | + |
| 39 | +#define RDBUF_INC 8192 /* buffer in 8 KiB incrs */ |
| 40 | + |
| 41 | +struct wrtbuf { |
| 42 | + /* for buffers only */ |
| 43 | +const void *wb_buf; |
| 44 | + /* for sendfile only */ |
| 45 | + off_t wb_off; |
| 46 | + int wb_source; |
| 47 | + /* for buffers & sendfile */ |
| 48 | + size_t wb_size; |
| 49 | + int wb_done; |
| 50 | + fdwcb wb_func; |
| 51 | + void *wb_udata; |
| 52 | +}; |
| 53 | + |
| 54 | +char current_time_str[30]; |
| 55 | +char current_time_short[30]; |
| 56 | +#ifdef __lint |
| 57 | +# pragma error_messages(off, E_GLOBAL_COULD_BE_STATIC) |
| 58 | +#endif |
| 59 | +time_t current_time; |
| 60 | +#ifdef __lint |
| 61 | +# pragma error_messages(default, E_GLOBAL_COULD_BE_STATIC) |
| 62 | +#endif |
| 63 | + |
| 64 | +static void init_fde(struct fde *); |
| 65 | + |
| 66 | +static void wnet_accept(struct fde *); |
| 67 | +static void wnet_write_do(struct fde *); |
| 68 | +static void wnet_sendfile_do(struct fde *); |
| 69 | + |
| 70 | +static void readbuf_reset(struct readbuf *); |
| 71 | + |
| 72 | +struct fde *fde_table; |
| 73 | +int max_fd; |
| 74 | + |
| 75 | +int wnet_exit; |
| 76 | + |
| 77 | +void |
| 78 | +wnet_init(void) |
| 79 | +{ |
| 80 | + int i; |
| 81 | + |
| 82 | + max_fd = getdtablesize(); |
| 83 | + if ((fde_table = wcalloc(max_fd, sizeof(struct fde))) == NULL) |
| 84 | + outofmemory(); |
| 85 | + |
| 86 | + wlog(WLOG_NOTICE, "maximum number of open files: %d", max_fd); |
| 87 | + |
| 88 | + (void)signal(SIGPIPE, SIG_IGN); |
| 89 | + wnet_init_select(); |
| 90 | + |
| 91 | + for (i = 0; i < nlisteners; ++i) { |
| 92 | + struct listener *lns = listeners[i]; |
| 93 | + |
| 94 | + int fd = wnet_open("listener"); |
| 95 | + int one = 1; |
| 96 | + if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) == -1) { |
| 97 | + wlog(WLOG_ERROR, "setsockopt: %s: %s\n", lns->name, strerror(errno)); |
| 98 | + exit(8); |
| 99 | + } |
| 100 | + if (bind(fd, (struct sockaddr *) &lns->addr, sizeof(lns->addr)) < 0) { |
| 101 | + wlog(WLOG_ERROR, "bind: %s: %s\n", lns->name, strerror(errno)); |
| 102 | + exit(8); |
| 103 | + } |
| 104 | + if (listen(fd, 10) < 0) { |
| 105 | + wlog(WLOG_ERROR, "listen: %s: %s\n", lns->name, strerror(errno)); |
| 106 | + exit(8); |
| 107 | + } |
| 108 | + wnet_register(fd, FDE_READ, wnet_accept, NULL); |
| 109 | + wlog(WLOG_NOTICE, "listening on %s", lns->name); |
| 110 | + } |
| 111 | +} |
| 112 | + |
| 113 | +void |
| 114 | +wnet_accept(e) |
| 115 | + struct fde *e; |
| 116 | +{ |
| 117 | +struct client_data *cdata; |
| 118 | +#ifdef __hpux |
| 119 | + int addrlen; |
| 120 | +#else |
| 121 | + socklen_t addrlen; |
| 122 | +#endif |
| 123 | + int newfd, val; |
| 124 | +struct fde *newe; |
| 125 | + |
| 126 | + if ((cdata = wcalloc(1, sizeof(*cdata))) == NULL) |
| 127 | + outofmemory(); |
| 128 | + |
| 129 | + addrlen = sizeof(cdata->cdat_addr); |
| 130 | + |
| 131 | + if ((newfd = accept(e->fde_fd, (struct sockaddr *) &cdata->cdat_addr, &addrlen)) < 0) { |
| 132 | + wlog(WLOG_NOTICE, "accept error: %s", strerror(errno)); |
| 133 | + wfree(cdata); |
| 134 | + return; |
| 135 | + } |
| 136 | + |
| 137 | + if (newfd >= max_fd) { |
| 138 | + wlog(WLOG_NOTICE, "out of file descriptors!"); |
| 139 | + wfree(cdata); |
| 140 | + (void)close(newfd); |
| 141 | + return; |
| 142 | + } |
| 143 | + |
| 144 | + val = fcntl(newfd, F_GETFL, 0); |
| 145 | + if (val == -1 || fcntl(newfd, F_SETFL, val | O_NONBLOCK) == -1) { |
| 146 | + wlog(WLOG_WARNING, "fcntl(%d) failed: %s", newfd, strerror(errno)); |
| 147 | + wfree(cdata); |
| 148 | + (void)close(newfd); |
| 149 | + return; |
| 150 | + } |
| 151 | + |
| 152 | + newe = &fde_table[newfd]; |
| 153 | + init_fde(newe); |
| 154 | + newe->fde_flags.open = 1; |
| 155 | +#ifdef USE_POLL |
| 156 | + if (newfd > highest_fd) |
| 157 | + highest_fd = newfd; |
| 158 | +#endif |
| 159 | + newe->fde_fd = newfd; |
| 160 | + newe->fde_cdata = cdata; |
| 161 | + newe->fde_desc = "accept()ed fd"; |
| 162 | + (void)inet_ntop(AF_INET, &cdata->cdat_addr.sin_addr.s_addr, newe->fde_straddr, sizeof(newe->fde_straddr)); |
| 163 | + |
| 164 | + WDEBUG((WLOG_DEBUG, "wnet_accept: new fd %d", newfd)); |
| 165 | + http_new(newe); |
| 166 | + return; |
| 167 | +} |
| 168 | + |
| 169 | +static void |
| 170 | +init_fde(fde) |
| 171 | + struct fde *fde; |
| 172 | +{ |
| 173 | + fde->fde_fd = 0; |
| 174 | + fde->fde_desc = "<unknown>"; |
| 175 | + fde->fde_read_handler = NULL; |
| 176 | + fde->fde_write_handler = NULL; |
| 177 | + fde->fde_cdata = NULL; |
| 178 | + fde->fde_rdata = fde->fde_wdata = NULL; |
| 179 | + (void)strcpy(fde->fde_straddr, "NONE"); |
| 180 | + fde->fde_epflags = 0; |
| 181 | + bzero(&fde->fde_readbuf, sizeof(fde->fde_readbuf)); |
| 182 | + fde->fde_flags.open = 0; |
| 183 | +} |
| 184 | + |
| 185 | +int |
| 186 | +wnet_open(desc) |
| 187 | + const char *desc; |
| 188 | +{ |
| 189 | + int fd, val; |
| 190 | + |
| 191 | + if ((fd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { |
| 192 | + wlog(WLOG_WARNING, "socket: %s", strerror(errno)); |
| 193 | + return -1; |
| 194 | + } |
| 195 | + |
| 196 | + val = fcntl(fd, F_GETFL, 0); |
| 197 | + if (val == -1 || fcntl(fd, F_SETFL, val | O_NONBLOCK) == -1) { |
| 198 | + wlog(WLOG_WARNING, "fcntl(%d) failed: %s", fd, strerror(errno)); |
| 199 | + return -1; |
| 200 | + } |
| 201 | + |
| 202 | + init_fde(&fde_table[fd]); |
| 203 | + fde_table[fd].fde_fd = fd; |
| 204 | + fde_table[fd].fde_desc = desc; |
| 205 | + fde_table[fd].fde_flags.open = 1; |
| 206 | +#ifdef USE_POLL |
| 207 | + if (fd > highest_fd) |
| 208 | + highest_fd = fd; |
| 209 | +#endif |
| 210 | + |
| 211 | + return fd; |
| 212 | +} |
| 213 | + |
| 214 | +void |
| 215 | +wnet_close(fd) |
| 216 | + int fd; |
| 217 | +{ |
| 218 | +struct fde *e = &fde_table[fd]; |
| 219 | + |
| 220 | + wnet_register(fd, FDE_READ | FDE_WRITE, NULL, NULL); |
| 221 | + (void)close(e->fde_fd); |
| 222 | + if (e->fde_cdata) |
| 223 | + wfree(e->fde_cdata); |
| 224 | + readbuf_free(&e->fde_readbuf); |
| 225 | + e->fde_flags.open = 0; |
| 226 | + e->fde_read_handler = NULL; |
| 227 | + e->fde_write_handler = NULL; |
| 228 | +#ifdef USE_POLL |
| 229 | + if (fd == highest_fd) |
| 230 | + --highest_fd; |
| 231 | +#endif |
| 232 | +} |
| 233 | + |
| 234 | +void |
| 235 | +wnet_sendfile(fd, source, size, off, cb, data) |
| 236 | + int fd, source; |
| 237 | + size_t size; |
| 238 | + off_t off; |
| 239 | + fdwcb cb; |
| 240 | + void *data; |
| 241 | +{ |
| 242 | +struct wrtbuf *wb; |
| 243 | +struct fde *e = &fde_table[fd]; |
| 244 | + |
| 245 | + WDEBUG((WLOG_DEBUG, "wnet_sendfile: %d (+%ld) bytes from %d to %d [%s]", size, (long)off, source, fd, e->fde_desc)); |
| 246 | + |
| 247 | + if ((wb = wcalloc(1, sizeof(*wb))) == NULL) |
| 248 | + outofmemory(); |
| 249 | + |
| 250 | + wb->wb_done = 0; |
| 251 | + wb->wb_func = cb; |
| 252 | + wb->wb_udata = data; |
| 253 | + wb->wb_size = size; |
| 254 | + wb->wb_source = source; |
| 255 | + wb->wb_off = off; |
| 256 | + |
| 257 | + e->fde_wdata = wb; |
| 258 | + wnet_register(e->fde_fd, FDE_WRITE, wnet_sendfile_do, e); |
| 259 | + wnet_sendfile_do(e); |
| 260 | +} |
| 261 | + |
| 262 | +void |
| 263 | +wnet_write(fd, buf, bufsz, cb, data) |
| 264 | + int fd; |
| 265 | + const void *buf; |
| 266 | + size_t bufsz; |
| 267 | + fdwcb cb; |
| 268 | + void *data; |
| 269 | +{ |
| 270 | +struct wrtbuf *wb; |
| 271 | +struct fde *e = &fde_table[fd]; |
| 272 | + |
| 273 | + WDEBUG((WLOG_DEBUG, "wnet_write: %d bytes to %d [%s]", bufsz, e->fde_fd, e->fde_desc)); |
| 274 | + |
| 275 | + if ((wb = wmalloc(sizeof(*wb))) == NULL) |
| 276 | + outofmemory(); |
| 277 | + |
| 278 | + wb->wb_buf = buf; |
| 279 | + wb->wb_size = bufsz; |
| 280 | + wb->wb_done = 0; |
| 281 | + wb->wb_func = cb; |
| 282 | + wb->wb_udata = data; |
| 283 | + |
| 284 | + e->fde_wdata = wb; |
| 285 | + |
| 286 | + wnet_register(e->fde_fd, FDE_WRITE, wnet_sendfile_do, e); |
| 287 | + wnet_write_do(e); |
| 288 | +} |
| 289 | + |
| 290 | +static void |
| 291 | +wnet_write_do(e) |
| 292 | + struct fde *e; |
| 293 | +{ |
| 294 | +struct wrtbuf *buf; |
| 295 | + int i; |
| 296 | +#ifdef WILLOW_DEBUG |
| 297 | + char *p; |
| 298 | +#endif |
| 299 | + |
| 300 | + buf = e->fde_wdata; |
| 301 | + while ((i = write(e->fde_fd, (char *)buf->wb_buf + buf->wb_done, buf->wb_size - buf->wb_done)) > -1) { |
| 302 | +#ifdef WILLOW_DEBUG |
| 303 | + fprintf(stderr, "write buf: ["); |
| 304 | + for (p = ((char *)buf->wb_buf + buf->wb_done); p < ((char *)buf->wb_buf + buf->wb_done + i); ++p) |
| 305 | + fputc(*p, stderr); |
| 306 | + fputs("]\n", stderr); |
| 307 | +#endif |
| 308 | + buf->wb_done += i; |
| 309 | + WDEBUG((WLOG_DEBUG, "%d of %d done", buf->wb_done, buf->wb_size)); |
| 310 | + if (buf->wb_done == buf->wb_size) { |
| 311 | + wnet_register(e->fde_fd, FDE_WRITE, NULL, NULL); |
| 312 | + buf->wb_func(e, buf->wb_udata, 0); |
| 313 | + wfree(buf); |
| 314 | + return; |
| 315 | + } |
| 316 | + } |
| 317 | + |
| 318 | + if (errno == EWOULDBLOCK) |
| 319 | + return; |
| 320 | + |
| 321 | + wnet_register(e->fde_fd, FDE_WRITE, NULL, NULL); |
| 322 | + buf->wb_func(e, buf->wb_udata, -1); |
| 323 | + wfree(buf); |
| 324 | +} |
| 325 | + |
| 326 | +static void |
| 327 | +wnet_sendfile_do(e) |
| 328 | + struct fde *e; |
| 329 | +{ |
| 330 | +struct wrtbuf *buf; |
| 331 | + int i; |
| 332 | + /*LINTED unused variable: freebsd-only*/ |
| 333 | + off_t off, origoff; |
| 334 | + |
| 335 | + buf = e->fde_wdata; |
| 336 | + origoff = buf->wb_off; |
| 337 | + |
| 338 | + WDEBUG((WLOG_DEBUG, "wnet_sendfile_do: for %d, off=%ld, size=%d", e->fde_fd, (long) buf->wb_off, buf->wb_size)); |
| 339 | + /* |
| 340 | + * On Solaris (sendfilev), FreeBSD, Tru64 UNIX and HP-UX (sendfile), we can write header data |
| 341 | + * along with the sendfile, which improves performance and reduces syscall usage. |
| 342 | + * At the moment this isn't supported, though... |
| 343 | + * |
| 344 | + * Linux sendfile() doesn't seem to have anything similar. |
| 345 | + */ |
| 346 | +#if defined __linux__ || defined __sun |
| 347 | + i = sendfile(e->fde_fd, buf->wb_source, &buf->wb_off, buf->wb_size); |
| 348 | +#elif defined __FreeBSD__ |
| 349 | + i = sendfile(buf->wb_source, e->fde_fd, buf->wb_size, NULL, &off, 0); |
| 350 | + buf->wb_off += off; |
| 351 | + i = off; |
| 352 | +#elif defined __hpux || (defined __digital__ && defined __unix__) |
| 353 | + i = sendfile(e->fde_fd, buf->wb_source, buf->wb_off, buf->wb_size, NULL, 0); |
| 354 | + buf->wb_off += i; |
| 355 | +#else |
| 356 | +# error i don't know how to invoke sendfile() on this system |
| 357 | +#endif |
| 358 | + buf->wb_size -= (buf->wb_off - origoff); |
| 359 | + |
| 360 | + if (buf->wb_size == 0) { |
| 361 | + wnet_register(e->fde_fd, FDE_WRITE, NULL, NULL); |
| 362 | + buf->wb_func(e, buf->wb_udata, 0); |
| 363 | + wfree(buf); |
| 364 | + return; |
| 365 | + } |
| 366 | + |
| 367 | + if (i == -1 && errno != EWOULDBLOCK) { |
| 368 | + wnet_register(e->fde_fd, FDE_WRITE, NULL, NULL); |
| 369 | + buf->wb_func(e, buf->wb_udata, -1); |
| 370 | + wfree(buf); |
| 371 | + } |
| 372 | + |
| 373 | + WDEBUG((WLOG_DEBUG, "wnet_sendfile_do: sendfile failed %s", strerror(errno))); |
| 374 | + |
| 375 | + if (errno == EWOULDBLOCK) |
| 376 | + return; |
| 377 | + |
| 378 | +} |
| 379 | + |
| 380 | +void |
| 381 | +wnet_set_time(void) |
| 382 | +{ |
| 383 | +struct tm *now; |
| 384 | + time_t old = current_time; |
| 385 | + size_t n; |
| 386 | + |
| 387 | + current_time = time(NULL); |
| 388 | + if (current_time == old) |
| 389 | + return; |
| 390 | + |
| 391 | + now = gmtime(¤t_time); |
| 392 | + |
| 393 | + n = strftime(current_time_str, sizeof(current_time_str), "%a, %d %b %Y %H:%M:%S GMT", now); |
| 394 | + assert(n); |
| 395 | + n = strftime(current_time_short, sizeof(current_time_short), "%Y-%m-%d %H:%M:%S", now); |
| 396 | + assert(n); |
| 397 | +} |
| 398 | + |
| 399 | + |
| 400 | +int |
| 401 | +readbuf_getdata(fde) |
| 402 | + struct fde *fde; |
| 403 | +{ |
| 404 | + int i; |
| 405 | + |
| 406 | + WDEBUG((WLOG_DEBUG, "readbuf_getdata: called")); |
| 407 | + if (readbuf_data_left(&fde->fde_readbuf) == 0) |
| 408 | + readbuf_reset(&fde->fde_readbuf); |
| 409 | + |
| 410 | + if (readbuf_spare_size(&fde->fde_readbuf) == 0) { |
| 411 | + WDEBUG((WLOG_DEBUG, "readbuf_getdata: no space in buffer")); |
| 412 | + fde->fde_readbuf.rb_size += RDBUF_INC; |
| 413 | + fde->fde_readbuf.rb_p = realloc(fde->fde_readbuf.rb_p, fde->fde_readbuf.rb_size); |
| 414 | + } |
| 415 | + |
| 416 | + if ((i = read(fde->fde_fd, readbuf_spare_start(&fde->fde_readbuf), readbuf_spare_size(&fde->fde_readbuf))) < 1) |
| 417 | + return i; |
| 418 | + fde->fde_readbuf.rb_dsize += i; |
| 419 | + WDEBUG((WLOG_DEBUG, "readbuf_getdata: read %d bytes", i)); |
| 420 | + |
| 421 | + return i; |
| 422 | +} |
| 423 | + |
| 424 | +void |
| 425 | +readbuf_free(buffer) |
| 426 | + struct readbuf *buffer; |
| 427 | +{ |
| 428 | + if (buffer->rb_p) |
| 429 | + free(buffer->rb_p); |
| 430 | + bzero(buffer, sizeof(*buffer)); |
| 431 | +} |
| 432 | + |
| 433 | +static void |
| 434 | +readbuf_reset(buffer) |
| 435 | + struct readbuf *buffer; |
| 436 | +{ |
| 437 | + buffer->rb_dpos = buffer->rb_dsize = 0; |
| 438 | +} |
Property changes on: trunk/willow/src/lib/wnet/wnet.c |
___________________________________________________________________ |
Added: svn:keywords |
1 | 439 | + Author Date Id Revision |
Added: svn:eol-style |
2 | 440 | + native |
Index: trunk/willow/src/lib/Makefile.in |
— | — | @@ -0,0 +1,10 @@ |
| 2 | +# @(#) $Header$ |
| 3 | +# |
| 4 | +# src/lib makefile. |
| 5 | + |
| 6 | +SUBDIRS=wnet wlog |
| 7 | + |
| 8 | +@include@ @q@@top_srcdir@/mk/subdir.mk@q@ |
| 9 | + |
| 10 | +DISTFILES=\ |
| 11 | + Makefile.in |
Property changes on: trunk/willow/src/lib/Makefile.in |
___________________________________________________________________ |
Added: svn:keywords |
1 | 12 | + Author Date Id Revision |
Added: svn:eol-style |
2 | 13 | + native |
Index: trunk/willow/src/lib/wlog/Makefile.in |
— | — | @@ -0,0 +1,10 @@ |
| 2 | +LIB = willowlog |
| 3 | + |
| 4 | +CPPFLAGS = -DDATADIR=\"$(_DATADIR)\" |
| 5 | +SRCS = wlog.c |
| 6 | + |
| 7 | +EXTRA_DIST=Makefile.in |
| 8 | + |
| 9 | +LDFLAGS = $(LIBOBJS) |
| 10 | + |
| 11 | +@include@ @q@@top_srcdir@/mk/lib.mk@q@ |
Property changes on: trunk/willow/src/lib/wlog/Makefile.in |
___________________________________________________________________ |
Added: svn:keywords |
1 | 12 | + Author Date Id Revision |
Added: svn:eol-style |
2 | 13 | + native |
Index: trunk/willow/src/lib/wlog/wlog.c |
— | — | @@ -0,0 +1,116 @@ |
| 2 | +/* @(#) $Header$ */ |
| 3 | +/* This source code is in the public domain. */ |
| 4 | +/* |
| 5 | + * Willow: Lightweight HTTP reverse-proxy. |
| 6 | + * wlog: logging. |
| 7 | + */ |
| 8 | + |
| 9 | +#if defined __SUNPRO_C || defined __DECC || defined __HP_cc |
| 10 | +# pragma ident "@(#)$Header$" |
| 11 | +#endif |
| 12 | + |
| 13 | +#include <stdio.h> |
| 14 | +#include <stdarg.h> |
| 15 | +#include <stdlib.h> |
| 16 | +#include <stdarg.h> |
| 17 | +#include <string.h> |
| 18 | +#include <syslog.h> |
| 19 | +#include <errno.h> |
| 20 | + |
| 21 | +#include "config.h" |
| 22 | +#ifdef THREADED_IO |
| 23 | +# include <pthread.h> |
| 24 | +#endif |
| 25 | + |
| 26 | +#include "wlog.h" |
| 27 | +#include "wnet.h" |
| 28 | +#include "wconfig.h" |
| 29 | + |
| 30 | +#ifdef THREADED_IO |
| 31 | +static pthread_mutex_t wlog_mtx = PTHREAD_MUTEX_INITIALIZER; |
| 32 | +# define WLOG_LOCK() pthread_mutex_lock(&wlog_mtx) |
| 33 | +# define WLOG_UNLOCK() pthread_mutex_unlock(&wlog_mtx) |
| 34 | +#else |
| 35 | +# define WLOG_LOCK() |
| 36 | +# define WLOG_UNLOCK() |
| 37 | +#endif |
| 38 | + |
| 39 | +struct log_variables logging; |
| 40 | + |
| 41 | +static const char *sev_names[] = { |
| 42 | + "Debug", |
| 43 | + "Notice", |
| 44 | + "Warning", |
| 45 | + "Error", |
| 46 | +}; |
| 47 | + |
| 48 | +static const int syslog_pri[] = { |
| 49 | + LOG_INFO, |
| 50 | + LOG_WARNING, |
| 51 | + LOG_ERR, |
| 52 | +}; |
| 53 | + |
| 54 | +void |
| 55 | +wlog_init(void) |
| 56 | +{ |
| 57 | + if (logging.syslog) |
| 58 | + openlog("willow", LOG_PID, logging.facility); |
| 59 | + |
| 60 | + if (!logging.file) |
| 61 | + return; |
| 62 | + |
| 63 | + /*LINTED unsafe fopen*/ |
| 64 | + logging.fp = fopen(logging.file, "a"); |
| 65 | + if (logging.fp == NULL) { |
| 66 | + perror(logging.file); |
| 67 | + exit(8); |
| 68 | + } |
| 69 | +} |
| 70 | + |
| 71 | +void |
| 72 | +wlog(int sev, const char *fmt, ...) |
| 73 | +{ |
| 74 | + char s[1024]; |
| 75 | + va_list ap; |
| 76 | + int i; |
| 77 | + |
| 78 | + if (sev > WLOG_MAX) |
| 79 | + sev = WLOG_NOTICE; |
| 80 | + if (sev < logging.level) |
| 81 | + return; |
| 82 | + va_start(ap, fmt); |
| 83 | + i = snprintf(s, 1024, "%s| %s: ", current_time_short, sev_names[sev]); |
| 84 | + if (i > 1023) |
| 85 | + abort(); |
| 86 | + if (vsnprintf(s + i, 1023 - i, fmt, ap) > (1023 - i - 1)) |
| 87 | + abort(); |
| 88 | + |
| 89 | + WLOG_LOCK(); |
| 90 | + if (logging.syslog) |
| 91 | + syslog(syslog_pri[sev], "%s", s + i); |
| 92 | + if (logging.fp) { |
| 93 | + if (fprintf(logging.fp, "%s\n", s) < 0) { |
| 94 | + (void)fclose(logging.fp); |
| 95 | + logging.fp = NULL; |
| 96 | + wlog(WLOG_ERROR, "writing to logfile: %s", strerror(errno)); |
| 97 | + exit(8); |
| 98 | + } |
| 99 | + } |
| 100 | + |
| 101 | + if (config.foreground) |
| 102 | + (void)fprintf(stderr, "%s\n", s); |
| 103 | + WLOG_UNLOCK(); |
| 104 | + va_end(ap); |
| 105 | +} |
| 106 | + |
| 107 | +void |
| 108 | +wlog_close(void) |
| 109 | +{ |
| 110 | + if (fclose(logging.fp) == EOF) { |
| 111 | + logging.fp = NULL; |
| 112 | + wlog(WLOG_WARNING, "closing logfile: %s", strerror(errno)); |
| 113 | + } |
| 114 | + |
| 115 | + if (logging.syslog) |
| 116 | + closelog(); |
| 117 | +} |
Property changes on: trunk/willow/src/lib/wlog/wlog.c |
___________________________________________________________________ |
Added: svn:keywords |
1 | 118 | + Author Date Id Revision |
Added: svn:eol-style |
2 | 119 | + native |
Index: trunk/willow/src/bin/Makefile.in |
— | — | @@ -0,0 +1,10 @@ |
| 2 | +# @(#) $Header$ |
| 3 | +# |
| 4 | +# src/ makefile. |
| 5 | + |
| 6 | +SUBDIRS=willow |
| 7 | + |
| 8 | +@include@ @q@@top_srcdir@/mk/subdir.mk@q@ |
| 9 | + |
| 10 | +DISTFILES=\ |
| 11 | + Makefile.in |
Property changes on: trunk/willow/src/bin/Makefile.in |
___________________________________________________________________ |
Added: svn:keywords |
1 | 12 | + Author Date Id Revision |
Added: svn:eol-style |
2 | 13 | + native |
Index: trunk/willow/src/bin/willow/strlcat.c |
— | — | @@ -0,0 +1,65 @@ |
| 2 | +/* @(#)$Header$ */ |
| 3 | +/* $NetBSD: strlcat.c,v 1.16 2003/10/27 00:12:42 lukem Exp $ */ |
| 4 | +/* $OpenBSD: strlcat.c,v 1.10 2003/04/12 21:56:39 millert Exp $ */ |
| 5 | + |
| 6 | +/* |
| 7 | + * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com> |
| 8 | + * |
| 9 | + * Permission to use, copy, modify, and distribute this software for any |
| 10 | + * purpose with or without fee is hereby granted, provided that the above |
| 11 | + * copyright notice and this permission notice appear in all copies. |
| 12 | + * |
| 13 | + * THE SOFTWARE IS PROVIDED "AS IS" AND TODD C. MILLER DISCLAIMS ALL |
| 14 | + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES |
| 15 | + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL TODD C. MILLER BE LIABLE |
| 16 | + * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
| 17 | + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION |
| 18 | + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN |
| 19 | + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
| 20 | + */ |
| 21 | + |
| 22 | +#if defined __SUNPRO_C || defined __DECC || defined __HP_cc |
| 23 | +# pragma ident "@(#)$Header$" |
| 24 | +#endif |
| 25 | + |
| 26 | +#include <sys/types.h> |
| 27 | +#include <assert.h> |
| 28 | +#include <string.h> |
| 29 | + |
| 30 | +/* |
| 31 | + * Appends src to string dst of size siz (unlike strncat, siz is the |
| 32 | + * full size of dst, not space left). At most siz-1 characters |
| 33 | + * will be copied. Always NUL terminates (unless siz <= strlen(dst)). |
| 34 | + * Returns strlen(src) + MIN(siz, strlen(initial dst)). |
| 35 | + * If retval >= siz, truncation occurred. |
| 36 | + */ |
| 37 | +size_t |
| 38 | +strlcat(dst, src, siz) |
| 39 | + char *dst; |
| 40 | + const char *src; |
| 41 | + size_t siz; |
| 42 | +{ |
| 43 | + char *d = dst; |
| 44 | + const char *s = src; |
| 45 | + size_t n = siz; |
| 46 | + size_t dlen; |
| 47 | + |
| 48 | + /* Find the end of dst and adjust bytes left but don't go past end */ |
| 49 | + while (n-- != 0 && *d != '\0') |
| 50 | + d++; |
| 51 | + dlen = d - dst; |
| 52 | + n = siz - dlen; |
| 53 | + |
| 54 | + if (n == 0) |
| 55 | + return(dlen + strlen(s)); |
| 56 | + while (*s != '\0') { |
| 57 | + if (n != 1) { |
| 58 | + *d++ = *s; |
| 59 | + n--; |
| 60 | + } |
| 61 | + s++; |
| 62 | + } |
| 63 | + *d = '\0'; |
| 64 | + |
| 65 | + return(dlen + (s - src)); /* count does not include NUL */ |
| 66 | +} |
Property changes on: trunk/willow/src/bin/willow/strlcat.c |
___________________________________________________________________ |
Added: svn:keywords |
1 | 67 | + Author Date Id Revision |
Added: svn:eol-style |
2 | 68 | + native |
Index: trunk/willow/src/bin/willow/wconfig.c |
— | — | @@ -0,0 +1,128 @@ |
| 2 | +/* @(#) $Header$ */ |
| 3 | +/* This source code is in the public domain. */ |
| 4 | +/* |
| 5 | + * Willow: Lightweight HTTP reverse-proxy. |
| 6 | + * wconfig: configuration. |
| 7 | + */ |
| 8 | + |
| 9 | +#if defined __SUNPRO_C || defined __DECC || defined __HP_cc |
| 10 | +# pragma ident "@(#)$Header$" |
| 11 | +#endif |
| 12 | + |
| 13 | +#include <sys/types.h> |
| 14 | +#include <sys/socket.h> |
| 15 | + |
| 16 | +#include <netinet/in.h> |
| 17 | + |
| 18 | +#include <arpa/inet.h> |
| 19 | + |
| 20 | +#include <stdlib.h> |
| 21 | +#include <stdio.h> |
| 22 | +#include <string.h> |
| 23 | +#include <syslog.h> |
| 24 | +#include <errno.h> |
| 25 | +#include <strings.h> |
| 26 | + |
| 27 | +#include "willow.h" |
| 28 | +#include "wconfig.h" |
| 29 | +#include "wbackend.h" |
| 30 | +#include "wlog.h" |
| 31 | +#include "confparse.h" |
| 32 | + |
| 33 | +#define CONFIGFILE "./willow.conf" |
| 34 | + |
| 35 | +int yyparse(); |
| 36 | + |
| 37 | +struct listener **listeners; |
| 38 | +int nlisteners; |
| 39 | +struct configuration config; |
| 40 | + |
| 41 | +const char *current_file; |
| 42 | + |
| 43 | +void |
| 44 | +wconfig_init(const char *file) |
| 45 | +{ |
| 46 | + FILE *cfg; |
| 47 | +extern FILE *yyin; |
| 48 | + |
| 49 | + if (file == NULL) |
| 50 | + file = CONFIGFILE; |
| 51 | + current_file = file; |
| 52 | + |
| 53 | + if ((cfg = fopen(file, "r")) == NULL) { |
| 54 | + perror(file); |
| 55 | + exit(8); |
| 56 | + } |
| 57 | + wlog(WLOG_NOTICE, "loading configuration from %s", current_file); |
| 58 | + yyin = cfg; |
| 59 | + newconf_init(); |
| 60 | + |
| 61 | + if (yyparse()) { |
| 62 | + wlog(WLOG_ERROR, "could not parse configuration file"); |
| 63 | + nerrors++; |
| 64 | + } |
| 65 | + if (!nlisteners) { |
| 66 | + wlog(WLOG_ERROR, "no listeners defined"); |
| 67 | + nerrors++; |
| 68 | + } |
| 69 | + if (!nbackends) { |
| 70 | + wlog(WLOG_ERROR, "no backends defined"); |
| 71 | + nerrors++; |
| 72 | + } |
| 73 | + if (nerrors) { |
| 74 | + wlog(WLOG_ERROR, "%d error(s) in configuration file. cannot continue.", nerrors); |
| 75 | + exit(8); |
| 76 | + } |
| 77 | + |
| 78 | + (void)fclose(cfg); |
| 79 | +} |
| 80 | + |
| 81 | +int |
| 82 | +add_listener(addr, port) |
| 83 | + const char *addr; |
| 84 | + int port; |
| 85 | +{ |
| 86 | +struct listener *nl; |
| 87 | + |
| 88 | + if (port < 0 || port > 65535) { |
| 89 | + conf_report_error("invalid listener port %d", port); |
| 90 | + nerrors++; |
| 91 | + return -1; |
| 92 | + } |
| 93 | + |
| 94 | + if ((nl = wcalloc(1, sizeof(*nl))) == NULL) |
| 95 | + outofmemory(); |
| 96 | + |
| 97 | + if ((listeners = wrealloc(listeners, sizeof(struct listener *) * ++nlisteners)) == NULL) |
| 98 | + outofmemory(); |
| 99 | + |
| 100 | + nl->port = port; |
| 101 | + nl->name = wstrdup(addr); |
| 102 | + nl->addr.sin_family = AF_INET; |
| 103 | + nl->addr.sin_port = htons(nl->port); |
| 104 | + nl->addr.sin_addr.s_addr = inet_addr(nl->name); |
| 105 | + listeners[nlisteners - 1] = nl; |
| 106 | + wlog(WLOG_NOTICE, "listening on %s:%d", addr, port); |
| 107 | + return 0; |
| 108 | +} |
| 109 | + |
| 110 | +int |
| 111 | +add_cachedir(dir, size) |
| 112 | + const char *dir; |
| 113 | + int size; |
| 114 | +{ |
| 115 | + if (size < 1) { |
| 116 | + conf_report_error("invalid cache size %d\n", size); |
| 117 | + nerrors++; |
| 118 | + return -1; |
| 119 | + } |
| 120 | + |
| 121 | + config.caches = wrealloc(config.caches, sizeof(*config.caches) * (config.ncaches + 1)); |
| 122 | + config.caches[config.ncaches].dir = wstrdup(dir); |
| 123 | + config.caches[config.ncaches].maxsize = size; |
| 124 | + wlog(WLOG_NOTICE, "cache dir \"%s\", size %d bytes", |
| 125 | + config.caches[config.ncaches].dir, |
| 126 | + config.caches[config.ncaches].maxsize); |
| 127 | + config.ncaches++; |
| 128 | + return 0; |
| 129 | +} |
Property changes on: trunk/willow/src/bin/willow/wconfig.c |
___________________________________________________________________ |
Added: svn:keywords |
1 | 130 | + Author Date Id Revision |
Added: svn:eol-style |
2 | 131 | + native |
Index: trunk/willow/src/bin/willow/willow.c |
— | — | @@ -0,0 +1,406 @@ |
| 2 | +/* @(#) $Header$ */ |
| 3 | +/* This source code is in the public domain. */ |
| 4 | +/* |
| 5 | + * Willow: Lightweight HTTP reverse-proxy. |
| 6 | + */ |
| 7 | + |
| 8 | +#if defined __SUNPRO_C || defined __DECC || defined __HP_cc |
| 9 | +# pragma ident "@(#)$Header$" |
| 10 | +#endif |
| 11 | + |
| 12 | +#include <sys/mman.h> |
| 13 | + |
| 14 | +#include <stdio.h> |
| 15 | +#include <stdlib.h> |
| 16 | +#include <signal.h> |
| 17 | +#include <stdarg.h> |
| 18 | +#include <string.h> |
| 19 | +#include <unistd.h> |
| 20 | +#include <errno.h> |
| 21 | + |
| 22 | +#include "wlog.h" |
| 23 | +#include "wnet.h" |
| 24 | +#include "wconfig.h" |
| 25 | +#include "willow.h" |
| 26 | +#include "whttp.h" |
| 27 | +#include "wcache.h" |
| 28 | + |
| 29 | +#ifdef WDEBUG_ALLOC |
| 30 | +static void ae_checkleaks(void); |
| 31 | +static void segv_action(int, siginfo_t *, void *); |
| 32 | +#endif |
| 33 | + |
| 34 | +static const char *progname; |
| 35 | + |
| 36 | +#define min(x,y) ((x) < (y) ? (x) : (y)) |
| 37 | + |
| 38 | +/*ARGSUSED*/ |
| 39 | +static void |
| 40 | +sig_exit(s) |
| 41 | + int s; |
| 42 | +{ |
| 43 | + wnet_exit = 1; |
| 44 | +} |
| 45 | + |
| 46 | +static void |
| 47 | +usage(void) |
| 48 | +{ |
| 49 | + (void)fprintf(stderr, "usage: %s [-fzv]\n" |
| 50 | + "\t-f\trun in foreground (don't detach)\n" |
| 51 | + "\t-z\tcreate cache directory structure and exit\n" |
| 52 | + "\t-v\tprint version number and exit\n" |
| 53 | + , progname); |
| 54 | +} |
| 55 | + |
| 56 | +#ifdef __lint |
| 57 | +# pragma error_messages(off, E_H_C_CHECK2) |
| 58 | +#endif |
| 59 | + |
| 60 | +int |
| 61 | +main(argc, argv) |
| 62 | + char *argv[]; |
| 63 | + int argc; |
| 64 | +{ |
| 65 | + int i; |
| 66 | + int zflag = 0; |
| 67 | + |
| 68 | +#ifdef WDEBUG_ALLOC |
| 69 | +struct sigaction segv_act; |
| 70 | + bzero(&segv_act, sizeof(segv_act)); |
| 71 | + segv_act.sa_sigaction = segv_action; |
| 72 | + segv_act.sa_flags = SA_SIGINFO; |
| 73 | + |
| 74 | + sigaction(SIGSEGV, &segv_act, NULL); |
| 75 | +#endif |
| 76 | + |
| 77 | + progname = argv[0]; |
| 78 | + |
| 79 | + while ((i = getopt(argc, argv, "fzv")) != -1) { |
| 80 | + switch (i) { |
| 81 | + case 'z': |
| 82 | + zflag++; |
| 83 | + /*FALLTHRU*/ |
| 84 | + case 'f': |
| 85 | + config.foreground = 1; |
| 86 | + break; |
| 87 | + case 'v': |
| 88 | + (void)fprintf(stderr, "%s\n", PACKAGE_VERSION); |
| 89 | + exit(0); |
| 90 | + default: |
| 91 | + usage(); |
| 92 | + exit(8); |
| 93 | + } |
| 94 | + } |
| 95 | + |
| 96 | + argv += optind; |
| 97 | + argc -= optind; |
| 98 | + |
| 99 | + if (argc) { |
| 100 | + (void)fprintf(stderr, "%s: too many argments\n", progname); |
| 101 | + usage(); |
| 102 | + exit(8); |
| 103 | + } |
| 104 | + |
| 105 | + wnet_set_time(); |
| 106 | + |
| 107 | + wconfig_init(NULL); |
| 108 | + wlog_init(); |
| 109 | + if (zflag) { |
| 110 | + wcache_setupfs(); |
| 111 | + exit(0); |
| 112 | + } |
| 113 | + wcache_init(1); |
| 114 | + |
| 115 | + /* |
| 116 | + * HTTP should be initialised before the network so that |
| 117 | + * the wlogwriter exits cleanly. |
| 118 | + */ |
| 119 | + whttp_init(); |
| 120 | + wnet_init(); |
| 121 | + |
| 122 | + (void)signal(SIGINT, sig_exit); |
| 123 | + (void)signal(SIGTERM, sig_exit); |
| 124 | + |
| 125 | + wlog(WLOG_NOTICE, "running"); |
| 126 | + |
| 127 | +#ifdef WDEBUG_ALLOC |
| 128 | + (void)fprintf(stderr, "debug allocator enabled, assuming -f\n"); |
| 129 | + config.foreground = 1; |
| 130 | +#endif |
| 131 | + |
| 132 | + if (!config.foreground) |
| 133 | + daemon(0, 0); |
| 134 | + |
| 135 | + wnet_run(); |
| 136 | + wlog_close(); |
| 137 | + wcache_shutdown(); |
| 138 | + whttp_shutdown(); |
| 139 | + |
| 140 | +#ifdef WDEBUG_ALLOC |
| 141 | + ae_checkleaks(); |
| 142 | +#endif |
| 143 | + return EXIT_SUCCESS; |
| 144 | +} |
| 145 | + |
| 146 | +#ifdef __lint |
| 147 | +# pragma error_messages(default, E_H_C_CHECK2) |
| 148 | +#endif |
| 149 | + |
| 150 | +void |
| 151 | +outofmemory(void) |
| 152 | +{ |
| 153 | + static int count; |
| 154 | + |
| 155 | + if (count++) |
| 156 | + abort(); |
| 157 | + |
| 158 | + wlog(WLOG_ERROR, "fatal: out of memory. exiting."); |
| 159 | + exit(8); |
| 160 | +} |
| 161 | + |
| 162 | +void |
| 163 | +realloc_addchar(sp, c) |
| 164 | + char **sp; |
| 165 | + int c; |
| 166 | +{ |
| 167 | + char *p; |
| 168 | + |
| 169 | + if ((*sp = wrealloc(*sp, strlen(*sp) + 2)) == NULL) |
| 170 | + outofmemory(); |
| 171 | + p = *sp + strlen(*sp); |
| 172 | + *p++ = (char) c; |
| 173 | + *p++ = '\0'; |
| 174 | +} |
| 175 | + |
| 176 | +void |
| 177 | +realloc_strcat(sp, s) |
| 178 | + char **sp; |
| 179 | + const char *s; |
| 180 | +{ |
| 181 | + if ((*sp = wrealloc(*sp, strlen(*sp) + strlen(s) + 1)) == NULL) |
| 182 | + outofmemory(); |
| 183 | + (void)strcat(*sp, s); |
| 184 | +} |
| 185 | + |
| 186 | +#ifdef WDEBUG_ALLOC |
| 187 | +# ifdef THREADED_IO |
| 188 | +pthread_mutex_t ae_mtx = PTHREAD_MUTEX_INITIALIZER; |
| 189 | +# define ALLOC_LOCK pthread_mutex_lock(&ae_mtx) |
| 190 | +# define ALLOC_UNLOCK pthread_mutex_unlock(&ae_mtx) |
| 191 | +# else |
| 192 | +# define ALLOC_LOCK ((void)0) |
| 193 | +# define ALLOC_UNLOCK ((void)0) |
| 194 | +# endif |
| 195 | + |
| 196 | +struct alloc_entry { |
| 197 | + char *ae_addr; |
| 198 | + char *ae_mapping; |
| 199 | + size_t ae_mapsize; |
| 200 | + size_t ae_size; |
| 201 | + int ae_freed; |
| 202 | + const char *ae_freed_file; |
| 203 | + int ae_freed_line; |
| 204 | + const char *ae_alloced_file; |
| 205 | + int ae_alloced_line; |
| 206 | +struct alloc_entry *ae_next; |
| 207 | +}; |
| 208 | + |
| 209 | +static struct alloc_entry allocs; |
| 210 | +static int pgsize; |
| 211 | + |
| 212 | +static void |
| 213 | +segv_action(sig, si, data) |
| 214 | + int sig; |
| 215 | + siginfo_t *si; |
| 216 | + void *data; |
| 217 | +{ |
| 218 | +struct alloc_entry *ae; |
| 219 | + |
| 220 | + /* |
| 221 | + * This is mostly non-standard, unportable and unreliable, but if the debug allocator |
| 222 | + * is enabled, it's more important to produce useful errors than conform to the letter |
| 223 | + * of the law. |
| 224 | + */ |
| 225 | + (void)fprintf(stderr, "SEGV at %p%s (pid %d)\n", si->si_addr, si->si_code == SI_NOINFO ? " [SI_NOINFO]" : "", |
| 226 | + (int) getpid()); |
| 227 | + for (ae = allocs.ae_next; ae; ae = ae->ae_next) |
| 228 | + if (!ae->ae_freed && (char *)si->si_addr > ae->ae_mapping && |
| 229 | + (char *)si->si_addr < ae->ae_mapping + ae->ae_mapsize) { |
| 230 | + (void)fprintf(stderr, "\t%p [map @ %p size %d] from %s:%d\n", ae->ae_addr, ae->ae_mapping, |
| 231 | + ae->ae_mapsize, ae->ae_alloced_file, ae->ae_alloced_line); |
| 232 | + break; |
| 233 | + } |
| 234 | + if (ae == NULL) |
| 235 | + (void)fprintf(stderr, "\tunknown address\n"); |
| 236 | + abort(); |
| 237 | + _exit(1); |
| 238 | +} |
| 239 | + |
| 240 | +static void |
| 241 | +ae_checkleaks(void) |
| 242 | +{ |
| 243 | +struct alloc_entry *ae; |
| 244 | + |
| 245 | + ALLOC_LOCK(); |
| 246 | + for (ae = allocs.ae_next; ae; ae = ae->ae_next) |
| 247 | + if (!ae->ae_freed) |
| 248 | + (void)fprintf(stderr, "%p @ %s:%d\n", ae->ae_addr, ae->ae_alloced_file, ae->ae_alloced_line); |
| 249 | + ALLOC_UNLOCK(); |
| 250 | +} |
| 251 | + |
| 252 | +void * |
| 253 | +internal_wmalloc(size, file, line) |
| 254 | + size_t size; |
| 255 | + const char *file; |
| 256 | + int line; |
| 257 | +{ |
| 258 | + void *p; |
| 259 | +struct alloc_entry *ae; |
| 260 | + size_t mapsize; |
| 261 | + |
| 262 | + ALLOC_LOCK(); |
| 263 | + |
| 264 | + if (pgsize == 0) |
| 265 | + pgsize = sysconf(_SC_PAGESIZE); |
| 266 | + |
| 267 | + mapsize = (size/pgsize + 2) * pgsize; |
| 268 | + if ((p = mmap(NULL, mapsize, PROT_READ|PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0)) == (void *)-1) { |
| 269 | + (void)fprintf(stderr, "mmap: %s\n", strerror(errno)); |
| 270 | + ALLOC_UNLOCK(); |
| 271 | + return NULL; |
| 272 | + } |
| 273 | + |
| 274 | + for (ae = &allocs; ae->ae_next; ae = ae->ae_next) |
| 275 | + if (ae->ae_next->ae_mapping == p) |
| 276 | + break; |
| 277 | + |
| 278 | + if (!ae->ae_next) { |
| 279 | + if ((ae->ae_next = malloc(sizeof(struct alloc_entry))) == NULL) { |
| 280 | + (void)fputs("out of memory\n", stderr); |
| 281 | + abort(); |
| 282 | + } |
| 283 | + bzero(ae->ae_next, sizeof(struct alloc_entry)); |
| 284 | + } |
| 285 | + |
| 286 | + ae = ae->ae_next; |
| 287 | + ae->ae_addr = ((char *)p + (mapsize - pgsize)) - size; |
| 288 | + ae->ae_mapping = p; |
| 289 | + ae->ae_mapsize = mapsize; |
| 290 | + ae->ae_size = size; |
| 291 | + ae->ae_freed = 0; |
| 292 | + ae->ae_alloced_file = file; |
| 293 | + ae->ae_alloced_line = line; |
| 294 | + (void)fprintf(stderr, "alloc %d @ %p [map @ %p:%p, size %d] at %s:%d\n", size, ae->ae_addr, |
| 295 | + ae->ae_mapping, ae->ae_mapping + ae->ae_mapsize, ae->ae_mapsize, file, line); |
| 296 | + if (mprotect(ae->ae_addr + size, pgsize, PROT_NONE) < 0) { |
| 297 | + (void)fprintf(stderr, "mprotect(0x%p, %d, PROT_NONE): %s\n", ae->ae_addr + size, pgsize, strerror(errno)); |
| 298 | + exit(8); |
| 299 | + } |
| 300 | + |
| 301 | + ALLOC_UNLOCK(); |
| 302 | + return ae->ae_addr; |
| 303 | +} |
| 304 | + |
| 305 | +void |
| 306 | +internal_wfree(p, file, line) |
| 307 | + void *p; |
| 308 | + const char *file; |
| 309 | + int line; |
| 310 | +{ |
| 311 | +struct alloc_entry *ae; |
| 312 | + |
| 313 | + ALLOC_LOCK(); |
| 314 | + |
| 315 | + (void)fprintf(stderr, "free %p @ %s:%d\n", p, file, line); |
| 316 | + |
| 317 | + for (ae = allocs.ae_next; ae; ae = ae->ae_next) { |
| 318 | + if (ae->ae_addr == p) { |
| 319 | + if (ae->ae_freed) { |
| 320 | + (void)fprintf(stderr, "wfree: ptr %p already freed @ %s:%d! [alloced at %s:%d]\n", |
| 321 | + p, ae->ae_freed_file, ae->ae_freed_line, |
| 322 | + ae->ae_alloced_file, ae->ae_alloced_line); |
| 323 | + ae_checkleaks(); |
| 324 | + abort(); |
| 325 | + } |
| 326 | + ae->ae_freed = 1; |
| 327 | + ae->ae_freed_file = file; |
| 328 | + ae->ae_freed_line = line; |
| 329 | + if (mprotect(ae->ae_addr + ae->ae_size, pgsize, PROT_READ | PROT_WRITE) < 0) { |
| 330 | + (void)fprintf(stderr, "mprotect(0x%p, %d, PROT_READ | PROT_WRITE): %s\n", |
| 331 | + ae->ae_addr + ae->ae_size, pgsize, strerror(errno)); |
| 332 | + exit(8); |
| 333 | + } |
| 334 | + munmap(ae->ae_mapping, ae->ae_mapsize); |
| 335 | + ALLOC_UNLOCK(); |
| 336 | + return; |
| 337 | + } |
| 338 | + } |
| 339 | + |
| 340 | + (void)fprintf(stderr, "wfree: ptr %p never malloced!\n", p); |
| 341 | + ae_checkleaks(); |
| 342 | + abort(); |
| 343 | +} |
| 344 | + |
| 345 | +char * |
| 346 | +internal_wstrdup(s, file, line) |
| 347 | + const char *s, *file; |
| 348 | + int line; |
| 349 | +{ |
| 350 | + char *ret = internal_wmalloc(strlen(s) + 1, file, line); |
| 351 | + (void)strcpy(ret, s); |
| 352 | + return ret; |
| 353 | +} |
| 354 | + |
| 355 | +void * |
| 356 | +internal_wrealloc(p, size, file, line) |
| 357 | + void *p; |
| 358 | + const char *file; |
| 359 | + int line; |
| 360 | + size_t size; |
| 361 | +{ |
| 362 | + void *new; |
| 363 | +struct alloc_entry *ae; |
| 364 | + size_t osize = 0; |
| 365 | + |
| 366 | + if (!p) |
| 367 | + return internal_wmalloc(size, file, line); |
| 368 | + |
| 369 | + ALLOC_LOCK(); |
| 370 | + |
| 371 | + for (ae = allocs.ae_next; ae; ae = ae->ae_next) |
| 372 | + if (ae->ae_addr == p) { |
| 373 | + osize = ae->ae_size; |
| 374 | + break; |
| 375 | + } |
| 376 | + |
| 377 | + if (osize == 0) { |
| 378 | + (void)fprintf(stderr, "wrealloc: ptr %p never malloced!\n", p); |
| 379 | + ae_checkleaks(); |
| 380 | + abort(); |
| 381 | + } |
| 382 | + |
| 383 | + ALLOC_UNLOCK(); |
| 384 | + |
| 385 | + new = internal_wmalloc(size, file, line); |
| 386 | + bcopy(p, new, min(osize, size)); |
| 387 | + internal_wfree(p, file, line); |
| 388 | + |
| 389 | + return new; |
| 390 | +} |
| 391 | + |
| 392 | +void * |
| 393 | +internal_wcalloc(num, size, file, line) |
| 394 | + size_t num, size; |
| 395 | + const char *file; |
| 396 | + int line; |
| 397 | +{ |
| 398 | + size_t t = size * num; |
| 399 | + void *p; |
| 400 | + |
| 401 | + if ((p = internal_wmalloc(t)) == NULL) |
| 402 | + return NULL; |
| 403 | + bzero(p, t); |
| 404 | + return p; |
| 405 | +} |
| 406 | + |
| 407 | +#endif |
Property changes on: trunk/willow/src/bin/willow/willow.c |
___________________________________________________________________ |
Added: svn:keywords |
1 | 408 | + Author Date Id Revision |
Added: svn:eol-style |
2 | 409 | + native |
Index: trunk/willow/src/bin/willow/wbackend.c |
— | — | @@ -0,0 +1,164 @@ |
| 2 | +/* @(#) $Header$ */ |
| 3 | +/* This source code is in the public domain. */ |
| 4 | +/* |
| 5 | + * Willow: Lightweight HTTP reverse-proxy. |
| 6 | + * wbackend: HTTP backend handling. |
| 7 | + */ |
| 8 | + |
| 9 | +#if defined __SUNPRO_C || defined __DECC || defined __HP_cc |
| 10 | +# pragma ident "@(#)$Header$" |
| 11 | +#endif |
| 12 | + |
| 13 | +#include <sys/types.h> |
| 14 | +#include <sys/socket.h> |
| 15 | + |
| 16 | +#include <arpa/inet.h> |
| 17 | + |
| 18 | +#include <stdlib.h> |
| 19 | +#include <stdio.h> |
| 20 | +#include <string.h> |
| 21 | +#include <errno.h> |
| 22 | +#include <strings.h> |
| 23 | + |
| 24 | +#include "willow.h" |
| 25 | +#include "wbackend.h" |
| 26 | +#include "wnet.h" |
| 27 | +#include "wlog.h" |
| 28 | +#include "confparse.h" |
| 29 | + |
| 30 | +static struct backend **backends; |
| 31 | +int nbackends; |
| 32 | + |
| 33 | +static struct backend *new_backend(const char *, int); |
| 34 | +static void backend_read(struct fde *); |
| 35 | +static struct backend *next_backend(void); |
| 36 | + |
| 37 | +struct backend_cb_data { |
| 38 | +struct backend *bc_backend; |
| 39 | + backend_cb bc_func; |
| 40 | + void *bc_data; |
| 41 | +}; |
| 42 | + |
| 43 | +static struct backend * |
| 44 | +new_backend(addr, port) |
| 45 | + const char *addr; |
| 46 | + int port; |
| 47 | +{ |
| 48 | +struct backend *nb; |
| 49 | + |
| 50 | + if ((nb = wcalloc(1, sizeof(*nb))) == NULL) |
| 51 | + outofmemory(); |
| 52 | + |
| 53 | + nb->be_port = port; |
| 54 | + nb->be_name = wstrdup(addr); |
| 55 | + nb->be_addr.sin_family = AF_INET; |
| 56 | + nb->be_addr.sin_port = htons(nb->be_port); |
| 57 | + nb->be_addr.sin_addr.s_addr = inet_addr(nb->be_name); |
| 58 | + nb->be_okay = 1; |
| 59 | + return nb; |
| 60 | +} |
| 61 | + |
| 62 | +void |
| 63 | +add_backend(addr, port) |
| 64 | + const char *addr; |
| 65 | + int port; |
| 66 | +{ |
| 67 | + if (port < 1 || port > 65535) { |
| 68 | + conf_report_error("invalid backend port: %d", port); |
| 69 | + nerrors++; |
| 70 | + return; |
| 71 | + } |
| 72 | + |
| 73 | + if ((backends = wrealloc(backends, sizeof(struct backend*) * ++nbackends)) == NULL) |
| 74 | + outofmemory(); |
| 75 | + backends[nbackends - 1] = new_backend(addr, port); |
| 76 | + wlog(WLOG_NOTICE, "backend: %s:%d", addr, port); |
| 77 | +} |
| 78 | + |
| 79 | +#if 0 |
| 80 | +void |
| 81 | +backend_file(file) |
| 82 | + char *file; |
| 83 | +{ |
| 84 | + FILE *f; |
| 85 | + char line[1024]; |
| 86 | + |
| 87 | + if ((f = fopen(file, "r")) == NULL) { |
| 88 | + perror(file); |
| 89 | + exit(8); |
| 90 | + } |
| 91 | + |
| 92 | + while (fgets(line, sizeof line, f)) { |
| 93 | + line[strlen(line) - 1] = '\0'; |
| 94 | + add_backend(line); |
| 95 | + } |
| 96 | + |
| 97 | + (void)fclose(f); |
| 98 | +} |
| 99 | +#endif |
| 100 | + |
| 101 | +int |
| 102 | +get_backend(func, data) |
| 103 | + backend_cb func; |
| 104 | + void *data; |
| 105 | +{ |
| 106 | +struct backend_cb_data *cbd; |
| 107 | + int s; |
| 108 | + |
| 109 | + WDEBUG((WLOG_DEBUG, "get_backend: called")); |
| 110 | + |
| 111 | + if ((cbd = wmalloc(sizeof(*cbd))) == NULL) |
| 112 | + outofmemory(); |
| 113 | + |
| 114 | + cbd->bc_func = func; |
| 115 | + cbd->bc_data = data; |
| 116 | + cbd->bc_backend = next_backend(); |
| 117 | + |
| 118 | + if ((s = wnet_open("backend connection")) == -1) { |
| 119 | + wlog(WLOG_WARNING, "opening backend socket: %s", strerror(errno)); |
| 120 | + return -1; |
| 121 | + } |
| 122 | + |
| 123 | + if (connect(s, (struct sockaddr *)&cbd->bc_backend->be_addr, sizeof(cbd->bc_backend->be_addr)) == 0) { |
| 124 | + WDEBUG((WLOG_DEBUG, "get_backend: connection completed immediately")); |
| 125 | + func(cbd->bc_backend, &fde_table[s], data); |
| 126 | + wfree(cbd); |
| 127 | + return 0; |
| 128 | + } |
| 129 | + |
| 130 | + if (errno != EINPROGRESS) { |
| 131 | + wlog(WLOG_WARNING, "%s: %s", cbd->bc_backend->be_name, strerror(errno)); |
| 132 | + return -1; |
| 133 | + } |
| 134 | + |
| 135 | + WDEBUG((WLOG_DEBUG, "get_backend: waiting for connection to complete")); |
| 136 | + wnet_register(s, FDE_WRITE, backend_read, cbd); |
| 137 | + return 0; |
| 138 | +} |
| 139 | + |
| 140 | +static void |
| 141 | +backend_read(e) |
| 142 | + struct fde *e; |
| 143 | +{ |
| 144 | +struct backend_cb_data *cbd = e->fde_rdata; |
| 145 | + |
| 146 | + /* |
| 147 | + * After handing the fd off to the caller, we don't care about it |
| 148 | + * any more. |
| 149 | + */ |
| 150 | + wnet_register(e->fde_fd, FDE_WRITE, NULL, NULL); |
| 151 | + |
| 152 | + cbd->bc_func(cbd->bc_backend, e, cbd->bc_data); |
| 153 | + wfree(cbd); |
| 154 | +} |
| 155 | + |
| 156 | +static struct backend * |
| 157 | +next_backend(void) |
| 158 | +{ |
| 159 | +static int cur = 0; |
| 160 | + |
| 161 | + if (cur >= nbackends) |
| 162 | + cur = 0; |
| 163 | + |
| 164 | + return backends[cur++]; |
| 165 | +} |
Property changes on: trunk/willow/src/bin/willow/wbackend.c |
___________________________________________________________________ |
Added: svn:keywords |
1 | 166 | + Author Date Id Revision |
Added: svn:eol-style |
2 | 167 | + native |
Index: trunk/willow/src/bin/willow/confparse.c |
— | — | @@ -0,0 +1,458 @@ |
| 2 | +/* @(#) $Header$ */ |
| 3 | +/* From ircd-ratbox: newconf.c,v 7.209 2005/04/05 01:22:57 leeh Exp */ |
| 4 | +/* This source code is in the public domain. */ |
| 5 | +/* |
| 6 | + * Willow: Lightweight HTTP reverse-proxy. |
| 7 | + * confparse: config parser implementation. |
| 8 | + */ |
| 9 | + |
| 10 | +#if defined __SUNPRO_C || defined __DECC || defined __HP_cc |
| 11 | +# pragma ident "@(#)$Header$" |
| 12 | +#endif |
| 13 | + |
| 14 | +#include <stdarg.h> |
| 15 | +#include <stdio.h> |
| 16 | +#include <string.h> |
| 17 | +#include <syslog.h> |
| 18 | + |
| 19 | +#include "willow.h" |
| 20 | +#include "confparse.h" |
| 21 | +#include "queue.h" |
| 22 | +#include "wlog.h" |
| 23 | +#include "wbackend.h" |
| 24 | +#include "wconfig.h" |
| 25 | + |
| 26 | +#define CF_TYPE(x) ((x) & CF_MTYPE) |
| 27 | + |
| 28 | +int nerrors; |
| 29 | +struct top_conf *conf_cur_block; |
| 30 | +char *conf_cur_block_name; |
| 31 | + |
| 32 | +static LIST_HEAD(conf_items_head, top_conf) conf_items = |
| 33 | + LIST_HEAD_INITIALIZER(conf_items); |
| 34 | + |
| 35 | +static struct conf_entry *find_conf_item(struct top_conf *top, const char *); |
| 36 | +static void conf_set_generic_int(void *, void *); |
| 37 | +static void conf_set_generic_string(void *, int, void *); |
| 38 | +static void add_top_conf(const char *name, int (*) (struct top_conf *), |
| 39 | + int (*) (struct top_conf *), struct conf_entry *); |
| 40 | + |
| 41 | +void |
| 42 | +conf_report_error(const char *fmt, ...) |
| 43 | +{ |
| 44 | + char buf[1024]; |
| 45 | + va_list ap; |
| 46 | + |
| 47 | + va_start(ap, fmt); |
| 48 | + (void)vsnprintf(buf, 1024, fmt, ap); |
| 49 | + va_end(ap); |
| 50 | + |
| 51 | + wlog(WLOG_ERROR, "\"%s\", line %d: %s", current_file, lineno, buf); |
| 52 | +} |
| 53 | + |
| 54 | +void |
| 55 | +yyerror(msg) |
| 56 | + const char *msg; |
| 57 | +{ |
| 58 | + conf_report_error("%s", msg); |
| 59 | +} |
| 60 | + |
| 61 | +static const char * |
| 62 | +conf_strtype(type) |
| 63 | + int type; |
| 64 | +{ |
| 65 | + switch (type & CF_MTYPE) |
| 66 | + { |
| 67 | + case CF_INT: |
| 68 | + return "integer value"; |
| 69 | + case CF_STRING: |
| 70 | + return "unquoted string"; |
| 71 | + case CF_YESNO: |
| 72 | + return "yes/no value"; |
| 73 | + case CF_QSTRING: |
| 74 | + return "quoted string"; |
| 75 | + case CF_TIME: |
| 76 | + return "time/size value"; |
| 77 | + default: |
| 78 | + return "unknown type"; |
| 79 | + } |
| 80 | +} |
| 81 | + |
| 82 | +static void |
| 83 | +add_top_conf(name, sfunc, efunc, items) |
| 84 | + const char *name; |
| 85 | + int (*sfunc) (struct top_conf *); |
| 86 | + int (*efunc) (struct top_conf *); |
| 87 | + struct conf_entry *items; |
| 88 | +{ |
| 89 | +struct top_conf *tc; |
| 90 | + |
| 91 | + tc = wmalloc(sizeof(struct top_conf)); |
| 92 | + |
| 93 | + tc->tc_name = wstrdup(name); |
| 94 | + tc->tc_sfunc = sfunc; |
| 95 | + tc->tc_efunc = efunc; |
| 96 | + tc->tc_entries = items; |
| 97 | + |
| 98 | + LIST_INSERT_HEAD(&conf_items, tc, entries); |
| 99 | +} |
| 100 | + |
| 101 | +static struct top_conf * |
| 102 | +find_top_conf(name) |
| 103 | + const char *name; |
| 104 | +{ |
| 105 | +struct top_conf *tc; |
| 106 | + |
| 107 | + LIST_FOREACH(tc, &conf_items, entries) { |
| 108 | + if (!strcasecmp(tc->tc_name, name)) |
| 109 | + return tc; |
| 110 | + } |
| 111 | + |
| 112 | + return NULL; |
| 113 | +} |
| 114 | + |
| 115 | +static struct conf_entry * |
| 116 | +find_conf_item(top, name) |
| 117 | + struct top_conf *top; |
| 118 | + const char *name; |
| 119 | +{ |
| 120 | +struct conf_entry *cf; |
| 121 | + |
| 122 | + if (top->tc_entries) { |
| 123 | + int i; |
| 124 | + |
| 125 | + for(i = 0; top->tc_entries[i].cf_type; i++) |
| 126 | + { |
| 127 | + cf = &top->tc_entries[i]; |
| 128 | + |
| 129 | + if(!strcasecmp(cf->cf_name, name)) |
| 130 | + return cf; |
| 131 | + } |
| 132 | + } |
| 133 | + |
| 134 | + LIST_FOREACH(cf, &top->tc_items, entries) { |
| 135 | + if(strcasecmp(cf->cf_name, name) == 0) |
| 136 | + return cf; |
| 137 | + } |
| 138 | + |
| 139 | + return NULL; |
| 140 | +} |
| 141 | + |
| 142 | +int |
| 143 | +conf_call_set(tc, item, value, type) |
| 144 | + struct top_conf *tc; |
| 145 | + char *item; |
| 146 | + conf_parm_t *value; |
| 147 | + int type; |
| 148 | +{ |
| 149 | +struct conf_entry *cf; |
| 150 | + conf_parm_t *cp; |
| 151 | + |
| 152 | + if (!tc) |
| 153 | + return -1; |
| 154 | + |
| 155 | + if ((cf = find_conf_item(tc, item)) == NULL) { |
| 156 | + conf_report_error("Non-existant configuration setting %s::%s.", |
| 157 | + tc->tc_name, (char *) item); |
| 158 | + nerrors++; |
| 159 | + return -1; |
| 160 | + } |
| 161 | + |
| 162 | + /* |
| 163 | + * If it takes one thing, make sure they only passed one thing, |
| 164 | + * and handle as needed. |
| 165 | + */ |
| 166 | + if (value->type & CF_FLIST && !cf->cf_type & CF_FLIST) { |
| 167 | + conf_report_error("Option %s::%s does not take a list of values.", |
| 168 | + tc->tc_name, item); |
| 169 | + nerrors++; |
| 170 | + return -1; |
| 171 | + } |
| 172 | + |
| 173 | + cp = value->v.list; |
| 174 | + |
| 175 | + if (CF_TYPE(value->v.list->type) != CF_TYPE(cf->cf_type)) { |
| 176 | + /* |
| 177 | + * If it expects a string value, but we got a yesno, |
| 178 | + * convert it back |
| 179 | + */ |
| 180 | + if((CF_TYPE(value->v.list->type) == CF_YESNO) && |
| 181 | + (CF_TYPE(cf->cf_type) == CF_STRING)) { |
| 182 | + value->v.list->type = CF_STRING; |
| 183 | + |
| 184 | + if(cp->v.number == 1) |
| 185 | + cp->v.string = wstrdup("yes"); |
| 186 | + else |
| 187 | + cp->v.string = wstrdup("no"); |
| 188 | + } |
| 189 | + |
| 190 | + /* |
| 191 | + * Maybe it's a CF_TIME and they passed CF_INT -- |
| 192 | + * should still be valid. |
| 193 | + */ |
| 194 | + else if(!((CF_TYPE(value->v.list->type) == CF_INT) && |
| 195 | + (CF_TYPE(cf->cf_type) == CF_TIME))) { |
| 196 | + conf_report_error("Wrong type for %s::%s (expected %s, got %s)", |
| 197 | + tc->tc_name, (char *) item, |
| 198 | + conf_strtype(cf->cf_type), conf_strtype(value->v.list->type)); |
| 199 | + nerrors++; |
| 200 | + return -1; |
| 201 | + } |
| 202 | + } |
| 203 | + |
| 204 | + if (cf->cf_type & CF_FLIST) { |
| 205 | + /* just pass it the extended argument list */ |
| 206 | + cf->cf_func(value->v.list); |
| 207 | + } else { |
| 208 | + /* it's old-style, needs only one arg */ |
| 209 | + switch (cf->cf_type) { |
| 210 | + case CF_INT: |
| 211 | + case CF_TIME: |
| 212 | + case CF_YESNO: |
| 213 | + if(cf->cf_arg) |
| 214 | + conf_set_generic_int(&cp->v.number, cf->cf_arg); |
| 215 | + else |
| 216 | + cf->cf_func(&cp->v.number); |
| 217 | + break; |
| 218 | + case CF_STRING: |
| 219 | + case CF_QSTRING: |
| 220 | + if(!*cp->v.string) |
| 221 | + conf_report_error("Ignoring %s::%s -- empty field", |
| 222 | + tc->tc_name, item); |
| 223 | + else if(cf->cf_arg) |
| 224 | + conf_set_generic_string(cp->v.string, cf->cf_len, cf->cf_arg); |
| 225 | + else |
| 226 | + cf->cf_func(cp->v.string); |
| 227 | + break; |
| 228 | + } |
| 229 | + } |
| 230 | + |
| 231 | + return 0; |
| 232 | +} |
| 233 | + |
| 234 | +int |
| 235 | +conf_start_block(block, name) |
| 236 | + const char *block, *name; |
| 237 | +{ |
| 238 | + if ((conf_cur_block = find_top_conf(block)) == NULL) { |
| 239 | + conf_report_error("Configuration block '%s' is not defined.", block); |
| 240 | + nerrors++; |
| 241 | + return -1; |
| 242 | + } |
| 243 | + |
| 244 | + if (name) |
| 245 | + conf_cur_block_name = wstrdup(name); |
| 246 | + else |
| 247 | + conf_cur_block_name = NULL; |
| 248 | + |
| 249 | + if (conf_cur_block->tc_sfunc) |
| 250 | + if (conf_cur_block->tc_sfunc(conf_cur_block) < 0) |
| 251 | + return -1; |
| 252 | + |
| 253 | + return 0; |
| 254 | +} |
| 255 | + |
| 256 | +int |
| 257 | +conf_end_block(tc) |
| 258 | + struct top_conf *tc; |
| 259 | +{ |
| 260 | + if(tc->tc_efunc) |
| 261 | + return tc->tc_efunc(tc); |
| 262 | + |
| 263 | + wfree(conf_cur_block_name); |
| 264 | + return 0; |
| 265 | +} |
| 266 | + |
| 267 | + |
| 268 | +static void |
| 269 | +conf_set_generic_int(data, location) |
| 270 | + void *data, *location; |
| 271 | +{ |
| 272 | + *((int *) location) = *((unsigned int *) data); |
| 273 | +} |
| 274 | + |
| 275 | +static void |
| 276 | +conf_set_generic_string(data, len, location) |
| 277 | + void *data, *location; |
| 278 | + int len; |
| 279 | +{ |
| 280 | + char **loc = location; |
| 281 | + char *input = data; |
| 282 | + |
| 283 | + if(len && strlen(input) > len) |
| 284 | + input[len] = '\0'; |
| 285 | + |
| 286 | + wfree(*loc); |
| 287 | + *loc = wstrdup(input); |
| 288 | +} |
| 289 | + |
| 290 | +static int backend_port; |
| 291 | + |
| 292 | +static int |
| 293 | +conf_begin_backend(tc) |
| 294 | + struct top_conf *tc; |
| 295 | +{ |
| 296 | + if (conf_cur_block_name == NULL) { |
| 297 | + conf_report_error("backend name not specified"); |
| 298 | + nerrors++; |
| 299 | + return -1; |
| 300 | + } |
| 301 | + |
| 302 | + return 0; |
| 303 | +} |
| 304 | + |
| 305 | +static int |
| 306 | +conf_end_backend(tc) |
| 307 | + struct top_conf *tc; |
| 308 | +{ |
| 309 | + add_backend(conf_cur_block_name, backend_port); |
| 310 | + backend_port = 0; |
| 311 | + |
| 312 | + return 0; |
| 313 | +} |
| 314 | + |
| 315 | +static int listen_port; |
| 316 | + |
| 317 | +static int |
| 318 | +conf_begin_listen(tc) |
| 319 | + struct top_conf *tc; |
| 320 | +{ |
| 321 | + if (conf_cur_block_name == NULL) { |
| 322 | + conf_report_error("listener host not specified"); |
| 323 | + nerrors++; |
| 324 | + return -1; |
| 325 | + } |
| 326 | + |
| 327 | + return 0; |
| 328 | +} |
| 329 | + |
| 330 | +static int |
| 331 | +conf_end_listen(tc) |
| 332 | + struct top_conf *tc; |
| 333 | +{ |
| 334 | + add_listener(conf_cur_block_name, listen_port); |
| 335 | + listen_port = 0; |
| 336 | + |
| 337 | + return 0; |
| 338 | +} |
| 339 | + |
| 340 | +static int cachedir_size; |
| 341 | + |
| 342 | +static int |
| 343 | +conf_begin_cachedir(tc) |
| 344 | + struct top_conf *tc; |
| 345 | +{ |
| 346 | + if (conf_cur_block_name == NULL) { |
| 347 | + conf_report_error("cache directory not specified"); |
| 348 | + nerrors++; |
| 349 | + return -1; |
| 350 | + } |
| 351 | + |
| 352 | + return 0; |
| 353 | +} |
| 354 | + |
| 355 | +static int |
| 356 | +conf_end_cachedir(tc) |
| 357 | + struct top_conf *tc; |
| 358 | +{ |
| 359 | + add_cachedir(conf_cur_block_name, cachedir_size); |
| 360 | + cachedir_size = 0; |
| 361 | + |
| 362 | + return 0; |
| 363 | +} |
| 364 | + |
| 365 | +static char *log_file, *log_syslog_facility, *log_access_log; |
| 366 | +static int log_level, log_syslog; |
| 367 | + |
| 368 | +static struct syslog_facility { |
| 369 | + char *name; |
| 370 | + int fac; |
| 371 | +} syslog_facilities[] = { |
| 372 | + {"user", LOG_USER}, |
| 373 | + {"mail", LOG_MAIL}, |
| 374 | + {"daemon", LOG_DAEMON}, |
| 375 | + {"auth", LOG_AUTH}, |
| 376 | + {"lpr", LOG_LPR}, |
| 377 | + {"news", LOG_NEWS}, |
| 378 | + {"uucp", LOG_UUCP}, |
| 379 | + {"cron", LOG_CRON}, |
| 380 | +#ifdef LOG_AUDIT |
| 381 | + {"audit", LOG_AUDIT}, |
| 382 | +#endif |
| 383 | + {"local0", LOG_LOCAL0}, |
| 384 | + {"local1", LOG_LOCAL0}, |
| 385 | + {"local2", LOG_LOCAL0}, |
| 386 | + {"local3", LOG_LOCAL0}, |
| 387 | + {"local4", LOG_LOCAL0}, |
| 388 | + {"local5", LOG_LOCAL0}, |
| 389 | + {"local6", LOG_LOCAL0}, |
| 390 | + {"local7", LOG_LOCAL0}, |
| 391 | + {NULL, 0}, |
| 392 | +}; |
| 393 | + |
| 394 | +static int |
| 395 | +conf_end_log(tc) |
| 396 | + struct top_conf *tc; |
| 397 | +{ |
| 398 | + if (log_file) { |
| 399 | + logging.file = wstrdup(log_file); |
| 400 | + } |
| 401 | + |
| 402 | + if (log_syslog) { |
| 403 | + struct syslog_facility *fac = syslog_facilities; |
| 404 | + |
| 405 | + logging.syslog = 1; |
| 406 | + |
| 407 | + if (log_syslog_facility) { |
| 408 | + for (; fac->name; fac++) { |
| 409 | + if (!strcmp(fac->name, log_syslog_facility)) { |
| 410 | + logging.facility = fac->fac; |
| 411 | + break; |
| 412 | + } |
| 413 | + } |
| 414 | + if (!fac->name) { |
| 415 | + conf_report_error("unrecognised syslog facility \"%s\"", log_syslog_facility); |
| 416 | + nerrors++; |
| 417 | + } |
| 418 | + } else |
| 419 | + logging.facility = LOG_DAEMON; |
| 420 | + } |
| 421 | + |
| 422 | + logging.level = log_level; |
| 423 | + if (log_access_log) |
| 424 | + config.access_log = wstrdup(log_access_log); |
| 425 | + return 0; |
| 426 | +} |
| 427 | + |
| 428 | +static struct conf_entry conf_backend_table[] = { |
| 429 | + { "port", CF_INT, NULL, 0, &backend_port }, |
| 430 | + { NULL } |
| 431 | +}; |
| 432 | + |
| 433 | +static struct conf_entry conf_listen_table[] = { |
| 434 | + { "port", CF_INT, NULL, 0, &listen_port }, |
| 435 | + { NULL } |
| 436 | +}; |
| 437 | + |
| 438 | +static struct conf_entry conf_cachedir_table[] = { |
| 439 | + { "size", CF_TIME, NULL, 0, &cachedir_size }, |
| 440 | + { NULL } |
| 441 | +}; |
| 442 | + |
| 443 | +static struct conf_entry conf_log_table[] = { |
| 444 | + { "level", CF_INT, NULL, 0, &log_level }, |
| 445 | + { "file", CF_QSTRING, NULL, 0, &log_file }, |
| 446 | + { "syslog", CF_YESNO, NULL, 0, &log_syslog }, |
| 447 | + { "facility", CF_STRING, NULL, 0, &log_syslog_facility }, |
| 448 | + { "access-log", CF_QSTRING, NULL, 0, &log_access_log }, |
| 449 | + { NULL } |
| 450 | +}; |
| 451 | + |
| 452 | +void |
| 453 | +newconf_init(void) |
| 454 | +{ |
| 455 | + add_top_conf("backend", conf_begin_backend, conf_end_backend, conf_backend_table); |
| 456 | + add_top_conf("listen", conf_begin_listen, conf_end_listen, conf_listen_table); |
| 457 | + add_top_conf("cache-dir", conf_begin_cachedir, conf_end_cachedir, conf_cachedir_table); |
| 458 | + add_top_conf("log", NULL, conf_end_log, conf_log_table); |
| 459 | +} |
Property changes on: trunk/willow/src/bin/willow/confparse.c |
___________________________________________________________________ |
Added: svn:keywords |
1 | 460 | + Author Date Id Revision |
Added: svn:eol-style |
2 | 461 | + native |
Index: trunk/willow/src/bin/willow/strlcpy.c |
— | — | @@ -0,0 +1,61 @@ |
| 2 | +/* @(#) $Header$ */ |
| 3 | +/* $NetBSD: strlcpy.c,v 1.14 2003/10/27 00:12:42 lukem Exp $ */ |
| 4 | +/* $OpenBSD: strlcpy.c,v 1.7 2003/04/12 21:56:39 millert Exp $ */ |
| 5 | + |
| 6 | +/* |
| 7 | + * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com> |
| 8 | + * |
| 9 | + * Permission to use, copy, modify, and distribute this software for any |
| 10 | + * purpose with or without fee is hereby granted, provided that the above |
| 11 | + * copyright notice and this permission notice appear in all copies. |
| 12 | + * |
| 13 | + * THE SOFTWARE IS PROVIDED "AS IS" AND TODD C. MILLER DISCLAIMS ALL |
| 14 | + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES |
| 15 | + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL TODD C. MILLER BE LIABLE |
| 16 | + * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
| 17 | + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION |
| 18 | + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN |
| 19 | + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
| 20 | + */ |
| 21 | + |
| 22 | +#if defined __SUNPRO_C || defined __DECC || defined __HP_cc |
| 23 | +# pragma ident "@(#) $Header$" |
| 24 | +#endif |
| 25 | + |
| 26 | +#include <sys/types.h> |
| 27 | +#include <assert.h> |
| 28 | +#include <string.h> |
| 29 | + |
| 30 | +/* |
| 31 | + * Copy src to string dst of size siz. At most siz-1 characters |
| 32 | + * will be copied. Always NUL terminates (unless siz == 0). |
| 33 | + * Returns strlen(src); if retval >= siz, truncation occurred. |
| 34 | + */ |
| 35 | +size_t |
| 36 | +strlcpy(dst, src, siz) |
| 37 | + char *dst; |
| 38 | + const char *src; |
| 39 | + size_t siz; |
| 40 | +{ |
| 41 | + char *d = dst; |
| 42 | + const char *s = src; |
| 43 | + size_t n = siz; |
| 44 | + |
| 45 | + /* Copy as many bytes as will fit */ |
| 46 | + if (n != 0 && --n != 0) { |
| 47 | + do { |
| 48 | + if ((*d++ = *s++) == 0) |
| 49 | + break; |
| 50 | + } while (--n != 0); |
| 51 | + } |
| 52 | + |
| 53 | + /* Not enough room in dst, add NUL and traverse rest of src */ |
| 54 | + if (n == 0) { |
| 55 | + if (siz != 0) |
| 56 | + *d = '\0'; /* NUL-terminate dst */ |
| 57 | + while (*s++) |
| 58 | + ; |
| 59 | + } |
| 60 | + |
| 61 | + return(s - src - 1); /* count does not include NUL */ |
| 62 | +} |
Property changes on: trunk/willow/src/bin/willow/strlcpy.c |
___________________________________________________________________ |
Added: svn:keywords |
1 | 63 | + Author Date Id Revision |
Added: svn:eol-style |
2 | 64 | + native |
Index: trunk/willow/src/bin/willow/Makefile.in |
— | — | @@ -0,0 +1,29 @@ |
| 2 | +PROGRAM = willow |
| 3 | + |
| 4 | +CPPFLAGS = -DDATADIR=\"$(_DATADIR)\" |
| 5 | +BASESRCS = willow.c wconfig.c whttp.c wbackend.c wlogwriter.c \ |
| 6 | + whttp_entity.c wcache.c confparse.c |
| 7 | +#GENSRCS=y.tab.c lex.yy.c |
| 8 | +SRCS=$(BASESRCS) |
| 9 | +OBJADD = @LIBOBJS@ y.tab.o lex.yy.o |
| 10 | + |
| 11 | +EXTRA_DIST=wnet_poll.c wnet_ports.c wnet_kqueue.c wnet_epoll.c wnet_devpoll.c \ |
| 12 | + lexer.l parser.y \ |
| 13 | + daemon.c \ |
| 14 | + Makefile.in |
| 15 | + |
| 16 | +LDFLAGS = -L$(SRCROOT)/src/lib/wnet -lwillownet \ |
| 17 | + -L$(SRCROOT)/src/lib/wlog -lwillowlog \ |
| 18 | + $(LIBOBJS) |
| 19 | + |
| 20 | +y.tab.o: y.tab.c |
| 21 | +lex.yy.o: lex.yy.c y.tab.h |
| 22 | + |
| 23 | +y.tab.c y.tab.h: parser.y |
| 24 | + @echo " $(_YACC) -d parser.y" |
| 25 | + @$(_YACC) -d parser.y |
| 26 | +lex.yy.c: lexer.l y.tab.h |
| 27 | + @echo " $(_LEX) lexer.l" |
| 28 | + @$(_LEX) lexer.l || rm -f lex.yy.c |
| 29 | + |
| 30 | +@include@ @q@@top_srcdir@/mk/prog.mk@q@ |
Property changes on: trunk/willow/src/bin/willow/Makefile.in |
___________________________________________________________________ |
Added: svn:keywords |
1 | 31 | + Author Date Id Revision |
Added: svn:eol-style |
2 | 32 | + native |
Index: trunk/willow/src/bin/willow/parser.y |
— | — | @@ -0,0 +1,317 @@ |
| 2 | +/* @(#) $Header$ */ |
| 3 | +/* From: $Nightmare: nightmare/src/main/parser.y,v 1.2.2.1.2.1 2002/07/02 03:42:10 ejb Exp $ */ |
| 4 | +/* From: ircd_parser.y,v 1.281 2005/03/22 16:27:48 androsyn Exp */ |
| 5 | +/* This source code is in the public domain. */ |
| 6 | +/* |
| 7 | + * Willow: Lightweight HTTP reverse-proxy. |
| 8 | + * parser: configuration file parser. |
| 9 | + */ |
| 10 | + |
| 11 | +%{ |
| 12 | +#if defined __SUNPRO_CC || defined __DECC || defined __HP_cc |
| 13 | +# pragma ident "@(#)$Header$" |
| 14 | +#endif |
| 15 | + |
| 16 | +#include <sys/types.h> |
| 17 | +#include <sys/stat.h> |
| 18 | + |
| 19 | +#include <netinet/in.h> |
| 20 | + |
| 21 | +#include <string.h> |
| 22 | +#include <stdlib.h> |
| 23 | +#include <stdarg.h> |
| 24 | +#include <stdio.h> |
| 25 | + |
| 26 | +#include "willow.h" |
| 27 | +#include "confparse.h" |
| 28 | + |
| 29 | +#define YY_NO_UNPUT |
| 30 | + |
| 31 | +int yyparse(); |
| 32 | +int yyerror(const char *); |
| 33 | +int yylex(); |
| 34 | + |
| 35 | +static time_t conf_find_time(const char*); |
| 36 | +static void add_cur_list(int, const char *, int); |
| 37 | + |
| 38 | +static struct { |
| 39 | + const char * name; |
| 40 | + const char * plural; |
| 41 | + time_t val; |
| 42 | +} conf_times[] = { |
| 43 | + {"second", "seconds", 1}, |
| 44 | + {"minute", "minutes", 60}, |
| 45 | + {"hour", "hours", 60 * 60}, |
| 46 | + {"day", "days", 60 * 60 * 24}, |
| 47 | + {"week", "weeks", 60 * 60 * 24 * 7}, |
| 48 | + {"fortnight", "fortnights", 60 * 60 * 24 * 14}, |
| 49 | + {"month", "months", 60 * 60 * 24 * 7 * 4}, |
| 50 | + {"year", "years", 60 * 60 * 24 * 365}, |
| 51 | + /* ok-- we now do sizes here too. they aren't times, but |
| 52 | + it's close enough */ |
| 53 | + {"byte", "bytes", 1}, |
| 54 | + {"kb", NULL, 1024}, |
| 55 | + {"kbyte", "kbytes", 1024}, |
| 56 | + {"kilobyte", "kilebytes", 1024}, |
| 57 | + {"mb", NULL, 1024 * 1024}, |
| 58 | + {"mbyte", "mbytes", 1024 * 1024}, |
| 59 | + {"megabyte", "megabytes", 1024 * 1024}, |
| 60 | + {NULL, NULL, 0}, |
| 61 | +}; |
| 62 | + |
| 63 | +static time_t |
| 64 | +conf_find_time(name) |
| 65 | + const char *name; |
| 66 | +{ |
| 67 | + int i; |
| 68 | + |
| 69 | + for (i = 0; conf_times[i].name; ++i) { |
| 70 | + if (!strcasecmp(conf_times[i].name, name) || |
| 71 | + (conf_times[i].plural && !strcasecmp(conf_times[i].plural, name))) |
| 72 | + return conf_times[i].val; |
| 73 | + } |
| 74 | + |
| 75 | + return 0; |
| 76 | +} |
| 77 | + |
| 78 | +static struct { |
| 79 | +const char *word; |
| 80 | + int yesno; |
| 81 | +} yesno[] = { |
| 82 | + {"yes", 1}, |
| 83 | + {"no", 0}, |
| 84 | + {"true", 1}, |
| 85 | + {"false", 0}, |
| 86 | + {"on", 1}, |
| 87 | + {"off", 0}, |
| 88 | + {NULL, 0} |
| 89 | +}; |
| 90 | + |
| 91 | +static int |
| 92 | +conf_get_yesno_value(str) |
| 93 | + const char *str; |
| 94 | +{ |
| 95 | + int i; |
| 96 | + |
| 97 | + for (i = 0; yesno[i].word; i++) |
| 98 | + if (!strcasecmp(str, yesno[i].word)) |
| 99 | + return yesno[i].yesno; |
| 100 | + |
| 101 | + return -1; |
| 102 | +} |
| 103 | + |
| 104 | +static void |
| 105 | +free_cur_list(list) |
| 106 | + conf_parm_t *list; |
| 107 | +{ |
| 108 | + switch (list->type & CF_MTYPE) { |
| 109 | + case CF_STRING: |
| 110 | + case CF_QSTRING: |
| 111 | + wfree(list->v.string); |
| 112 | + break; |
| 113 | + case CF_LIST: |
| 114 | + free_cur_list(list->v.list); |
| 115 | + break; |
| 116 | + default: break; |
| 117 | + } |
| 118 | + |
| 119 | + if (list->next) |
| 120 | + free_cur_list(list->next); |
| 121 | +} |
| 122 | + |
| 123 | + |
| 124 | +conf_parm_t * cur_list = NULL; |
| 125 | + |
| 126 | +static void |
| 127 | +add_cur_list_cpt(new) |
| 128 | + conf_parm_t *new; |
| 129 | +{ |
| 130 | + if (cur_list == NULL) { |
| 131 | + cur_list = wcalloc(1, sizeof(conf_parm_t)); |
| 132 | + cur_list->type |= CF_FLIST; |
| 133 | + cur_list->v.list = new; |
| 134 | + } else { |
| 135 | + new->next = cur_list->v.list; |
| 136 | + cur_list->v.list = new; |
| 137 | + } |
| 138 | +} |
| 139 | + |
| 140 | +static void |
| 141 | +add_cur_list(type, str, number) |
| 142 | + int type, number; |
| 143 | + const char *str; |
| 144 | +{ |
| 145 | + conf_parm_t *new; |
| 146 | + |
| 147 | + new = wmalloc(sizeof(conf_parm_t)); |
| 148 | + new->next = NULL; |
| 149 | + new->type = type; |
| 150 | + |
| 151 | + switch(type) { |
| 152 | + case CF_INT: |
| 153 | + case CF_TIME: |
| 154 | + case CF_YESNO: |
| 155 | + new->v.number = number; |
| 156 | + break; |
| 157 | + case CF_STRING: |
| 158 | + case CF_QSTRING: |
| 159 | + new->v.string = wstrdup(str); |
| 160 | + break; |
| 161 | + } |
| 162 | + |
| 163 | + add_cur_list_cpt(new); |
| 164 | +} |
| 165 | + |
| 166 | + |
| 167 | +%} |
| 168 | + |
| 169 | +%union { |
| 170 | + int number; |
| 171 | + char *string; |
| 172 | + conf_parm_t *conf_parm; |
| 173 | +} |
| 174 | + |
| 175 | +%token TWODOTS |
| 176 | + |
| 177 | +%token <string> QSTRING STRING |
| 178 | +%token <number> NUMBER |
| 179 | + |
| 180 | +%type <string> qstring string |
| 181 | +%type <number> number timespec |
| 182 | +%type <conf_parm> oneitem single itemlist |
| 183 | + |
| 184 | +%start conf |
| 185 | + |
| 186 | +%% |
| 187 | + |
| 188 | +conf: |
| 189 | + | conf conf_item |
| 190 | + | error |
| 191 | + ; |
| 192 | + |
| 193 | +conf_item: block |
| 194 | + ; |
| 195 | + |
| 196 | +block: string |
| 197 | + { |
| 198 | + conf_start_block($1, NULL); |
| 199 | + wfree($1); |
| 200 | + } |
| 201 | + '{' block_items '}' ';' |
| 202 | + { |
| 203 | + if (conf_cur_block) |
| 204 | + conf_end_block(conf_cur_block); |
| 205 | + } |
| 206 | + | string qstring |
| 207 | + { |
| 208 | + conf_start_block($1, $2); |
| 209 | + wfree($1); |
| 210 | + wfree($2); |
| 211 | + } |
| 212 | + '{' block_items '}' ';' |
| 213 | + { |
| 214 | + if (conf_cur_block) |
| 215 | + conf_end_block(conf_cur_block); |
| 216 | + } |
| 217 | + ; |
| 218 | + |
| 219 | +block_items: block_items block_item |
| 220 | + | block_item |
| 221 | + ; |
| 222 | + |
| 223 | +block_item: string '=' itemlist ';' |
| 224 | + { |
| 225 | + conf_call_set(conf_cur_block, $1, cur_list, CF_LIST); |
| 226 | + free_cur_list(cur_list); |
| 227 | + cur_list = NULL; |
| 228 | + wfree($1); |
| 229 | + } |
| 230 | + ; |
| 231 | + |
| 232 | +itemlist: itemlist ',' single |
| 233 | + | single |
| 234 | + ; |
| 235 | + |
| 236 | +single: oneitem |
| 237 | + { |
| 238 | + add_cur_list_cpt($1); |
| 239 | + } |
| 240 | + | oneitem TWODOTS oneitem |
| 241 | + { |
| 242 | + /* "1 .. 5" meaning 1,2,3,4,5 - only valid for integers */ |
| 243 | + if (($1->type & CF_MTYPE) != CF_INT || |
| 244 | + ($3->type & CF_MTYPE) != CF_INT) { |
| 245 | + conf_report_error("Both arguments in '..' notation must be integers."); |
| 246 | + break; |
| 247 | + } else { |
| 248 | + int i; |
| 249 | + |
| 250 | + for (i = $1->v.number; i <= $3->v.number; i++) { |
| 251 | + add_cur_list(CF_INT, 0, i); |
| 252 | + } |
| 253 | + } |
| 254 | + } |
| 255 | + ; |
| 256 | + |
| 257 | +oneitem: qstring |
| 258 | + { |
| 259 | + $$ = wmalloc(sizeof(conf_parm_t)); |
| 260 | + $$->type = CF_QSTRING; |
| 261 | + $$->v.string = wstrdup($1); |
| 262 | + wfree($1); |
| 263 | + } |
| 264 | + | timespec |
| 265 | + { |
| 266 | + $$ = wmalloc(sizeof(conf_parm_t)); |
| 267 | + $$->type = CF_TIME; |
| 268 | + $$->v.number = $1; |
| 269 | + } |
| 270 | + | number |
| 271 | + { |
| 272 | + $$ = wmalloc(sizeof(conf_parm_t)); |
| 273 | + $$->type = CF_INT; |
| 274 | + $$->v.number = $1; |
| 275 | + } |
| 276 | + | string |
| 277 | + { |
| 278 | + /* a 'string' could also be a yes/no value .. |
| 279 | + so pass it as that, if so */ |
| 280 | + int val = conf_get_yesno_value($1); |
| 281 | + |
| 282 | + $$ = wmalloc(sizeof(conf_parm_t)); |
| 283 | + |
| 284 | + if (val != -1) { |
| 285 | + $$->type = CF_YESNO; |
| 286 | + $$->v.number = val; |
| 287 | + } else { |
| 288 | + $$->type = CF_STRING; |
| 289 | + $$->v.string = wstrdup($1); |
| 290 | + } |
| 291 | + wfree($1); |
| 292 | + } |
| 293 | + ; |
| 294 | + |
| 295 | +qstring: QSTRING { strcpy($$, $1); } ; |
| 296 | +string: STRING { strcpy($$, $1); } ; |
| 297 | +number: NUMBER { $$ = $1; } ; |
| 298 | + |
| 299 | +timespec: number string |
| 300 | + { |
| 301 | + time_t t; |
| 302 | + |
| 303 | + if ((t = conf_find_time($2)) == 0) { |
| 304 | + conf_report_error("Unrecognised time type/size '%s'", $2); |
| 305 | + t = 1; |
| 306 | + } |
| 307 | + |
| 308 | + $$ = $1 * t; |
| 309 | + } |
| 310 | + | timespec timespec |
| 311 | + { |
| 312 | + $$ = $1 + $2; |
| 313 | + } |
| 314 | + | timespec number |
| 315 | + { |
| 316 | + $$ = $1 + $2; |
| 317 | + } |
| 318 | + ; |
Property changes on: trunk/willow/src/bin/willow/parser.y |
___________________________________________________________________ |
Added: svn:keywords |
1 | 319 | + Author Date Id Revision |
Added: svn:eol-style |
2 | 320 | + native |
Index: trunk/willow/src/bin/willow/whttp_entity.c |
— | — | @@ -0,0 +1,791 @@ |
| 2 | +/* @(#) $Header$ */ |
| 3 | +/* This source code is in the public domain. */ |
| 4 | +/* |
| 5 | + * Willow: Lightweight HTTP reverse-proxy. |
| 6 | + * whttp_entity: HTTP entity handling. |
| 7 | + */ |
| 8 | + |
| 9 | +#if defined __SUNPRO_C || defined __DECC || defined __HP_cc |
| 10 | +# pragma ident "@(#)$Header$" |
| 11 | +#endif |
| 12 | + |
| 13 | +/* How does this work? |
| 14 | + * |
| 15 | + * Each HTTP request can be divided into two entities: the request and the |
| 16 | + * response. The client sends the request, i.e. the headers and possibly |
| 17 | + * a body, to the server, which considers it and sends a reply. |
| 18 | + * |
| 19 | + * Internally, we read the request headers and ignore the |
| 20 | + * body [entity_read_headers]. We then examine the headers |
| 21 | + * [whttp:client_read_done] and decide if it has a body. We modify |
| 22 | + * the entry slightly, and send it to the backend with either no source |
| 23 | + * or, if it had a body, the client's FDE as the source [entity_send]. |
| 24 | + * We then wait for the server to reply with its header. When it does |
| 25 | + * [whttp:backend_headers_done], we send the request to the client, using |
| 26 | + * the backend's FDE as the body, if it has one, and close it. |
| 27 | + * |
| 28 | + * See "Entity sending" below for a detailed description of how entity |
| 29 | + * sending works. |
| 30 | + * |
| 31 | + * TODO: We don't have to buffer the headers, _but_ it makes things easier |
| 32 | + * for now and doesn't cost much. if we start not buffering we need to |
| 33 | + * decide what to do when the client goes away unexpectedly. probably it's |
| 34 | + * easiest to just drop the backend connection (this is wasteful of backends |
| 35 | + * but we don't cache them at the moment anyway). what do we do when the |
| 36 | + * client sends "Foo: bar\r\n baz\r\n" and we decide after baz that we |
| 37 | + * shouldn't send that header after all? |
| 38 | + * |
| 39 | + * There is a trade-off in some places between excessive copying and |
| 40 | + * excessive syscalls. In some cases we copy data (headers) when we could |
| 41 | + * undo the parser mangling and send them as-is. IMO this is not likely |
| 42 | + * to be a worthwhile optimisation, needs profiling. |
| 43 | + * |
| 44 | + * As for FDE backending, Unix sucks: |
| 45 | + * |
| 46 | + * The sendfile() function copies data from in_fd to out_fd starting |
| 47 | + * at offset off and of length len bytes. The in_fd argument should |
| 48 | + * be a file descriptor to a regular file opened for reading. |
| 49 | + */ |
| 50 | + |
| 51 | +#include <sys/uio.h> |
| 52 | + |
| 53 | +#include <unistd.h> |
| 54 | +#include <errno.h> |
| 55 | +#include <string.h> |
| 56 | +#include <stdlib.h> |
| 57 | +#include <stdio.h> |
| 58 | +#include <assert.h> |
| 59 | +/*LINTED*/ |
| 60 | +#include <fcntl.h> |
| 61 | +#include <strings.h> |
| 62 | + |
| 63 | +#include "willow.h" |
| 64 | +#include "whttp.h" |
| 65 | +#include "whttp_entity.h" |
| 66 | +#include "wnet.h" |
| 67 | +#include "wlog.h" |
| 68 | + |
| 69 | +#define ENTITY_STATE_START 0 |
| 70 | +#define ENTITY_STATE_CR 1 |
| 71 | +#define ENTITY_STATE_NL 2 |
| 72 | +#define ENTITY_STATE_HDR 3 |
| 73 | +#define ENTITY_STATE_COLON 4 |
| 74 | +#define ENTITY_STATE_SPACE 5 |
| 75 | +#define ENTITY_STATE_VALUE 6 |
| 76 | +#define ENTITY_STATE_CREMPTY 7 |
| 77 | +#define ENTITY_STATE_DONE 8 |
| 78 | +#define ENTITY_STATE_BODY 9 |
| 79 | + |
| 80 | +static void entity_read_callback(struct fde *); |
| 81 | +static int parse_headers(struct http_entity *); |
| 82 | +static int parse_reqtype(struct http_entity *); |
| 83 | + |
| 84 | +static void entity_send_headers_done(struct fde *, void *, int); |
| 85 | +static void entity_send_fde_write_done(struct fde *, void *, int); |
| 86 | +static void entity_send_buf_done(struct fde *, void *, int); |
| 87 | +static void entity_send_fde_read(struct fde *); |
| 88 | +static void entity_send_file_done(struct fde *, void *, int); |
| 89 | + |
| 90 | +void |
| 91 | +entity_free(entity) |
| 92 | + struct http_entity *entity; |
| 93 | +{ |
| 94 | + if (!entity->he_flags.response) |
| 95 | + if (entity->he_rdata.request.path) |
| 96 | + wfree(entity->he_rdata.request.path); |
| 97 | + header_free(&entity->he_headers); |
| 98 | +} |
| 99 | + |
| 100 | +void |
| 101 | +entity_read_headers(entity, func, udata) |
| 102 | + struct http_entity *entity; |
| 103 | + header_cb func; |
| 104 | + void *udata; |
| 105 | +{ |
| 106 | + entity->_he_cbdata = udata; |
| 107 | + entity->_he_func = func; |
| 108 | + |
| 109 | + WDEBUG((WLOG_DEBUG, "entity_read_headers: starting")); |
| 110 | + /* XXX source for an entity header read is _always_ an fde */ |
| 111 | + wnet_register(entity->he_source.fde.fde->fde_fd, FDE_READ, entity_read_callback, entity); |
| 112 | + //entity_read_callback(entity->he_source.fde); |
| 113 | +} |
| 114 | + |
| 115 | +static void |
| 116 | +entity_read_callback(fde) |
| 117 | + struct fde *fde; |
| 118 | +{ |
| 119 | +struct http_entity *entity = fde->fde_rdata; |
| 120 | + |
| 121 | + WDEBUG((WLOG_DEBUG, "entity_read_callback: called, source %d, left=%d", |
| 122 | + entity->he_source.fde.fde->fde_fd, |
| 123 | + readbuf_data_left(&entity->he_source.fde.fde->fde_readbuf))); |
| 124 | + |
| 125 | + if (readbuf_data_left(&entity->he_source.fde.fde->fde_readbuf) == 0) { |
| 126 | + switch (readbuf_getdata(entity->he_source.fde.fde)) { |
| 127 | + case -1: |
| 128 | + WDEBUG((WLOG_DEBUG, "entity_read_callback: readbuf_getdata returned -1, errno=%d %s", |
| 129 | + errno, strerror(errno))); |
| 130 | + if (errno == EWOULDBLOCK) |
| 131 | + return; |
| 132 | + /*FALLTHRU*/ |
| 133 | + case 0: |
| 134 | + WDEBUG((WLOG_DEBUG, "entity_read_callback: readbuf_getdata returned 0")); |
| 135 | + wnet_register(entity->he_source.fde.fde->fde_fd, FDE_READ, NULL, NULL); |
| 136 | + entity->he_flags.error = 1; |
| 137 | + entity->_he_func(entity, entity->_he_cbdata, -1); |
| 138 | + return; |
| 139 | + } |
| 140 | + } |
| 141 | + |
| 142 | + WDEBUG((WLOG_DEBUG, "entity_read_callback: running header parse, %d left in buffer", |
| 143 | + readbuf_data_left(&entity->he_source.fde.fde->fde_readbuf))); |
| 144 | + if (parse_headers(entity) == -1) { |
| 145 | + WDEBUG((WLOG_DEBUG, "entity_read_callback: parse_headers returned -1")); |
| 146 | + wnet_register(entity->he_source.fde.fde->fde_fd, FDE_READ, NULL, NULL); |
| 147 | + entity->he_flags.error = 1; |
| 148 | + entity->_he_func(entity, entity->_he_cbdata, -1); |
| 149 | + return; |
| 150 | + } |
| 151 | + |
| 152 | + if (entity->_he_state == ENTITY_STATE_DONE) { |
| 153 | + WDEBUG((WLOG_DEBUG, "entity_read_callback: client is ENTITY_STATE_DONE")); |
| 154 | + wnet_register(entity->he_source.fde.fde->fde_fd, FDE_READ, NULL, NULL); |
| 155 | + entity->_he_func(entity, entity->_he_cbdata, 01); |
| 156 | + return; |
| 157 | + } |
| 158 | + |
| 159 | + return; |
| 160 | +} |
| 161 | + |
| 162 | +/* |
| 163 | + * I don't like this. There should be an easier/faster way to do it, but this |
| 164 | + * is the most understandable form for me... |
| 165 | + * |
| 166 | + * TODO: handle headers of the form "Name: value\r\n more value\r\n". |
| 167 | + * |
| 168 | + * This is more strict than it needs to be in some places, e.g. enforcement of |
| 169 | + * \r\n over \n. |
| 170 | + */ |
| 171 | +static int |
| 172 | +parse_headers(entity) |
| 173 | + struct http_entity *entity; |
| 174 | +{ |
| 175 | + assert(entity->he_source_type == ENT_SOURCE_FDE); |
| 176 | + |
| 177 | + while (readbuf_data_left(&entity->he_source.fde.fde->fde_readbuf) > 0) { |
| 178 | + char c = *readbuf_cur_pos(&entity->he_source.fde.fde->fde_readbuf); |
| 179 | + |
| 180 | + switch(entity->_he_state) { |
| 181 | + case ENTITY_STATE_START: |
| 182 | + /* should be reading a request type */ |
| 183 | + switch(c) { |
| 184 | + case '\r': |
| 185 | + *readbuf_cur_pos(&entity->he_source.fde.fde->fde_readbuf) = '\0'; |
| 186 | + if (parse_reqtype(entity) == -1) |
| 187 | + return -1; |
| 188 | + entity->_he_state = ENTITY_STATE_CR; |
| 189 | + break; |
| 190 | + case '\n': |
| 191 | + return -1; |
| 192 | + default: |
| 193 | + break; |
| 194 | + } |
| 195 | + break; |
| 196 | + case ENTITY_STATE_CR: |
| 197 | + switch(c) { |
| 198 | + case '\n': |
| 199 | + entity->_he_state = ENTITY_STATE_NL; |
| 200 | + break; |
| 201 | + default: |
| 202 | + return -1; |
| 203 | + } |
| 204 | + break; |
| 205 | + case ENTITY_STATE_NL: |
| 206 | + switch(c) { |
| 207 | + case '\r': |
| 208 | + entity->_he_state = ENTITY_STATE_CREMPTY; |
| 209 | + break; |
| 210 | + case '\n': case ' ': case ':': |
| 211 | + return -1; |
| 212 | + default: /* header name */ |
| 213 | + entity->_he_state = ENTITY_STATE_HDR; |
| 214 | + entity->_he_hdrbuf = entity->he_source.fde.fde->fde_readbuf.rb_p |
| 215 | + + entity->he_source.fde.fde->fde_readbuf.rb_dpos; |
| 216 | + entity->_he_lastname = entity->_he_hdrbuf; |
| 217 | + break; |
| 218 | + } |
| 219 | + break; |
| 220 | + case ENTITY_STATE_HDR: |
| 221 | + switch(c) { |
| 222 | + case ':': |
| 223 | + entity->_he_state = ENTITY_STATE_COLON; |
| 224 | + *readbuf_cur_pos(&entity->he_source.fde.fde->fde_readbuf) = '\0'; |
| 225 | + break; |
| 226 | + case ' ': case '\r': case '\n': |
| 227 | + return -1; |
| 228 | + default: |
| 229 | + break; |
| 230 | + } |
| 231 | + break; |
| 232 | + case ENTITY_STATE_COLON: |
| 233 | + switch(c) { |
| 234 | + case ' ': |
| 235 | + entity->_he_state = ENTITY_STATE_SPACE; |
| 236 | + break; |
| 237 | + default: |
| 238 | + return -1; |
| 239 | + } |
| 240 | + break; |
| 241 | + case ENTITY_STATE_SPACE: |
| 242 | + switch(c) { |
| 243 | + case '\r': case '\n': case ':': case ' ': |
| 244 | + return -1; |
| 245 | + default: |
| 246 | + entity->_he_valstart = entity->he_source.fde.fde->fde_readbuf.rb_p + |
| 247 | + entity->he_source.fde.fde->fde_readbuf.rb_dpos; |
| 248 | + entity->_he_state = ENTITY_STATE_VALUE; |
| 249 | + break; |
| 250 | + } |
| 251 | + break; |
| 252 | + case ENTITY_STATE_VALUE: |
| 253 | + switch(c) { |
| 254 | + case '\r': |
| 255 | + *readbuf_cur_pos(&entity->he_source.fde.fde->fde_readbuf) = '\0'; |
| 256 | + /* |
| 257 | + * Check for "interesting" headers that we want to do |
| 258 | + * extra processing on. |
| 259 | + */ |
| 260 | + if (entity->he_headers.hl_num++ > MAX_HEADERS) |
| 261 | + return -1; |
| 262 | + header_add(&entity->he_headers, entity->_he_lastname, entity->_he_valstart); |
| 263 | + if (!strcmp(entity->_he_lastname, "Host")) |
| 264 | + entity->he_rdata.request.host = entity->_he_valstart; |
| 265 | + else if (!strcmp(entity->_he_lastname, "Content-Length")) { |
| 266 | + char *cl = entity->_he_valstart; |
| 267 | + entity->he_rdata.request.contlen = atoi(cl); |
| 268 | + WDEBUG((WLOG_DEBUG, "got content-length: %d [%s]", |
| 269 | + entity->he_rdata.request.contlen, cl)); |
| 270 | + } |
| 271 | + entity->_he_state = ENTITY_STATE_CR; |
| 272 | + break; |
| 273 | + case '\n': |
| 274 | + return -1; |
| 275 | + default: |
| 276 | + break; |
| 277 | + } |
| 278 | + break; |
| 279 | + case ENTITY_STATE_CREMPTY: |
| 280 | + switch(c) { |
| 281 | + case '\n': |
| 282 | + entity->_he_state = ENTITY_STATE_DONE; |
| 283 | + readbuf_inc_data_pos(&entity->he_source.fde.fde->fde_readbuf, 1); |
| 284 | + return 0; |
| 285 | + default: |
| 286 | + return -1; |
| 287 | + } |
| 288 | + case ENTITY_STATE_DONE: |
| 289 | + /* |
| 290 | + * We're done parsing headers on this client, but they |
| 291 | + * sent more data. Shouldn't ever happen, but kill |
| 292 | + * them if it does. |
| 293 | + */ |
| 294 | + return -1; |
| 295 | + default: |
| 296 | + abort(); /* ??? This should be handled above for |
| 297 | + * consistency (ENTITY_STATE_BODY) but i |
| 298 | + * don't know which is correct. |
| 299 | + */ |
| 300 | + } |
| 301 | + readbuf_inc_data_pos(&entity->he_source.fde.fde->fde_readbuf, 1); |
| 302 | + } |
| 303 | + return 0; |
| 304 | +} |
| 305 | + |
| 306 | +static int |
| 307 | +parse_reqtype(entity) |
| 308 | + struct http_entity *entity; |
| 309 | +{ |
| 310 | + char *p, *s; |
| 311 | + char *request = entity->he_source.fde.fde->fde_readbuf.rb_p; |
| 312 | + int i; |
| 313 | + |
| 314 | + WDEBUG((WLOG_DEBUG, "parse_reqtype: called, response=%d", (int)entity->he_flags.response)); |
| 315 | + |
| 316 | + /* |
| 317 | + * These probably shouldn't be handled in the same function. |
| 318 | + */ |
| 319 | + if (entity->he_flags.response) { |
| 320 | + /* |
| 321 | + * HTTP/1.0 |
| 322 | + */ |
| 323 | + if ((p = strchr(request, ' ')) == NULL) |
| 324 | + return -1; |
| 325 | + *p++ = '\0'; |
| 326 | + |
| 327 | + /* 200 */ |
| 328 | + if ((s = strchr(p, ' ')) == NULL) |
| 329 | + return -1; |
| 330 | + *s++ = '\0'; |
| 331 | + entity->he_rdata.response.status = atoi(p); |
| 332 | + |
| 333 | + /* OK */ |
| 334 | + entity->he_rdata.response.status_str = s; |
| 335 | + |
| 336 | + WDEBUG((WLOG_DEBUG, "parse_reqtype: \"%s\" \"%d\" \"%s\"", |
| 337 | + request, entity->he_rdata.response.status, |
| 338 | + entity->he_rdata.response.status_str)); |
| 339 | + return 0; |
| 340 | + } |
| 341 | + |
| 342 | + /* GET */ |
| 343 | + if ((p = strchr(request, ' ')) == NULL) |
| 344 | + return -1; |
| 345 | + |
| 346 | + *p++ = '\0'; |
| 347 | + |
| 348 | + for (i = 0; supported_reqtypes[i].name; i++) |
| 349 | + if (!strcmp(request, supported_reqtypes[i].name)) |
| 350 | + break; |
| 351 | + |
| 352 | + entity->he_rdata.request.reqtype = supported_reqtypes[i].type; |
| 353 | + if (entity->he_rdata.request.reqtype == REQTYPE_INVALID) |
| 354 | + return -1; |
| 355 | + |
| 356 | + /* /path/to/file */ |
| 357 | + if ((s = strchr(p, ' ')) == NULL) |
| 358 | + return -1; |
| 359 | + |
| 360 | + *s++ = '\0'; |
| 361 | + |
| 362 | + entity->he_rdata.request.path = wstrdup(p); |
| 363 | + |
| 364 | + /* HTTP/1.0 */ |
| 365 | + /* |
| 366 | + * Ignore this for now... |
| 367 | + */ |
| 368 | + return 0; |
| 369 | +} |
| 370 | + |
| 371 | +#ifdef __lint |
| 372 | +# pragma error_messages(off, E_GLOBAL_COULD_BE_STATIC) |
| 373 | +#endif |
| 374 | +/* |
| 375 | + * Header handling. |
| 376 | + */ |
| 377 | +void |
| 378 | +header_free(head) |
| 379 | + struct header_list *head; |
| 380 | +{ |
| 381 | +struct header_list *next = head->hl_next; |
| 382 | + |
| 383 | + while (next) { |
| 384 | + struct header_list *this = next; |
| 385 | + next = this->hl_next; |
| 386 | + if (this->hl_flags & HDR_ALLOCED) |
| 387 | + wfree((char *)this->hl_name); |
| 388 | + wfree(this); |
| 389 | + } |
| 390 | + |
| 391 | + bzero(head, sizeof(*head)); |
| 392 | +} |
| 393 | +#ifdef __lint |
| 394 | +# pragma error_messages(default, E_GLOBAL_COULD_BE_STATIC) |
| 395 | +#endif |
| 396 | + |
| 397 | +void |
| 398 | +header_add(head, name, value) |
| 399 | + struct header_list *head; |
| 400 | + const char *name, *value; |
| 401 | +{ |
| 402 | +struct header_list *new = head; |
| 403 | + |
| 404 | + head->hl_num++; |
| 405 | + |
| 406 | + if (head->hl_tail) |
| 407 | + new = head->hl_tail; |
| 408 | + else |
| 409 | + while (new->hl_next) |
| 410 | + new = new->hl_next; |
| 411 | + new->hl_next = wmalloc(sizeof(*head->hl_next)); |
| 412 | + head->hl_tail = new->hl_next; |
| 413 | + head->hl_len += strlen(name) + strlen(value) + 4; |
| 414 | + new = new->hl_next; |
| 415 | + new->hl_name = name; |
| 416 | + new->hl_value = value; |
| 417 | + new->hl_next = new->hl_tail = NULL; |
| 418 | + new->hl_flags = 0; |
| 419 | +} |
| 420 | + |
| 421 | +void |
| 422 | +header_remove(head, it) |
| 423 | + struct header_list *head, *it; |
| 424 | +{ |
| 425 | +struct header_list *jt; |
| 426 | + |
| 427 | + jt = head; |
| 428 | + while (jt->hl_next && jt->hl_next != it) |
| 429 | + jt = jt->hl_next; |
| 430 | + jt->hl_next = jt->hl_next->hl_next; |
| 431 | + if (it == head->hl_tail) |
| 432 | + head->hl_tail = jt; |
| 433 | + wfree(it); |
| 434 | +} |
| 435 | + |
| 436 | +#ifdef __lint |
| 437 | +# pragma error_messages(off, E_GLOBAL_COULD_BE_STATIC) |
| 438 | +#endif |
| 439 | +char * |
| 440 | +header_build(head) |
| 441 | + struct header_list *head; |
| 442 | +{ |
| 443 | + char *buf; |
| 444 | + size_t bufsz; |
| 445 | + size_t buflen = 0; |
| 446 | + |
| 447 | + bufsz = head->hl_len + 3; |
| 448 | + if ((buf = wmalloc(bufsz)) == NULL) |
| 449 | + outofmemory(); |
| 450 | + |
| 451 | + *buf = '\0'; |
| 452 | + while (head->hl_next) { |
| 453 | + head = head->hl_next; |
| 454 | + buflen += snprintf(buf + buflen, bufsz - buflen - 1, "%s: %s\r\n", head->hl_name, head->hl_value); |
| 455 | + } |
| 456 | + if (strlcat(buf, "\r\n", bufsz) >= bufsz ) |
| 457 | + abort(); |
| 458 | + |
| 459 | + return buf; |
| 460 | +} |
| 461 | +#ifdef __lint |
| 462 | +# pragma error_messages(default, E_GLOBAL_COULD_BE_STATIC) |
| 463 | +#endif |
| 464 | + |
| 465 | +void |
| 466 | +header_dump(head, fd) |
| 467 | + struct header_list *head; |
| 468 | + int fd; |
| 469 | +{ |
| 470 | + int i = 0; |
| 471 | +struct header_list *h; |
| 472 | + |
| 473 | + h = head->hl_next; |
| 474 | + while (h) { |
| 475 | + h = h->hl_next; |
| 476 | + ++i; |
| 477 | + } |
| 478 | + |
| 479 | + write(fd, &i, sizeof(i)); |
| 480 | + |
| 481 | + while (head->hl_next) { |
| 482 | + int i, j; |
| 483 | + head = head->hl_next; |
| 484 | + i = strlen(head->hl_name); |
| 485 | + write(fd, &i, sizeof(i)); |
| 486 | + j = strlen(head->hl_value); |
| 487 | + write(fd, &j, sizeof(j)); |
| 488 | + write(fd, head->hl_name, i); |
| 489 | + write(fd, head->hl_value, j); |
| 490 | + } |
| 491 | +} |
| 492 | + |
| 493 | +int |
| 494 | +header_undump(head, fd, len) |
| 495 | + struct header_list *head; |
| 496 | + int fd; |
| 497 | + off_t *len; |
| 498 | +{ |
| 499 | + int i = 0, j = 0, n = 0; |
| 500 | +struct header_list *it = head; |
| 501 | + ssize_t r; |
| 502 | + |
| 503 | + *len = 0; |
| 504 | + bzero(head, sizeof(*head)); |
| 505 | + head->hl_flags |= HDR_ALLOCED; |
| 506 | + if ((r = read(fd, &n, sizeof(n))) < 0) { |
| 507 | + wlog(WLOG_WARNING, "reading cache file: %s", strerror(errno)); |
| 508 | + return -1; /* XXX */ |
| 509 | + } |
| 510 | + |
| 511 | + *len += r; |
| 512 | + WDEBUG((WLOG_DEBUG, "header_undump: %d entries", n)); |
| 513 | + |
| 514 | + while (n--) { |
| 515 | + char *n, *v, *s; |
| 516 | + int k; |
| 517 | + |
| 518 | + if ((it->hl_next = wcalloc(1, sizeof(struct header_list))) == NULL) |
| 519 | + outofmemory(); |
| 520 | + it = it->hl_next; |
| 521 | + *len += read(fd, &i, sizeof(i)); |
| 522 | + *len += read(fd, &j, sizeof(j)); |
| 523 | + WDEBUG((WLOG_DEBUG, "header_undump: i=%d j=%d", i, j)); |
| 524 | + n = wmalloc(i + j + 2); |
| 525 | + i = read(fd, n, i); |
| 526 | + *len += i; |
| 527 | + s = n + i; |
| 528 | + *s++ = '\0'; |
| 529 | + v = s; |
| 530 | + k = read(fd, s, j); |
| 531 | + *len += k; |
| 532 | + s += k; |
| 533 | + *s = '\0'; |
| 534 | + it->hl_name = n; |
| 535 | + it->hl_value = v; |
| 536 | + it->hl_flags = HDR_ALLOCED; |
| 537 | + head->hl_len += i + j + 4; |
| 538 | + } |
| 539 | + |
| 540 | + head->hl_tail = it; |
| 541 | + return 0; |
| 542 | +} |
| 543 | + |
| 544 | +/* |
| 545 | + * Entity sending. This is not pretty. |
| 546 | + * |
| 547 | + * The entry point is entity_send(). This writes the request [XXX: this should |
| 548 | + * be done async. I'm pretty certain it'll never block, but we can't guarantee |
| 549 | + * that], builds a string from the headers, and wnet_writes it with |
| 550 | + * entity_send_headers_done as the callback. |
| 551 | + * |
| 552 | + * entity_send_headers_done decides what to do next: |
| 553 | + * NO BODY -> call user's callback immediately. |
| 554 | + * FDE BODY -> entity_send_start_proxy |
| 555 | + * BUF BODY -> entity_send_from_buf |
| 556 | + * |
| 557 | + * entity_send_start_proxy: |
| 558 | + * registers a read callback for the source FDE with entity_send_source_read |
| 559 | + * as the callback. entity_send_source_read reads the available data, then |
| 560 | + * writes it with entity_send_source_write as the callback. _write CALLS |
| 561 | + * SOURCE_READ AGAIN. this is important because otherwise we run into bad |
| 562 | + * interactions with the edge-triggered wnet [? i don't think this is |
| 563 | + * actually true but it's what the old code did and it's simpler than |
| 564 | + * registering in two places]. source_read handles EAGAIN and wnet_register |
| 565 | + * itself. |
| 566 | + * |
| 567 | + * entity_send_from_buf: |
| 568 | + * calls wnet_write on the buffer with entity_send_buf_done as the callback. |
| 569 | + * entity_send_buf_done calls the user's callback and returns. |
| 570 | + * |
| 571 | + * WARNING: if wnet_write completes immediately, i.e. does not block, it will |
| 572 | + * call your callback before it returns. after this, the entity may no longer |
| 573 | + * exist. wnet_write should generally be the last thing a function does |
| 574 | + * before it returns. |
| 575 | + */ |
| 576 | + |
| 577 | +void |
| 578 | +entity_send(fde, entity, cb, data) |
| 579 | + struct fde *fde; |
| 580 | + struct http_entity *entity; |
| 581 | + header_cb cb; |
| 582 | + void *data; |
| 583 | +{ |
| 584 | + char status[4]; |
| 585 | + |
| 586 | + entity->_he_func = cb; |
| 587 | + entity->_he_cbdata = data; |
| 588 | + |
| 589 | + WDEBUG((WLOG_DEBUG, "entity_send: writing to %d [%s]", fde->fde_fd, fde->fde_desc)); |
| 590 | + |
| 591 | + if (entity->he_flags.response) { |
| 592 | + struct iovec vec[5]; |
| 593 | + |
| 594 | + safe_snprintf(4, (status, 4, "%d", entity->he_rdata.response.status)); |
| 595 | + vec[0].iov_base = "HTTP/1.0 "; |
| 596 | + vec[0].iov_len = 9; |
| 597 | + vec[1].iov_base = status; |
| 598 | + vec[1].iov_len = strlen(status); |
| 599 | + vec[2].iov_base = " "; |
| 600 | + vec[2].iov_len = 1; |
| 601 | + vec[3].iov_base = (void *)entity->he_rdata.response.status_str; |
| 602 | + vec[3].iov_len = strlen(entity->he_rdata.response.status_str); |
| 603 | + vec[4].iov_base = "\r\n"; |
| 604 | + vec[4].iov_len = 2; |
| 605 | + writev(fde->fde_fd, vec, 5); |
| 606 | + } else { |
| 607 | + struct iovec vec[4]; |
| 608 | + |
| 609 | + vec[0].iov_base = (void *)request_string[entity->he_rdata.request.reqtype]; |
| 610 | + vec[0].iov_len = strlen(request_string[entity->he_rdata.request.reqtype]); |
| 611 | + vec[1].iov_base = " "; |
| 612 | + vec[1].iov_len = 1; |
| 613 | + vec[2].iov_base = entity->he_rdata.request.path; |
| 614 | + vec[2].iov_len = strlen(entity->he_rdata.request.path); |
| 615 | + vec[3].iov_base = " HTTP/1.0\r\n"; |
| 616 | + vec[3].iov_len = 11; |
| 617 | + writev(fde->fde_fd, vec, 4); |
| 618 | + } |
| 619 | + |
| 620 | + entity->_he_target = fde; |
| 621 | + |
| 622 | + entity->_he_hdrbuf = header_build(&entity->he_headers); |
| 623 | + wnet_write(fde->fde_fd, entity->_he_hdrbuf, strlen(entity->_he_hdrbuf), |
| 624 | + entity_send_headers_done, entity); |
| 625 | +} |
| 626 | + |
| 627 | +/*ARGSUSED*/ |
| 628 | +static void |
| 629 | +entity_send_headers_done(fde, data, res) |
| 630 | + struct fde *fde; |
| 631 | + void *data; |
| 632 | + int res; |
| 633 | +{ |
| 634 | +struct http_entity *entity = data; |
| 635 | + |
| 636 | + wfree(entity->_he_hdrbuf); |
| 637 | + |
| 638 | + WDEBUG((WLOG_DEBUG, "entity_send_headers_done: called for %d [%s], res=%d", fde->fde_fd, fde->fde_desc, res)); |
| 639 | + |
| 640 | + if (res == -1) { |
| 641 | + entity->_he_func(entity, entity->_he_cbdata, -1); |
| 642 | + return; |
| 643 | + } |
| 644 | + |
| 645 | + if (entity->he_source_type == ENT_SOURCE_NONE) { |
| 646 | + /* no body for this request */ |
| 647 | + WDEBUG((WLOG_DEBUG, "entity_send_headers_done: no body, return immediately")); |
| 648 | + entity->_he_func(entity, entity->_he_cbdata, 0); |
| 649 | + return; |
| 650 | + } |
| 651 | + |
| 652 | + if (entity->he_source_type == ENT_SOURCE_BUFFER) { |
| 653 | + /* write buffer, callback when done */ |
| 654 | + WDEBUG((WLOG_DEBUG, "entity_send_headers_done: source is buffer, %d bytes", |
| 655 | + entity->he_source.buffer.len)); |
| 656 | + wnet_write(fde->fde_fd, entity->he_source.buffer.addr, |
| 657 | + entity->he_source.buffer.len, entity_send_buf_done, entity); |
| 658 | + return; |
| 659 | + } |
| 660 | + |
| 661 | + if (entity->he_source_type == ENT_SOURCE_FILE) { |
| 662 | + /* write file */ |
| 663 | + wnet_sendfile(fde->fde_fd, entity->he_source.fd.fd, |
| 664 | + entity->he_source.fd.size - entity->he_source.fd.off, |
| 665 | + entity->he_source.fd.off, entity_send_file_done, entity); |
| 666 | + return; |
| 667 | + } |
| 668 | + |
| 669 | + /* FDE backended write */ |
| 670 | + /* |
| 671 | + * fde_read reads some amount of data (not necessarily all of it), and |
| 672 | + * then calls wnet_write to write it. it then unregisters the fd as |
| 673 | + * readable. when wnet_write completes and calls fde_write_done, it |
| 674 | + * registers the fd as readable again.. |
| 675 | + */ |
| 676 | + WDEBUG((WLOG_DEBUG, "entity_send_headers_done: source is FDE")); |
| 677 | + entity->he_source.fde._wrt = entity->he_source.fde.len; |
| 678 | + wnet_register(entity->he_source.fde.fde->fde_fd, FDE_READ, entity_send_fde_read, entity); |
| 679 | + entity_send_fde_read(entity->he_source.fde.fde); |
| 680 | +} |
| 681 | + |
| 682 | +static void |
| 683 | +entity_send_fde_read(fde) |
| 684 | + struct fde *fde; |
| 685 | +{ |
| 686 | +struct http_entity *entity = fde->fde_rdata; |
| 687 | + ssize_t len; |
| 688 | + size_t wrt; |
| 689 | + void *cur_pos; |
| 690 | + |
| 691 | + WDEBUG((WLOG_DEBUG, "entity_send_fde_read: called for %d [%s]", fde->fde_fd, fde->fde_desc)); |
| 692 | + WDEBUG((WLOG_DEBUG, "entity_send_fde_read: %d bytes left in readbuf", |
| 693 | + readbuf_data_left(&entity->he_source.fde.fde->fde_readbuf))); |
| 694 | + |
| 695 | + if (entity->he_source.fde._wrt == 0) { |
| 696 | + entity->_he_func(entity, entity->_he_cbdata, 0); |
| 697 | + return; |
| 698 | + } |
| 699 | + |
| 700 | + if (readbuf_data_left(&entity->he_source.fde.fde->fde_readbuf) == 0) { |
| 701 | + len = readbuf_getdata(fde); |
| 702 | + } else |
| 703 | + len = readbuf_data_left(&entity->he_source.fde.fde->fde_readbuf); |
| 704 | + |
| 705 | + WDEBUG((WLOG_DEBUG, "entity_send_fde_read: read %d bytes", len)); |
| 706 | + |
| 707 | + if (len == 0) { |
| 708 | + /* remote closed */ |
| 709 | + entity->_he_func(entity, entity->_he_cbdata, 0); |
| 710 | + return; |
| 711 | + } |
| 712 | + |
| 713 | + if (len == -1) { |
| 714 | + if (errno == EAGAIN) { |
| 715 | + return; |
| 716 | + } |
| 717 | + |
| 718 | + entity->_he_func(entity, entity->_he_cbdata, -1); |
| 719 | + return; |
| 720 | + } |
| 721 | + |
| 722 | + if (entity->he_cache_callback) { |
| 723 | + entity->he_cache_callback(readbuf_cur_pos(&entity->he_source.fde.fde->fde_readbuf), |
| 724 | + readbuf_data_left(&entity->he_source.fde.fde->fde_readbuf), |
| 725 | + entity->he_cache_callback_data); |
| 726 | + } |
| 727 | + |
| 728 | + if (entity->he_source.fde._wrt == -1) |
| 729 | + wrt = readbuf_data_left(&entity->he_source.fde.fde->fde_readbuf); |
| 730 | + else { |
| 731 | + wrt = min(readbuf_data_left(&entity->he_source.fde.fde->fde_readbuf), |
| 732 | + entity->he_source.fde._wrt); |
| 733 | + entity->he_source.fde._wrt -= wrt; |
| 734 | + } |
| 735 | + |
| 736 | + WDEBUG((WLOG_DEBUG, "_wrt=%d, writing %d", entity->he_source.fde._wrt, wrt)); |
| 737 | + cur_pos = readbuf_cur_pos(&entity->he_source.fde.fde->fde_readbuf); |
| 738 | + readbuf_inc_data_pos(&entity->he_source.fde.fde->fde_readbuf, wrt); |
| 739 | + wnet_write(entity->_he_target->fde_fd, cur_pos, |
| 740 | + wrt, entity_send_fde_write_done, entity); |
| 741 | +} |
| 742 | + |
| 743 | +/*ARGSUSED*/ |
| 744 | +static void |
| 745 | +entity_send_fde_write_done(fde, data, res) |
| 746 | + struct fde *fde; |
| 747 | + void *data; |
| 748 | + int res; |
| 749 | +{ |
| 750 | +struct http_entity *entity = data; |
| 751 | + |
| 752 | + WDEBUG((WLOG_DEBUG, "entity_send_fde_write_done: called")); |
| 753 | + |
| 754 | + if (entity->he_source.fde._wrt == 0) { |
| 755 | + wnet_register(entity->he_source.fde.fde->fde_fd, FDE_READ, NULL, NULL); |
| 756 | + WDEBUG((WLOG_DEBUG, "entity_send_fde_write_done: _wrt = 0, fd=%d, target=%d", |
| 757 | + entity->he_source.fde.fde->fde_fd, entity->_he_target->fde_fd)); |
| 758 | + readbuf_free(&entity->_he_target->fde_readbuf); |
| 759 | + entity->_he_func(entity, entity->_he_cbdata, 0); |
| 760 | + return; |
| 761 | + } |
| 762 | + |
| 763 | + wnet_register(entity->he_source.fde.fde->fde_fd, FDE_READ, entity_send_fde_read, entity); |
| 764 | +} |
| 765 | + |
| 766 | +/*ARGSUSED*/ |
| 767 | +static void |
| 768 | +entity_send_buf_done(fde, data, res) |
| 769 | + struct fde *fde; |
| 770 | + void *data; |
| 771 | + int res; |
| 772 | +{ |
| 773 | +struct http_entity *entity = data; |
| 774 | + |
| 775 | + WDEBUG((WLOG_DEBUG, "entity_send_buf_done: called for %d [%s], res=%d", fde->fde_fd, fde->fde_desc, res)); |
| 776 | + entity->_he_func(entity, entity->_he_cbdata, res); |
| 777 | + return; |
| 778 | +} |
| 779 | + |
| 780 | +/*ARGSUSED*/ |
| 781 | +static void |
| 782 | +entity_send_file_done(fde, data, res) |
| 783 | + struct fde *fde; |
| 784 | + void *data; |
| 785 | + int res; |
| 786 | +{ |
| 787 | +struct http_entity *entity = data; |
| 788 | + |
| 789 | + WDEBUG((WLOG_DEBUG, "entity_send_file_done: called for %d [%s], res=%d", fde->fde_fd, fde->fde_desc, res)); |
| 790 | + entity->_he_func(entity, entity->_he_cbdata, res); |
| 791 | + return; |
| 792 | +} |
Property changes on: trunk/willow/src/bin/willow/whttp_entity.c |
___________________________________________________________________ |
Added: svn:keywords |
1 | 793 | + Author Date Id Revision |
Added: svn:eol-style |
2 | 794 | + native |
Index: trunk/willow/src/bin/willow/daemon.c |
— | — | @@ -0,0 +1,71 @@ |
| 2 | +/* $Header$ */ |
| 3 | +/* $NetBSD: daemon.c,v 1.9 2003/08/07 16:42:46 agc Exp $ */ |
| 4 | + |
| 5 | +/*- |
| 6 | + * Copyright (c) 1990, 1993 |
| 7 | + * The Regents of the University of California. All rights reserved. |
| 8 | + * |
| 9 | + * Redistribution and use in source and binary forms, with or without |
| 10 | + * modification, are permitted provided that the following conditions |
| 11 | + * are met: |
| 12 | + * 1. Redistributions of source code must retain the above copyright |
| 13 | + * notice, this list of conditions and the following disclaimer. |
| 14 | + * 2. Redistributions in binary form must reproduce the above copyright |
| 15 | + * notice, this list of conditions and the following disclaimer in the |
| 16 | + * documentation and/or other materials provided with the distribution. |
| 17 | + * 3. Neither the name of the University nor the names of its contributors |
| 18 | + * may be used to endorse or promote products derived from this software |
| 19 | + * without specific prior written permission. |
| 20 | + * |
| 21 | + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
| 22 | + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| 23 | + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| 24 | + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
| 25 | + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
| 26 | + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
| 27 | + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
| 28 | + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
| 29 | + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
| 30 | + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
| 31 | + * SUCH DAMAGE. |
| 32 | + */ |
| 33 | + |
| 34 | +#if defined __SUNPRO_C || defined __DECC || defined __HP_cc |
| 35 | +# pragma ident "@(#)$Header$" |
| 36 | +# pragma ident "$NetBSD: daemon.c,v 1.9 2003/08/07 16:42:46 agc Exp $" |
| 37 | +#endif |
| 38 | + |
| 39 | +#include <fcntl.h> |
| 40 | +#include <stdlib.h> |
| 41 | +#include <unistd.h> |
| 42 | + |
| 43 | +int |
| 44 | +daemon(nochdir, noclose) |
| 45 | + int nochdir, noclose; |
| 46 | +{ |
| 47 | + int fd; |
| 48 | + |
| 49 | + switch (fork()) { |
| 50 | + case -1: |
| 51 | + return (-1); |
| 52 | + case 0: |
| 53 | + break; |
| 54 | + default: |
| 55 | + _exit(0); |
| 56 | + } |
| 57 | + |
| 58 | + if (setsid() == -1) |
| 59 | + return (-1); |
| 60 | + |
| 61 | + if (!nochdir) |
| 62 | + (void)chdir("/"); |
| 63 | + |
| 64 | + if (!noclose && (fd = open("/dev/null", O_RDWR, 0)) != -1) { |
| 65 | + (void)dup2(fd, STDIN_FILENO); |
| 66 | + (void)dup2(fd, STDOUT_FILENO); |
| 67 | + (void)dup2(fd, STDERR_FILENO); |
| 68 | + if (fd > STDERR_FILENO) |
| 69 | + (void)close(fd); |
| 70 | + } |
| 71 | + return (0); |
| 72 | +} |
Property changes on: trunk/willow/src/bin/willow/daemon.c |
___________________________________________________________________ |
Added: svn:keywords |
1 | 73 | + Author Date Id Revision |
Added: svn:eol-style |
2 | 74 | + native |
Index: trunk/willow/src/bin/willow/wlogwriter.c |
— | — | @@ -0,0 +1,83 @@ |
| 2 | +/* @(#) $Header$ */ |
| 3 | +/* This source code is in the public domain. */ |
| 4 | +/* |
| 5 | + * Willow: Lightweight HTTP reverse-proxy. |
| 6 | + * wlogwriter: child process for log writing. |
| 7 | + */ |
| 8 | + |
| 9 | +#if defined __SUNPRO_C || defined __DECC || defined __HP_cc |
| 10 | +# pragma ident "@(#)$Header$" |
| 11 | +#endif |
| 12 | + |
| 13 | +#include <stdio.h> |
| 14 | +#include <unistd.h> |
| 15 | +#include <errno.h> |
| 16 | +#include <string.h> |
| 17 | +#include <stdlib.h> |
| 18 | +#include <signal.h> |
| 19 | + |
| 20 | +#include "willow.h" |
| 21 | +#include "wlogwriter.h" |
| 22 | +#include "wconfig.h" |
| 23 | +#include "wlog.h" |
| 24 | + |
| 25 | +static void wlogwriter_run(int); |
| 26 | + |
| 27 | +void |
| 28 | +wlogwriter_start(fd) |
| 29 | + int *fd; |
| 30 | +{ |
| 31 | + switch (fork()) { |
| 32 | + case -1: |
| 33 | + wlog(WLOG_ERROR, "fork: %s", strerror(errno)); |
| 34 | + exit(8); |
| 35 | + /*NOTREACHED*/ |
| 36 | + case 0: |
| 37 | + (void)close(fd[0]); |
| 38 | + wlogwriter_run(fd[1]); |
| 39 | + break; |
| 40 | + default: |
| 41 | + (void)close(fd[1]); |
| 42 | + break; |
| 43 | + } |
| 44 | +} |
| 45 | + |
| 46 | +static void |
| 47 | +wlogwriter_run(pipe) |
| 48 | + int pipe; |
| 49 | +{ |
| 50 | + FILE *inf, *outf; |
| 51 | + char *line; |
| 52 | + size_t lnsz; |
| 53 | + |
| 54 | + lnsz = 8192; |
| 55 | + line = malloc(lnsz); |
| 56 | + |
| 57 | + (void)signal(SIGPIPE, SIG_IGN); |
| 58 | + |
| 59 | +#ifdef HAVE_SETPROCTITLE |
| 60 | + setproctitle("log writer: %s", config.access_log); |
| 61 | +#endif |
| 62 | + wlog(WLOG_NOTICE, "wlogwriter starting (pid %d) for %s", (int)getpid(), config.access_log); |
| 63 | + |
| 64 | + if ((inf = fdopen(pipe, "r")) == NULL) { |
| 65 | + perror("fdopen"); |
| 66 | + exit(8); |
| 67 | + } |
| 68 | + /*LINTED unsafe fopen*/ |
| 69 | + if ((outf = fopen(config.access_log, "a")) == NULL) { |
| 70 | + perror(config.access_log); |
| 71 | + exit(8); |
| 72 | + } |
| 73 | + |
| 74 | + while (fgets(line, lnsz, inf)) { |
| 75 | + if (fputs(line, outf) == EOF || fflush(outf) == EOF) { |
| 76 | + wlog(WLOG_NOTICE, "fatal: writing access log: %s", strerror(errno)); |
| 77 | + exit(8); |
| 78 | + } |
| 79 | + } |
| 80 | + |
| 81 | + wlog(WLOG_NOTICE, "wlogwriter terminating"); |
| 82 | + exit(0); |
| 83 | +} |
| 84 | + |
Property changes on: trunk/willow/src/bin/willow/wlogwriter.c |
___________________________________________________________________ |
Added: svn:keywords |
1 | 85 | + Author Date Id Revision |
Added: svn:eol-style |
2 | 86 | + native |
Index: trunk/willow/src/bin/willow/whttp.c |
— | — | @@ -0,0 +1,649 @@ |
| 2 | +/* @(#) $Header$ */ |
| 3 | +/* This source code is in the public domain. */ |
| 4 | +/* |
| 5 | + * Willow: Lightweight HTTP reverse-proxy. |
| 6 | + * whttp: HTTP implementation. |
| 7 | + */ |
| 8 | + |
| 9 | +#if defined __SUNPRO_C || defined __DECC || defined __HP_cc |
| 10 | +# pragma ident "@(#)$Header$" |
| 11 | +#endif |
| 12 | + |
| 13 | +/* |
| 14 | + * The logic of whttp is explained in whttp_entity.c |
| 15 | + */ |
| 16 | + |
| 17 | +#include <sys/types.h> |
| 18 | +#include <sys/stat.h> |
| 19 | +#include <sys/param.h> |
| 20 | + |
| 21 | +#include <stdlib.h> |
| 22 | +#include <stdio.h> |
| 23 | +#include <string.h> |
| 24 | +#include <unistd.h> |
| 25 | +#include <errno.h> |
| 26 | +#include <netdb.h> |
| 27 | +#include <fcntl.h> |
| 28 | +#include <strings.h> |
| 29 | + |
| 30 | +#include "willow.h" |
| 31 | +#include "whttp.h" |
| 32 | +#include "wnet.h" |
| 33 | +#include "wbackend.h" |
| 34 | +#include "wconfig.h" |
| 35 | +#include "wlogwriter.h" |
| 36 | +#include "whttp_entity.h" |
| 37 | +#include "wlog.h" |
| 38 | +#include "wcache.h" |
| 39 | + |
| 40 | +#ifndef MAXHOSTNAMELEN |
| 41 | +# define MAXHOSTNAMELEN HOST_NAME_MAX /* SysV / BSD disagreement */ |
| 42 | +#endif |
| 43 | + |
| 44 | +/* |
| 45 | + * Error handling. |
| 46 | + */ |
| 47 | +#define ERR_GENERAL 0 |
| 48 | +#define ERR_BADREQUEST 1 |
| 49 | +#define ERR_BADRESPONSE 2 |
| 50 | +#define ERR_CACHE_IO 3 |
| 51 | + |
| 52 | +static const char *error_files[] = { |
| 53 | + /* ERR_GENERAL */ DATADIR "/errors/ERR_GENERAL", |
| 54 | + /* ERR_BADREQUEST */ DATADIR "/errors/ERR_BADREQUEST", |
| 55 | + /* ERR_BADRESPONSE */ DATADIR "/errors/ERR_BADRESPONSE", |
| 56 | + /* ERR_CACHE_IO */ DATADIR "/errors/ERR_CACHE_IO", |
| 57 | +}; |
| 58 | + |
| 59 | +const char *request_string[] = { |
| 60 | + "GET", |
| 61 | + "POST", |
| 62 | + "HEAD", |
| 63 | + "TRACE", |
| 64 | + "OPTIONS", |
| 65 | +}; |
| 66 | + |
| 67 | +struct request_type supported_reqtypes[] = { |
| 68 | + { "GET", 3, REQTYPE_GET }, |
| 69 | + { "POST", 4, REQTYPE_POST }, |
| 70 | + { "HEAD", 4, REQTYPE_HEAD }, |
| 71 | + { "TRACE", 5, REQTYPE_TRACE }, |
| 72 | + { "OPTIONS", 7, REQTYPE_OPTIONS }, |
| 73 | + { NULL, 0, REQTYPE_INVALID } |
| 74 | +}; |
| 75 | + |
| 76 | +struct http_client { |
| 77 | +struct fde *cl_fde; /* backref to fd */ |
| 78 | + int cl_reqtype; /* request type or 0 */ |
| 79 | + char *cl_path; /* path they want */ |
| 80 | + char *cl_wrtbuf; /* write buf (either to client or be) */ |
| 81 | +struct backend *cl_backend; /* backend servicing this client */ |
| 82 | +struct fde *cl_backendfde; /* fde for backend */ |
| 83 | +struct http_entity cl_entity; /* reply to send back */ |
| 84 | + |
| 85 | + /* Cache-related data */ |
| 86 | + int cl_cfd; /* FD of cache file for writing, or 0 */ |
| 87 | +struct cache_key cl_key; /* Cache key */ |
| 88 | +struct cache_object *cl_co; /* Cache object */ |
| 89 | + struct { |
| 90 | + int f_cached:1; |
| 91 | + } cl_flags; |
| 92 | + |
| 93 | +struct http_client *fe_next; /* freelist */ |
| 94 | +}; |
| 95 | + |
| 96 | +static struct http_client freelist; |
| 97 | + |
| 98 | +static void client_close(struct http_client *); |
| 99 | +static void proxy_start_backend(struct backend *, struct fde *, void *); |
| 100 | +static void client_read_done(struct http_entity *, void *, int); |
| 101 | +static void client_response_done(struct http_entity *, void *, int); |
| 102 | +static void backend_headers_done(struct http_entity *, void *, int); |
| 103 | +static void client_headers_done(struct http_entity *, void *, int); |
| 104 | +static void client_write_cached(struct http_client *); |
| 105 | + |
| 106 | +static void client_send_error(struct http_client *, int, const char *); |
| 107 | +static void client_log_request(struct http_client *); |
| 108 | + |
| 109 | +static void do_cache_write(const char *, size_t, void *); |
| 110 | + |
| 111 | +static char via_hdr[1024]; |
| 112 | +static char *cache_hit_hdr; |
| 113 | +static char *cache_miss_hdr; |
| 114 | + |
| 115 | +static char my_hostname[MAXHOSTNAMELEN + 1]; |
| 116 | +static char my_version[64]; |
| 117 | +static int logwr_pipe[2]; |
| 118 | +static FILE *alf; |
| 119 | + |
| 120 | +/* |
| 121 | + * Initialize whttp, start loggers. |
| 122 | + */ |
| 123 | +void |
| 124 | +whttp_init(void) |
| 125 | +{ |
| 126 | + size_t hsize; |
| 127 | + |
| 128 | + if (gethostname(my_hostname, MAXHOSTNAMELEN) < 0) { |
| 129 | + perror("gethostname"); |
| 130 | + exit(8); |
| 131 | + } |
| 132 | + |
| 133 | + (void)strlcpy(my_version, "Willow/" PACKAGE_VERSION, 64); |
| 134 | + safe_snprintf(1023, (via_hdr, 1023, "1.0 %s (%s)", my_hostname, my_version)); |
| 135 | + |
| 136 | + hsize = sizeof("MISS from ") + strlen(my_hostname); |
| 137 | + cache_hit_hdr = wmalloc(hsize + 1); |
| 138 | + cache_miss_hdr = wmalloc(hsize + 1); |
| 139 | + |
| 140 | + if (cache_hit_hdr == NULL || cache_miss_hdr == NULL) |
| 141 | + outofmemory(); |
| 142 | + |
| 143 | + safe_snprintf(hsize, (cache_hit_hdr, hsize, "HIT from %s", my_hostname)); |
| 144 | + safe_snprintf(hsize, (cache_miss_hdr, hsize, "MISS from %s", my_hostname)); |
| 145 | + |
| 146 | + /* |
| 147 | + * Fork the logwriter. |
| 148 | + */ |
| 149 | + if (config.access_log) { |
| 150 | + if (pipe(logwr_pipe) < 0) { |
| 151 | + perror("pipe"); |
| 152 | + exit(8); |
| 153 | + } |
| 154 | + wlogwriter_start(logwr_pipe); |
| 155 | + if ((alf = fdopen(logwr_pipe[0], "w")) == NULL) { |
| 156 | + perror("fdopen"); |
| 157 | + exit(8); |
| 158 | + } |
| 159 | + } |
| 160 | +} |
| 161 | + |
| 162 | +void |
| 163 | +whttp_shutdown(void) |
| 164 | +{ |
| 165 | + wfree(cache_hit_hdr); |
| 166 | + wfree(cache_miss_hdr); |
| 167 | +} |
| 168 | + |
| 169 | +/* |
| 170 | + * Create a new client associated with the FDE 'e'. |
| 171 | + */ |
| 172 | +static struct http_client * |
| 173 | +new_client(e) |
| 174 | + struct fde *e; |
| 175 | +{ |
| 176 | +struct http_client *cl; |
| 177 | + |
| 178 | + if (freelist.fe_next) { |
| 179 | + cl = freelist.fe_next; |
| 180 | + freelist.fe_next = cl->fe_next; |
| 181 | + bzero(cl, sizeof(*cl)); |
| 182 | + } else { |
| 183 | + if ((cl = wcalloc(1, sizeof(*cl))) == NULL) |
| 184 | + outofmemory(); |
| 185 | + } |
| 186 | + |
| 187 | + cl->cl_fde = e; |
| 188 | + return cl; |
| 189 | +} |
| 190 | + |
| 191 | +/* |
| 192 | + * Called by wnet_accept to regiister a new client. Reads the request headers |
| 193 | + * from the client. |
| 194 | + */ |
| 195 | +void |
| 196 | +http_new(e) |
| 197 | + struct fde *e; |
| 198 | +{ |
| 199 | +struct http_client *cl; |
| 200 | + |
| 201 | + cl = new_client(e); |
| 202 | + cl->cl_entity.he_source_type = ENT_SOURCE_FDE; |
| 203 | + cl->cl_entity.he_source.fde.fde = e; |
| 204 | + cl->cl_entity.he_rdata.request.contlen = -1; |
| 205 | + |
| 206 | + WDEBUG((WLOG_DEBUG, "http_new: starting header read for %d", cl->cl_fde->fde_fd)); |
| 207 | + entity_read_headers(&cl->cl_entity, client_read_done, cl); |
| 208 | +} |
| 209 | + |
| 210 | +/* |
| 211 | + * Called when the initial request has been read. Checks if the object is |
| 212 | + * cached, and starts a backend request if not. If it it, sends the cached |
| 213 | + * object to the client. |
| 214 | + */ |
| 215 | +/*ARGSUSED*/ |
| 216 | +static void |
| 217 | +client_read_done(entity, data, res) |
| 218 | + struct http_entity *entity; |
| 219 | + void *data; |
| 220 | + int res; |
| 221 | +{ |
| 222 | +struct http_client *client = data; |
| 223 | +struct cache_key ckey; |
| 224 | +struct cache_object *cobj; |
| 225 | + |
| 226 | + WDEBUG((WLOG_DEBUG, "client_read_done: called")); |
| 227 | + |
| 228 | + if (res == -1) { |
| 229 | + client_close(client); |
| 230 | + return; |
| 231 | + } |
| 232 | + |
| 233 | + if (client->cl_entity.he_rdata.request.host == NULL) |
| 234 | + client->cl_path = wstrdup(client->cl_entity.he_rdata.request.path); |
| 235 | + else { |
| 236 | + size_t len; |
| 237 | + |
| 238 | + len = strlen(client->cl_entity.he_rdata.request.host) + |
| 239 | + strlen(client->cl_entity.he_rdata.request.path) + 7; |
| 240 | + |
| 241 | + client->cl_path = wmalloc(len + 1); |
| 242 | + if (client->cl_path == NULL) |
| 243 | + outofmemory(); |
| 244 | + safe_snprintf(len + 1, (client->cl_path, len + 1, "http://%s%s", client->cl_entity.he_rdata.request.host, |
| 245 | + client->cl_entity.he_rdata.request.path)); |
| 246 | + } |
| 247 | + |
| 248 | + client->cl_reqtype = client->cl_entity.he_rdata.request.reqtype; |
| 249 | + |
| 250 | + /* |
| 251 | + * Check for cached object. |
| 252 | + */ |
| 253 | + if (client->cl_reqtype == REQTYPE_GET) { |
| 254 | + ckey.ck_len = strlen(client->cl_path); |
| 255 | + ckey.ck_key = client->cl_path; |
| 256 | + cobj = wcache_find_object(&ckey); |
| 257 | + if (cobj != NULL) { |
| 258 | + client->cl_co = cobj; |
| 259 | + WDEBUG((WLOG_DEBUG, "client_read_done: object %s cached", client->cl_path)); |
| 260 | + client_write_cached(client); |
| 261 | + return; |
| 262 | + } |
| 263 | + } |
| 264 | + |
| 265 | + /* |
| 266 | + * Not cached. Find a backend. |
| 267 | + */ |
| 268 | + if (get_backend(proxy_start_backend, client) == -1) { |
| 269 | + client_send_error(client, ERR_GENERAL, strerror(errno)); |
| 270 | + return; |
| 271 | + } |
| 272 | +} |
| 273 | + |
| 274 | +/* |
| 275 | + * Called when backend is ready. backend==NULL if none was found. |
| 276 | + */ |
| 277 | +static void |
| 278 | +proxy_start_backend(backend, e, data) |
| 279 | + struct backend *backend; |
| 280 | + struct fde *e; |
| 281 | + void *data; |
| 282 | +{ |
| 283 | +struct http_client *client = data; |
| 284 | +struct header_list *it; |
| 285 | + |
| 286 | + WDEBUG((WLOG_DEBUG, "proxy_start_backend: called")); |
| 287 | + |
| 288 | + if (backend == NULL) { |
| 289 | + client_send_error(client, ERR_GENERAL, strerror(errno)); |
| 290 | + return; |
| 291 | + } |
| 292 | + |
| 293 | + client->cl_backend = backend; |
| 294 | + client->cl_backendfde = e; |
| 295 | + |
| 296 | + for (it = client->cl_entity.he_headers.hl_next; it; it = it->hl_next) { |
| 297 | + if (!strcmp(it->hl_name, "Connection")) { |
| 298 | + header_remove(&client->cl_entity.he_headers, it); |
| 299 | + it = client->cl_entity.he_headers.hl_next; |
| 300 | + continue; |
| 301 | + } |
| 302 | + } |
| 303 | + |
| 304 | + header_add(&client->cl_entity.he_headers, "X-Forwarded-For", client->cl_fde->fde_straddr); |
| 305 | + /* |
| 306 | + * POST requests require Content-Length. |
| 307 | + */ |
| 308 | + if (client->cl_reqtype == REQTYPE_POST) { |
| 309 | + if (client->cl_entity.he_rdata.request.contlen == -1) { |
| 310 | + client_send_error(client, ERR_BADREQUEST, "POST request without Content-Length"); |
| 311 | + return; |
| 312 | + } |
| 313 | + |
| 314 | + WDEBUG((WLOG_DEBUG, "client content-length=%d", client->cl_entity.he_rdata.request.contlen)); |
| 315 | + client->cl_entity.he_source_type = ENT_SOURCE_FDE; |
| 316 | + client->cl_entity.he_source.fde.fde = client->cl_fde; |
| 317 | + client->cl_entity.he_source.fde.len = client->cl_entity.he_rdata.request.contlen; |
| 318 | + } else |
| 319 | + client->cl_entity.he_source_type = ENT_SOURCE_NONE; |
| 320 | + |
| 321 | + entity_send(e, &client->cl_entity, backend_headers_done, client); |
| 322 | +} |
| 323 | + |
| 324 | +/* |
| 325 | + * Called when clients request was written to the backend. |
| 326 | + */ |
| 327 | +/*ARGSUSED*/ |
| 328 | +static void |
| 329 | +backend_headers_done(entity, data, res) |
| 330 | + struct http_entity *entity; |
| 331 | + void *data; |
| 332 | + int res; |
| 333 | +{ |
| 334 | +struct http_client *client = data; |
| 335 | + |
| 336 | + WDEBUG((WLOG_DEBUG, "backend_headers_done: called")); |
| 337 | + if (res == -1) { |
| 338 | + client_send_error(client, ERR_GENERAL, strerror(errno)); |
| 339 | + return; |
| 340 | + } |
| 341 | + |
| 342 | + entity_free(&client->cl_entity); |
| 343 | + bzero(&client->cl_entity, sizeof(client->cl_entity)); |
| 344 | + client->cl_entity.he_source_type = ENT_SOURCE_FDE; |
| 345 | + client->cl_entity.he_source.fde.fde = client->cl_backendfde; |
| 346 | + client->cl_entity.he_source.fde.len = -1; |
| 347 | + |
| 348 | + client->cl_entity.he_flags.response = 1; |
| 349 | + |
| 350 | + /* |
| 351 | + * This should probably be handled somewhere inside |
| 352 | + * whttp_entity.c ... |
| 353 | + */ |
| 354 | + entity_read_headers(&client->cl_entity, client_headers_done, client); |
| 355 | +} |
| 356 | + |
| 357 | +/* |
| 358 | + * Called when backend's headers are finished reading. |
| 359 | + */ |
| 360 | +static void |
| 361 | +client_headers_done(entity, data, res) |
| 362 | + struct http_entity *entity; |
| 363 | + void *data; |
| 364 | + int res; |
| 365 | +{ |
| 366 | +struct http_client *client = data; |
| 367 | + char *cache_path; |
| 368 | + size_t plen; |
| 369 | + |
| 370 | + WDEBUG((WLOG_DEBUG, "client_headers_done: called")); |
| 371 | + |
| 372 | + if (res == -1) { |
| 373 | + client_close(client); |
| 374 | + return; |
| 375 | + } |
| 376 | + |
| 377 | + /* |
| 378 | + * If cachable, open the cache file and write data. |
| 379 | + * |
| 380 | + * Don't cache responses to non-GET requests, or non-200 replies. |
| 381 | + */ |
| 382 | + if (client->cl_reqtype == REQTYPE_GET && entity->he_rdata.response.status == 200 |
| 383 | + && config.ncaches) { |
| 384 | + client->cl_key.ck_len = strlen(client->cl_path); |
| 385 | + client->cl_key.ck_key = client->cl_path; |
| 386 | + client->cl_co = wcache_new_object(); |
| 387 | + plen = strlen(config.caches[0].dir) + client->cl_co->co_plen + 12 + 2; |
| 388 | + if ((cache_path = wcalloc(1, plen + 1)) == NULL) |
| 389 | + outofmemory(); |
| 390 | + safe_snprintf(plen, (cache_path, plen, "%s/__objects__/%s", config.caches[0].dir, client->cl_co->co_path)); |
| 391 | + WDEBUG((WLOG_DEBUG, "caching %s at %s", client->cl_path, cache_path)); |
| 392 | + if ((client->cl_cfd = open(cache_path, O_WRONLY | O_CREAT | O_EXCL, 0600)) == -1) { |
| 393 | + wlog(WLOG_WARNING, "opening cache file %s: %s", cache_path, strerror(errno)); |
| 394 | + client->cl_cfd = 0; |
| 395 | + } else { |
| 396 | + entity->he_cache_callback = do_cache_write; |
| 397 | + entity->he_cache_callback_data = client; |
| 398 | + header_dump(&client->cl_entity.he_headers, client->cl_cfd); |
| 399 | + } |
| 400 | + wfree(cache_path); |
| 401 | + } |
| 402 | + |
| 403 | + header_add(&client->cl_entity.he_headers, "Via", via_hdr); |
| 404 | + header_add(&client->cl_entity.he_headers, "X-Cache", cache_miss_hdr); |
| 405 | + client->cl_entity.he_source.fde.len = -1; |
| 406 | + entity_send(client->cl_fde, &client->cl_entity, client_response_done, client); |
| 407 | +} |
| 408 | + |
| 409 | +/* |
| 410 | + * Write a cached object to the client. |
| 411 | + */ |
| 412 | +static void |
| 413 | +client_write_cached(client) |
| 414 | + struct http_client *client; |
| 415 | +{ |
| 416 | + size_t plen; |
| 417 | + char *cache_path; |
| 418 | +struct stat sb; |
| 419 | + |
| 420 | + plen = strlen(config.caches[0].dir) + client->cl_co->co_plen + 12 + 2; |
| 421 | + if ((cache_path = wcalloc(1, plen + 1)) == NULL) |
| 422 | + outofmemory(); |
| 423 | + safe_snprintf(plen, (cache_path, plen, "%s/__objects__/%s", config.caches[0].dir, client->cl_co->co_path)); |
| 424 | + WDEBUG((WLOG_DEBUG, "serving %s from cache at %s [path %s]", client->cl_path, cache_path, client->cl_co->co_path)); |
| 425 | + |
| 426 | + if ((client->cl_cfd = open(cache_path, O_RDONLY)) == -1) { |
| 427 | + wlog(WLOG_WARNING, "opening cache file %s: %s", cache_path, strerror(errno)); |
| 428 | + client_send_error(client, ERR_CACHE_IO, strerror(errno)); |
| 429 | + wfree(cache_path); |
| 430 | + return; |
| 431 | + } |
| 432 | + |
| 433 | + if (fstat(client->cl_cfd, &sb) < 0) { |
| 434 | + wlog(WLOG_WARNING, "stat(%s): %s", cache_path, strerror(errno)); |
| 435 | + client_send_error(client, ERR_CACHE_IO, strerror(errno)); |
| 436 | + wfree(cache_path); |
| 437 | + return; |
| 438 | + } |
| 439 | + |
| 440 | + wfree(cache_path); |
| 441 | + |
| 442 | + entity_free(&client->cl_entity); |
| 443 | + bzero(&client->cl_entity, sizeof(client->cl_entity)); |
| 444 | + header_undump(&client->cl_entity.he_headers, client->cl_cfd, &client->cl_entity.he_source.fd.off); |
| 445 | + header_add(&client->cl_entity.he_headers, "Via", via_hdr); |
| 446 | + header_add(&client->cl_entity.he_headers, "X-Cache", cache_hit_hdr); |
| 447 | + |
| 448 | + client->cl_entity.he_flags.response = 1; |
| 449 | + client->cl_entity.he_rdata.response.status = 200; |
| 450 | + client->cl_entity.he_rdata.response.status_str = "OK"; |
| 451 | + |
| 452 | + client->cl_entity.he_source.fd.fd = client->cl_cfd; |
| 453 | + client->cl_entity.he_source.fd.size = sb.st_size; |
| 454 | + |
| 455 | + client->cl_entity.he_source_type = ENT_SOURCE_FILE; |
| 456 | + |
| 457 | + client->cl_flags.f_cached = 1; |
| 458 | + entity_send(client->cl_fde, &client->cl_entity, client_response_done, client); |
| 459 | +} |
| 460 | + |
| 461 | +/* |
| 462 | + * Called when response was finished writing to the client. |
| 463 | + */ |
| 464 | +/*ARGSUSED*/ |
| 465 | +static void |
| 466 | +client_response_done(entity, data, res) |
| 467 | + struct http_entity *entity; |
| 468 | + void *data; |
| 469 | + int res; |
| 470 | +{ |
| 471 | +struct http_client *client = data; |
| 472 | + |
| 473 | + WDEBUG((WLOG_DEBUG, "client_response_done: called")); |
| 474 | + |
| 475 | + if (client->cl_cfd) { |
| 476 | + if (close(client->cl_cfd) < 0) { |
| 477 | + wlog(WLOG_WARNING, "writing cache file: %s\n", strerror(errno)); |
| 478 | + } |
| 479 | + } |
| 480 | + |
| 481 | + if (client->cl_co) { |
| 482 | + if (res != -1) { |
| 483 | + if (!client->cl_flags.f_cached) { |
| 484 | + if (wcache_store_object(&client->cl_key, client->cl_co) == -1) { |
| 485 | + /* normally, this means someone else cached it before us */ |
| 486 | + wlog(WLOG_WARNING, "object cache store failed"); |
| 487 | + } |
| 488 | + } |
| 489 | + } else { |
| 490 | + wlog(WLOG_WARNING, "writing cached file: %s", strerror(errno)); |
| 491 | + /* XXX should unlink cached file */ |
| 492 | + } |
| 493 | + wcache_free_object(client->cl_co); |
| 494 | + } |
| 495 | + |
| 496 | + client_log_request(client); |
| 497 | + client_close(client); |
| 498 | +} |
| 499 | + |
| 500 | +static void |
| 501 | +client_close(client) |
| 502 | + struct http_client *client; |
| 503 | +{ |
| 504 | + WDEBUG((WLOG_DEBUG, "close client %d", client->cl_fde->fde_fd)); |
| 505 | + if (client->cl_wrtbuf) |
| 506 | + wfree(client->cl_wrtbuf); |
| 507 | + if (client->cl_path) |
| 508 | + wfree(client->cl_path); |
| 509 | + wnet_close(client->cl_fde->fde_fd); |
| 510 | + if (client->cl_backendfde) |
| 511 | + wnet_close(client->cl_backendfde->fde_fd); |
| 512 | + entity_free(&client->cl_entity); |
| 513 | + |
| 514 | + client->fe_next = freelist.fe_next; |
| 515 | + freelist.fe_next = client; |
| 516 | +} |
| 517 | + |
| 518 | +static void |
| 519 | +client_send_error(client, errnum, errdata) |
| 520 | + struct http_client *client; |
| 521 | + int errnum; |
| 522 | + const char *errdata; |
| 523 | +{ |
| 524 | + FILE *errfile; |
| 525 | + char errbuf[8192]; |
| 526 | + char *p = errbuf, *u; |
| 527 | + ssize_t size; |
| 528 | + |
| 529 | + if ((errfile = fopen(error_files[errnum], "r")) == NULL) { |
| 530 | + client_close(client); |
| 531 | + return; |
| 532 | + } |
| 533 | + |
| 534 | + if ((size = fread(errbuf, 1, sizeof(errbuf) - 1, errfile)) < 0) { |
| 535 | + (void)fclose(errfile); |
| 536 | + client_close(client); |
| 537 | + return; |
| 538 | + } |
| 539 | + |
| 540 | + (void)fclose(errfile); |
| 541 | + errbuf[size] = '\0'; |
| 542 | + |
| 543 | + if (!errdata) |
| 544 | + errdata = "Unknown error"; |
| 545 | + if (!client->cl_path) |
| 546 | + client->cl_path = wstrdup("NONE"); |
| 547 | + |
| 548 | + u = NULL; |
| 549 | + |
| 550 | + while (*p) { |
| 551 | + switch(*p) { |
| 552 | + case '%': |
| 553 | + switch (*++p) { |
| 554 | + case 'U': |
| 555 | + realloc_strcat(&u, client->cl_path); |
| 556 | + break; |
| 557 | + case 'D': |
| 558 | + realloc_strcat(&u, current_time_str); |
| 559 | + break; |
| 560 | + case 'H': |
| 561 | + realloc_strcat(&u, my_hostname); |
| 562 | + break; |
| 563 | + case 'E': |
| 564 | + realloc_strcat(&u, errdata); |
| 565 | + break; |
| 566 | + case 'V': |
| 567 | + realloc_strcat(&u, my_version); |
| 568 | + break; |
| 569 | + default: |
| 570 | + break; |
| 571 | + } |
| 572 | + p++; |
| 573 | + continue; |
| 574 | + default: |
| 575 | + realloc_addchar(&u, *p); |
| 576 | + break; |
| 577 | + } |
| 578 | + ++p; |
| 579 | + } |
| 580 | + |
| 581 | + client->cl_wrtbuf = u; |
| 582 | + |
| 583 | + bzero(&client->cl_entity.he_headers, sizeof(client->cl_entity.he_headers)); |
| 584 | + header_add(&client->cl_entity.he_headers, "Date", current_time_str); |
| 585 | + header_add(&client->cl_entity.he_headers, "Expires", current_time_str); |
| 586 | + header_add(&client->cl_entity.he_headers, "Server", my_version); |
| 587 | + header_add(&client->cl_entity.he_headers, "Content-Type", "text/html"); |
| 588 | + header_add(&client->cl_entity.he_headers, "Connection", "close"); |
| 589 | + |
| 590 | + client->cl_entity.he_flags.response = 1; |
| 591 | + client->cl_entity.he_rdata.response.status = 503; |
| 592 | + client->cl_entity.he_rdata.response.status_str = "Service unavailable"; |
| 593 | + client->cl_entity.he_source_type = ENT_SOURCE_BUFFER; |
| 594 | + client->cl_entity.he_source.buffer.addr = client->cl_wrtbuf; |
| 595 | + client->cl_entity.he_source.buffer.len = strlen(client->cl_wrtbuf); |
| 596 | + |
| 597 | + client->cl_entity.he_flags.cachable = 0; |
| 598 | + entity_send(client->cl_fde, &client->cl_entity, client_response_done, client); |
| 599 | +} |
| 600 | + |
| 601 | +static void |
| 602 | +client_log_request(client) |
| 603 | + struct http_client *client; |
| 604 | +{ |
| 605 | +#ifdef THREADED_IO |
| 606 | +static pthread_mutex_t mtx; |
| 607 | +#endif |
| 608 | + |
| 609 | + int i; |
| 610 | + |
| 611 | + if (!config.access_log) |
| 612 | + return; |
| 613 | + |
| 614 | +#ifdef THREADED_IO |
| 615 | + (void)pthread_mutex_lock(&mtx); |
| 616 | +#endif |
| 617 | + i = fprintf(alf, "[%s] %s %s \"%s\" %d %s %s\n", |
| 618 | + current_time_short, client->cl_fde->fde_straddr, |
| 619 | + request_string[client->cl_reqtype], |
| 620 | + client->cl_path, client->cl_entity.he_rdata.response.status, |
| 621 | + client->cl_backend ? client->cl_backend->be_name : "-", |
| 622 | + client->cl_flags.f_cached ? "HIT" : "MISS"); |
| 623 | + if (i < 0) { |
| 624 | + wlog(WLOG_ERROR, "writing logfile: %s", strerror(errno)); |
| 625 | + exit(8); |
| 626 | + } |
| 627 | + |
| 628 | + if (fflush(alf) == EOF) { |
| 629 | + wlog(WLOG_ERROR, "flushing logfile: %s", strerror(errno)); |
| 630 | + exit(8); |
| 631 | + } |
| 632 | +#ifdef THREADED_IO |
| 633 | + (void)pthread_mutex_unlock(&mtx); |
| 634 | +#endif |
| 635 | +} |
| 636 | + |
| 637 | +static void |
| 638 | +do_cache_write(buf, len, data) |
| 639 | + const char *buf; |
| 640 | + size_t len; |
| 641 | + void *data; |
| 642 | +{ |
| 643 | +struct http_client *client = data; |
| 644 | + |
| 645 | + if (write(client->cl_cfd, buf, len) < 0) { |
| 646 | + /*EMPTY*/ |
| 647 | + WDEBUG((WLOG_WARNING, "writing cached data: %s", strerror(errno))); |
| 648 | + } |
| 649 | +} |
| 650 | + |
Property changes on: trunk/willow/src/bin/willow/whttp.c |
___________________________________________________________________ |
Added: svn:keywords |
1 | 651 | + Author Date Id Revision |
Added: svn:eol-style |
2 | 652 | + native |
Index: trunk/willow/src/bin/willow/lexer.l |
— | — | @@ -0,0 +1,66 @@ |
| 2 | +%{ |
| 3 | +/* @(#) $Header$ */ |
| 4 | +/* This source code is in the public domain. */ |
| 5 | +/* |
| 6 | + * Willow: Lightweight HTTP reverse-proxy. |
| 7 | + * lexer: configuration file lexer. |
| 8 | + */ |
| 9 | + |
| 10 | +#if defined __SUNPRO_C || defined __DECC || defined __HP_cc |
| 11 | +# pragma ident "@(#)$Header$" |
| 12 | +#endif |
| 13 | + |
| 14 | +#include <string.h> |
| 15 | +#include <errno.h> |
| 16 | + |
| 17 | +#include "willow.h" |
| 18 | +#include "confparse.h" |
| 19 | +#include "y.tab.h" |
| 20 | + |
| 21 | +int lineno = 1; |
| 22 | + |
| 23 | +int |
| 24 | +yywrap(void) |
| 25 | +{ |
| 26 | + return 1; |
| 27 | +} |
| 28 | +%} |
| 29 | + |
| 30 | +%x COMMENT |
| 31 | + |
| 32 | +ws [ \t]* |
| 33 | +number [0-9][0-9]* |
| 34 | +comment #.* |
| 35 | +qstring \"[^\"\n]*[\"] |
| 36 | +string [a-zA-Z_\~][a-zA-Z0-9_-]* |
| 37 | + |
| 38 | +%% |
| 39 | + |
| 40 | +^[ \t]*"/*" { BEGIN COMMENT; } |
| 41 | +^[ \t]*"/*".*"*/"[ \t]*\n { lineno++; } |
| 42 | + |
| 43 | +<COMMENT>"*/"[ \t]*\n { BEGIN 0; lineno++; break; } |
| 44 | +<COMMENT>"*/" { BEGIN 0; break; } |
| 45 | +<COMMENT>\n { lineno++; break; } |
| 46 | +<COMMENT>.\n { lineno++; break; } |
| 47 | +<COMMENT>. { break; } |
| 48 | +\n { lineno++; } |
| 49 | +{ws} ; |
| 50 | +{comment} ; |
| 51 | +{number} { char *s; |
| 52 | + yylval.number = strtol(yytext, &s, 0); |
| 53 | + if (*s) { |
| 54 | + conf_report_error("invalid number '%s': %s", yytext, strerror(errno)); |
| 55 | + break; |
| 56 | + } |
| 57 | + return NUMBER; |
| 58 | + } |
| 59 | +{string} { yylval.string = wstrdup(yytext); |
| 60 | + return STRING; |
| 61 | + } |
| 62 | +{qstring} { yylval.string = wstrdup(yytext + 1); |
| 63 | + yylval.string[yyleng - 2] = '\0'; |
| 64 | + return QSTRING; |
| 65 | + } |
| 66 | +. { return yytext[0]; |
| 67 | + } |
Property changes on: trunk/willow/src/bin/willow/lexer.l |
___________________________________________________________________ |
Added: svn:keywords |
1 | 68 | + Author Date Id Revision |
Added: svn:eol-style |
2 | 69 | + native |
Index: trunk/willow/src/bin/willow/wcache.c |
— | — | @@ -0,0 +1,466 @@ |
| 2 | +/* @(#) $Header$ */ |
| 3 | +/* This source code is in the public domain. */ |
| 4 | +/* |
| 5 | + * Willow: Lightweight HTTP reverse-proxy. |
| 6 | + * wcache: entity caching. |
| 7 | + */ |
| 8 | + |
| 9 | +#if defined __SUNPRO_C || defined __DECC || defined __HP_cc |
| 10 | +# pragma ident "@(#)$Header$" |
| 11 | +#endif |
| 12 | + |
| 13 | +/* |
| 14 | + * Cache metadata is stored in a BerkeleyDB database, along with a key which |
| 15 | + * represents the filename. The objects themselves are stored on a filesystem, |
| 16 | + * using the key and a path constructed from the key's prefix; for example, |
| 17 | + * the key "123456" would be stored as "1/2/3/123456". |
| 18 | + * |
| 19 | + * This is rather flawed, because if two people try to start caching the same |
| 20 | + * object at the same time, duplicate files are created in the cache, and |
| 21 | + * won't ever be deleted. What should happen is that finding or creating |
| 22 | + * a cached object is a single atomic operation. |
| 23 | + */ |
| 24 | + |
| 25 | +#include <sys/types.h> |
| 26 | +#include <sys/stat.h> |
| 27 | + |
| 28 | +#include <string.h> |
| 29 | +#include <errno.h> |
| 30 | +#include <stdlib.h> |
| 31 | +#include <math.h> |
| 32 | +#include <strings.h> |
| 33 | +#include <limits.h> |
| 34 | +#include <assert.h> |
| 35 | + |
| 36 | +#include <db.h> |
| 37 | + |
| 38 | +#include "wcache.h" |
| 39 | +#include "wlog.h" |
| 40 | +#include "wconfig.h" |
| 41 | +#include "willow.h" |
| 42 | + |
| 43 | +static DB_ENV *cacheenv; |
| 44 | +static DB *cacheobjs; |
| 45 | + |
| 46 | +#define CACHEDIR "__objects__" |
| 47 | + |
| 48 | +static void dberror(const char *, int); |
| 49 | +static void cache_writestate(struct cache_state *, DB_TXN *); |
| 50 | +static int cache_getstate(struct cache_state *, DB_TXN *); |
| 51 | +static int cache_next_id(void); |
| 52 | + |
| 53 | +static struct cache_state state; |
| 54 | +static int int_max_len; |
| 55 | + |
| 56 | +static void dberror(txt, err) |
| 57 | + const char *txt; |
| 58 | + int err; |
| 59 | +{ |
| 60 | + wlog(WLOG_ERROR, "fatal database error: %s: %s", txt, db_strerror(err)); |
| 61 | + wcache_shutdown(); |
| 62 | + exit(8); |
| 63 | +} |
| 64 | + |
| 65 | +void |
| 66 | +wcache_setupfs(void) |
| 67 | +{ |
| 68 | + int i, j, k; |
| 69 | +struct cachedir *cd; |
| 70 | +struct cache_state state; |
| 71 | + DB_TXN *txn; |
| 72 | + |
| 73 | + for (cd = config.caches; cd < config.caches + config.ncaches; ++cd) { |
| 74 | + size_t len, dlen; |
| 75 | + char *dir, *env; |
| 76 | + |
| 77 | + dlen = strlen(cd->dir) + sizeof(CACHEDIR) + 1 + 6 /* 0/1/2/ */; |
| 78 | + if ((dir = wmalloc(dlen)) == NULL) |
| 79 | + outofmemory(); |
| 80 | + |
| 81 | + safe_snprintf(dlen, (dir, dlen, "%s/%s", cd->dir, CACHEDIR)); |
| 82 | + |
| 83 | + len = strlen(cd->dir) + sizeof("/__env__") + 1; |
| 84 | + if ((env = wmalloc(len)) == NULL) |
| 85 | + outofmemory(); |
| 86 | + |
| 87 | + safe_snprintf(len, (env, len, "%s/__env__", cd->dir)); |
| 88 | + |
| 89 | + /* create base directory if it doesn't exist */ |
| 90 | + /*LINTED unsafe mkdir*/ |
| 91 | + if (mkdir(cd->dir, 0700) < 0 || mkdir(dir, 0700) < 0 || mkdir(env, 0700)) { |
| 92 | + wlog(WLOG_ERROR, "%s: mkdir: %s", cd->dir, strerror(errno)); |
| 93 | + exit(8); |
| 94 | + } |
| 95 | + |
| 96 | + for (i = 0; i < 10; ++i) { |
| 97 | + safe_snprintf(dlen, (dir, dlen, "%s/%s/%d", cd->dir, CACHEDIR, i)); |
| 98 | + |
| 99 | + /*LINTED unsafe mkdir*/ |
| 100 | + if (mkdir(dir, 0700) < 0) { |
| 101 | + wlog(WLOG_ERROR, "%s: mkdir: %s", dir, strerror(errno)); |
| 102 | + exit(8); |
| 103 | + } |
| 104 | + |
| 105 | + for (j = 0; j < 10; ++j) { |
| 106 | + safe_snprintf(dlen, (dir, dlen, "%s/%s/%d/%d", cd->dir, CACHEDIR, i, j)); |
| 107 | + /*LINTED unsafe mkdir*/ |
| 108 | + if (mkdir(dir, 0700) < 0) { |
| 109 | + wlog(WLOG_ERROR, "%s: mkdir: %s", dir, strerror(errno)); |
| 110 | + exit(8); |
| 111 | + } |
| 112 | + for (k = 0; k < 10; ++k) { |
| 113 | + safe_snprintf(dlen, (dir, dlen, "%s/%s/%d/%d/%d", cd->dir, CACHEDIR, i, j, k)); |
| 114 | + /*LINTED unsafe mkdir*/ |
| 115 | + if (mkdir(dir, 0700) < 0) { |
| 116 | + wlog(WLOG_ERROR, "%s: mkdir: %s", dir, strerror(errno)); |
| 117 | + exit(8); |
| 118 | + } |
| 119 | + } |
| 120 | + } |
| 121 | + } |
| 122 | + wfree(dir); |
| 123 | + wfree(env); |
| 124 | + wlog(WLOG_NOTICE, "created cache directory structure for %s", cd->dir); |
| 125 | + } |
| 126 | + wcache_init(0); |
| 127 | + |
| 128 | + bzero(&state, sizeof(state)); |
| 129 | + state.cs_id = 1000; |
| 130 | + if (i = cacheenv->txn_begin(cacheenv, NULL, &txn, 0)) |
| 131 | + dberror("setupfs: txn_begin", i); |
| 132 | + |
| 133 | + cache_writestate(&state, txn); |
| 134 | + |
| 135 | + if (i = txn->commit(txn, 0)) |
| 136 | + dberror("setupfs: commit", i); |
| 137 | + |
| 138 | + wlog(WLOG_NOTICE, "wrote initial cache state"); |
| 139 | + wcache_shutdown(); |
| 140 | +} |
| 141 | + |
| 142 | +void |
| 143 | +wcache_shutdown(void) |
| 144 | +{ |
| 145 | + int i; |
| 146 | + |
| 147 | + /* don't use dberror() here because it calls us */ |
| 148 | + /*LINTED =/==*/ |
| 149 | + if ((i = cacheobjs->close(cacheobjs, 0)) || (i = cacheenv->close(cacheenv, 0))) { |
| 150 | + wlog(WLOG_ERROR, "error closing database: %s", db_strerror(i)); |
| 151 | + exit(8); |
| 152 | + } |
| 153 | +} |
| 154 | + |
| 155 | +void |
| 156 | +wcache_init(readstate) |
| 157 | + int readstate; |
| 158 | +{ |
| 159 | +struct cachedir *cd; |
| 160 | + int i; |
| 161 | + DB_TXN *txn; |
| 162 | + |
| 163 | + wlog(WLOG_NOTICE, "using bdb: %s", DB_VERSION_STRING); |
| 164 | + |
| 165 | + if (config.ncaches == 0) { |
| 166 | + wlog(WLOG_WARNING, "no cache directories specified"); |
| 167 | + return; |
| 168 | + } |
| 169 | + |
| 170 | + /* only one cache dir supported for now... */ |
| 171 | + for (cd = config.caches; cd < config.caches + config.ncaches; ++cd) { |
| 172 | + size_t len; |
| 173 | + char *dir; |
| 174 | + |
| 175 | + len = strlen(cd->dir) + sizeof("/__env__"); |
| 176 | + if ((dir = wmalloc(len)) == NULL) |
| 177 | + outofmemory(); |
| 178 | + |
| 179 | + safe_snprintf(len, (dir, len, "%s/__env__", cd->dir)); |
| 180 | + |
| 181 | + if (i = db_env_create(&cacheenv, 0)) |
| 182 | + dberror("init: env_create", i); |
| 183 | + |
| 184 | + cacheenv->set_errfile(cacheenv, stderr); |
| 185 | + cacheenv->set_errpfx(cacheenv, "willow"); |
| 186 | + |
| 187 | + if (i = cacheenv->open(cacheenv, dir, DB_CREATE | DB_INIT_TXN | DB_INIT_LOCK | |
| 188 | + DB_INIT_MPOOL | DB_PRIVATE |
| 189 | +#ifdef THREADED_IO |
| 190 | + | DB_THREAD |
| 191 | +#endif |
| 192 | + , 0)) |
| 193 | + dberror("init: env open", i); |
| 194 | + |
| 195 | + if (i = db_create(&cacheobjs, cacheenv, 0)) |
| 196 | + dberror("init: db_create", i); |
| 197 | + |
| 198 | + if (i = cacheenv->txn_begin(cacheenv, NULL, &txn, 0)) |
| 199 | + dberror("init: open txn_begin", i); |
| 200 | + |
| 201 | + if (i = cacheobjs->open(cacheobjs, txn, "cacheobjs.db", NULL, DB_HASH, |
| 202 | + DB_CREATE, 0600)) |
| 203 | + dberror("init: db open", i); |
| 204 | + |
| 205 | + if (i = txn->commit(txn, 0)) |
| 206 | + dberror("init: open commit", i); |
| 207 | + |
| 208 | + wfree(dir); |
| 209 | + } |
| 210 | + |
| 211 | + if (readstate) { |
| 212 | + if (i = cacheenv->txn_begin(cacheenv, NULL, &txn, 0)) |
| 213 | + dberror("init: state txn_begin", i); |
| 214 | + if (cache_getstate(&state, txn) == -1) { |
| 215 | + wlog(WLOG_ERROR, "cache state unavailable"); |
| 216 | + exit(8); |
| 217 | + } |
| 218 | + if (i = txn->commit(txn, 0)) |
| 219 | + dberror("init: state commit", i); |
| 220 | + } |
| 221 | + |
| 222 | + int_max_len = log10(INT_MAX) + 1; |
| 223 | +} |
| 224 | + |
| 225 | +static char * |
| 226 | +make_keybuf(key) |
| 227 | + struct cache_key *key; |
| 228 | +{ |
| 229 | + char *buf; |
| 230 | + |
| 231 | + if ((buf = wmalloc(key->ck_len + 1)) == NULL) |
| 232 | + outofmemory(); |
| 233 | + bcopy(key->ck_key, buf, key->ck_len + 1); |
| 234 | + return buf; |
| 235 | +} |
| 236 | + |
| 237 | +static char * |
| 238 | +make_databuf(obj) |
| 239 | + struct cache_object *obj; |
| 240 | +{ |
| 241 | + char *buf; |
| 242 | + |
| 243 | + if ((buf = wmalloc(sizeof(struct cache_object) + obj->co_plen + 1)) == NULL) |
| 244 | + outofmemory(); |
| 245 | + |
| 246 | + bcopy(obj, buf, sizeof(struct cache_object)); |
| 247 | + bcopy(obj->co_path, buf + sizeof(struct cache_object), obj->co_plen + 1); |
| 248 | + return buf; |
| 249 | +} |
| 250 | + |
| 251 | +struct cache_object * |
| 252 | +wcache_find_object(key) |
| 253 | + struct cache_key *key; |
| 254 | +{ |
| 255 | + DBT keyt, datat; |
| 256 | + DB_TXN *txn; |
| 257 | +struct cache_object *data; |
| 258 | + int i, j; |
| 259 | + char *keybuf; |
| 260 | + |
| 261 | + WDEBUG((WLOG_DEBUG, "wcache_find_object: looking for %s %d", key->ck_key, key->ck_len)); |
| 262 | + if (cacheobjs == NULL) |
| 263 | + return NULL; |
| 264 | + |
| 265 | + keybuf = make_keybuf(key); |
| 266 | + |
| 267 | + bzero(&keyt, sizeof(keyt)); |
| 268 | + bzero(&datat, sizeof(datat)); |
| 269 | + |
| 270 | + keyt.data = keybuf; |
| 271 | + keyt.size = key->ck_len + 1; |
| 272 | + |
| 273 | + datat.flags = DB_DBT_MALLOC; |
| 274 | + |
| 275 | + if (i = cacheenv->txn_begin(cacheenv, NULL, &txn, 0)) |
| 276 | + dberror("find_object: txn_begin", i); |
| 277 | + |
| 278 | + if (i = cacheobjs->get(cacheobjs, txn, &keyt, &datat, 0)) { |
| 279 | + wfree(keybuf); |
| 280 | + if (j = txn->abort(txn)) |
| 281 | + dberror("find_object: abort", j); |
| 282 | + if (i != DB_NOTFOUND) |
| 283 | + dberror("find_object: get", i); |
| 284 | + return NULL; |
| 285 | + } |
| 286 | + if (i = txn->commit(txn, 0)) |
| 287 | + dberror("find_object: commit", i); |
| 288 | + |
| 289 | + wfree(keybuf); |
| 290 | + |
| 291 | + data = datat.data; |
| 292 | + data->co_path = (char *)data + sizeof(*data); |
| 293 | + WDEBUG((WLOG_DEBUG, "found %s, path=[%s]", key->ck_key, data->co_path)); |
| 294 | + data->co_flags &= ~WCACHE_FREE; |
| 295 | + return data; |
| 296 | +} |
| 297 | + |
| 298 | +int |
| 299 | +wcache_store_object(key, obj) |
| 300 | + struct cache_key *key; |
| 301 | + struct cache_object *obj; |
| 302 | +{ |
| 303 | + DBT keyt, datat; |
| 304 | + DB_TXN *txn; |
| 305 | + char *keybuf; |
| 306 | + int i, ret = 0; |
| 307 | + |
| 308 | + WDEBUG((WLOG_DEBUG, "storing %s %d in cache, path %s", key->ck_key, key->ck_len, obj->co_path)); |
| 309 | + |
| 310 | + bzero(&keyt, sizeof(keyt)); |
| 311 | + bzero(&datat, sizeof(datat)); |
| 312 | + keybuf = make_keybuf(key); |
| 313 | + |
| 314 | + keyt.data = keybuf; |
| 315 | + keyt.size = key->ck_len + 1; |
| 316 | + |
| 317 | + datat.data = make_databuf(obj); |
| 318 | + datat.size = sizeof(struct cache_object) + obj->co_plen + 1; |
| 319 | + |
| 320 | + if (i = cacheenv->txn_begin(cacheenv, NULL, &txn, 0)) |
| 321 | + dberror("store_object: txn_begin", i); |
| 322 | + if (cacheobjs->put(cacheobjs, txn, &keyt, &datat, DB_NOOVERWRITE)) |
| 323 | + ret = -1; |
| 324 | + if (i = txn->commit(txn, 0)) |
| 325 | + dberror("store_object: commit", i); |
| 326 | + |
| 327 | + wfree(keybuf); |
| 328 | + wfree(datat.data); |
| 329 | + |
| 330 | + return ret; |
| 331 | +} |
| 332 | + |
| 333 | +struct cache_key * |
| 334 | +wcache_make_key(host, path) |
| 335 | + const char *host, *path; |
| 336 | +{ |
| 337 | +struct cache_key *ret; |
| 338 | + |
| 339 | + if ((ret = wmalloc(sizeof(*ret))) == NULL) |
| 340 | + outofmemory(); |
| 341 | + |
| 342 | + ret->ck_len = strlen(host) + strlen(path); |
| 343 | + ret->ck_key = wmalloc(ret->ck_len + 1); |
| 344 | + safe_snprintf(ret->ck_len, (ret->ck_key, ret->ck_len, "%s%s", host, path)); |
| 345 | + return ret; |
| 346 | +} |
| 347 | + |
| 348 | +void |
| 349 | +wcache_free_key(key) |
| 350 | + struct cache_key *key; |
| 351 | +{ |
| 352 | + wfree(key->ck_key); |
| 353 | + wfree(key); |
| 354 | +} |
| 355 | + |
| 356 | +void |
| 357 | +wcache_free_object(obj) |
| 358 | + struct cache_object *obj; |
| 359 | +{ |
| 360 | + if (obj->co_flags & WCACHE_FREE) { |
| 361 | + wfree(obj->co_path); |
| 362 | + wfree(obj); |
| 363 | + } else { |
| 364 | + free(obj); |
| 365 | + } |
| 366 | +} |
| 367 | + |
| 368 | +static void |
| 369 | +cache_writestate(state, txn) |
| 370 | + struct cache_state *state; |
| 371 | + DB_TXN *txn; |
| 372 | +{ |
| 373 | + DBT keyt, datat; |
| 374 | + int i; |
| 375 | + |
| 376 | + WDEBUG((WLOG_DEBUG, "writing cache state")); |
| 377 | + |
| 378 | + bzero(&keyt, sizeof(keyt)); |
| 379 | + bzero(&datat, sizeof(datat)); |
| 380 | + |
| 381 | + keyt.size = 5; |
| 382 | + keyt.data = "STATE"; |
| 383 | + |
| 384 | + datat.size = sizeof(*state); |
| 385 | + datat.data = state; |
| 386 | + |
| 387 | + if (i = cacheobjs->put(cacheobjs, txn, &keyt, &datat, 0)) |
| 388 | + dberror("writestate: put", i); |
| 389 | +} |
| 390 | + |
| 391 | +static int |
| 392 | +cache_getstate(state, txn) |
| 393 | + struct cache_state *state; |
| 394 | + DB_TXN *txn; |
| 395 | +{ |
| 396 | + DBT keyt, datat; |
| 397 | + int i; |
| 398 | + |
| 399 | + WDEBUG((WLOG_DEBUG, "reading cache state")); |
| 400 | + |
| 401 | + bzero(&keyt, sizeof(keyt)); |
| 402 | + bzero(&datat, sizeof(datat)); |
| 403 | + |
| 404 | + keyt.size = 5; |
| 405 | + keyt.data = "STATE"; |
| 406 | + |
| 407 | + datat.ulen = sizeof(*state); |
| 408 | + datat.data = state; |
| 409 | + datat.flags = DB_DBT_USERMEM; |
| 410 | + |
| 411 | + if (i = cacheobjs->get(cacheobjs, txn, &keyt, &datat, 0)) |
| 412 | + dberror("getstate: get", i); |
| 413 | + |
| 414 | + WDEBUG((WLOG_DEBUG, "cs_id = %d", state->cs_id)); |
| 415 | + return 0; |
| 416 | +} |
| 417 | + |
| 418 | +static int |
| 419 | +cache_next_id(void) |
| 420 | +{ |
| 421 | + DB_TXN *txn; |
| 422 | + int i; |
| 423 | + |
| 424 | + if (i = cacheenv->txn_begin(cacheenv, NULL, &txn, 0)) |
| 425 | + dberror("next_id: txn_begin", i); |
| 426 | + |
| 427 | + state.cs_id++; |
| 428 | + cache_writestate(&state, txn); |
| 429 | + |
| 430 | + if (i = txn->commit(txn, 0)) |
| 431 | + dberror("next_id: commit", i); |
| 432 | + |
| 433 | + return state.cs_id; |
| 434 | +} |
| 435 | + |
| 436 | +struct cache_object * |
| 437 | +wcache_new_object(void) |
| 438 | +{ |
| 439 | +struct cache_object *ret; |
| 440 | + int i; |
| 441 | + char *p, *s, a[11]; |
| 442 | + |
| 443 | + if ((ret = wcalloc(1, sizeof(*ret))) == NULL) |
| 444 | + outofmemory(); |
| 445 | + |
| 446 | + ret->co_id = cache_next_id(); |
| 447 | + |
| 448 | + assert(ret->co_id > 999); |
| 449 | + ret->co_plen = int_max_len + 6; |
| 450 | + if ((ret->co_path = wmalloc(ret->co_plen + 1)) == NULL) |
| 451 | + outofmemory(); |
| 452 | + p = ret->co_path; |
| 453 | + safe_snprintf(10, (a, 10, "%d", ret->co_id)); |
| 454 | + s = a + strlen(a) - 1; |
| 455 | + WDEBUG((WLOG_DEBUG, "id=%d a=%s", ret->co_id, a)); |
| 456 | + |
| 457 | + for (i = 0; i < 3; ++i) { |
| 458 | + *p++ = *s--; |
| 459 | + *p++ = '/'; |
| 460 | + } |
| 461 | + *p = '\0'; |
| 462 | + if (strlcat(ret->co_path, a, ret->co_plen + 1) >= ret->co_plen + 1) |
| 463 | + abort(); |
| 464 | + ret->co_flags |= WCACHE_FREE; |
| 465 | + WDEBUG((WLOG_DEBUG, "new object path is [%s], len %d", ret->co_path, ret->co_plen)); |
| 466 | + return ret; |
| 467 | +} |
Property changes on: trunk/willow/src/bin/willow/wcache.c |
___________________________________________________________________ |
Added: svn:keywords |
1 | 468 | + Author Date Id Revision |
Added: svn:eol-style |
2 | 469 | + native |
Index: trunk/willow/src/Makefile.in |
— | — | @@ -1,30 +1,10 @@ |
2 | | -PROGRAM = willow |
| 2 | +# @(#) $Header$ |
| 3 | +# |
| 4 | +# src/ makefile. |
3 | 5 | |
4 | | -selectsrc=wnet_@SELECTTYPE@.c |
| 6 | +SUBDIRS=lib bin |
5 | 7 | |
6 | | -CPPFLAGS = -DDATADIR=\"$(_DATADIR)\" |
7 | | -BASESRCS = willow.c wlog.c wconfig.c wnet.c whttp.c wbackend.c wlogwriter.c \ |
8 | | - whttp_entity.c wcache.c confparse.c ${selectsrc} |
9 | | -#GENSRCS=y.tab.c lex.yy.c |
10 | | -SRCS=$(BASESRCS) |
11 | | -OBJADD = @LIBOBJS@ y.tab.o lex.yy.o |
| 8 | +@include@ @q@@top_srcdir@/mk/subdir.mk@q@ |
12 | 9 | |
13 | | -EXTRA_DIST=wnet_poll.c wnet_ports.c wnet_kqueue.c wnet_epoll.c wnet_devpoll.c \ |
14 | | - wlog.h wconfig.h wnet.h whttp.h wbackend.h willow.h confparse.h \ |
15 | | - wcache.h wlogwriter.h whttp_entity.h queue.h lexer.l parser.y \ |
16 | | - daemon.c \ |
17 | | - Makefile.in |
18 | | - |
19 | | -LDFLAGS = $(LIBOBJS) |
20 | | - |
21 | | -y.tab.o: y.tab.c |
22 | | -lex.yy.o: lex.yy.c y.tab.h |
23 | | - |
24 | | -y.tab.c y.tab.h: parser.y |
25 | | - @echo " $(_YACC) -d parser.y" |
26 | | - @$(_YACC) -d parser.y |
27 | | -lex.yy.c: lexer.l y.tab.h |
28 | | - @echo " $(_LEX) lexer.l" |
29 | | - @$(_LEX) lexer.l || rm -f lex.yy.c |
30 | | - |
31 | | -@include@ @q@@top_srcdir@/mk/prog.mk@q@ |
| 10 | +DISTFILES=\ |
| 11 | + Makefile.in |
Index: trunk/willow/svr4/proto.suffix |
— | — | @@ -0,0 +1,2 @@ |
| 2 | +i copyright |
| 3 | +i pkginfo |
Property changes on: trunk/willow/svr4/proto.suffix |
___________________________________________________________________ |
Added: svn:keywords |
1 | 4 | + Author Date Id Revision |
Added: svn:eol-style |
2 | 5 | + native |
Index: trunk/willow/svr4/pkginfo |
— | — | @@ -0,0 +1,6 @@ |
| 2 | +PKG=WMFwillow |
| 3 | +ARCH=i86pc |
| 4 | +VERSION=1.0-cvs |
| 5 | +NAME=Lightweight HTTP reverse-proxy |
| 6 | +CATEGORY=application |
| 7 | +BASEDIR=/ |
Property changes on: trunk/willow/svr4/pkginfo |
___________________________________________________________________ |
Added: svn:keywords |
1 | 8 | + Author Date Id Revision |
Added: svn:eol-style |
2 | 9 | + native |