From ad5d7446611e252f155e273237eb5ce78aa1349a Mon Sep 17 00:00:00 2001 From: des Date: Fri, 10 Feb 2006 14:41:36 +0000 Subject: [PATCH] This is the skeleton code I wrote on my way back from Basel last fall. The code itself is probably not worth much, but I've put quite a lot of work into two portions of it: the autoconf framework and the listener code. git-svn-id: svn+ssh://projects.linpro.no/svn/varnish/trunk@3 d4fa192b-c00b-0410-8231-f00ffab90ce4 --- Makefile.am | 10 ++++ autogen.sh | 9 ++++ configure.ac | 64 ++++++++++++++++++++++++ connection.c | 22 +++++++++ connection.h | 13 +++++ listener.c | 136 +++++++++++++++++++++++++++++++++++++++++++++++++++ listener.h | 13 +++++ log.c | 94 +++++++++++++++++++++++++++++++++++ request.c | 31 ++++++++++++ request.h | 12 +++++ varnish.c | 55 +++++++++++++++++++++ varnish.h | 38 ++++++++++++++ 12 files changed, 497 insertions(+) create mode 100644 Makefile.am create mode 100755 autogen.sh create mode 100644 configure.ac create mode 100644 connection.c create mode 100644 connection.h create mode 100644 listener.c create mode 100644 listener.h create mode 100644 log.c create mode 100644 request.c create mode 100644 request.h create mode 100644 varnish.c create mode 100644 varnish.h diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 00000000..04d11a2f --- /dev/null +++ b/Makefile.am @@ -0,0 +1,10 @@ +# $Id$ + +bin_PROGRAMS = varnish + +varnish_SOURCES = \ + connection.c \ + listener.c \ + log.c \ + request.c \ + varnish.c diff --git a/autogen.sh b/autogen.sh new file mode 100755 index 00000000..be61b2b0 --- /dev/null +++ b/autogen.sh @@ -0,0 +1,9 @@ +#!/bin/sh +# +# $Id$ +# + +aclocal +autoheader +automake --add-missing --copy --force --foreign +autoconf diff --git a/configure.ac b/configure.ac new file mode 100644 index 00000000..ca8869df --- /dev/null +++ b/configure.ac @@ -0,0 +1,64 @@ +# $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 +#ifdef HAVE_SYS_SOCKET_H +#include +#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 diff --git a/connection.c b/connection.c new file mode 100644 index 00000000..4e226407 --- /dev/null +++ b/connection.c @@ -0,0 +1,22 @@ +/* + * $Id$ + */ + +#include +#include + +#include + +#include +#include + +#include "varnish.h" +#include "connection.h" + +void +connection_destroy(struct connection *c) +{ + close(c->sd); + /* bzero(c, sizeof *c); */ + free(c); +} diff --git a/connection.h b/connection.h new file mode 100644 index 00000000..dfabe0b9 --- /dev/null +++ b/connection.h @@ -0,0 +1,13 @@ +/* + * $Id$ + */ + +#ifndef CONNECTION_H_INCLUDED +#define CONNECTION_H_INCLUDED + +struct connection { + int sd; + struct sockaddr_storage addr; +}; + +#endif diff --git a/listener.c b/listener.c new file mode 100644 index 00000000..9c319003 --- /dev/null +++ b/listener.c @@ -0,0 +1,136 @@ +/* + * $Id$ + */ + +#include +#include + +#include + +#include +#include +#include +#include + +#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); + } + } +} diff --git a/listener.h b/listener.h new file mode 100644 index 00000000..15d83ff7 --- /dev/null +++ b/listener.h @@ -0,0 +1,13 @@ +/* + * $Id$ + */ + +#ifndef LISTENER_H_INCLUDED +#define LISTENER_H_INCLUDED + +struct listener { + int sd; + struct sockaddr_storage addr; +}; + +#endif diff --git a/log.c b/log.c new file mode 100644 index 00000000..de52de15 --- /dev/null +++ b/log.c @@ -0,0 +1,94 @@ +/* + * $Id$ + */ + +#include + +#include +#include +#include +#include +#include +#include + +#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(); +} diff --git a/request.c b/request.c new file mode 100644 index 00000000..a8d17f67 --- /dev/null +++ b/request.c @@ -0,0 +1,31 @@ +/* + * $Id$ + */ + +#include + +#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); +} diff --git a/request.h b/request.h new file mode 100644 index 00000000..3fd94d85 --- /dev/null +++ b/request.h @@ -0,0 +1,12 @@ +/* + * $Id$ + */ + +#ifndef REQUEST_H_INCLUDED +#define REQUEST_H_INCLUDED + +struct request { + struct connection *conn; +}; + +#endif diff --git a/varnish.c b/varnish.c new file mode 100644 index 00000000..3484e3eb --- /dev/null +++ b/varnish.c @@ -0,0 +1,55 @@ +/* + * $Id$ + */ + +#include +#include +#include + +#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); +} diff --git a/varnish.h b/varnish.h new file mode 100644 index 00000000..7d3d3c53 --- /dev/null +++ b/varnish.h @@ -0,0 +1,38 @@ +/* + * $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 -- 2.39.5