#ifndef __PLB_H__
#define __PLB_H__ 1

#ifndef __GNUC__
# ifdef __attribute__
#  undef __attribute__
# endif
# define __attribute__(a)
#endif

#include <stdio.h>
#ifdef STDC_HEADERS
# include <stdlib.h>
# include <stddef.h>
# include <stdarg.h>
#else
# if HAVE_STDLIB_H
#  include <stdlib.h>
# endif
#endif
#ifdef HAVE_STRING_H
# if !STDC_HEADERS && HAVE_MEMORY_H
#  include <memory.h>
# endif
# include <string.h>
#else
# if HAVE_STRINGS_H
#  include <strings.h>
# endif
#endif
#include <limits.h>
#include <errno.h>
#include <ctype.h>
#include <signal.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#ifdef TIME_WITH_SYS_TIME
# include <sys/time.h>
# include <time.h>
#else
# if HAVE_SYS_TIME_H
#  include <sys/time.h>
# else
#  include <time.h>
# endif
#endif
#include <syslog.h>
#include <sys/types.h>
#include <sys/stat.h>
#ifdef HAVE_FCNTL_H
# include <fcntl.h>
#elif defined(HAVE_SYS_FCNTL_H)
# include <sys/fcntl.h>
#endif
#ifdef HAVE_IOCTL_H
# include <ioctl.h>
#elif defined(HAVE_SYS_IOCTL_H)
# include <sys/ioctl.h>
#endif
#include <sys/socket.h>
#ifdef HAVE_NETINET_IN_SYSTM_H
# include <netinet/in_systm.h>
#endif
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <pwd.h>
#include <grp.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <event.h>

#ifndef HAVE_GETOPT_LONG
# include "bsd-getopt_long.h"
#else
# include <getopt.h>
#endif

#ifdef HAVE_ALLOCA
# ifdef HAVE_ALLOCA_H
#  include <alloca.h>
# endif
# define ALLOCA(X) alloca(X)
# define ALLOCA_FREE(X) do { } while (0)
#else
# define ALLOCA(X) malloc(X)
# define ALLOCA_FREE(X) free(X)
#endif

#include "mysnprintf.h"

#ifndef errno
extern int errno;
#endif

#ifdef TCP_CORK
# define CORK_ON(SK) do { int optval = 1; setsockopt(SK, SOL_TCP, TCP_CORK, \
  &optval, sizeof optval); } while(0)
# define CORK_OFF(SK) do { int optval = 0; setsockopt(SK, SOL_TCP, TCP_CORK, \
  &optval, sizeof optval); } while(0)
#else
# define CORK_ON(SK) do { } while(0)
# define CORK_OFF(SK) do { } while(0)
#endif

#ifndef O_NOFOLLOW
# define O_NOFOLLOW 0
#endif

#ifndef O_DIRECTORY
# define O_DIRECTORY 0
#endif

#ifndef SOL_IP
# define SOL_IP IPPROTO_IP
#endif
#ifndef SOL_TCP
# define SOL_TCP IPPROTO_TCP
#endif

#ifndef INADDR_NONE
# define INADDR_NONE 0
#endif

#if !defined(O_NDELAY) && defined(O_NONBLOCK)
# define O_NDELAY O_NONBLOCK
#endif

#ifndef FNDELAY
# define FNDELAY O_NDELAY
#endif

#ifndef HAVE_STRTOULL
# ifdef HAVE_STRTOQ
#  define strtoull(X, Y, Z) strtoq(X, Y, Z)
# else
#  define strtoull(X, Y, Z) strtoul(X, Y, Z)
# endif
#endif

#ifndef ULONG_LONG_MAX
# define ULONG_LONG_MAX (1ULL << 63)
#endif

#ifdef STAT_MACROS_BROKEN
# undef S_ISBLK
# undef S_ISCHR
# undef S_ISDIR
# undef S_ISFIFO
# undef S_ISLNK
# undef S_ISMPB
# undef S_ISMPC
# undef S_ISNWK
# undef S_ISREG
# undef S_ISSOCK
#endif                            /* STAT_MACROS_BROKEN.  */
    
#ifndef S_IFMT
# define S_IFMT 0170000
#endif
#if !defined(S_ISBLK) && defined(S_IFBLK)
# define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK)
#endif
#if !defined(S_ISCHR) && defined(S_IFCHR)
# define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
#endif
#if !defined(S_ISDIR) && defined(S_IFDIR)
# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
#endif
#if !defined(S_ISREG) && defined(S_IFREG)
# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
#endif
#if !defined(S_ISFIFO) && defined(S_IFIFO)
# define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO)
#endif
#if !defined(S_ISLNK) && defined(S_IFLNK)
# define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
#endif
#if !defined(S_ISSOCK) && defined(S_IFSOCK)
# define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
#endif
#if !defined(S_ISMPB) && defined(S_IFMPB)    /* V7 */
# define S_ISMPB(m) (((m) & S_IFMT) == S_IFMPB)
# define S_ISMPC(m) (((m) & S_IFMT) == S_IFMPC)
#endif
#if !defined(S_ISNWK) && defined(S_IFNWK)    /* HP/UX */
# define S_ISNWK(m) (((m) & S_IFMT) == S_IFNWK)
#endif
    
