mirror of https://github.com/yandex/odyssey.git
odissey: begin reconstruction for new arch
This commit is contained in:
parent
f11f115006
commit
ca5cf157dd
|
@ -49,4 +49,4 @@ message (STATUS "")
|
|||
message (STATUS "ODISSEY (version: ${OD_VERSION_GIT} ${OD_VERSION_BUILD})")
|
||||
message (STATUS "")
|
||||
|
||||
add_subdirectory(core)
|
||||
add_subdirectory(src)
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit cb588f49734eb302b98dc372990eed45facacf0b
|
||||
Subproject commit 069879865159c1f082bc036db7a974d867f4d191
|
|
@ -0,0 +1,150 @@
|
|||
|
||||
/*
|
||||
* odissey.
|
||||
*
|
||||
* PostgreSQL connection pooler and request router.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include <machinarium.h>
|
||||
#include <soprano.h>
|
||||
|
||||
#include "od_macro.h"
|
||||
#include "od_version.h"
|
||||
#include "od_list.h"
|
||||
#include "od_pid.h"
|
||||
#include "od_syslog.h"
|
||||
#include "od_log.h"
|
||||
#include "od_daemon.h"
|
||||
#include "od_scheme.h"
|
||||
#include "od_lex.h"
|
||||
#include "od_config.h"
|
||||
#include "od.h"
|
||||
|
||||
/*
|
||||
#include "od_stat.h"
|
||||
#include "od_server.h"
|
||||
#include "od_server_pool.h"
|
||||
#include "od_client.h"
|
||||
#include "od_client_list.h"
|
||||
#include "od_client_pool.h"
|
||||
#include "od_route_id.h"
|
||||
#include "od_route.h"
|
||||
#include "od_route_pool.h"
|
||||
#include "od_pooler.h"
|
||||
*/
|
||||
|
||||
void od_init(od_t *od)
|
||||
{
|
||||
od_pidinit(&od->pid);
|
||||
od_syslog_init(&od->syslog);
|
||||
od_loginit(&od->log, &od->pid, &od->syslog);
|
||||
od_schemeinit(&od->scheme);
|
||||
od_configinit(&od->config, &od->log, &od->scheme);
|
||||
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
}
|
||||
|
||||
void od_free(od_t *od)
|
||||
{
|
||||
if (od->scheme.pid_file)
|
||||
od_pidfile_unlink(&od->pid, od->scheme.pid_file);
|
||||
od_schemefree(&od->scheme);
|
||||
od_configclose(&od->config);
|
||||
od_logclose(&od->log);
|
||||
od_syslog_close(&od->syslog);
|
||||
}
|
||||
|
||||
static inline void
|
||||
od_usage(od_t *od, char *path)
|
||||
{
|
||||
od_log(&od->log, NULL, "odissey (version: %s %s)",
|
||||
OD_VERSION_GIT,
|
||||
OD_VERSION_BUILD);
|
||||
od_log(&od->log, NULL, "usage: %s <config_file>", path);
|
||||
}
|
||||
|
||||
int od_main(od_t *od, int argc, char **argv)
|
||||
{
|
||||
/* validate command line options */
|
||||
if (argc != 2) {
|
||||
od_usage(od, argv[0]);
|
||||
return 1;
|
||||
}
|
||||
char *config_file;
|
||||
if (argc == 2) {
|
||||
if (strcmp(argv[1], "-h") == 0 ||
|
||||
strcmp(argv[1], "--help") == 0) {
|
||||
od_usage(od, argv[0]);
|
||||
return 0;
|
||||
}
|
||||
config_file = argv[1];
|
||||
}
|
||||
/* read config file */
|
||||
int rc;
|
||||
rc = od_configopen(&od->config, config_file);
|
||||
if (rc == -1)
|
||||
return 1;
|
||||
rc = od_configparse(&od->config);
|
||||
if (rc == -1)
|
||||
return 1;
|
||||
/* set log verbosity level */
|
||||
od_logset_verbosity(&od->log, od->scheme.log_verbosity);
|
||||
/* run as daemon */
|
||||
if (od->scheme.daemonize) {
|
||||
rc = od_daemonize();
|
||||
if (rc == -1)
|
||||
return 1;
|
||||
/* update pid */
|
||||
od_pidinit(&od->pid);
|
||||
}
|
||||
/* reopen log file after config parsing */
|
||||
if (od->scheme.log_file) {
|
||||
rc = od_logopen(&od->log, od->scheme.log_file);
|
||||
if (rc == -1) {
|
||||
od_error(&od->log, NULL, "failed to open log file '%s'",
|
||||
od->scheme.log_file);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
/* syslog */
|
||||
if (od->scheme.syslog) {
|
||||
od_syslog_open(&od->syslog,
|
||||
od->scheme.syslog_ident,
|
||||
od->scheme.syslog_facility);
|
||||
}
|
||||
od_log(&od->log, NULL, "odissey (version: %s %s)",
|
||||
OD_VERSION_GIT,
|
||||
OD_VERSION_BUILD);
|
||||
od_log(&od->log, NULL, "");
|
||||
/* validate configuration scheme */
|
||||
rc = od_schemevalidate(&od->scheme, &od->log);
|
||||
if (rc == -1)
|
||||
return 1;
|
||||
/* print configuration scheme */
|
||||
if (od->scheme.log_verbosity >= 1) {
|
||||
od_schemeprint(&od->scheme, &od->log);
|
||||
od_log(&od->log, NULL, "");
|
||||
}
|
||||
/* create pid file */
|
||||
if (od->scheme.pid_file)
|
||||
od_pidfile_create(&od->pid, od->scheme.pid_file);
|
||||
|
||||
#if 0
|
||||
/* run connection pooler */
|
||||
od_pooler_t pooler;
|
||||
rc = od_pooler_init(&pooler, od);
|
||||
if (rc == -1)
|
||||
return 1;
|
||||
rc = od_pooler_start(&pooler);
|
||||
if (rc == -1)
|
||||
return 1;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
#ifndef OD_H_
|
||||
#define OD_H_
|
||||
|
||||
/*
|
||||
* odissey.
|
||||
*
|
||||
* PostgreSQL connection pooler and request router.
|
||||
*/
|
||||
|
||||
typedef struct od od_t;
|
||||
|
||||
struct od
|
||||
{
|
||||
od_pid_t pid;
|
||||
od_syslog_t syslog;
|
||||
od_log_t log;
|
||||
od_config_t config;
|
||||
od_scheme_t scheme;
|
||||
};
|
||||
|
||||
void od_init(od_t*);
|
||||
void od_free(od_t*);
|
||||
int od_main(od_t*, int, char**);
|
||||
|
||||
#endif /* OD_H */
|
|
@ -0,0 +1,720 @@
|
|||
|
||||
/*
|
||||
* odissey.
|
||||
*
|
||||
* PostgreSQL connection pooler and request router.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <machinarium.h>
|
||||
|
||||
#include "od_macro.h"
|
||||
#include "od_list.h"
|
||||
#include "od_pid.h"
|
||||
#include "od_syslog.h"
|
||||
#include "od_log.h"
|
||||
#include "od_scheme.h"
|
||||
#include "od_lex.h"
|
||||
#include "od_config.h"
|
||||
|
||||
#define od_keyword(name, token) { name, sizeof(name) - 1, token }
|
||||
|
||||
static od_keyword_t od_config_keywords[] =
|
||||
{
|
||||
/* main */
|
||||
od_keyword("odissey", OD_LODISSEY),
|
||||
od_keyword("yes", OD_LYES),
|
||||
od_keyword("no", OD_LNO),
|
||||
od_keyword("on", OD_LON),
|
||||
od_keyword("off", OD_LOFF),
|
||||
od_keyword("daemonize", OD_LDAEMONIZE),
|
||||
od_keyword("log_verbosity", OD_LLOG_VERBOSITY),
|
||||
od_keyword("log_file", OD_LLOG_FILE),
|
||||
od_keyword("pid_file", OD_LPID_FILE),
|
||||
od_keyword("syslog", OD_LSYSLOG),
|
||||
od_keyword("syslog_ident", OD_LSYSLOG_IDENT),
|
||||
od_keyword("syslog_facility", OD_LSYSLOG_FACILITY),
|
||||
od_keyword("stats_period", OD_LSTATS_PERIOD),
|
||||
od_keyword("pooling", OD_LPOOLING),
|
||||
/* listen */
|
||||
od_keyword("listen", OD_LLISTEN),
|
||||
od_keyword("host", OD_LHOST),
|
||||
od_keyword("port", OD_LPORT),
|
||||
od_keyword("backlog", OD_LBACKLOG),
|
||||
od_keyword("nodelay", OD_LNODELAY),
|
||||
od_keyword("keepalive", OD_LKEEPALIVE),
|
||||
od_keyword("readahead", OD_LREADAHEAD),
|
||||
od_keyword("workers", OD_LWORKERS),
|
||||
od_keyword("client_max", OD_LCLIENT_MAX),
|
||||
od_keyword("tls_mode", OD_LTLS_MODE),
|
||||
od_keyword("tls_ca_file", OD_LTLS_CA_FILE),
|
||||
od_keyword("tls_key_file", OD_LTLS_KEY_FILE),
|
||||
od_keyword("tls_cert_file", OD_LTLS_CERT_FILE),
|
||||
od_keyword("tls_protocols", OD_LTLS_PROTOCOLS),
|
||||
/* server */
|
||||
od_keyword("server", OD_LSERVER),
|
||||
/* routing */
|
||||
od_keyword("routing", OD_LROUTING),
|
||||
od_keyword("default", OD_LDEFAULT),
|
||||
od_keyword("mode", OD_LMODE),
|
||||
od_keyword("database", OD_LDATABASE),
|
||||
od_keyword("user", OD_LUSER),
|
||||
od_keyword("password", OD_LPASSWORD),
|
||||
od_keyword("ttl", OD_LTTL),
|
||||
od_keyword("cancel", OD_LCANCEL),
|
||||
od_keyword("discard", OD_LDISCARD),
|
||||
od_keyword("rollback", OD_LROLLBACK),
|
||||
od_keyword("pool_size", OD_LPOOL_SIZE),
|
||||
od_keyword("pool_timeout", OD_LPOOL_TIMEOUT),
|
||||
/* users */
|
||||
od_keyword("authentication", OD_LAUTHENTICATION),
|
||||
od_keyword("users", OD_LUSERS),
|
||||
od_keyword("deny", OD_LDENY),
|
||||
{ NULL, 0, 0 }
|
||||
};
|
||||
|
||||
void
|
||||
od_configinit(od_config_t *config,
|
||||
od_log_t *log,
|
||||
od_scheme_t *scheme)
|
||||
{
|
||||
od_lexinit(&config->lex);
|
||||
config->log = log;
|
||||
config->scheme = scheme;
|
||||
}
|
||||
|
||||
int
|
||||
od_configopen(od_config_t *config, char *file)
|
||||
{
|
||||
/* read file */
|
||||
struct stat st;
|
||||
int rc = lstat(file, &st);
|
||||
if (rc == -1) {
|
||||
od_error(config->log, NULL, "failed to open config file '%s'",
|
||||
file);
|
||||
return -1;
|
||||
}
|
||||
char *config_buf = malloc(st.st_size);
|
||||
if (config_buf == NULL) {
|
||||
od_error(config->log, NULL, "memory allocation error");
|
||||
return -1;
|
||||
}
|
||||
FILE *f = fopen(file, "r");
|
||||
if (f == NULL) {
|
||||
free(config_buf);
|
||||
od_error(config->log, NULL, "failed to open config file '%s'",
|
||||
file);
|
||||
return -1;
|
||||
}
|
||||
rc = fread(config_buf, st.st_size, 1, f);
|
||||
fclose(f);
|
||||
if (rc != 1) {
|
||||
free(config_buf);
|
||||
od_error(config->log, NULL, "failed to open config file '%s'",
|
||||
file);
|
||||
return -1;
|
||||
}
|
||||
od_lexopen(&config->lex, od_config_keywords, config_buf,
|
||||
st.st_size);
|
||||
config->scheme->config_file = file;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
od_configclose(od_config_t *config)
|
||||
{
|
||||
od_lexfree(&config->lex);
|
||||
}
|
||||
|
||||
static void
|
||||
od_configerror(od_config_t *config, od_token_t *tk, char *fmt, ...)
|
||||
{
|
||||
char msg[256];
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
vsnprintf(msg, sizeof(msg), fmt, args);
|
||||
va_end(args);
|
||||
int line = config->lex.line;
|
||||
if (tk)
|
||||
line = tk->line;
|
||||
od_error(config->log, NULL, "%s:%d %s",
|
||||
config->scheme->config_file, line, msg);
|
||||
}
|
||||
|
||||
static int
|
||||
od_confignext(od_config_t *config, int id, od_token_t **tk)
|
||||
{
|
||||
od_token_t *tkp = NULL;
|
||||
int token = od_lexpop(&config->lex, &tkp);
|
||||
if (token == OD_LERROR) {
|
||||
od_configerror(config, NULL, "%s", config->lex.error);
|
||||
return -1;
|
||||
}
|
||||
if (tk) {
|
||||
*tk = tkp;
|
||||
}
|
||||
if (token != id) {
|
||||
if (id < 0xff && ispunct(id)) {
|
||||
od_configerror(config, tkp, "expected '%c'", id);
|
||||
return -1;
|
||||
}
|
||||
od_configerror(config, tkp, "expected '%s'",
|
||||
od_lexname_of(&config->lex, id));
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
od_confignext_yes_no(od_config_t *config, od_token_t **tk)
|
||||
{
|
||||
int rc;
|
||||
rc = od_lexpop(&config->lex, tk);
|
||||
if (rc == OD_LYES)
|
||||
return 1;
|
||||
if (rc == OD_LNO)
|
||||
return 0;
|
||||
od_configerror(config, *tk, "expected yes/no");
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
od_configparse_listen(od_config_t *config)
|
||||
{
|
||||
if (od_confignext(config, '{', NULL) == -1)
|
||||
return -1;
|
||||
od_token_t *tk;
|
||||
int rc;
|
||||
int eof = 0;
|
||||
while (! eof)
|
||||
{
|
||||
rc = od_lexpop(&config->lex, &tk);
|
||||
switch (rc) {
|
||||
/* host */
|
||||
case OD_LHOST:
|
||||
if (od_confignext(config, OD_LSTRING, &tk) == -1)
|
||||
return -1;
|
||||
config->scheme->host = tk->v.string;
|
||||
continue;
|
||||
/* port */
|
||||
case OD_LPORT:
|
||||
if (od_confignext(config, OD_LNUMBER, &tk) == -1)
|
||||
return -1;
|
||||
config->scheme->port = tk->v.num;
|
||||
continue;
|
||||
/* backlog */
|
||||
case OD_LBACKLOG:
|
||||
if (od_confignext(config, OD_LNUMBER, &tk) == -1)
|
||||
return -1;
|
||||
config->scheme->backlog = tk->v.num;
|
||||
continue;
|
||||
/* nodelay */
|
||||
case OD_LNODELAY:
|
||||
rc = od_confignext_yes_no(config, &tk);
|
||||
if (rc == -1)
|
||||
return -1;
|
||||
config->scheme->nodelay = rc;
|
||||
continue;
|
||||
/* keepalive */
|
||||
case OD_LKEEPALIVE:
|
||||
if (od_confignext(config, OD_LNUMBER, &tk) == -1)
|
||||
return -1;
|
||||
config->scheme->keepalive = tk->v.num;
|
||||
continue;
|
||||
/* readahead */
|
||||
case OD_LREADAHEAD:
|
||||
if (od_confignext(config, OD_LNUMBER, &tk) == -1)
|
||||
return -1;
|
||||
config->scheme->readahead = tk->v.num;
|
||||
continue;
|
||||
/* client_max */
|
||||
case OD_LCLIENT_MAX:
|
||||
if (od_confignext(config, OD_LNUMBER, &tk) == -1)
|
||||
return -1;
|
||||
config->scheme->client_max = tk->v.num;
|
||||
continue;
|
||||
/* workers */
|
||||
case OD_LWORKERS:
|
||||
if (od_confignext(config, OD_LNUMBER, &tk) == -1)
|
||||
return -1;
|
||||
config->scheme->workers = tk->v.num;
|
||||
continue;
|
||||
/* tls_mode */
|
||||
case OD_LTLS_MODE:
|
||||
if (od_confignext(config, OD_LSTRING, &tk) == -1)
|
||||
return -1;
|
||||
config->scheme->tls_mode = tk->v.string;
|
||||
continue;
|
||||
/* tls_ca_file */
|
||||
case OD_LTLS_CA_FILE:
|
||||
if (od_confignext(config, OD_LSTRING, &tk) == -1)
|
||||
return -1;
|
||||
config->scheme->tls_ca_file = tk->v.string;
|
||||
continue;
|
||||
/* tls_key_file */
|
||||
case OD_LTLS_KEY_FILE:
|
||||
if (od_confignext(config, OD_LSTRING, &tk) == -1)
|
||||
return -1;
|
||||
config->scheme->tls_key_file = tk->v.string;
|
||||
continue;
|
||||
/* tls_cert_file */
|
||||
case OD_LTLS_CERT_FILE:
|
||||
if (od_confignext(config, OD_LSTRING, &tk) == -1)
|
||||
return -1;
|
||||
config->scheme->tls_cert_file = tk->v.string;
|
||||
continue;
|
||||
/* tls_protocols */
|
||||
case OD_LTLS_PROTOCOLS:
|
||||
if (od_confignext(config, OD_LSTRING, &tk) == -1)
|
||||
return -1;
|
||||
config->scheme->tls_protocols = tk->v.string;
|
||||
continue;
|
||||
case OD_LEOF:
|
||||
od_configerror(config, tk, "unexpected end of config file");
|
||||
return -1;
|
||||
case '}':
|
||||
eof = 1;
|
||||
continue;
|
||||
default:
|
||||
od_configerror(config, tk, "unknown option");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
od_configparse_server(od_config_t *config)
|
||||
{
|
||||
od_schemeserver_t *server =
|
||||
od_schemeserver_add(config->scheme);
|
||||
if (server == NULL)
|
||||
return -1;
|
||||
od_token_t *tk;
|
||||
int rc;
|
||||
/* name */
|
||||
if (od_confignext(config, OD_LSTRING, &tk) == -1)
|
||||
return -1;
|
||||
server->name = tk->v.string;
|
||||
if (od_confignext(config, '{', NULL) == -1)
|
||||
return -1;
|
||||
int eof = 0;
|
||||
while (! eof)
|
||||
{
|
||||
rc = od_lexpop(&config->lex, &tk);
|
||||
switch (rc) {
|
||||
/* host */
|
||||
case OD_LHOST:
|
||||
if (od_confignext(config, OD_LSTRING, &tk) == -1)
|
||||
return -1;
|
||||
server->host = tk->v.string;
|
||||
continue;
|
||||
/* port */
|
||||
case OD_LPORT:
|
||||
if (od_confignext(config, OD_LNUMBER, &tk) == -1)
|
||||
return -1;
|
||||
server->port = tk->v.num;
|
||||
continue;
|
||||
/* tls_mode */
|
||||
case OD_LTLS_MODE:
|
||||
if (od_confignext(config, OD_LSTRING, &tk) == -1)
|
||||
return -1;
|
||||
server->tls_mode = tk->v.string;
|
||||
continue;
|
||||
/* tls_ca_file */
|
||||
case OD_LTLS_CA_FILE:
|
||||
if (od_confignext(config, OD_LSTRING, &tk) == -1)
|
||||
return -1;
|
||||
server->tls_ca_file = tk->v.string;
|
||||
continue;
|
||||
/* tls_key_file */
|
||||
case OD_LTLS_KEY_FILE:
|
||||
if (od_confignext(config, OD_LSTRING, &tk) == -1)
|
||||
return -1;
|
||||
server->tls_key_file = tk->v.string;
|
||||
continue;
|
||||
/* tls_cert_file */
|
||||
case OD_LTLS_CERT_FILE:
|
||||
if (od_confignext(config, OD_LSTRING, &tk) == -1)
|
||||
return -1;
|
||||
server->tls_cert_file = tk->v.string;
|
||||
continue;
|
||||
/* tls_protocols */
|
||||
case OD_LTLS_PROTOCOLS:
|
||||
if (od_confignext(config, OD_LSTRING, &tk) == -1)
|
||||
return -1;
|
||||
server->tls_protocols = tk->v.string;
|
||||
continue;
|
||||
case OD_LEOF:
|
||||
od_configerror(config, tk, "unexpected end of config file");
|
||||
return -1;
|
||||
case '}':
|
||||
eof = 1;
|
||||
continue;
|
||||
default:
|
||||
od_configerror(config, tk, "unknown option");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
od_configparse_route(od_config_t *config, od_token_t *name)
|
||||
{
|
||||
od_schemeroute_t *route =
|
||||
od_schemeroute_add(config->scheme);
|
||||
if (route == NULL)
|
||||
return -1;
|
||||
if (name == NULL) {
|
||||
route->is_default = 1;
|
||||
route->target = "";
|
||||
} else {
|
||||
route->target = name->v.string;
|
||||
}
|
||||
if (od_confignext(config, '{', NULL) == -1)
|
||||
return -1;
|
||||
od_token_t *tk;
|
||||
int rc;
|
||||
int eof = 0;
|
||||
while (! eof)
|
||||
{
|
||||
rc = od_lexpop(&config->lex, &tk);
|
||||
switch (rc) {
|
||||
/* server */
|
||||
case OD_LSERVER:
|
||||
if (od_confignext(config, OD_LSTRING, &tk) == -1)
|
||||
return -1;
|
||||
route->route = tk->v.string;
|
||||
continue;
|
||||
/* client_max */
|
||||
case OD_LCLIENT_MAX:
|
||||
if (od_confignext(config, OD_LNUMBER, &tk) == -1)
|
||||
return -1;
|
||||
route->client_max = tk->v.num;
|
||||
continue;
|
||||
/* pool_size */
|
||||
case OD_LPOOL_SIZE:
|
||||
if (od_confignext(config, OD_LNUMBER, &tk) == -1)
|
||||
return -1;
|
||||
route->pool_size = tk->v.num;
|
||||
continue;
|
||||
/* pool_timeout */
|
||||
case OD_LPOOL_TIMEOUT:
|
||||
if (od_confignext(config, OD_LNUMBER, &tk) == -1)
|
||||
return -1;
|
||||
route->pool_timeout = tk->v.num;
|
||||
continue;
|
||||
/* database */
|
||||
case OD_LDATABASE:
|
||||
if (od_confignext(config, OD_LSTRING, &tk) == -1)
|
||||
return -1;
|
||||
route->database = tk->v.string;
|
||||
continue;
|
||||
/* user */
|
||||
case OD_LUSER:
|
||||
if (od_confignext(config, OD_LSTRING, &tk) == -1)
|
||||
return -1;
|
||||
route->user = tk->v.string;
|
||||
route->user_len = strlen(route->user);
|
||||
continue;
|
||||
/* password */
|
||||
case OD_LPASSWORD:
|
||||
if (od_confignext(config, OD_LSTRING, &tk) == -1)
|
||||
return -1;
|
||||
route->password = tk->v.string;
|
||||
route->password_len = strlen(route->password);
|
||||
continue;
|
||||
/* ttl */
|
||||
case OD_LTTL:
|
||||
if (od_confignext(config, OD_LNUMBER, &tk) == -1)
|
||||
return -1;
|
||||
route->ttl = tk->v.num;
|
||||
continue;
|
||||
/* cancel */
|
||||
case OD_LCANCEL:
|
||||
rc = od_confignext_yes_no(config, &tk);
|
||||
if (rc == -1)
|
||||
return -1;
|
||||
route->cancel = rc;
|
||||
continue;
|
||||
/* discard */
|
||||
case OD_LDISCARD:
|
||||
rc = od_confignext_yes_no(config, &tk);
|
||||
if (rc == -1)
|
||||
return -1;
|
||||
route->discard = rc;
|
||||
continue;
|
||||
/* rollback */
|
||||
case OD_LROLLBACK:
|
||||
rc = od_confignext_yes_no(config, &tk);
|
||||
if (rc == -1)
|
||||
return -1;
|
||||
route->rollback = rc;
|
||||
continue;
|
||||
case OD_LEOF:
|
||||
od_configerror(config, tk, "unexpected end of config file");
|
||||
return -1;
|
||||
case '}':
|
||||
eof = 1;
|
||||
continue;
|
||||
default:
|
||||
od_configerror(config, tk, "unknown option");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
od_configparse_routing(od_config_t *config)
|
||||
{
|
||||
if (od_confignext(config, '{', NULL) == -1)
|
||||
return -1;
|
||||
od_token_t *tk;
|
||||
int rc;
|
||||
int eof = 0;
|
||||
while (! eof)
|
||||
{
|
||||
rc = od_lexpop(&config->lex, &tk);
|
||||
switch (rc) {
|
||||
/* mode */
|
||||
case OD_LMODE:
|
||||
if (od_confignext(config, OD_LSTRING, &tk) == -1)
|
||||
return -1;
|
||||
config->scheme->routing = tk->v.string;
|
||||
continue;
|
||||
/* route (database name) */
|
||||
case OD_LSTRING:
|
||||
rc = od_configparse_route(config, tk);
|
||||
if (rc == -1)
|
||||
return -1;
|
||||
break;
|
||||
/* route default */
|
||||
case OD_LDEFAULT:
|
||||
rc = od_configparse_route(config, NULL);
|
||||
if (rc == -1)
|
||||
return -1;
|
||||
break;
|
||||
case OD_LEOF:
|
||||
od_configerror(config, tk, "unexpected end of config file");
|
||||
return -1;
|
||||
case '}':
|
||||
eof = 1;
|
||||
continue;
|
||||
default:
|
||||
od_configerror(config, tk, "unknown option");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
od_configparse_user(od_config_t *config, od_token_t *name)
|
||||
{
|
||||
od_schemeuser_t *user =
|
||||
od_schemeuser_add(config->scheme);
|
||||
if (user == NULL)
|
||||
return -1;
|
||||
if (name == NULL) {
|
||||
user->is_default = 1;
|
||||
user->user = "";
|
||||
} else {
|
||||
user->user = name->v.string;
|
||||
}
|
||||
if (od_confignext(config, '{', NULL) == -1)
|
||||
return -1;
|
||||
od_token_t *tk;
|
||||
int rc;
|
||||
int eof = 0;
|
||||
while (! eof)
|
||||
{
|
||||
rc = od_lexpop(&config->lex, &tk);
|
||||
switch (rc) {
|
||||
/* authentication */
|
||||
case OD_LAUTHENTICATION:
|
||||
if (od_confignext(config, OD_LSTRING, &tk) == -1)
|
||||
return -1;
|
||||
user->auth = tk->v.string;
|
||||
break;
|
||||
/* password */
|
||||
case OD_LPASSWORD:
|
||||
if (od_confignext(config, OD_LSTRING, &tk) == -1)
|
||||
return -1;
|
||||
user->password = tk->v.string;
|
||||
user->password_len = strlen(user->password);
|
||||
continue;
|
||||
/* deny */
|
||||
case OD_LDENY:
|
||||
user->is_deny = 1;
|
||||
continue;
|
||||
case OD_LEOF:
|
||||
od_configerror(config, tk, "unexpected end of config file");
|
||||
return -1;
|
||||
case '}':
|
||||
eof = 1;
|
||||
continue;
|
||||
default:
|
||||
od_configerror(config, tk, "unknown option");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
od_configparse_users(od_config_t *config)
|
||||
{
|
||||
if (od_confignext(config, '{', NULL) == -1)
|
||||
return -1;
|
||||
od_token_t *tk;
|
||||
int rc;
|
||||
int eof = 0;
|
||||
while (! eof)
|
||||
{
|
||||
rc = od_lexpop(&config->lex, &tk);
|
||||
switch (rc) {
|
||||
/* user */
|
||||
case OD_LSTRING:
|
||||
rc = od_configparse_user(config, tk);
|
||||
if (rc == -1)
|
||||
return -1;
|
||||
break;
|
||||
/* user default */
|
||||
case OD_LDEFAULT:
|
||||
rc = od_configparse_user(config, NULL);
|
||||
if (rc == -1)
|
||||
return -1;
|
||||
break;
|
||||
case OD_LEOF:
|
||||
od_configerror(config, tk, "unexpected end of config file");
|
||||
return -1;
|
||||
case '}':
|
||||
eof = 1;
|
||||
continue;
|
||||
default:
|
||||
od_configerror(config, tk, "unknown option");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
od_configparse(od_config_t *config)
|
||||
{
|
||||
od_token_t *tk;
|
||||
if (od_confignext(config, OD_LODISSEY, NULL) == -1)
|
||||
return -1;
|
||||
if (od_confignext(config, '{', NULL) == -1)
|
||||
return -1;
|
||||
int rc;
|
||||
int eof = 0;
|
||||
while (! eof)
|
||||
{
|
||||
rc = od_lexpop(&config->lex, &tk);
|
||||
switch (rc) {
|
||||
/* daemonize */
|
||||
case OD_LDAEMONIZE:
|
||||
rc = od_confignext_yes_no(config, &tk);
|
||||
if (rc == -1)
|
||||
return -1;
|
||||
config->scheme->daemonize = rc;
|
||||
continue;
|
||||
/* log_verbosity */
|
||||
case OD_LLOG_VERBOSITY:
|
||||
if (od_confignext(config, OD_LNUMBER, &tk) == -1)
|
||||
return -1;
|
||||
config->scheme->log_verbosity = tk->v.num;
|
||||
continue;
|
||||
/* log_file */
|
||||
case OD_LLOG_FILE:
|
||||
if (od_confignext(config, OD_LSTRING, &tk) == -1)
|
||||
return -1;
|
||||
config->scheme->log_file = tk->v.string;
|
||||
continue;
|
||||
/* pid_file */
|
||||
case OD_LPID_FILE:
|
||||
if (od_confignext(config, OD_LSTRING, &tk) == -1)
|
||||
return -1;
|
||||
config->scheme->pid_file = tk->v.string;
|
||||
continue;
|
||||
/* syslog */
|
||||
case OD_LSYSLOG:
|
||||
rc = od_confignext_yes_no(config, &tk);
|
||||
if (rc == -1)
|
||||
return -1;
|
||||
config->scheme->syslog = rc;
|
||||
continue;
|
||||
/* syslog_ident */
|
||||
case OD_LSYSLOG_IDENT:
|
||||
if (od_confignext(config, OD_LSTRING, &tk) == -1)
|
||||
return -1;
|
||||
config->scheme->syslog_ident = tk->v.string;
|
||||
continue;
|
||||
/* syslog_facility */
|
||||
case OD_LSYSLOG_FACILITY:
|
||||
if (od_confignext(config, OD_LSTRING, &tk) == -1)
|
||||
return -1;
|
||||
config->scheme->syslog_facility = tk->v.string;
|
||||
continue;
|
||||
/* stats_period */
|
||||
case OD_LSTATS_PERIOD:
|
||||
if (od_confignext(config, OD_LNUMBER, &tk) == -1)
|
||||
return -1;
|
||||
config->scheme->stats_period = tk->v.num;
|
||||
continue;
|
||||
/* pooling */
|
||||
case OD_LPOOLING:
|
||||
if (od_confignext(config, OD_LSTRING, &tk) == -1)
|
||||
return -1;
|
||||
config->scheme->pooling = tk->v.string;
|
||||
continue;
|
||||
/* listen */
|
||||
case OD_LLISTEN:
|
||||
rc = od_configparse_listen(config);
|
||||
if (rc == -1)
|
||||
return -1;
|
||||
continue;
|
||||
/* server */
|
||||
case OD_LSERVER:
|
||||
rc = od_configparse_server(config);
|
||||
if (rc == -1)
|
||||
return -1;
|
||||
continue;
|
||||
/* routing */
|
||||
case OD_LROUTING:
|
||||
rc = od_configparse_routing(config);
|
||||
if (rc == -1)
|
||||
return -1;
|
||||
continue;
|
||||
/* users */
|
||||
case OD_LUSERS:
|
||||
rc = od_configparse_users(config);
|
||||
if (rc == -1)
|
||||
return -1;
|
||||
continue;
|
||||
case OD_LEOF:
|
||||
od_configerror(config, tk, "unexpected end of config file");
|
||||
return -1;
|
||||
case '}':
|
||||
eof = 1;
|
||||
continue;
|
||||
default:
|
||||
od_configerror(config, tk, "unknown option");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
#ifndef OD_CONFIG_H
|
||||
#define OD_CONFIG_H
|
||||
|
||||
/*
|
||||
* odissey.
|
||||
*
|
||||
* PostgreSQL connection pooler and request router.
|
||||
*/
|
||||
|
||||
enum
|
||||
{
|
||||
OD_LODISSEY = OD_LCUSTOM,
|
||||
OD_LYES,
|
||||
OD_LNO,
|
||||
OD_LON,
|
||||
OD_LOFF,
|
||||
OD_LDAEMONIZE,
|
||||
OD_LLOG_VERBOSITY,
|
||||
OD_LLOG_FILE,
|
||||
OD_LPID_FILE,
|
||||
OD_LSYSLOG,
|
||||
OD_LSYSLOG_IDENT,
|
||||
OD_LSYSLOG_FACILITY,
|
||||
OD_LSTATS_PERIOD,
|
||||
OD_LPOOLING,
|
||||
OD_LLISTEN,
|
||||
OD_LHOST,
|
||||
OD_LPORT,
|
||||
OD_LBACKLOG,
|
||||
OD_LNODELAY,
|
||||
OD_LKEEPALIVE,
|
||||
OD_LREADAHEAD,
|
||||
OD_LWORKERS,
|
||||
OD_LCLIENT_MAX,
|
||||
OD_LTLS_MODE,
|
||||
OD_LTLS_CA_FILE,
|
||||
OD_LTLS_KEY_FILE,
|
||||
OD_LTLS_CERT_FILE,
|
||||
OD_LTLS_PROTOCOLS,
|
||||
OD_LSERVER,
|
||||
OD_LROUTING,
|
||||
OD_LDEFAULT,
|
||||
OD_LMODE,
|
||||
OD_LDATABASE,
|
||||
OD_LUSER,
|
||||
OD_LPASSWORD,
|
||||
OD_LTTL,
|
||||
OD_LCANCEL,
|
||||
OD_LDISCARD,
|
||||
OD_LROLLBACK,
|
||||
OD_LPOOL_SIZE,
|
||||
OD_LPOOL_TIMEOUT,
|
||||
OD_LAUTHENTICATION,
|
||||
OD_LUSERS,
|
||||
OD_LDENY
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
od_lex_t lex;
|
||||
od_log_t *log;
|
||||
od_scheme_t *scheme;
|
||||
} od_config_t;
|
||||
|
||||
void od_configinit(od_config_t*, od_log_t*, od_scheme_t*);
|
||||
int od_configopen(od_config_t*, char*);
|
||||
void od_configclose(od_config_t*);
|
||||
int od_configparse(od_config_t*);
|
||||
|
||||
#endif /* OD_CONFIG_H */
|
|
@ -0,0 +1,45 @@
|
|||
|
||||
/*
|
||||
* odissey.
|
||||
*
|
||||
* PostgreSQL connection pooler and request router.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <machinarium.h>
|
||||
#include <soprano.h>
|
||||
|
||||
#include "od_macro.h"
|
||||
#include "od_daemon.h"
|
||||
|
||||
int od_daemonize(void)
|
||||
{
|
||||
pid_t pid = fork();
|
||||
if (pid < 0)
|
||||
return -1;
|
||||
if (pid > 0) {
|
||||
/* shutdown parent */
|
||||
_exit(0);
|
||||
}
|
||||
setsid();
|
||||
int fd;
|
||||
fd = open("/dev/null", O_RDWR);
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
dup2(fd, 0);
|
||||
dup2(fd, 1);
|
||||
dup2(fd, 2);
|
||||
if (fd > 2)
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
#ifndef OD_DAEMON_H
|
||||
#define OD_DAEMON_H
|
||||
|
||||
/*
|
||||
* odissey.
|
||||
*
|
||||
* PostgreSQL connection pooler and request router.
|
||||
*/
|
||||
|
||||
int od_daemonize(void);
|
||||
|
||||
#endif /* OD_DAEMON_H */
|
|
@ -0,0 +1,273 @@
|
|||
|
||||
/*
|
||||
* odissey.
|
||||
*
|
||||
* PostgreSQL connection pooler and request router.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "od_macro.h"
|
||||
#include "od_list.h"
|
||||
#include "od_lex.h"
|
||||
|
||||
void od_lexinit(od_lex_t *lex)
|
||||
{
|
||||
memset(lex, 0, sizeof(*lex));
|
||||
od_listinit(&lex->stack);
|
||||
od_listinit(&lex->list);
|
||||
}
|
||||
|
||||
void od_lexopen(od_lex_t *lex, od_keyword_t *list, char *buf, int size)
|
||||
{
|
||||
lex->buf = buf;
|
||||
lex->size = size;
|
||||
lex->keywords = list;
|
||||
}
|
||||
|
||||
void od_lexfree(od_lex_t *lex)
|
||||
{
|
||||
od_list_t *i, *n;
|
||||
od_listforeach_safe(&lex->list, i, n) {
|
||||
od_token_t *tk = od_container_of(i, od_token_t, link_alloc);
|
||||
if (tk->id == OD_LSTRING ||
|
||||
tk->id == OD_LID) {
|
||||
free(tk->v.string);
|
||||
}
|
||||
free(tk);
|
||||
}
|
||||
if (lex->buf)
|
||||
free(lex->buf);
|
||||
if (lex->error)
|
||||
free(lex->error);
|
||||
}
|
||||
|
||||
char *od_lexname_of(od_lex_t *lex, int id)
|
||||
{
|
||||
switch (id) {
|
||||
case OD_LEOF: return "eof";
|
||||
case OD_LERROR: return "error";
|
||||
case OD_LNUMBER: return "number";
|
||||
case OD_LSTRING: return "string";
|
||||
case OD_LID: return "name";
|
||||
case OD_LPUNCT: return "punctuation";
|
||||
}
|
||||
int i;
|
||||
for (i = 0 ; lex->keywords[i].name ; i++)
|
||||
if (lex->keywords[i].id == id)
|
||||
return lex->keywords[i].name;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void od_lexpush(od_lex_t *lex, od_token_t *tk)
|
||||
{
|
||||
od_listpush(&lex->stack, &tk->link);
|
||||
lex->count++;
|
||||
}
|
||||
|
||||
static int
|
||||
od_lexerror(od_lex_t *lex, const char *fmt, ...)
|
||||
{
|
||||
if (fmt == NULL)
|
||||
return OD_LEOF;
|
||||
if (lex->error)
|
||||
free(lex->error);
|
||||
char msg[256];
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
vsnprintf(msg, sizeof(msg), fmt, args);
|
||||
va_end(args);
|
||||
lex->error = strdup(msg);
|
||||
return OD_LERROR;
|
||||
}
|
||||
|
||||
static inline od_token_t*
|
||||
od_lexalloc(od_lex_t *lex, int id, int line)
|
||||
{
|
||||
od_token_t *tk = malloc(sizeof(od_token_t));
|
||||
if (tk == NULL)
|
||||
return NULL;
|
||||
memset(tk, 0, sizeof(*tk));
|
||||
tk->id = id;
|
||||
tk->line = line;
|
||||
od_listinit(&tk->link);
|
||||
od_listinit(&tk->link_alloc);
|
||||
od_listappend(&lex->list, &tk->link_alloc);
|
||||
return tk;
|
||||
}
|
||||
|
||||
static inline int
|
||||
od_lexnext(od_lex_t *lex) {
|
||||
if (lex->pos == lex->size)
|
||||
return 0;
|
||||
lex->pos++;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline uint8_t
|
||||
od_lexchar(od_lex_t *lex) {
|
||||
return *(lex->buf + lex->pos);
|
||||
}
|
||||
|
||||
static inline od_token_t*
|
||||
od_lexpop_stack(od_lex_t *lex)
|
||||
{
|
||||
if (lex->count == 0)
|
||||
return NULL;
|
||||
od_token_t *tk = od_container_of(lex->stack.next, od_token_t, link);
|
||||
od_listunlink(&tk->link);
|
||||
lex->count--;
|
||||
return tk;
|
||||
}
|
||||
|
||||
int od_lexpop(od_lex_t *lex, od_token_t **result)
|
||||
{
|
||||
/* stack first */
|
||||
if (lex->count) {
|
||||
*result = od_lexpop_stack(lex);
|
||||
if ((*result)->id == OD_LPUNCT)
|
||||
return (*result)->v.num;
|
||||
return (*result)->id;
|
||||
}
|
||||
|
||||
/* skip white-spaces and comments */
|
||||
unsigned char ch;
|
||||
while (1) {
|
||||
if (lex->pos == lex->size) {
|
||||
*result = od_lexalloc(lex, OD_LEOF, lex->line);
|
||||
if (*result == NULL)
|
||||
return od_lexerror(lex, "memory allocation error");
|
||||
return OD_LEOF;
|
||||
}
|
||||
ch = od_lexchar(lex);
|
||||
if (isspace(ch)) {
|
||||
if (ch == '\n') {
|
||||
if (((lex->pos + 1) != lex->size))
|
||||
lex->line++;
|
||||
}
|
||||
od_lexnext(lex);
|
||||
continue;
|
||||
}
|
||||
if (ch == '#') {
|
||||
while (1) {
|
||||
if (lex->pos == lex->size) {
|
||||
*result = od_lexalloc(lex, OD_LEOF, lex->line);
|
||||
if (*result == NULL)
|
||||
return od_lexerror(lex, "memory allocation error");
|
||||
return OD_LEOF;
|
||||
}
|
||||
od_lexnext(lex);
|
||||
ch = od_lexchar(lex);
|
||||
if (ch == '\n') {
|
||||
if (((lex->pos + 1) != lex->size))
|
||||
lex->line++;
|
||||
od_lexnext(lex);
|
||||
break;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* token position */
|
||||
int line = lex->line;
|
||||
int start = lex->pos;
|
||||
int size = 0;
|
||||
|
||||
/* string */
|
||||
ch = od_lexchar(lex);
|
||||
if (ch == '\"') {
|
||||
start++;
|
||||
while (1) {
|
||||
if (od_lexnext(lex) == 0)
|
||||
return od_lexerror(lex, "bad string definition");
|
||||
ch = od_lexchar(lex);
|
||||
if (ch == '\"')
|
||||
break;
|
||||
if (ch == '\n')
|
||||
return od_lexerror(lex, "bad string definition");
|
||||
}
|
||||
size = lex->pos - start;
|
||||
od_lexnext(lex);
|
||||
*result = od_lexalloc(lex, OD_LSTRING, line);
|
||||
if (*result == NULL)
|
||||
return od_lexerror(lex, "memory allocation error");
|
||||
od_token_t *tk = *result;
|
||||
tk->v.string = malloc(size + 1);
|
||||
if (tk->v.string == NULL)
|
||||
return od_lexerror(lex, "memory allocation error");
|
||||
memcpy(tk->v.string, lex->buf + start, size);
|
||||
tk->v.string[size] = 0;
|
||||
return OD_LSTRING;
|
||||
}
|
||||
|
||||
/* punctuation */
|
||||
if (ispunct(ch) && ch != '_') {
|
||||
od_lexnext(lex);
|
||||
*result = od_lexalloc(lex, OD_LPUNCT, line);
|
||||
if (*result == NULL)
|
||||
return od_lexerror(lex, "memory allocation error");
|
||||
(*result)->v.num = ch;
|
||||
return ch;
|
||||
}
|
||||
|
||||
/* numeric value */
|
||||
if (isdigit(ch)) {
|
||||
int64_t num = 0;
|
||||
while (1) {
|
||||
ch = od_lexchar(lex);
|
||||
if (isdigit(ch))
|
||||
num = (num * 10) + ch - '0';
|
||||
else
|
||||
break;
|
||||
if (od_lexnext(lex) == 0)
|
||||
break;
|
||||
}
|
||||
*result = od_lexalloc(lex, OD_LNUMBER, line);
|
||||
if (*result == NULL)
|
||||
return od_lexerror(lex, "memory allocation error");
|
||||
(*result)->v.num = num;
|
||||
return OD_LNUMBER;
|
||||
}
|
||||
|
||||
/* skip to the end of lexem */
|
||||
while (1) {
|
||||
ch = od_lexchar(lex);
|
||||
if (isspace(ch) || (ispunct(ch) && ch != '_'))
|
||||
break;
|
||||
if (od_lexnext(lex) == 0)
|
||||
break;
|
||||
}
|
||||
size = lex->pos - start;
|
||||
|
||||
/* match keyword */
|
||||
int i = 0;
|
||||
for ( ; lex->keywords[i].name ; i++) {
|
||||
if (lex->keywords[i].size != size)
|
||||
continue;
|
||||
if (strncasecmp(lex->keywords[i].name, lex->buf + start, size) == 0) {
|
||||
*result = od_lexalloc(lex, lex->keywords[i].id, line);
|
||||
if (*result == NULL)
|
||||
return od_lexerror(lex, "memory allocation error");
|
||||
return lex->keywords[i].id;
|
||||
}
|
||||
}
|
||||
|
||||
/* identification */
|
||||
*result = od_lexalloc(lex, OD_LID, line);
|
||||
if (*result == NULL)
|
||||
return od_lexerror(lex, "memory allocation error");
|
||||
od_token_t *tk = *result;
|
||||
tk->v.string = malloc(size + 1);
|
||||
if (tk->v.string == NULL)
|
||||
return od_lexerror(lex, "memory allocation error");
|
||||
memcpy(tk->v.string, lex->buf + start, size);
|
||||
tk->v.string[size] = 0;
|
||||
return OD_LID;
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
#ifndef OD_LEX_H
|
||||
#define OD_LEX_H
|
||||
|
||||
/*
|
||||
* odissey.
|
||||
*
|
||||
* PostgreSQL connection pooler and request router.
|
||||
*/
|
||||
|
||||
typedef struct od_keyword od_keyword_t;
|
||||
typedef struct od_token od_token_t;
|
||||
typedef struct od_lex od_lex_t;
|
||||
|
||||
enum
|
||||
{
|
||||
OD_LERROR = -1,
|
||||
OD_LEOF = 0,
|
||||
OD_LNUMBER = 1000,
|
||||
OD_LPUNCT,
|
||||
OD_LID,
|
||||
OD_LSTRING,
|
||||
OD_LCUSTOM
|
||||
};
|
||||
|
||||
struct od_keyword
|
||||
{
|
||||
char *name;
|
||||
int size;
|
||||
int id;
|
||||
};
|
||||
|
||||
struct od_token
|
||||
{
|
||||
int id;
|
||||
union {
|
||||
uint64_t num;
|
||||
char *string;
|
||||
} v;
|
||||
int line;
|
||||
od_list_t link_alloc;
|
||||
od_list_t link;
|
||||
};
|
||||
|
||||
struct od_lex
|
||||
{
|
||||
char *buf;
|
||||
int size;
|
||||
int pos;
|
||||
int line;
|
||||
od_keyword_t *keywords;
|
||||
int count;
|
||||
od_list_t stack;
|
||||
od_list_t list;
|
||||
char *error;
|
||||
};
|
||||
|
||||
void od_lexinit(od_lex_t*);
|
||||
void od_lexopen(od_lex_t*, od_keyword_t*, char*, int);
|
||||
void od_lexfree(od_lex_t*);
|
||||
char *od_lexname_of(od_lex_t*, int);
|
||||
void od_lexpush(od_lex_t*, od_token_t*);
|
||||
int od_lexpop(od_lex_t*, od_token_t**);
|
||||
|
||||
#endif /* OD_LEX_H */
|
|
@ -0,0 +1,68 @@
|
|||
#ifndef OD_LIST_H
|
||||
#define OD_LIST_H
|
||||
|
||||
/*
|
||||
* odissey.
|
||||
*
|
||||
* PostgreSQL connection pooler and request router.
|
||||
*/
|
||||
|
||||
typedef struct od_list od_list_t;
|
||||
|
||||
struct od_list
|
||||
{
|
||||
od_list_t *next, *prev;
|
||||
};
|
||||
|
||||
static inline void
|
||||
od_listinit(od_list_t *list)
|
||||
{
|
||||
list->next = list->prev = list;
|
||||
}
|
||||
|
||||
static inline void
|
||||
od_listappend(od_list_t *list, od_list_t *node)
|
||||
{
|
||||
node->next = list;
|
||||
node->prev = list->prev;
|
||||
node->prev->next = node;
|
||||
node->next->prev = node;
|
||||
}
|
||||
|
||||
static inline void
|
||||
od_listunlink(od_list_t *node)
|
||||
{
|
||||
node->prev->next = node->next;
|
||||
node->next->prev = node->prev;
|
||||
}
|
||||
|
||||
static inline void
|
||||
od_listpush(od_list_t *list, od_list_t *node)
|
||||
{
|
||||
node->next = list->next;
|
||||
node->prev = list;
|
||||
node->prev->next = node;
|
||||
node->next->prev = node;
|
||||
}
|
||||
|
||||
static inline od_list_t*
|
||||
od_listpop(od_list_t *list)
|
||||
{
|
||||
register od_list_t *pop = list->next;
|
||||
od_listunlink(pop);
|
||||
return pop;
|
||||
}
|
||||
|
||||
static inline int
|
||||
od_listempty(od_list_t *list)
|
||||
{
|
||||
return list->next == list && list->prev == list;
|
||||
}
|
||||
|
||||
#define od_listforeach(LIST, I) \
|
||||
for (I = (LIST)->next; I != LIST; I = (I)->next)
|
||||
|
||||
#define od_listforeach_safe(LIST, I, N) \
|
||||
for (I = (LIST)->next; I != LIST && (N = I->next); I = N)
|
||||
|
||||
#endif /* OD_LIST_H */
|
|
@ -0,0 +1,91 @@
|
|||
|
||||
/*
|
||||
* odissey.
|
||||
*
|
||||
* PostgreSQL connection pooler and request router.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include <machinarium.h>
|
||||
#include <soprano.h>
|
||||
|
||||
#include "od_macro.h"
|
||||
#include "od_pid.h"
|
||||
#include "od_syslog.h"
|
||||
#include "od_log.h"
|
||||
/*#include "od_io.h"*/
|
||||
|
||||
int od_loginit(od_log_t *l, od_pid_t *pid, od_syslog_t *syslog)
|
||||
{
|
||||
l->verbosity = 0;
|
||||
l->pid = pid;
|
||||
l->syslog = syslog;
|
||||
l->fd = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int od_logopen(od_log_t *l, char *path)
|
||||
{
|
||||
int rc = open(path, O_RDWR|O_CREAT|O_APPEND, 0644);
|
||||
if (rc == -1)
|
||||
return -1;
|
||||
l->fd = rc;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int od_logclose(od_log_t *l)
|
||||
{
|
||||
if (l->fd == -1)
|
||||
return 0;
|
||||
int rc = close(l->fd);
|
||||
l->fd = -1;
|
||||
return rc;
|
||||
}
|
||||
|
||||
int od_logv(od_log_t *l, od_syslogprio_t prio,
|
||||
machine_io_t peer,
|
||||
char *ident,
|
||||
char *fmt, va_list args)
|
||||
{
|
||||
char buffer[512];
|
||||
/* pid */
|
||||
int len = snprintf(buffer, sizeof(buffer), "%d ", l->pid->pid);
|
||||
/* time */
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
len += strftime(buffer + len, sizeof(buffer) - len, "%d %b %H:%M:%S.",
|
||||
localtime(&tv.tv_sec));
|
||||
len += snprintf(buffer + len, sizeof(buffer) - len, "%03d ",
|
||||
(int)tv.tv_usec / 1000);
|
||||
/* message ident */
|
||||
if (ident)
|
||||
len += snprintf(buffer + len, sizeof(buffer) - len, "%s ", ident);
|
||||
/* peer */
|
||||
// XXX
|
||||
(void)peer;
|
||||
/*
|
||||
if (peer) {
|
||||
char *peer_name = od_getpeername(peer);
|
||||
len += snprintf(buffer + len, sizeof(buffer) - len, "%s ", peer_name);
|
||||
}
|
||||
*/
|
||||
/* message */
|
||||
len += vsnprintf(buffer + len, sizeof(buffer) - len, fmt, args);
|
||||
va_end(args);
|
||||
len += snprintf(buffer + len, sizeof(buffer), "\n");
|
||||
int rc = write(l->fd, buffer, len);
|
||||
od_syslog(l->syslog, prio, buffer);
|
||||
return rc > 0;
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
#ifndef OD_LOG_H
|
||||
#define OD_LOG_H
|
||||
|
||||
/*
|
||||
* odissey.
|
||||
*
|
||||
* PostgreSQL connection pooler and request router.
|
||||
*/
|
||||
|
||||
typedef struct od_log od_log_t;
|
||||
|
||||
struct od_log
|
||||
{
|
||||
int fd;
|
||||
int verbosity;
|
||||
od_pid_t *pid;
|
||||
od_syslog_t *syslog;
|
||||
};
|
||||
|
||||
int od_loginit(od_log_t*, od_pid_t*, od_syslog_t*);
|
||||
int od_logopen(od_log_t*, char*);
|
||||
int od_logclose(od_log_t*);
|
||||
int od_logv(od_log_t*, od_syslogprio_t, machine_io_t, char*, char*, va_list);
|
||||
|
||||
static inline void
|
||||
od_logset_verbosity(od_log_t *l, int level) {
|
||||
l->verbosity = level;
|
||||
}
|
||||
|
||||
static inline int
|
||||
od_log(od_log_t *l, machine_io_t peer, char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
int rc = od_logv(l, OD_SYSLOG_INFO, peer, NULL, fmt, args);
|
||||
va_end(args);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static inline int
|
||||
od_debug(od_log_t *l, machine_io_t peer, char *fmt, ...)
|
||||
{
|
||||
if (l->verbosity < 2)
|
||||
return 0;
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
int rc = od_logv(l, OD_SYSLOG_DEBUG, peer, "debug:", fmt, args);
|
||||
va_end(args);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static inline int
|
||||
od_error(od_log_t *l, machine_io_t peer, char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
int rc = od_logv(l, OD_SYSLOG_ERROR, peer, "error:", fmt, args);
|
||||
va_end(args);
|
||||
return rc;
|
||||
}
|
||||
|
||||
#endif /* OD_LOG_H */
|
|
@ -0,0 +1,16 @@
|
|||
#ifndef OD_MACRO_H
|
||||
#define OD_MACRO_H
|
||||
|
||||
/*
|
||||
* odissey.
|
||||
*
|
||||
* PostgreSQL connection pooler and request router.
|
||||
*/
|
||||
|
||||
#define od_likely(EXPR) __builtin_expect(!! (EXPR), 1)
|
||||
#define od_unlikely(EXPR) __builtin_expect(!! (EXPR), 0)
|
||||
|
||||
#define od_container_of(N, T, F) \
|
||||
((T*)((char*)(N) - __builtin_offsetof(T, F)))
|
||||
|
||||
#endif /* OD_MACRO_H */
|
|
@ -0,0 +1,52 @@
|
|||
|
||||
/*
|
||||
* odissey.
|
||||
*
|
||||
* PostgreSQL connection pooler and request router.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include "od_macro.h"
|
||||
#include "od_pid.h"
|
||||
|
||||
void od_pidinit(od_pid_t *pid)
|
||||
{
|
||||
pid->pid = getpid();
|
||||
}
|
||||
|
||||
int od_pidfile_create(od_pid_t *pid, char *path)
|
||||
{
|
||||
char buffer[32];
|
||||
int size = snprintf(buffer, sizeof(buffer), "%d\n", pid->pid);
|
||||
int rc;
|
||||
rc = open(path, O_WRONLY|O_CREAT|O_TRUNC, 0644);
|
||||
if (rc == -1)
|
||||
return -1;
|
||||
int fd = rc;
|
||||
rc = write(fd, buffer, size);
|
||||
if (rc != size) {
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
rc = close(fd);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int od_pidfile_unlink(od_pid_t *pid, char *path)
|
||||
{
|
||||
(void)pid;
|
||||
int rc = unlink(path);
|
||||
return rc;
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
#ifndef OD_PID_H
|
||||
#define OD_PID_H
|
||||
|
||||
/*
|
||||
* odissey.
|
||||
*
|
||||
* PostgreSQL connection pooler and request router.
|
||||
*/
|
||||
|
||||
typedef struct od_pid od_pid_t;
|
||||
|
||||
struct od_pid
|
||||
{
|
||||
pid_t pid;
|
||||
};
|
||||
|
||||
void od_pidinit(od_pid_t*);
|
||||
int od_pidfile_create(od_pid_t*, char*);
|
||||
int od_pidfile_unlink(od_pid_t*, char*);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,451 @@
|
|||
|
||||
/*
|
||||
* odissey.
|
||||
*
|
||||
* PostgreSQL connection pooler and request router.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <machinarium.h>
|
||||
|
||||
#include "od_macro.h"
|
||||
#include "od_list.h"
|
||||
#include "od_pid.h"
|
||||
#include "od_syslog.h"
|
||||
#include "od_log.h"
|
||||
#include "od_scheme.h"
|
||||
|
||||
void od_schemeinit(od_scheme_t *scheme)
|
||||
{
|
||||
scheme->config_file = NULL;
|
||||
scheme->daemonize = 0;
|
||||
scheme->log_verbosity = 1;
|
||||
scheme->log_file = NULL;
|
||||
scheme->pid_file = NULL;
|
||||
scheme->syslog = 0;
|
||||
scheme->syslog_ident = NULL;
|
||||
scheme->syslog_facility = NULL;
|
||||
scheme->stats_period = 0;
|
||||
scheme->host = NULL;
|
||||
scheme->port = 6432;
|
||||
scheme->backlog = 128;
|
||||
scheme->nodelay = 1;
|
||||
scheme->keepalive = 7200;
|
||||
scheme->readahead = 8096;
|
||||
scheme->workers = 1;
|
||||
scheme->client_max = 100;
|
||||
scheme->tls_verify = OD_TDISABLE;
|
||||
scheme->tls_mode = NULL;
|
||||
scheme->tls_ca_file = NULL;
|
||||
scheme->tls_key_file = NULL;
|
||||
scheme->tls_cert_file = NULL;
|
||||
scheme->tls_protocols = NULL;
|
||||
scheme->pooling = NULL;
|
||||
scheme->pooling_mode = OD_PUNDEF;
|
||||
scheme->routing = NULL;
|
||||
scheme->routing_mode = OD_RUNDEF;
|
||||
scheme->routing_default = NULL;
|
||||
scheme->server_id = 0;
|
||||
scheme->users_default = NULL;
|
||||
od_listinit(&scheme->servers);
|
||||
od_listinit(&scheme->routing_table);
|
||||
od_listinit(&scheme->users);
|
||||
}
|
||||
|
||||
void od_schemefree(od_scheme_t *scheme)
|
||||
{
|
||||
od_list_t *i, *n;
|
||||
od_listforeach_safe(&scheme->servers, i, n) {
|
||||
od_schemeserver_t *server;
|
||||
server = od_container_of(i, od_schemeserver_t, link);
|
||||
free(server);
|
||||
}
|
||||
od_listforeach_safe(&scheme->routing_table, i, n) {
|
||||
od_schemeroute_t *route;
|
||||
route = od_container_of(i, od_schemeroute_t, link);
|
||||
free(route);
|
||||
}
|
||||
od_listforeach_safe(&scheme->users, i, n) {
|
||||
od_schemeuser_t *user;
|
||||
user = od_container_of(i, od_schemeuser_t, link);
|
||||
free(user);
|
||||
}
|
||||
}
|
||||
|
||||
od_schemeserver_t*
|
||||
od_schemeserver_add(od_scheme_t *scheme)
|
||||
{
|
||||
od_schemeserver_t *s =
|
||||
(od_schemeserver_t*)malloc(sizeof(*s));
|
||||
if (s == NULL)
|
||||
return NULL;
|
||||
memset(s, 0, sizeof(*s));
|
||||
s->id = scheme->server_id++;
|
||||
od_listinit(&s->link);
|
||||
od_listappend(&scheme->servers, &s->link);
|
||||
return s;
|
||||
}
|
||||
|
||||
od_schemeserver_t*
|
||||
od_schemeserver_match(od_scheme_t *scheme, char *name)
|
||||
{
|
||||
od_list_t *i;
|
||||
od_listforeach(&scheme->servers, i) {
|
||||
od_schemeserver_t *server;
|
||||
server = od_container_of(i, od_schemeserver_t, link);
|
||||
if (strcmp(server->name, name) == 0)
|
||||
return server;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
od_schemeroute_t*
|
||||
od_schemeroute_match(od_scheme_t *scheme, char *name)
|
||||
{
|
||||
od_list_t *i;
|
||||
od_listforeach(&scheme->routing_table, i) {
|
||||
od_schemeroute_t *route;
|
||||
route = od_container_of(i, od_schemeroute_t, link);
|
||||
if (strcmp(route->target, name) == 0)
|
||||
return route;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline void
|
||||
od_schemeroute_init(od_schemeroute_t *route)
|
||||
{
|
||||
route->client_max = 100;
|
||||
route->pool_size = 100;
|
||||
route->cancel = 1;
|
||||
route->discard = 1;
|
||||
route->rollback = 1;
|
||||
}
|
||||
|
||||
static inline void
|
||||
od_schemeuser_init(od_schemeuser_t *user)
|
||||
{
|
||||
user->auth_mode = OD_AUNDEF;
|
||||
user->auth = NULL;
|
||||
}
|
||||
|
||||
od_schemeroute_t*
|
||||
od_schemeroute_add(od_scheme_t *scheme)
|
||||
{
|
||||
od_schemeroute_t *r =
|
||||
(od_schemeroute_t*)malloc(sizeof(*r));
|
||||
if (r == NULL)
|
||||
return NULL;
|
||||
memset(r, 0, sizeof(*r));
|
||||
od_schemeroute_init(r);
|
||||
od_listinit(&r->link);
|
||||
od_listappend(&scheme->routing_table, &r->link);
|
||||
return r;
|
||||
}
|
||||
|
||||
od_schemeuser_t*
|
||||
od_schemeuser_add(od_scheme_t *scheme)
|
||||
{
|
||||
od_schemeuser_t *user =
|
||||
(od_schemeuser_t*)malloc(sizeof(*user));
|
||||
if (user == NULL)
|
||||
return NULL;
|
||||
memset(user, 0, sizeof(*user));
|
||||
od_schemeuser_init(user);
|
||||
od_listinit(&user->link);
|
||||
od_listappend(&scheme->users, &user->link);
|
||||
return user;
|
||||
}
|
||||
|
||||
od_schemeuser_t*
|
||||
od_schemeuser_match(od_scheme_t *scheme, char *name)
|
||||
{
|
||||
od_list_t *i;
|
||||
od_listforeach(&scheme->users, i) {
|
||||
od_schemeuser_t *user;
|
||||
user = od_container_of(i, od_schemeuser_t, link);
|
||||
if (strcmp(user->user, name) == 0)
|
||||
return user;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int od_schemevalidate(od_scheme_t *scheme, od_log_t *log)
|
||||
{
|
||||
/* pooling mode */
|
||||
if (scheme->pooling == NULL) {
|
||||
od_error(log, NULL, "pooling mode is not set");
|
||||
return -1;
|
||||
}
|
||||
if (strcmp(scheme->pooling, "session") == 0)
|
||||
scheme->pooling_mode = OD_PSESSION;
|
||||
else
|
||||
if (strcmp(scheme->pooling, "transaction") == 0)
|
||||
scheme->pooling_mode = OD_PTRANSACTION;
|
||||
|
||||
if (scheme->pooling_mode == OD_PUNDEF) {
|
||||
od_error(log, NULL, "unknown pooling mode");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* routing mode */
|
||||
if (scheme->routing == NULL) {
|
||||
od_error(log, NULL, "routing mode is not set");
|
||||
return -1;
|
||||
}
|
||||
if (strcmp(scheme->routing, "forward") == 0)
|
||||
scheme->routing_mode = OD_RFORWARD;
|
||||
|
||||
if (scheme->routing_mode == OD_RUNDEF) {
|
||||
od_error(log, NULL, "unknown routing mode");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* listen */
|
||||
if (scheme->host == NULL)
|
||||
scheme->host = "*";
|
||||
|
||||
/* tls */
|
||||
if (scheme->tls_mode) {
|
||||
if (strcmp(scheme->tls_mode, "disable") == 0) {
|
||||
scheme->tls_verify = OD_TDISABLE;
|
||||
} else
|
||||
if (strcmp(scheme->tls_mode, "allow") == 0) {
|
||||
scheme->tls_verify = OD_TALLOW;
|
||||
} else
|
||||
if (strcmp(scheme->tls_mode, "require") == 0) {
|
||||
scheme->tls_verify = OD_TREQUIRE;
|
||||
} else
|
||||
if (strcmp(scheme->tls_mode, "verify_ca") == 0) {
|
||||
scheme->tls_verify = OD_TVERIFY_CA;
|
||||
} else
|
||||
if (strcmp(scheme->tls_mode, "verify_full") == 0) {
|
||||
scheme->tls_verify = OD_TVERIFY_FULL;
|
||||
} else {
|
||||
od_error(log, NULL, "unknown tls mode");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* servers */
|
||||
if (od_listempty(&scheme->servers)) {
|
||||
od_error(log, NULL, "no servers defined");
|
||||
return -1;
|
||||
}
|
||||
od_list_t *i;
|
||||
od_listforeach(&scheme->servers, i) {
|
||||
od_schemeserver_t *server;
|
||||
server = od_container_of(i, od_schemeserver_t, link);
|
||||
if (server->host == NULL) {
|
||||
od_error(log, NULL, "server '%s': no host is specified",
|
||||
server->name);
|
||||
return -1;
|
||||
}
|
||||
if (server->tls_mode) {
|
||||
if (strcmp(server->tls_mode, "disable") == 0) {
|
||||
server->tls_verify = OD_TDISABLE;
|
||||
} else
|
||||
if (strcmp(server->tls_mode, "allow") == 0) {
|
||||
server->tls_verify = OD_TALLOW;
|
||||
} else
|
||||
if (strcmp(server->tls_mode, "require") == 0) {
|
||||
server->tls_verify = OD_TREQUIRE;
|
||||
} else
|
||||
if (strcmp(server->tls_mode, "verify_ca") == 0) {
|
||||
server->tls_verify = OD_TVERIFY_CA;
|
||||
} else
|
||||
if (strcmp(server->tls_mode, "verify_full") == 0) {
|
||||
server->tls_verify = OD_TVERIFY_FULL;
|
||||
} else {
|
||||
od_error(log, NULL, "unknown server tls mode");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
od_schemeroute_t *default_route = NULL;
|
||||
|
||||
/* routing table */
|
||||
od_listforeach(&scheme->routing_table, i) {
|
||||
od_schemeroute_t *route;
|
||||
route = od_container_of(i, od_schemeroute_t, link);
|
||||
if (route->route == NULL) {
|
||||
od_error(log, NULL, "route '%s': no route server is specified",
|
||||
route->target);
|
||||
return -1;
|
||||
}
|
||||
route->server = od_schemeserver_match(scheme, route->route);
|
||||
if (route->server == NULL) {
|
||||
od_error(log, NULL, "route '%s': no route server '%s' found",
|
||||
route->target);
|
||||
return -1;
|
||||
}
|
||||
if (route->is_default) {
|
||||
if (default_route) {
|
||||
od_error(log, NULL, "more than one default route");
|
||||
return -1;
|
||||
}
|
||||
default_route = route;
|
||||
}
|
||||
}
|
||||
scheme->routing_default = default_route;
|
||||
|
||||
/* users */
|
||||
if (od_listempty(&scheme->users)) {
|
||||
od_error(log, NULL, "no users defined");
|
||||
return -1;
|
||||
}
|
||||
|
||||
od_schemeuser_t *default_user = NULL;
|
||||
|
||||
od_listforeach(&scheme->users, i) {
|
||||
od_schemeuser_t *user;
|
||||
user = od_container_of(i, od_schemeuser_t, link);
|
||||
if (! user->auth) {
|
||||
if (user->is_default)
|
||||
od_error(log, NULL, "default user authentication mode is not defined");
|
||||
else
|
||||
od_error(log, NULL, "user '%s' authentication mode is not defined",
|
||||
user->user);
|
||||
return -1;
|
||||
}
|
||||
if (strcmp(user->auth, "none") == 0) {
|
||||
user->auth_mode = OD_ANONE;
|
||||
} else
|
||||
if (strcmp(user->auth, "clear_text") == 0) {
|
||||
user->auth_mode = OD_ACLEAR_TEXT;
|
||||
if (user->password == NULL) {
|
||||
od_error(log, NULL, "user '%s' password is not set",
|
||||
user->user);
|
||||
return -1;
|
||||
}
|
||||
} else
|
||||
if (strcmp(user->auth, "md5") == 0) {
|
||||
user->auth_mode = OD_AMD5;
|
||||
if (user->password == NULL) {
|
||||
od_error(log, NULL, "user '%s' password is not set",
|
||||
user->user);
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
od_error(log, NULL, "user '%s' has unknown authentication mode",
|
||||
user->user);
|
||||
return -1;
|
||||
}
|
||||
if (user->is_default) {
|
||||
if (default_user) {
|
||||
od_error(log, NULL, "more than one default user");
|
||||
return -1;
|
||||
}
|
||||
default_user = user;
|
||||
}
|
||||
}
|
||||
scheme->users_default = default_user;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void od_schemeprint(od_scheme_t *scheme, od_log_t *log)
|
||||
{
|
||||
od_log(log, NULL, "using configuration file '%s'",
|
||||
scheme->config_file);
|
||||
if (scheme->log_verbosity)
|
||||
od_log(log, NULL, "log_verbosity %d", scheme->log_verbosity);
|
||||
if (scheme->log_file)
|
||||
od_log(log, NULL, "log_file %s", scheme->log_file);
|
||||
if (scheme->pid_file)
|
||||
od_log(log, NULL, "pid_file %s", scheme->pid_file);
|
||||
if (scheme->syslog)
|
||||
od_log(log, NULL, "syslog %d", scheme->syslog);
|
||||
if (scheme->syslog_ident)
|
||||
od_log(log, NULL, "syslog_ident %s", scheme->syslog_ident);
|
||||
if (scheme->syslog_facility)
|
||||
od_log(log, NULL, "syslog_facility %s", scheme->syslog_facility);
|
||||
if (scheme->stats_period)
|
||||
od_log(log, NULL, "stats_period %d", scheme->stats_period);
|
||||
if (scheme->daemonize)
|
||||
od_log(log, NULL, "daemonize %s",
|
||||
scheme->daemonize ? "yes" : "no");
|
||||
od_log(log, NULL, "");
|
||||
od_log(log, NULL, "pooling %s", scheme->pooling);
|
||||
od_log(log, NULL, "");
|
||||
od_log(log, NULL, "listen");
|
||||
od_log(log, NULL, " host %s ", scheme->host);
|
||||
od_log(log, NULL, " port %d", scheme->port);
|
||||
od_log(log, NULL, " backlog %d", scheme->backlog);
|
||||
od_log(log, NULL, " nodelay %d", scheme->nodelay);
|
||||
od_log(log, NULL, " keepalive %d", scheme->keepalive);
|
||||
od_log(log, NULL, " readahead %d", scheme->readahead);
|
||||
if (scheme->tls_mode)
|
||||
od_log(log, NULL, " tls_mode %s", scheme->tls_mode);
|
||||
if (scheme->tls_ca_file)
|
||||
od_log(log, NULL, " tls_ca_file %s", scheme->tls_ca_file);
|
||||
if (scheme->tls_key_file)
|
||||
od_log(log, NULL, " tls_key_file %s", scheme->tls_key_file);
|
||||
if (scheme->tls_cert_file)
|
||||
od_log(log, NULL, " tls_cert_file %s", scheme->tls_cert_file);
|
||||
if (scheme->tls_protocols)
|
||||
od_log(log, NULL, " tls_protocols %s", scheme->tls_protocols);
|
||||
od_log(log, NULL, "");
|
||||
od_log(log, NULL, "servers");
|
||||
od_list_t *i;
|
||||
od_listforeach(&scheme->servers, i) {
|
||||
od_schemeserver_t *server;
|
||||
server = od_container_of(i, od_schemeserver_t, link);
|
||||
od_log(log, NULL, " <%s> %s",
|
||||
server->name ? server->name : "",
|
||||
server->is_default ? "default" : "");
|
||||
od_log(log, NULL, " host %s", server->host);
|
||||
od_log(log, NULL, " port %d", server->port);
|
||||
if (server->tls_mode)
|
||||
od_log(log, NULL, " tls_mode %s", server->tls_mode);
|
||||
if (server->tls_ca_file)
|
||||
od_log(log, NULL, " tls_ca_file %s", server->tls_ca_file);
|
||||
if (server->tls_key_file)
|
||||
od_log(log, NULL, " tls_key_file %s", server->tls_key_file);
|
||||
if (server->tls_cert_file)
|
||||
od_log(log, NULL, " tls_cert_file %s", server->tls_cert_file);
|
||||
if (server->tls_protocols)
|
||||
od_log(log, NULL, " tls_protocols %s", server->tls_protocols);
|
||||
}
|
||||
od_log(log, NULL, "");
|
||||
od_log(log, NULL, "routing");
|
||||
od_log(log, NULL, " mode %s", scheme->routing);
|
||||
od_listforeach(&scheme->routing_table, i) {
|
||||
od_schemeroute_t *route;
|
||||
route = od_container_of(i, od_schemeroute_t, link);
|
||||
od_log(log, NULL, " <%s>", route->target);
|
||||
od_log(log, NULL, " server %s", route->route);
|
||||
if (route->database)
|
||||
od_log(log, NULL, " database %s", route->database);
|
||||
if (route->user)
|
||||
od_log(log, NULL, " user %s", route->user);
|
||||
od_log(log, NULL, " ttl %d", route->ttl);
|
||||
od_log(log, NULL, " cancel %s",
|
||||
route->discard ? "yes" : "no");
|
||||
od_log(log, NULL, " rollback %s",
|
||||
route->discard ? "yes" : "no");
|
||||
od_log(log, NULL, " discard %s",
|
||||
route->discard ? "yes" : "no");
|
||||
od_log(log, NULL, " pool_size %d", route->pool_size);
|
||||
od_log(log, NULL, " pool_timeout %d", route->pool_timeout);
|
||||
}
|
||||
if (! od_listempty(&scheme->users)) {
|
||||
od_log(log, NULL, "");
|
||||
od_log(log, NULL, "users");
|
||||
od_listforeach(&scheme->users, i) {
|
||||
od_schemeuser_t *user;
|
||||
user = od_container_of(i, od_schemeuser_t, link);
|
||||
if (user->is_default)
|
||||
od_log(log, NULL, " default");
|
||||
else
|
||||
od_log(log, NULL, " <%s>", user->user);
|
||||
if (user->is_deny)
|
||||
od_log(log, NULL, " deny");
|
||||
od_log(log, NULL, " authentication %s", user->auth);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,159 @@
|
|||
#ifndef OD_SCHEME_H
|
||||
#define OD_SCHEME_H
|
||||
|
||||
/*
|
||||
* odissey.
|
||||
*
|
||||
* PostgreSQL connection pooler and request router.
|
||||
*/
|
||||
|
||||
typedef struct od_schemeserver od_schemeserver_t;
|
||||
typedef struct od_schemeroute od_schemeroute_t;
|
||||
typedef struct od_schemeuser od_schemeuser_t;
|
||||
typedef struct od_scheme od_scheme_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
OD_PUNDEF,
|
||||
OD_PSESSION,
|
||||
OD_PTRANSACTION
|
||||
} od_pooling_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
OD_RUNDEF,
|
||||
OD_RFORWARD
|
||||
} od_routing_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
OD_AUNDEF,
|
||||
OD_ANONE,
|
||||
OD_ACLEAR_TEXT,
|
||||
OD_AMD5
|
||||
} od_auth_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
OD_TDISABLE,
|
||||
OD_TALLOW,
|
||||
OD_TREQUIRE,
|
||||
OD_TVERIFY_CA,
|
||||
OD_TVERIFY_FULL
|
||||
} od_tls_t;
|
||||
|
||||
struct od_schemeserver
|
||||
{
|
||||
int id;
|
||||
char *name;
|
||||
char *host;
|
||||
int port;
|
||||
od_tls_t tls_verify;
|
||||
char *tls_mode;
|
||||
char *tls_ca_file;
|
||||
char *tls_key_file;
|
||||
char *tls_cert_file;
|
||||
char *tls_protocols;
|
||||
int is_default;
|
||||
od_list_t link;
|
||||
};
|
||||
|
||||
struct od_schemeroute
|
||||
{
|
||||
od_schemeserver_t *server;
|
||||
int is_default;
|
||||
char *target;
|
||||
char *route;
|
||||
char *database;
|
||||
char *user;
|
||||
int user_len;
|
||||
char *password;
|
||||
int password_len;
|
||||
int ttl;
|
||||
int cancel;
|
||||
int discard;
|
||||
int rollback;
|
||||
int client_max;
|
||||
int pool_size;
|
||||
int pool_timeout;
|
||||
od_list_t link;
|
||||
};
|
||||
|
||||
struct od_schemeuser
|
||||
{
|
||||
char *auth;
|
||||
od_auth_t auth_mode;
|
||||
char *user;
|
||||
char *password;
|
||||
int password_len;
|
||||
int is_default;
|
||||
int is_deny;
|
||||
od_list_t link;
|
||||
};
|
||||
|
||||
struct od_scheme
|
||||
{
|
||||
char *config_file;
|
||||
int server_id;
|
||||
/* main */
|
||||
int daemonize;
|
||||
int log_verbosity;
|
||||
char *log_file;
|
||||
char *pid_file;
|
||||
int syslog;
|
||||
char *syslog_ident;
|
||||
char *syslog_facility;
|
||||
int stats_period;
|
||||
int readahead;
|
||||
char *pooling;
|
||||
od_pooling_t pooling_mode;
|
||||
/* listen */
|
||||
char *host;
|
||||
int port;
|
||||
int backlog;
|
||||
int nodelay;
|
||||
int keepalive;
|
||||
int workers;
|
||||
int client_max;
|
||||
od_tls_t tls_verify;
|
||||
char *tls_mode;
|
||||
char *tls_ca_file;
|
||||
char *tls_key_file;
|
||||
char *tls_cert_file;
|
||||
char *tls_protocols;
|
||||
/* servers */
|
||||
od_list_t servers;
|
||||
/* routing */
|
||||
char *routing;
|
||||
od_routing_t routing_mode;
|
||||
od_schemeroute_t *routing_default;
|
||||
od_list_t routing_table;
|
||||
/* users */
|
||||
od_list_t users;
|
||||
od_schemeuser_t *users_default;
|
||||
};
|
||||
|
||||
void od_schemeinit(od_scheme_t*);
|
||||
void od_schemefree(od_scheme_t*);
|
||||
int od_schemevalidate(od_scheme_t*, od_log_t*);
|
||||
void od_schemeprint(od_scheme_t*, od_log_t*);
|
||||
|
||||
od_schemeserver_t*
|
||||
od_schemeserver_add(od_scheme_t*);
|
||||
|
||||
od_schemeserver_t*
|
||||
od_schemeserver_match(od_scheme_t*, char*);
|
||||
|
||||
od_schemeroute_t*
|
||||
od_schemeroute_add(od_scheme_t*);
|
||||
|
||||
od_schemeroute_t*
|
||||
od_schemeroute_match(od_scheme_t*, char*);
|
||||
|
||||
od_schemeuser_t*
|
||||
od_schemeuser_add(od_scheme_t*);
|
||||
|
||||
od_schemeuser_t*
|
||||
od_schemeuser_match(od_scheme_t*, char*);
|
||||
|
||||
#endif /* OD_SCHEME_H */
|
|
@ -0,0 +1,88 @@
|
|||
|
||||
/*
|
||||
* odissey.
|
||||
*
|
||||
* PostgreSQL connection pooler and request router.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <syslog.h>
|
||||
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include "od_macro.h"
|
||||
#include "od_syslog.h"
|
||||
|
||||
typedef struct od_syslog_facility od_syslog_facility_t;
|
||||
|
||||
struct od_syslog_facility
|
||||
{
|
||||
char *name;
|
||||
int id;
|
||||
};
|
||||
|
||||
od_syslog_facility_t od_syslog_facilities[] =
|
||||
{
|
||||
{ "daemon", LOG_DAEMON },
|
||||
{ "user", LOG_USER },
|
||||
{ "local0", LOG_LOCAL0 },
|
||||
{ "local1", LOG_LOCAL1 },
|
||||
{ "local2", LOG_LOCAL2 },
|
||||
{ "local3", LOG_LOCAL3 },
|
||||
{ "local4", LOG_LOCAL4 },
|
||||
{ "local5", LOG_LOCAL5 },
|
||||
{ "local6", LOG_LOCAL6 },
|
||||
{ "local7", LOG_LOCAL7 },
|
||||
{ NULL, 0 }
|
||||
};
|
||||
|
||||
static int od_syslog_prio[] = {
|
||||
LOG_INFO, LOG_ERR, LOG_DEBUG
|
||||
};
|
||||
|
||||
int od_syslog_open(od_syslog_t *slog, char *ident, char *facility)
|
||||
{
|
||||
int facility_id = LOG_DAEMON;
|
||||
if (facility) {
|
||||
int i = 0;
|
||||
od_syslog_facility_t *facility_ptr;
|
||||
for (;;) {
|
||||
facility_ptr = &od_syslog_facilities[i];
|
||||
if (facility_ptr->name == NULL)
|
||||
break;
|
||||
if (strcasecmp(facility_ptr->name, facility) == 0) {
|
||||
facility_id = facility_ptr->id;
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
slog->in_use = 1;
|
||||
if (ident == NULL)
|
||||
ident = "odissey";
|
||||
openlog(ident, 0, facility_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void od_syslog_close(od_syslog_t *slog)
|
||||
{
|
||||
if (! slog->in_use)
|
||||
return;
|
||||
closelog();
|
||||
}
|
||||
|
||||
void od_syslog(od_syslog_t *slog, od_syslogprio_t prio, char *msg)
|
||||
{
|
||||
if (slog->in_use)
|
||||
syslog(od_syslog_prio[prio], "%s", msg);
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
#ifndef OD_SYSLOG_H
|
||||
#define OD_SYSLOG_H
|
||||
|
||||
/*
|
||||
* odissey.
|
||||
*
|
||||
* PostgreSQL connection pooler and request router.
|
||||
*/
|
||||
|
||||
typedef struct od_syslog od_syslog_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
OD_SYSLOG_INFO,
|
||||
OD_SYSLOG_ERROR,
|
||||
OD_SYSLOG_DEBUG
|
||||
} od_syslogprio_t;
|
||||
|
||||
struct od_syslog
|
||||
{
|
||||
int in_use;
|
||||
};
|
||||
|
||||
static inline void
|
||||
od_syslog_init(od_syslog_t *syslog) {
|
||||
syslog->in_use = 0;
|
||||
}
|
||||
|
||||
int od_syslog_open(od_syslog_t*, char*, char*);
|
||||
void od_syslog_close(od_syslog_t*);
|
||||
void od_syslog(od_syslog_t*, od_syslogprio_t, char*);
|
||||
|
||||
#endif /* OD_SYSLOG_H */
|
|
@ -0,0 +1,13 @@
|
|||
#ifndef OD_VERSION_H
|
||||
#define OD_VERSION_H
|
||||
|
||||
/*
|
||||
* odissey.
|
||||
*
|
||||
* PostgreSQL connection pooler and request router.
|
||||
*/
|
||||
|
||||
#define OD_VERSION_GIT "f11f115"
|
||||
#define OD_VERSION_BUILD "debug"
|
||||
|
||||
#endif /* OD_VERSION_H */
|
|
@ -0,0 +1,13 @@
|
|||
#ifndef OD_VERSION_H
|
||||
#define OD_VERSION_H
|
||||
|
||||
/*
|
||||
* odissey.
|
||||
*
|
||||
* PostgreSQL connection pooler and request router.
|
||||
*/
|
||||
|
||||
#cmakedefine OD_VERSION_GIT "@OD_VERSION_GIT@"
|
||||
#cmakedefine OD_VERSION_BUILD "@OD_VERSION_BUILD@"
|
||||
|
||||
#endif /* OD_VERSION_H */
|
|
@ -0,0 +1,33 @@
|
|||
|
||||
/*
|
||||
* odissey.
|
||||
*
|
||||
* PostgreSQL connection pooler and request router.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <machinarium.h>
|
||||
|
||||
#include "od_macro.h"
|
||||
#include "od_list.h"
|
||||
#include "od_pid.h"
|
||||
#include "od_syslog.h"
|
||||
#include "od_log.h"
|
||||
#include "od_scheme.h"
|
||||
#include "od_lex.h"
|
||||
#include "od_config.h"
|
||||
#include "od.h"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
od_t odissey;
|
||||
od_init(&odissey);
|
||||
int rc = od_main(&odissey, argc, argv);
|
||||
od_free(&odissey);
|
||||
return rc;
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue