r8811 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r8810‎ | r8811 | r8812 >
Date:19:15, 2 May 2005
Author:kateturner
Status:old
Tags:
Comment:
source code reorganisation.
add 'make svr4-package' command to make svr4 packages
split some things into libraries (unfinished)
Modified paths:
  • /trunk/willow/Makefile.in (modified) (history)
  • /trunk/willow/configure.in (modified) (history)
  • /trunk/willow/mk/prog.mk.in (modified) (history)
  • /trunk/willow/mk/subdir.mk.in (modified) (history)
  • /trunk/willow/mk/vars.mk.in (modified) (history)
  • /trunk/willow/src/Makefile.in (modified) (history)
  • /trunk/willow/src/bin (added) (history)
  • /trunk/willow/src/bin/Makefile.in (added) (history)
  • /trunk/willow/src/bin/willow (added) (history)
  • /trunk/willow/src/bin/willow/Makefile.in (added) (history)
  • /trunk/willow/src/bin/willow/confparse.c (added) (history)
  • /trunk/willow/src/bin/willow/daemon.c (added) (history)
  • /trunk/willow/src/bin/willow/lexer.l (added) (history)
  • /trunk/willow/src/bin/willow/parser.y (added) (history)
  • /trunk/willow/src/bin/willow/strlcat.c (added) (history)
  • /trunk/willow/src/bin/willow/strlcpy.c (added) (history)
  • /trunk/willow/src/bin/willow/wbackend.c (added) (history)
  • /trunk/willow/src/bin/willow/wcache.c (added) (history)
  • /trunk/willow/src/bin/willow/wconfig.c (added) (history)
  • /trunk/willow/src/bin/willow/whttp.c (added) (history)
  • /trunk/willow/src/bin/willow/whttp_entity.c (added) (history)
  • /trunk/willow/src/bin/willow/willow.c (added) (history)
  • /trunk/willow/src/bin/willow/wlogwriter.c (added) (history)
  • /trunk/willow/src/confparse.c (deleted) (history)
  • /trunk/willow/src/confparse.h (deleted) (history)
  • /trunk/willow/src/daemon.c (deleted) (history)
  • /trunk/willow/src/include (added) (history)
  • /trunk/willow/src/include/confparse.h (added) (history)
  • /trunk/willow/src/include/queue.h (added) (history)
  • /trunk/willow/src/include/wbackend.h (added) (history)
  • /trunk/willow/src/include/wcache.h (added) (history)
  • /trunk/willow/src/include/wconfig.h (added) (history)
  • /trunk/willow/src/include/whttp.h (added) (history)
  • /trunk/willow/src/include/whttp_entity.h (added) (history)
  • /trunk/willow/src/include/willow.h (added) (history)
  • /trunk/willow/src/include/wlog.h (added) (history)
  • /trunk/willow/src/include/wlogwriter.h (added) (history)
  • /trunk/willow/src/include/wnet.h (added) (history)
  • /trunk/willow/src/lexer.l (deleted) (history)
  • /trunk/willow/src/lib (added) (history)
  • /trunk/willow/src/lib/Makefile.in (added) (history)
  • /trunk/willow/src/lib/wlog (added) (history)
  • /trunk/willow/src/lib/wlog/Makefile.in (added) (history)
  • /trunk/willow/src/lib/wlog/wlog.c (added) (history)
  • /trunk/willow/src/lib/wnet (added) (history)
  • /trunk/willow/src/lib/wnet/Makefile.in (added) (history)
  • /trunk/willow/src/lib/wnet/wnet.c (added) (history)
  • /trunk/willow/src/lib/wnet/wnet_devpoll.c (added) (history)
  • /trunk/willow/src/lib/wnet/wnet_epoll.c (added) (history)
  • /trunk/willow/src/lib/wnet/wnet_kqueue.c (added) (history)
  • /trunk/willow/src/lib/wnet/wnet_poll.c (added) (history)
  • /trunk/willow/src/lib/wnet/wnet_ports.c (added) (history)
  • /trunk/willow/src/parser.y (deleted) (history)
  • /trunk/willow/src/queue.h (deleted) (history)
  • /trunk/willow/src/strlcat.c (deleted) (history)
  • /trunk/willow/src/strlcpy.c (deleted) (history)
  • /trunk/willow/src/wbackend.c (deleted) (history)
  • /trunk/willow/src/wbackend.h (deleted) (history)
  • /trunk/willow/src/wcache.c (deleted) (history)
  • /trunk/willow/src/wcache.h (deleted) (history)
  • /trunk/willow/src/wconfig.c (deleted) (history)
  • /trunk/willow/src/wconfig.h (deleted) (history)
  • /trunk/willow/src/whttp.c (deleted) (history)
  • /trunk/willow/src/whttp_entity.c (deleted) (history)
  • /trunk/willow/src/whttp_entity.h (deleted) (history)
  • /trunk/willow/src/willow.c (deleted) (history)
  • /trunk/willow/src/willow.h (deleted) (history)
  • /trunk/willow/src/wlog.c (deleted) (history)
  • /trunk/willow/src/wlog.h (deleted) (history)
  • /trunk/willow/src/wlogwriter.h (deleted) (history)
  • /trunk/willow/src/wnet.c (deleted) (history)
  • /trunk/willow/src/wnet.h (deleted) (history)
  • /trunk/willow/src/wnet_devpoll.c (deleted) (history)
  • /trunk/willow/src/wnet_epoll.c (deleted) (history)
  • /trunk/willow/src/wnet_kqueue.c (deleted) (history)
  • /trunk/willow/src/wnet_poll.c (deleted) (history)
  • /trunk/willow/src/wnet_ports.c (deleted) (history)
  • /trunk/willow/svr4 (added) (history)
  • /trunk/willow/svr4/pkginfo (added) (history)
  • /trunk/willow/svr4/proto.suffix (added) (history)