#ifndef S_IEXEC
# define S_IEXEC S_IXUSR
#endif
    
#ifndef S_IXUSR
# define S_IXUSR S_IEXEC
#endif
#ifndef S_IXGRP
# define S_IXGRP (S_IEXEC >> 3)
#endif
#ifndef S_IXOTH
# define S_IXOTH (S_IEXEC >> 6)
#endif
#ifndef S_IXUGO
# define S_IXUGO (S_IXUSR | S_IXGRP | S_IXOTH)
#endif

#ifndef STDIN_FILENO
# define STDIN_FILENO 0
#endif
#ifndef STDOUT_FILENO
# define STDOUT_FILENO 1
#endif
#ifndef STDERR_FILENO
# define STDERR_FILENO 2
#endif

#ifndef HAVE_SETEUID
# ifdef HAVE_SETREUID
#  define seteuid(X) setreuid(-1, (X))
# elif defined(HAVE_SETRESUID)
#  define seteuid(X) setresuid(-1, (X), -1)
# else
#  define seteuid(X) (-1)
# endif
#endif
#ifndef HAVE_SETEGID
# ifdef HAVE_SETREGID
#  define setegid(X) setregid(-1, (X))
# elif defined(HAVE_SETRESGID)
#  define setegid(X) setresgid(-1, (X), -1)
# else
#  define setegid(X) (-1)
# endif
#endif

#ifdef ACCEPT_UNICODE_CONTROL_CHARS
# define ISCTRLCODE(X) ((X) == 0x7f || ((unsigned char) (X)) < 32U)
#else
# define ISCTRLCODE(X) ((X) == 0x7f || !(((unsigned char) (X)) & 0x60))
#endif



#define DEFAULT_BACKLOG 100
#define HEADER_MAX 8192
#define POSTBUF_CHUNKS 8192
#define REPLYBUF_CHUNKS 32768

#define DEFAULT_SERVER_TIMEOUT 30
#define DEFAULT_CLIENT_TIMEOUT 30
#define DEFAULT_CLEANUP_TIMEOUT 30
#define DEFAULT_MAX_CLIENTS 1000
#define DEFAULT_SERVER_RETRY 15U

#define HTTP_HEADER_END "\r\n\r\n"
#define SMTP_HEADER_END "\r\n"

#define DEFAULT_LOG_LEVEL LL_WARNING

#define SERVER_FULL_MSG "Server too busy, sorry\r\n"   /* change this for smtp */

typedef enum State_ {
    STATE_OFFLINE, STATE_HEADER, STATE_SEND_HEADER, STATE_HEADER_SENT,
    STATE_IGNORE
} State;

typedef enum LogLevel_ {
    LL_DEBUG, LL_NOTIFY, LL_WARNING, LL_ERROR, LL_FATAL
} LogLevel;

typedef enum Protocol_ {
    PROTOCOL_HTTP, PROTOCOL_SMTP
} Protocol;

typedef struct Server_ {
    char *name;
    struct Server_ *next;    
    struct sockaddr_storage ai_addr;
    socklen_t ai_addrlen;
    int ai_family;
    unsigned int status;
    int cleanup_fd;
    struct event cleanup_ev;
} Server;

typedef struct Client_ {
    char *header;
    char *postbuf;
    char *replybuf;    
    struct event client_read_ev;        
    struct event client_write_ev;
    struct event server_read_ev;
    struct event server_write_ev;    
    size_t header_len;
    size_t postbuf_len;   
    size_t replybuf_len;
    size_t header_written;    
    size_t postbuf_written;
    size_t replybuf_written;    
    int client_fd;
    int server_fd;    
    State state;
    Server *server;
} Client;

void init_timeouts(void);
int setsockopt_aggressive(const int fd);
void socket_nonblock(const int fd);
int daemonize(void);
int update_pid_file(const char * const pid_file);
int delete_pid_file(void);

void server_send_header(int evfd, short event, void *client_);
void client_read_header(Client * const client);

void server_forward_request(int evfd, short event, void *client_);
void client_forward_request(Client * const client);
void server_forward_reply(int evfd, short event, void *client_);
void client_forward_reply(int evfd, short event, void *client_);

int connect_server(Client * const client);
void server_mark_failure(Client * const client);

void client_read(const int evfd, short event, void * const client_);

void client_disconnect(Client * const client);
int handle_timeout(const short event, Client * const client);
void new_client(const int listenfd, short event, void *ev_);

void periodic_cleanup(int dummy, const short event, void *ev);

int plb_open_log(const char * const log_file);
void plb_close_log(void);
void plb_log(const LogLevel level, const char * const fmt, ...)
    __attribute__ ((format(printf, 2, 3)));

int plb_drop_caps(const char * const user, const char * const group,
                  const char * const emptydir);

#endif


syntax highlighted by Code2HTML, v. 0.9.1