From: des Date: Fri, 10 Feb 2006 14:41:36 +0000 (+0000) Subject: This is the skeleton code I wrote on my way back from Basel last fall. The X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ad5d7446611e252f155e273237eb5ce78aa1349a;p=varnish 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 --- 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