Diff [purge]

Index: trunk/willow/Makefile.in
@@ -7,6 +7,7 @@
88 SUBDIRS=src errors mk
99
1010 @include@ @q@@top_srcdir@/mk/subdir.mk@q@
 11+@include@ @q@@top_srcdir@/mk/vars.mk@q@
1112
1213 DISTFILES=\
1314 Makefile.in \
@@ -22,3 +23,16 @@
2324 tar cf $(DISTNAME).tar $(DISTNAME)
2425 compress $(DISTNAME).tar
2526 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 @@
309309
310310 AC_OUTPUT(
311311 mk/prog.mk
 312+ mk/lib.mk
312313 mk/vars.mk
313314 mk/rules.mk
314315 mk/data.mk
@@ -318,6 +319,11 @@
319320 mk/Makefile
320321 Makefile
321322 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
322328 errors/Makefile)
323329
324330 if test x$epoll_in_kernel = xno; then
Index: trunk/willow/mk/prog.mk.in
@@ -2,8 +2,8 @@
33 #
44 # Build a program.
55
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@
88
99 default: all
1010
@@ -39,4 +39,4 @@
4040 _MYDISTFILES=$(SRCS) $(EXTRA_DIST)
4141 _extradist:
4242
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 @@
1212
1313 all install lint clean depend _extradist:
1414 @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" ;\
1818 cd .. ;\
1919 done
2020
Index: trunk/willow/mk/vars.mk.in
@@ -1,6 +1,9 @@
22 # @(#) $Header$
33 #
44 # Standard variables.
 5+#
 6+# Warning! don't use top_srcdir in this file, use abs_top_srcdir (or, better,
 7+# use $(SRCROOT).)
58
69 PACKAGE= willow
710 VERSION= @VERSION@
@@ -9,19 +12,28 @@
1013 _YACC= @YACC@
1114
1215 CC= @CC@
13 -_CPPFLAGS= -I@top_srcdir@ -I. @CPPFLAGS@
 16+_CPPFLAGS= -I@abs_top_srcdir@ -I. -I@abs_top_srcdir@/src/include @CPPFLAGS@
1417 _CFLAGS= @CFLAGS@
1518 _LDFLAGS= @LDFLAGS@ @LIBS@
1619
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@
2421
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
2727
 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+
2840 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(&current_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
1137 + Author Date Id Revision
Added: svn:eol-style
2138 + 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
1519 + Author Date Id Revision
Added: svn:eol-style
2520 + 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
119 + Author Date Id Revision
Added: svn:eol-style
220 + 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
130 + Author Date Id Revision
Added: svn:eol-style
231 + 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
144 + Author Date Id Revision
Added: svn:eol-style
245 + 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
153 + Author Date Id Revision
Added: svn:eol-style
254 + 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
146 + Author Date Id Revision
Added: svn:eol-style
247 + 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
159 + Author Date Id Revision
Added: svn:eol-style
260 + 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
1126 + Author Date Id Revision
Added: svn:eol-style
2127 + 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
139 + Author Date Id Revision
Added: svn:eol-style
240 + 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
180 + Author Date Id Revision
Added: svn:eol-style
281 + 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
115 + Author Date Id Revision
Added: svn:eol-style
216 + 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
1130 + Author Date Id Revision
Added: svn:eol-style
2131 + 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
1115 + Author Date Id Revision
Added: svn:eol-style
2116 + 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
1247 + Author Date Id Revision
Added: svn:eol-style
2248 + 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
1138 + Author Date Id Revision
Added: svn:eol-style
2139 + 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
1145 + Author Date Id Revision
Added: svn:eol-style
2146 + 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(&current_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
1439 + Author Date Id Revision
Added: svn:eol-style
2440 + 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
112 + Author Date Id Revision
Added: svn:eol-style
213 + 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
112 + Author Date Id Revision
Added: svn:eol-style
213 + 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
1118 + Author Date Id Revision
Added: svn:eol-style
2119 + 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
112 + Author Date Id Revision
Added: svn:eol-style
213 + 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
167 + Author Date Id Revision
Added: svn:eol-style
268 + 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
1130 + Author Date Id Revision
Added: svn:eol-style
2131 + 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
1408 + Author Date Id Revision
Added: svn:eol-style
2409 + 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
1166 + Author Date Id Revision
Added: svn:eol-style
2167 + 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
1460 + Author Date Id Revision
Added: svn:eol-style
2461 + 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
163 + Author Date Id Revision
Added: svn:eol-style
264 + 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
131 + Author Date Id Revision
Added: svn:eol-style
232 + 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
1319 + Author Date Id Revision
Added: svn:eol-style
2320 + 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
1793 + Author Date Id Revision
Added: svn:eol-style
2794 + 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
173 + Author Date Id Revision
Added: svn:eol-style
274 + 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
185 + Author Date Id Revision
Added: svn:eol-style
286 + 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
1651 + Author Date Id Revision
Added: svn:eol-style
2652 + 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
168 + Author Date Id Revision
Added: svn:eol-style
269 + 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
1468 + Author Date Id Revision
Added: svn:eol-style
2469 + native
Index: trunk/willow/src/Makefile.in
@@ -1,30 +1,10 @@
2 -PROGRAM = willow
 2+# @(#) $Header$
 3+#
 4+# src/ makefile.
35
4 -selectsrc=wnet_@SELECTTYPE@.c
 6+SUBDIRS=lib bin
57
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@
129
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
14 + Author Date Id Revision
Added: svn:eol-style
25 + 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
18 + Author Date Id Revision
Added: svn:eol-style
29 + native

Status & tagging log