2017-05-25 12:01:56 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* odissey.
|
|
|
|
*
|
|
|
|
* PostgreSQL connection pooler and request router.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdarg.h>
|
|
|
|
#include <stdint.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
2017-05-31 15:47:15 +00:00
|
|
|
#include <inttypes.h>
|
2017-05-25 12:01:56 +00:00
|
|
|
#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_msg.h"
|
2017-05-26 12:17:45 +00:00
|
|
|
#include "od_system.h"
|
2017-05-25 12:01:56 +00:00
|
|
|
#include "od_instance.h"
|
|
|
|
#include "od_server.h"
|
|
|
|
#include "od_server_pool.h"
|
|
|
|
#include "od_client.h"
|
|
|
|
#include "od_client_pool.h"
|
|
|
|
#include "od_route_id.h"
|
|
|
|
#include "od_route.h"
|
2017-06-05 13:45:28 +00:00
|
|
|
#include "od_route_pool.h"
|
|
|
|
#include "od_router.h"
|
2017-05-26 12:17:45 +00:00
|
|
|
#include "od_pooler.h"
|
2017-06-02 13:49:20 +00:00
|
|
|
#include "od_tls.h"
|
2017-05-25 12:01:56 +00:00
|
|
|
|
|
|
|
static inline void
|
|
|
|
od_pooler(void *arg)
|
|
|
|
{
|
|
|
|
od_pooler_t *pooler = arg;
|
2017-06-05 13:45:28 +00:00
|
|
|
od_router_t *router = pooler->system->router;
|
2017-05-26 12:17:45 +00:00
|
|
|
od_instance_t *instance = pooler->system->instance;
|
2017-05-25 12:01:56 +00:00
|
|
|
|
2017-06-01 09:28:23 +00:00
|
|
|
od_log(&instance->log, "pooler: started");
|
2017-05-31 15:47:15 +00:00
|
|
|
|
2017-06-05 13:45:28 +00:00
|
|
|
/* start router coroutine */
|
2017-05-25 12:01:56 +00:00
|
|
|
int rc;
|
2017-06-05 13:45:28 +00:00
|
|
|
rc = od_router_start(router);
|
|
|
|
if (rc == -1)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* init pooler tls */
|
2017-05-25 12:01:56 +00:00
|
|
|
pooler->tls = NULL;
|
2017-06-02 13:49:20 +00:00
|
|
|
od_scheme_t *scheme = &instance->scheme;
|
2017-05-25 12:01:56 +00:00
|
|
|
if (scheme->tls_verify != OD_TDISABLE) {
|
2017-06-02 13:49:20 +00:00
|
|
|
pooler->tls = od_tls_frontend(scheme);
|
2017-05-25 12:01:56 +00:00
|
|
|
if (pooler->tls == NULL)
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* listen '*' */
|
|
|
|
struct addrinfo *hints_ptr = NULL;
|
|
|
|
struct addrinfo hints;
|
|
|
|
memset(&hints, 0, sizeof(struct addrinfo));
|
|
|
|
hints.ai_family = AF_UNSPEC;
|
|
|
|
hints.ai_socktype = SOCK_STREAM;
|
|
|
|
hints.ai_flags = AI_PASSIVE;
|
|
|
|
hints.ai_protocol = 0;
|
|
|
|
hints.ai_canonname = NULL;
|
|
|
|
hints.ai_addr = NULL;
|
|
|
|
hints.ai_next = NULL;
|
|
|
|
char *host = instance->scheme.host;
|
|
|
|
if (strcmp(instance->scheme.host, "*") == 0) {
|
|
|
|
hints_ptr = &hints;
|
|
|
|
host = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* resolve listen address and port */
|
|
|
|
char port[16];
|
|
|
|
snprintf(port, sizeof(port), "%d", instance->scheme.port);
|
|
|
|
struct addrinfo *ai = NULL;
|
|
|
|
rc = machine_getaddrinfo(host, port, hints_ptr, &ai, UINT32_MAX);
|
|
|
|
if (rc < 0) {
|
2017-05-31 15:47:15 +00:00
|
|
|
od_error(&instance->log, "failed to resolve %s:%d",
|
2017-05-25 12:01:56 +00:00
|
|
|
instance->scheme.host,
|
|
|
|
instance->scheme.port);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
assert(ai != NULL);
|
|
|
|
|
|
|
|
/* io */
|
|
|
|
pooler->server = machine_io_create();
|
|
|
|
if (pooler->server == NULL) {
|
2017-05-31 15:47:15 +00:00
|
|
|
od_error(&instance->log, "failed to create pooler io");
|
2017-05-25 12:01:56 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* bind to listen address and port */
|
|
|
|
rc = machine_bind(pooler->server, ai->ai_addr);
|
|
|
|
freeaddrinfo(ai);
|
|
|
|
if (rc < 0) {
|
2017-05-31 15:47:15 +00:00
|
|
|
od_error(&instance->log, "bind %s:%d failed",
|
2017-05-25 12:01:56 +00:00
|
|
|
instance->scheme.host,
|
|
|
|
instance->scheme.port);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-06-01 09:45:49 +00:00
|
|
|
od_log(&instance->log, "");
|
|
|
|
od_log(&instance->log, "listening on %s:%d",
|
2017-05-25 12:01:56 +00:00
|
|
|
instance->scheme.host,
|
|
|
|
instance->scheme.port);
|
2017-05-31 15:47:15 +00:00
|
|
|
od_log(&instance->log, "");
|
2017-05-25 12:01:56 +00:00
|
|
|
|
|
|
|
/* main loop */
|
|
|
|
while (machine_active())
|
|
|
|
{
|
|
|
|
machine_io_t client_io;
|
|
|
|
rc = machine_accept(pooler->server, &client_io,
|
|
|
|
instance->scheme.backlog, UINT32_MAX);
|
|
|
|
if (rc < 0) {
|
2017-06-01 09:28:23 +00:00
|
|
|
od_error(&instance->log, "pooler: accept failed");
|
2017-05-25 12:01:56 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
/* todo: client_max limit */
|
|
|
|
|
2017-05-30 15:04:59 +00:00
|
|
|
/* set network options */
|
2017-05-25 12:01:56 +00:00
|
|
|
machine_set_nodelay(client_io, instance->scheme.nodelay);
|
|
|
|
if (instance->scheme.keepalive > 0)
|
|
|
|
machine_set_keepalive(client_io, 1, instance->scheme.keepalive);
|
|
|
|
rc = machine_set_readahead(client_io, instance->scheme.readahead);
|
|
|
|
if (rc == -1) {
|
2017-05-31 15:47:15 +00:00
|
|
|
od_error(&instance->log, "failed to set client readahead");
|
2017-05-25 12:01:56 +00:00
|
|
|
machine_close(client_io);
|
|
|
|
machine_io_free(client_io);
|
|
|
|
continue;
|
|
|
|
}
|
2017-05-26 11:49:17 +00:00
|
|
|
|
2017-05-30 15:04:59 +00:00
|
|
|
/* detach io from pooler event loop */
|
2017-05-26 11:49:17 +00:00
|
|
|
rc = machine_io_detach(client_io);
|
|
|
|
if (rc == -1) {
|
2017-05-31 15:47:15 +00:00
|
|
|
od_error(&instance->log, "failed to transfer client io");
|
2017-05-26 11:49:17 +00:00
|
|
|
machine_close(client_io);
|
|
|
|
machine_io_free(client_io);
|
|
|
|
continue;
|
|
|
|
}
|
2017-05-25 12:01:56 +00:00
|
|
|
|
|
|
|
/* allocate new client */
|
|
|
|
od_client_t *client = od_client_allocate();
|
|
|
|
if (client == NULL) {
|
2017-05-31 15:47:15 +00:00
|
|
|
od_error(&instance->log, "failed to allocate client object");
|
2017-05-25 12:01:56 +00:00
|
|
|
machine_close(client_io);
|
|
|
|
machine_io_free(client_io);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
client->id = pooler->client_seq++;
|
|
|
|
client->io = client_io;
|
|
|
|
|
|
|
|
/* create new client event */
|
|
|
|
machine_msg_t msg;
|
|
|
|
msg = machine_msg_create(OD_MCLIENT_NEW, sizeof(od_client_t*));
|
|
|
|
char *msg_data = machine_msg_get_data(msg);
|
|
|
|
memcpy(msg_data, &client, sizeof(od_client_t*));
|
2017-05-26 12:17:45 +00:00
|
|
|
machine_queue_put(pooler->system->task_queue, msg);
|
2017-05-25 12:01:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-26 12:17:45 +00:00
|
|
|
int od_pooler_init(od_pooler_t *pooler, od_system_t *system)
|
2017-05-25 12:01:56 +00:00
|
|
|
{
|
|
|
|
pooler->machine = -1;
|
|
|
|
pooler->server = NULL;
|
|
|
|
pooler->client_seq = 0;
|
2017-05-26 12:17:45 +00:00
|
|
|
pooler->system = system;
|
2017-05-26 11:49:17 +00:00
|
|
|
return 0;
|
2017-05-25 12:01:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int od_pooler_start(od_pooler_t *pooler)
|
|
|
|
{
|
2017-05-26 12:17:45 +00:00
|
|
|
od_instance_t *instance = pooler->system->instance;
|
2017-05-25 12:01:56 +00:00
|
|
|
pooler->machine = machine_create("pooler", od_pooler, pooler);
|
|
|
|
if (pooler->machine == -1) {
|
2017-05-31 15:47:15 +00:00
|
|
|
od_error(&instance->log, "failed to start server");
|
2017-05-25 12:01:56 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|