--- /dev/null
+# $Id$
+
+bin_PROGRAMS = varnish
+
+varnish_SOURCES = \
+ connection.c \
+ listener.c \
+ log.c \
+ request.c \
+ varnish.c
--- /dev/null
+#!/bin/sh
+#
+# $Id$
+#
+
+aclocal
+autoheader
+automake --add-missing --copy --force --foreign
+autoconf
--- /dev/null
+# $Id$
+
+AC_PREREQ(2.59)
+AC_COPYRIGHT([Copyright (c) 2006 Linpro AS])
+AC_REVISION([$Id$])
+AC_INIT([Varnish], [0.1], [varnish-dev@projects.linpro.no])
+AC_CONFIG_SRCDIR([varnish.c])
+AC_CONFIG_HEADER([config.h])
+
+AC_CANONICAL_SYSTEM
+AC_LANG(C)
+
+AM_INIT_AUTOMAKE(AC_PACKAGE_NAME, AC_PACKAGE_VERSION)
+
+# Compiler flags (assume GCC).
+# This section *must* come before AC_PROG_CC / AC_PROG_CPP.
+CFLAGS="${CFLAGS:--O2}"
+AC_ARG_ENABLE(wall,
+ AS_HELP_STRING([--enable-wall],[use -Wall (default is NO)]),
+ CFLAGS="${CFLAGS} -Wall")
+AC_ARG_ENABLE(pedantic,
+ AS_HELP_STRING([--enable-pedantic],[enable pedantic warnings (default is NO)]),
+ CFLAGS="${CFLAGS} -pedantic")
+AC_ARG_ENABLE(werror,
+ AS_HELP_STRING([--enable-werror],[use -Werror (default is NO)]),
+ CFLAGS="${CFLAGS} -Werror")
+
+# Checks for programs.
+AC_PROG_CC
+AC_PROG_CPP
+AC_PROG_INSTALL
+AC_PROG_MAKE_SET
+
+# Checks for libraries.
+
+# Checks for header files.
+AC_HEADER_STDC
+AC_CHECK_HEADERS([sys/socket.h])
+AC_CHECK_HEADERS([netinet/in.h])
+AC_CHECK_HEADERS([stddef.h])
+AC_CHECK_HEADERS([stdlib.h])
+AC_CHECK_HEADERS([unistd.h])
+
+# Checks for typedefs, structures, and compiler characteristics.
+AC_C_CONST
+AC_CHECK_MEMBERS([struct sockaddr.sa_len],,,[
+#include <sys/types.h>
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+])
+
+# Checks for library functions.
+AC_TYPE_SIGNAL
+AC_TYPE_SIZE_T
+AC_FUNC_VPRINTF
+AC_CHECK_FUNCS([strerror])
+AC_FUNC_STRERROR_R
+AC_CHECK_FUNCS([socket])
+
+AC_CONFIG_FILES([
+ Makefile
+])
+AC_OUTPUT
--- /dev/null
+/*
+ * $Id$
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "varnish.h"
+#include "connection.h"
+
+void
+connection_destroy(struct connection *c)
+{
+ close(c->sd);
+ /* bzero(c, sizeof *c); */
+ free(c);
+}
--- /dev/null
+/*
+ * $Id$
+ */
+
+#ifndef CONNECTION_H_INCLUDED
+#define CONNECTION_H_INCLUDED
+
+struct connection {
+ int sd;
+ struct sockaddr_storage addr;
+};
+
+#endif
--- /dev/null
+/*
+ * $Id$
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+
+#include <errno.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "varnish.h"
+#include "listener.h"
+#include "connection.h"
+
+/*
+ * Create a socket that listens on the specified port. We use an IPv6 TCP
+ * socket and clear the IPV6_V6ONLY option to accept IPv4 connections on
+ * the same socket.
+ */
+struct listener *
+listener_create(int port)
+{
+ struct listener *l;
+ socklen_t addr_len;
+ int zero = 0;
+
+ l = calloc(1, sizeof *l);
+ if (l == NULL) {
+ log_syserr("calloc()");
+ return (NULL);
+ }
+ l->sd = -1;
+#if defined(AF_INET6) && defined(IPV6_V6ONLY)
+ if ((l->sd = socket(AF_INET6, SOCK_STREAM, 0)) > 0) {
+ struct sockaddr_in6 *addr = (struct sockaddr_in6 *)&l->addr;
+#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
+ addr->sin6_len =
+#endif
+ addr_len = sizeof *addr;
+ addr->sin6_family = AF_INET6;
+ addr->sin6_port = htons(port);
+ if (setsockopt(l->sd, IPPROTO_IPV6, IPV6_V6ONLY, &zero, sizeof zero) != 0) {
+ log_syserr("setsockopt()");
+ return (NULL);
+ }
+ } else if (errno != EPROTONOSUPPORT) {
+ log_syserr("socket()");
+ return (NULL);
+ } else
+#endif
+ if ((l->sd = socket(AF_INET, SOCK_STREAM, 0)) > 0) {
+ struct sockaddr_in *addr = (struct sockaddr_in *)&l->addr;
+#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
+ addr->sin_len =
+#endif
+ addr_len = sizeof *addr;
+ addr->sin_family = AF_INET;
+ addr->sin_port = htons(port);
+ } else {
+ log_syserr("socket()");
+ return (NULL);
+ }
+ if (bind(l->sd, (struct sockaddr *)&l->addr, addr_len) != 0) {
+ log_syserr("bind()");
+ return (NULL);
+ }
+ if (listen(l->sd, 16) != 0) {
+ log_syserr("listen()");
+ return (NULL);
+ }
+ return (l);
+}
+
+void
+listener_destroy(struct listener *l)
+{
+ close(l->sd);
+ /* bzero(l, sizeof *l); */
+ free(l);
+}
+
+struct connection *
+listener_accept(struct listener *l)
+{
+ struct connection *c;
+ socklen_t len;
+
+ c = calloc(1, sizeof *c);
+ for (;;) {
+ len = sizeof c->addr;
+ c->sd = accept(l->sd, (struct sockaddr *)&c->addr, &len);
+ if (c->sd != -1) {
+ switch (c->addr.ss_family) {
+#if defined(AF_INET6)
+ case AF_INET6: {
+ struct sockaddr_in6 *addr =
+ (struct sockaddr_in6 *)&c->addr;
+ uint16_t *ip = (uint16_t *)&addr->sin6_addr;
+
+ log_info("%s(): [%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x]:%u",
+ __func__,
+ ntohs(ip[0]), ntohs(ip[1]),
+ ntohs(ip[2]), ntohs(ip[3]),
+ ntohs(ip[4]), ntohs(ip[5]),
+ ntohs(ip[6]), ntohs(ip[7]),
+ ntohs(addr->sin6_port));
+ break;
+ }
+#endif
+ case AF_INET: {
+ struct sockaddr_in *addr =
+ (struct sockaddr_in *)&c->addr;
+ uint8_t *ip = (uint8_t *)&addr->sin_addr;
+
+ log_info("%s(): %u.%u.%u.%u:%u",
+ __func__,
+ ip[0], ip[1], ip[2], ip[3],
+ ntohs(addr->sin_port));
+ break;
+ }
+ default:
+ LOG_UNREACHABLE();
+ }
+ return (c);
+ }
+ if (errno != EINTR) {
+ log_syserr("accept()");
+ free(c);
+ return (NULL);
+ }
+ }
+}
--- /dev/null
+/*
+ * $Id$
+ */
+
+#ifndef LISTENER_H_INCLUDED
+#define LISTENER_H_INCLUDED
+
+struct listener {
+ int sd;
+ struct sockaddr_storage addr;
+};
+
+#endif
--- /dev/null
+/*
+ * $Id$
+ */
+
+#include <sys/signal.h>
+
+#include <errno.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "varnish.h"
+
+static void
+emit(const char *fmt, va_list ap)
+{
+ vfprintf(stderr, fmt, ap);
+ fprintf(stderr, "\n");
+}
+
+static void
+sysemit(const char *fmt, va_list ap)
+{
+ char errstr[64];
+
+#if defined(HAVE_STRERROR_R)
+ strerror_r(errno, errstr, sizeof errstr);
+#else
+ snprintf(errstr, sizeof errstr, "%s", strerror(errno));
+#endif
+ vfprintf(stderr, fmt, ap);
+ fprintf(stderr, ": %s\n", errstr);
+}
+
+static void
+panic(void)
+{
+ signal(SIGABRT, SIG_DFL);
+ kill(getpid(), SIGABRT);
+}
+
+void
+log_info(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ emit(fmt, ap);
+ va_end(ap);
+}
+
+void
+log_err(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ emit(fmt, ap);
+ va_end(ap);
+}
+
+void
+log_syserr(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ sysemit(fmt, ap);
+ va_end(ap);
+}
+
+void
+log_panic(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ emit(fmt, ap);
+ va_end(ap);
+ panic();
+}
+
+void
+log_syspanic(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ sysemit(fmt, ap);
+ va_end(ap);
+ panic();
+}
--- /dev/null
+/*
+ * $Id$
+ */
+
+#include <stdlib.h>
+
+#include "varnish.h"
+#include "request.h"
+
+request_t *
+request_wait(connection_t *c, unsigned int timeout)
+{
+ request_t *r;
+
+ r = calloc(1, sizeof *r);
+ if (r == NULL) {
+ log_syserr("calloc()");
+ return (NULL);
+ }
+
+ /* ... */
+
+ return (r);
+}
+
+void
+request_destroy(request_t *r)
+{
+ /* bzero(r, sizeof *r); */
+ free(r);
+}
--- /dev/null
+/*
+ * $Id$
+ */
+
+#ifndef REQUEST_H_INCLUDED
+#define REQUEST_H_INCLUDED
+
+struct request {
+ struct connection *conn;
+};
+
+#endif
--- /dev/null
+/*
+ * $Id$
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "varnish.h"
+
+static void
+varnish(void)
+{
+ listener_t *l;
+ connection_t *c;
+ request_t *r;
+
+ l = listener_create(8080);
+ while ((c = listener_accept(l)) != NULL) {
+ r = request_wait(c, 0);
+ /* ... */
+ request_destroy(r);
+ connection_destroy(c);
+ }
+}
+
+static void
+usage(void)
+{
+ fprintf(stderr, "usage: varnish\n");
+ exit(1);
+}
+
+int
+main(int argc, char *argv[])
+{
+ int o;
+
+ while ((o = getopt(argc, argv, "")) != -1)
+ switch (o) {
+ default:
+ usage();
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (argc != 0)
+ usage();
+
+ varnish();
+
+ LOG_UNREACHABLE();
+ exit(1);
+}
--- /dev/null
+/*
+ * $Id$
+ */
+
+#ifndef VARNISH_H_INCLUDED
+#define VARNISH_H_INCLUDED
+
+#include "config.h"
+
+/* opaque structures */
+typedef struct listener listener_t;
+typedef struct connection connection_t;
+typedef struct request request_t;
+
+/* connection.c */
+void connection_destroy(connection_t *c);
+
+/* listener.c */
+listener_t *listener_create(int port);
+void listener_destroy(listener_t *l);
+connection_t *listener_accept(listener_t *l);
+
+/* log.c */
+void log_info(const char *fmt, ...);
+void log_err(const char *fmt, ...);
+void log_syserr(const char *fmt, ...);
+void log_panic(const char *fmt, ...);
+void log_syspanic(const char *fmt, ...);
+
+#define LOG_UNREACHABLE() \
+ log_panic("%s(%d): %s(): unreachable code reached", \
+ __FILE__, __LINE__, __func__)
+
+/* request.c */
+request_t *request_wait(connection_t *c, unsigned int timeout);
+void request_destroy(request_t *r);
+
+#endif