1
0
mirror of https://github.com/graygnuorg/pound.git synced 2026-10-28 11:35:07 +03:00
Files
pound/src/pound.h
Sergey Poznyakoff 8f0228551b Identify listeners and services by their names (labels) as well as indices
* src/config.c (parse_listen_http)
(parse_listen_https): Handle optional listener name.  Make sure it
is unique.
(parse_service): Make sure service name is unique.
* src/pound.h (LISTENER): New field: name.
* src/poundctl.tmpl: Show listener name, if available.
* svc.c (get_nth_listener, get_nth_service)
(get_nth_backend,ctl_getnum): Remove.
(IDENT): New data type.
(ctl_getident,locate_listener,locate_service)
(locate_backend): New functions.
(service_serialize): Represent NULL service name as null.
(listener_serialize): Add listener name.
(ctl_service,ctl_listener): Identify objects by their ids or numbers.

* NEWS: Document changes.
* doc/pound.8: Likewise.
* doc/poundctl.8: Likewise.
2023-03-03 12:14:33 +02:00

1010 lines
24 KiB
C
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* Pound - the reverse-proxy load-balancer
* Copyright (C) 2002-2010 Apsis GmbH
* Copyright (C) 2018-2023 Sergey Poznyakoff
*
* This file is part of Pound.
*
* Pound is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* Pound is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <unistd.h>
#include <pthread.h>
#include <string.h>
#include <inttypes.h>
#include <time.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <poll.h>
#include <pwd.h>
#include <grp.h>
#include <syslog.h>
#include <signal.h>
#include <ctype.h>
#include <errno.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <fnmatch.h>
#if HAVE_GETOPT_H
# include <getopt.h>
#endif
#ifndef UNIX_PATH_MAX
/* on Linux this is defined in linux/un.h rather than sys/un.h - go figure */
# define UNIX_PATH_MAX 108
#endif
#ifndef NI_MAXHOST
# define NI_MAXHOST 1025
#endif
#ifndef NI_MAXSERV
# define NI_MAXSERV 32
#endif
#define MAX_ADDR_BUFSIZE (NI_MAXHOST + NI_MAXSERV + 4)
#if HAVE_OPENSSL_SSL_H
# define OPENSSL_THREAD_DEFINES
# include <openssl/ssl.h>
# include <openssl/lhash.h>
# include <openssl/err.h>
# if OPENSSL_VERSION_NUMBER >= 0x00907000L
# ifndef OPENSSL_THREADS
# error "Pound requires OpenSSL with thread support"
# endif
# else
# ifndef THREADS
# error "Pound requires OpenSSL with thread support"
# endif
# endif
#else
# error "Pound needs openssl/ssl.h"
#endif
#if HAVE_OPENSSL_ENGINE_H
# include <openssl/engine.h>
#endif
#if HAVE_LIBPCREPOSIX
# if HAVE_PCREPOSIX_H
# include <pcreposix.h>
# elif HAVE_PCRE_PCREPOSIX_H
# include <pcre/pcreposix.h>
# else
# error "You have libpcreposix, but the header files are missing. Use --disable-pcreposix"
# endif
#else
# include <regex.h>
#endif
#ifdef HAVE_LONG_LONG_INT
typedef long long CONTENT_LENGTH;
# define STRTOCLEN strtoll
# define PRICLEN "lld"
#else
typedef long CONTENT_LENGTH;
# define STRTOCLEN strtol
# define PRICLEN "ld"
#endif
#define NO_CONTENT_LENGTH ((CONTENT_LENGTH) -1)
#ifndef DEFAULT_WORKER_MIN
# define DEFAULT_WORKER_MIN 5
#endif
#ifndef DEFAULT_WORKER_MAX
# define DEFAULT_WORKER_MAX 128
#endif
#ifndef DEFAULT_WORKER_IDLE_TIMEOUT
# define DEFAULT_WORKER_IDLE_TIMEOUT 30
#endif
#ifndef DEFAULT_GRACE_TO
# define DEFAULT_GRACE_TO 30
#endif
#ifndef DEFAULT_ALIVE_TO
# define DEFAULT_ALIVE_TO 30
#endif
#ifndef MAXBUF
# define MAXBUF 4096
#endif
#ifndef SYSCONFDIR
# define SYSCONFDIR "/etc"
#endif
#ifndef LOCALSTATEDIR
# define LOCALSTATEDIR "/var"
#endif
#ifndef PKGDATADIR
# define PKGDATADIR "/usr/share/pound"
#endif
#define POUND_TMPL_PATH "~/.poundctl.tmpl:" PKGDATADIR
#ifndef POUND_CONF
# define POUND_CONF SYSCONFDIR "/" "pound.cfg"
#endif
#ifndef POUND_PID
# define POUND_PID LOCALSTATEDIR "/run/pound.pid"
#endif
#define ATTR_PRINTFLIKE(fmt,narg) \
__attribute__ ((__format__ (__printf__, fmt, narg)))
/* HTTP methods */
enum
{
METH_GET,
METH_POST,
METH_HEAD,
METH_PUT,
METH_PATCH,
METH_DELETE,
METH_LOCK,
METH_UNLOCK,
METH_PROPFIND,
METH_PROPPATCH,
METH_SEARCH,
METH_MKCOL,
METH_MOVE,
METH_COPY,
METH_OPTIONS,
METH_TRACE,
METH_MKACTIVITY,
METH_CHECKOUT,
METH_MERGE,
METH_REPORT,
METH_SUBSCRIBE,
METH_UNSUBSCRIBE,
METH_BPROPPATCH,
METH_POLL,
METH_BMOVE,
METH_BCOPY,
METH_BDELETE,
METH_BPROPFIND,
METH_NOTIFY,
METH_CONNECT,
};
/* HTTP errors */
enum
{
HTTP_STATUS_OK, // 200
HTTP_STATUS_BAD_REQUEST, // 400
HTTP_STATUS_NOT_FOUND, // 404
HTTP_STATUS_PAYLOAD_TOO_LARGE, // 413
HTTP_STATUS_URI_TOO_LONG, // 414
HTTP_STATUS_INTERNAL_SERVER_ERROR, // 500
HTTP_STATUS_NOT_IMPLEMENTED, // 501
HTTP_STATUS_SERVICE_UNAVAILABLE, // 503
HTTP_STATUS_MAX
};
/*
* Operations on struct timespec
*/
/*
* Compare two timespecs
*/
static inline int
timespec_cmp (struct timespec const *a, struct timespec const *b)
{
if (a->tv_sec < b->tv_sec)
return -1;
if (a->tv_sec > b->tv_sec)
return 1;
if (a->tv_nsec < b->tv_nsec)
return -1;
if (a->tv_nsec > b->tv_nsec)
return 1;
return 0;
}
static inline struct timespec
timespec_sub (struct timespec const *a, struct timespec const *b)
{
struct timespec d;
d.tv_sec = a->tv_sec - b->tv_sec;
d.tv_nsec = a->tv_nsec - b->tv_nsec;
if (d.tv_nsec < 0)
{
--d.tv_sec;
d.tv_nsec += 1e9;
}
return d;
}
/* List definitions. */
#include "list.h"
/* Header types */
enum
{
HEADER_ILLEGAL = -1,
HEADER_OTHER = 0,
HEADER_TRANSFER_ENCODING,
HEADER_CONTENT_LENGTH,
HEADER_CONNECTION,
HEADER_LOCATION,
HEADER_CONTLOCATION,
HEADER_HOST,
HEADER_REFERER,
HEADER_USER_AGENT,
HEADER_URI,
HEADER_DESTINATION,
HEADER_EXPECT,
HEADER_UPGRADE,
HEADER_AUTHORIZATION,
};
struct http_header
{
char *header;
int code;
size_t name_start;
size_t name_end;
size_t val_start;
size_t val_end;
char *value;
DLIST_ENTRY (http_header) link;
};
typedef DLIST_HEAD(,http_header) HTTP_HEADER_LIST;
enum
{
H_DROP,
H_REPLACE
};
int http_header_list_append (HTTP_HEADER_LIST *head, char *text, int replace);
struct query_param
{
char *name;
char *value;
DLIST_ENTRY (query_param) link;
};
typedef DLIST_HEAD (,query_param) QUERY_HEAD;
#define QUERY_EMPTY DLIST_EMPTY
struct http_request
{
char *request; /* Request line */
HTTP_HEADER_LIST headers; /* Request headers */
int method; /* Method code (see METH_* constants above) */
int version; /* HTTP minor version: 0 or 1 */
char *url; /* URL part of the request */
char *user; /* Username extracted from Authorization header */
char *path; /* URL Path */
char *query; /* URL query */
QUERY_HEAD query_head;
char *orig_request_line; /* Original request line (for logging purposes) */
int split;
};
static inline void http_request_init (struct http_request *http)
{
memset (http, 0, sizeof (*http));
DLIST_INIT (&http->headers);
DLIST_INIT (&http->query_head);
}
void http_request_free (struct http_request *);
#define POUND_TID() ((unsigned long)pthread_self ())
#define PRItid "lx"
struct cidr;
typedef struct acl
{
char *name; /* ACL name (optional) */
SLIST_HEAD (,cidr) head; /* List of CIDRs */
SLIST_ENTRY (acl) next;
} ACL;
typedef SLIST_HEAD (,acl) ACL_HEAD;
int acl_match (ACL *acl, struct sockaddr *sa);
/* matcher chain */
typedef struct _matcher
{
regex_t pat; /* pattern to match the request/header against */
SLIST_ENTRY (_matcher) next;
} MATCHER;
typedef SLIST_HEAD(,_matcher) MATCHER_HEAD;
/* back-end types */
typedef enum
{
SESS_NONE,
SESS_IP,
SESS_COOKIE,
SESS_URL,
SESS_PARM,
SESS_HEADER,
SESS_BASIC
}
SESS_TYPE;
typedef enum
{
BE_BACKEND,
BE_REDIRECT,
BE_ACME,
BE_CONTROL,
BE_ERROR,
BE_METRICS
}
BACKEND_TYPE;
struct be_regular
{
struct addrinfo addr; /* IPv4/6 address */
int alive; /* false if the back-end is dead */
unsigned to; /* read/write time-out */
unsigned conn_to; /* connection time-out */
unsigned ws_to; /* websocket time-out */
SSL_CTX *ctx; /* CTX for SSL connections */
};
struct be_redirect
{
char *url; /* for redirectors */
int status; /* Redirection status (301, 302, 303, 307, or 308 ) */
int has_uri; /* URL has path and/or query part. */
};
struct be_acme
{
char *dir; /* Name of the directory for ACME challenges. */
};
struct be_error
{
int status; /* Pound HTTP status index */
char *file; /* File with error content page */
};
/* back-end definition */
typedef struct _backend
{
struct _service *service; /* Back pointer to the owning service */
BACKEND_TYPE be_type; /* Backend type */
int priority; /* priority */
int disabled; /* true if the back-end is disabled */
SLIST_ENTRY (_backend) next;
/* Statistics */
pthread_mutex_t mut; /* mutex for this back-end */
double numreq; /* number of requests seen */
double avgtime; /* Avg. time per request */
double avgsqtime; /* Avg. squared time per request */
/* Data specific for each backend type. */
union
{
struct be_regular reg;
struct be_acme acme;
struct be_redirect redirect;
struct be_error error;
} v;
} BACKEND;
typedef SLIST_HEAD (,_backend) BACKEND_HEAD;
static inline int backend_is_https (BACKEND *be)
{
return be->be_type == BE_BACKEND && be->v.reg.ctx != NULL;
}
static inline int backend_is_alive (BACKEND *be)
{
/* Redirects, ACME, and control backends are always alive */
return be->be_type != BE_BACKEND || be->v.reg.alive;
}
typedef struct session
{
char *key;
BACKEND *backend;
struct timespec expire;
DLIST_ENTRY (session) link;
} SESSION;
/* maximal session key size */
#define KEY_SIZE 127
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
DEFINE_LHASH_OF (SESSION);
#elif OPENSSL_VERSION_NUMBER >= 0x10000000L
DECLARE_LHASH_OF (SESSION);
#endif
typedef LHASH_OF (SESSION) SESSION_HASH;
typedef struct
{
SESSION_HASH *hash;
DLIST_HEAD (,session) head;
} SESSION_TABLE;
SESSION_TABLE *session_table_new (void);
enum
{
BOOL_AND,
BOOL_OR,
BOOL_NOT
};
struct bool_service_cond
{
int op;
SLIST_HEAD(,_service_cond) head;
};
enum service_cond_type
{
COND_BOOL, /* Boolean operation. */
COND_ACL, /* ACL match. */
COND_URL, /* URL match. */
COND_PATH, /* Path match. */
COND_QUERY, /* Raw query match. */
COND_QUERY_PARAM, /* Query parameter match */
COND_HDR, /* Header match. */
COND_HOST, /* Special case od COND_HDR: matches the value of the
Host: header */
};
struct query_param_match
{
char *name;
regex_t re;
};
typedef struct _service_cond
{
enum service_cond_type type;
union
{
ACL *acl;
regex_t re;
struct bool_service_cond bool;
struct _service_cond *cond;
struct query_param_match qp;
};
SLIST_ENTRY (_service_cond) next;
} SERVICE_COND;
static inline void
service_cond_init (SERVICE_COND *cond, int type)
{
cond->type = type;
switch (type)
{
case COND_ACL:
case COND_URL:
case COND_HDR:
break;
case COND_BOOL:
cond->bool.op = BOOL_AND;
SLIST_INIT (&cond->bool.head);
break;
}
}
enum rewrite_type
{
REWRITE_REWRITE_RULE,
REWRITE_HDR_DEL,
REWRITE_HDR_SET,
REWRITE_URL_SET,
REWRITE_PATH_SET,
REWRITE_QUERY_SET,
REWRITE_QUERY_PARAM_SET
};
typedef SLIST_HEAD(,rewrite_op) REWRITE_OP_HEAD;
typedef SLIST_HEAD(,rewrite_rule) REWRITE_RULE_HEAD;
typedef struct rewrite_op
{
SLIST_ENTRY (rewrite_op) next; /* Next op in the list. */
enum rewrite_type type; /* Rewrite operation type. */
union
{
struct rewrite_rule *rule; /* type == REWRITE_REWRITE_RULE */
MATCHER *hdrdel; /* type == REWRITE_HDR_DEL */
struct
{
char *name;
char *value;
} qp; /* type == REWRITE_QUERY_PARAM_SET */
char *str; /* type == REWRITE_*_SET */
} v;
} REWRITE_OP;
typedef struct rewrite_rule
{
SERVICE_COND cond; /* Optional condition. */
SLIST_ENTRY (rewrite_rule) next; /* Next rule in the list. */
struct rewrite_rule *iffalse; /* Branch to go if cond yields false. */
REWRITE_OP_HEAD ophead; /* Do this if cond yields true. */
} REWRITE_RULE;
/* service definition */
typedef struct _service
{
char *name; /* symbolic name */
SERVICE_COND cond;
REWRITE_RULE_HEAD rewrite;
BACKEND_HEAD backends;
BACKEND *emergency;
int abs_pri; /* abs total priority for all back-ends */
int tot_pri; /* total priority for current back-ends */
pthread_mutex_t mut; /* mutex for this service */
SESS_TYPE sess_type;
unsigned sess_ttl; /* session time-to-live */
char *sess_id; /* Session anchor ID */
SESSION_TABLE *sessions; /* currently active sessions */
int disabled; /* true if the service is disabled */
SLIST_ENTRY (_service) next;
} SERVICE;
typedef SLIST_HEAD (,_service) SERVICE_HEAD;
typedef struct _pound_ctx
{
SSL_CTX *ctx;
char *server_name;
char **subjectAltNames;
size_t subjectAltNameCount;
SLIST_ENTRY (_pound_ctx) next;
} POUND_CTX;
typedef SLIST_HEAD (,_pound_ctx) POUND_CTX_HEAD;
/* Additional listener options */
#define HDROPT_NONE 0 /* Nothing special */
#define HDROPT_FORWARDED_HEADERS 0x1 /* Add X-Forwarded headers */
#define HDROPT_SSL_HEADERS 0x2 /* Add X-SSL- headers */
/* Listener definition */
typedef struct _listener
{
char *name; /* symbolic name */
struct addrinfo addr; /* IPv4/6 address */
int sock; /* listening socket */
POUND_CTX_HEAD ctx_head; /* CTX for SSL connections */
int clnt_check; /* client verification mode */
int noHTTPS11; /* HTTP 1.1 mode for SSL */
int header_options; /* additional header options */
REWRITE_RULE_HEAD rewrite;
int verb; /* allowed HTTP verb group */
unsigned to; /* client time-out */
int has_pat; /* was a URL pattern defined? */
regex_t url_pat; /* pattern to match the request URL against */
char *http_err[HTTP_STATUS_MAX]; /* error messages */
CONTENT_LENGTH max_req; /* max. request size */
int rewr_loc; /* rewrite location response */
int rewr_dest; /* rewrite destination header */
int disabled; /* true if the listener is disabled */
int log_level; /* log level for this listener */
int allow_client_reneg; /* Allow Client SSL Renegotiation */
SERVICE_HEAD services;
SLIST_ENTRY (_listener) next;
/* Used during configuration parsing */
int ssl_op_enable;
int ssl_op_disable;
int has_other;
} LISTENER;
typedef SLIST_HEAD(,_listener) LISTENER_HEAD;
struct submatch
{
size_t matchn;
size_t matchmax;
regmatch_t *matchv;
char *subject;
};
#define SMQ_SIZE 8
struct submatch_queue
{
int cur;
struct submatch sm[SMQ_SIZE+1];
};
#define SUBMATCH_INITIALIZER { 0, 0, NULL, NULL }
static inline void
submatch_init (struct submatch *sm)
{
sm->matchn = 0;
sm->matchmax = 0;
sm->matchv = NULL;
sm->subject = NULL;
}
void submatch_queue_free (struct submatch_queue *smq);
enum
{
WSS_INIT = 0,
WSS_REQ_GET = 0x01,
WSS_REQ_HEADER_CONNECTION_UPGRADE = 0x02,
WSS_REQ_HEADER_UPGRADE_WEBSOCKET = 0x04,
WSS_RESP_101 = 0x08,
WSS_RESP_HEADER_CONNECTION_UPGRADE = 0x10,
WSS_RESP_HEADER_UPGRADE_WEBSOCKET = 0x20,
WSS_COMPLETE = WSS_REQ_GET
| WSS_REQ_HEADER_CONNECTION_UPGRADE
| WSS_REQ_HEADER_UPGRADE_WEBSOCKET | WSS_RESP_101 |
WSS_RESP_HEADER_CONNECTION_UPGRADE | WSS_RESP_HEADER_UPGRADE_WEBSOCKET
};
/* Track SSL handshare/renegotiation so we can reject client-renegotiations. */
typedef enum
{
RENEG_INIT = 0,
RENEG_REJECT,
RENEG_ALLOW,
RENEG_ABORT
}
RENEG_STATE;
typedef struct _pound_http
{
/* Input parameters */
int sock;
LISTENER *lstn;
struct addrinfo from_host;
/* Deduced information */
SERVICE *svc;
BACKEND *backend;
/* Data used during http processing */
BIO *cl;
BIO *be;
X509 *x509;
SSL *ssl;
struct submatch_queue smq;
RENEG_STATE reneg_state;
int ws_state; /* Websocket state */
int no_cont; /* True if no content is expected */
int conn_closed; /* True if the connection is closed */
struct http_request request;
struct http_request response;
struct timespec start_req; /* Time when original request was received */
int response_code;
CONTENT_LENGTH res_bytes;
SLIST_ENTRY(_pound_http) next;
} POUND_HTTP;
typedef SLIST_HEAD(,_pound_http) POUND_HTTP_HEAD;
/* control request stuff */
typedef enum
{
CTRL_LST,
CTRL_EN_LSTN, CTRL_DE_LSTN,
CTRL_EN_SVC, CTRL_DE_SVC,
CTRL_EN_BE, CTRL_DE_BE,
CTRL_ADD_SESS, CTRL_DEL_SESS
} CTRL_CODE;
typedef struct
{
CTRL_CODE cmd;
int listener;
int service;
int backend;
char key[KEY_SIZE + 1];
} CTRL_CMD;
/* add a request to the queue */
int pound_http_enqueue (int sock, LISTENER *lstn, struct sockaddr *sa, socklen_t salen);
/* get a request from the queue */
POUND_HTTP *pound_http_dequeue (void);
/* Free the argument */
void pound_http_destroy (POUND_HTTP *arg);
/* get the current queue length */
int get_thr_qlen (void);
/* Decrement number of active threads. */
void active_threads_decr (void);
/* handle HTTP requests */
void *thr_http (void *);
/* Log an error to the syslog or to stderr */
void logmsg (const int, const char *, ...)
ATTR_PRINTFLIKE(2,3);
void abend (char const *fmt, ...)
ATTR_PRINTFLIKE(1,2);
/* Translate inet/inet6 address into a string */
char *addr2str (char *, int, const struct addrinfo *, int);
/* Return a string representation for a back-end address */
char *str_be (char *buf, size_t size, BACKEND *be);
/* Find the right service for a request */
SERVICE *get_service (const LISTENER *, struct sockaddr *,
struct http_request *, struct submatch_queue *);
/* Find the right back-end for a request */
BACKEND *get_backend (POUND_HTTP *phttp);
/* Search for a host name, return the addrinfo for it */
int get_host (char *const, struct addrinfo *, int);
/*
* Find if a redirect needs rewriting
* In general we have two possibilities that require it:
* (1) if the redirect was done to the correct location with the wrong protocol
* (2) if the redirect was done to the back-end rather than the listener
*/
int need_rewrite (const char *, const char *,
const LISTENER *, const BACKEND *, const char **);
/*
* (for cookies only) possibly create session based on response headers
*/
void upd_session (SERVICE *, HTTP_HEADER_LIST *, BACKEND *);
#define BE_DISABLE -1
#define BE_KILL 1
#define BE_ENABLE 0
/*
* mark a backend host as dead;
* do nothing if no resurection code is active
*/
void kill_be (SERVICE *, BACKEND *, const int);
/*
* Update the number of requests and time to answer for a given back-end
*/
void upd_be (SERVICE * const svc, BACKEND * const be, const double);
/*
* Non-blocking version of connect(2). Does the same as connect(2) but
* ensures it will time-out after a much shorter time period CONN_TO.
*/
int connect_nb (const int, const struct addrinfo *, const int);
/*
* Parse arguments/config file
*/
void config_parse (int, char **);
/*
* RSA ephemeral keys: how many and how often
*/
#define N_RSA_KEYS 11
#ifndef T_RSA_KEYS
# define T_RSA_KEYS 7200
#endif
/*
* Renegotiation callback
*/
void SSLINFO_callback (const SSL * s, int where, int rc);
/*
* run periodic functions:
* - RSAgen every T_RSA_KEYS seconds (on older OpenSSL)
* - probe dead backends every alive_to seconds
* - clean up expire sessions as needed
*/
void *thr_timer (void *);
void POUND_SSL_CTX_init (SSL_CTX *ctx);
int set_ECDHCurve (char *name);
void *mem2nrealloc (void *p, size_t *pn, size_t s);
void xnomem (void);
void *xmalloc (size_t s);
void *xcalloc (size_t nmemb, size_t size);
#define xzalloc(s) xcalloc(1, s)
#define XZALLOC(v) (v = xzalloc (sizeof ((v)[0])))
void *xrealloc (void *p, size_t s);
void *x2nrealloc (void *p, size_t *pn, size_t s);
char *xstrdup (char const *s);
char *xstrndup (const char *s, size_t n);
struct stringbuf
{
char *base; /* Buffer storage. */
size_t size; /* Size of buf. */
size_t len; /* Actually used length in buf. */
void (*nomem) (void); /* Out of memory handler. */
int err; /* Error indicator */
};
void stringbuf_init (struct stringbuf *sb, void (*nomem) (void));
void stringbuf_reset (struct stringbuf *sb);
char *stringbuf_finish (struct stringbuf *sb);
void stringbuf_free (struct stringbuf *sb);
int stringbuf_add (struct stringbuf *sb, char const *str, size_t len);
int stringbuf_add_char (struct stringbuf *sb, int c);
int stringbuf_add_string (struct stringbuf *sb, char const *str);
int stringbuf_vprintf (struct stringbuf *sb, char const *fmt, va_list ap);
int stringbuf_printf (struct stringbuf *sb, char const *fmt, ...)
ATTR_PRINTFLIKE(2,3);
char *stringbuf_set (struct stringbuf *sb, int c, size_t n);
static inline int
stringbuf_err (struct stringbuf *sb)
{
return sb->err;
}
static inline char *stringbuf_value (struct stringbuf *sb)
{
return sb->base;
}
static inline size_t stringbuf_len (struct stringbuf *sb)
{
return sb->len;
}
extern void xnomem (void);
extern void lognomem (void);
static inline void xstringbuf_init (struct stringbuf *sb)
{
stringbuf_init (sb, xnomem);
}
static inline void stringbuf_init_log (struct stringbuf *sb)
{
stringbuf_init (sb, lognomem);
}
void job_enqueue_unlocked (struct timespec const *ts, void (*func) (void *), void *data);
void job_enqueue_after_unlocked (unsigned t, void (*func) (void *), void *data);
void job_enqueue (struct timespec const *ts, void (*func) (void *), void *data);
void job_enqueue_after (unsigned t, void (*func) (void *), void *data);
void job_rearm_unlocked (struct timespec *ts, void (*func) (void *), void *data);
void job_rearm (struct timespec *ts, void (*func) (void *), void *data);
char const *sess_type_to_str (int type);
int control_response (POUND_HTTP *arg);
void pound_atexit (void (*func) (void *), void *arg);
void unlink_file (void *arg);
extern char const *progname;
enum string_value_type
{
STRING_CONSTANT,
STRING_INT,
STRING_VARIABLE,
STRING_FUNCTION,
STRING_PRINTER
};
struct string_value
{
char const *kw;
enum string_value_type type;
union
{
char *s_const;
char **s_var;
int s_int;
char const *(*s_func) (void);
void (*s_print) (FILE *);
} data;
};
void set_progname (char const *arg);
void print_version (struct string_value *settings);
typedef struct template *TEMPLATE;
struct json_value;
enum
{
TMPL_ERR_OK, /* No error */
TMPL_ERR_EOF, /* Unexpected end of file */
TMPL_ERR_RANGE, /* Number out of range */
TMPL_ERR_NOFUNC,/* No such function */
TMPL_ERR_BADTOK,/* Unexpected token */
TMPL_ERR_NOTMPL,/* No such template */
};
TEMPLATE template_lookup (const char *name);
int template_parse (char *text, TEMPLATE *ret_tmpl, size_t *end);
void template_run (TEMPLATE tmpl, struct json_value *val, FILE *outfile);
char const *template_strerror (int ec);
void template_free (TEMPLATE tmpl);
void errormsg (int ex, int ec, char const *fmt, ...);
void json_error (struct json_value *val, char const *fmt, ...);
int http_status_to_pound (int status);
int pound_to_http_status (int err);
struct json_value *workers_serialize (void);
struct json_value *pound_serialize (void);
int metrics_response (POUND_HTTP *phttp);
int match_cond (const SERVICE_COND *cond, struct sockaddr *srcaddr,
struct http_request *req, struct submatch_queue *smq);
struct http_header *http_header_list_locate_name (HTTP_HEADER_LIST *head, char const *name, size_t len);
char *http_header_get_value (struct http_header *hdr);
/*
* Return codes for http_request_get_query_param,
* http_request_get_query_param_value, and request accessors.
*/
enum
{
RETRIEVE_OK,
RETRIEVE_NOT_FOUND,
RETRIEVE_ERROR = -1
};
int http_request_get_path (struct http_request *req, char const **retval);
int http_request_get_query_param_value (struct http_request *req,
char const *name,
char const **retval);