mirror of https://git.kore.io/kore.git
Merge branch 'master' into oneswig
This commit is contained in:
commit
2ac6e7d41d
2
LICENSE
2
LICENSE
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2013-2015 Joris Vink <joris@coders.se>
|
||||
* Copyright (c) 2013-2016 Joris Vink <joris@coders.se>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
|
|
|
@ -59,6 +59,17 @@ workers 4
|
|||
# http_header_max Maximum size of HTTP headers (in bytes).
|
||||
#
|
||||
# http_body_max Maximum size of an HTTP body (in bytes).
|
||||
# If set to 0 disallows requests with a body
|
||||
# all together.
|
||||
#
|
||||
# http_body_disk_offload Number of bytes after which Kore will use
|
||||
# a temporary file to hold the HTTP body
|
||||
# instead of holding it in memory. If set to
|
||||
# 0 no disk offloading will be done. This is
|
||||
# turned off by default.
|
||||
#
|
||||
# http_body_disk_path Path where Kore will store any temporary
|
||||
# HTTP body files.
|
||||
#
|
||||
# http_keepalive_time Maximum seconds an HTTP connection can be
|
||||
# kept alive by the browser.
|
||||
|
@ -71,10 +82,12 @@ workers 4
|
|||
# http_request_limit Limit the number of requests Kore processes
|
||||
# in a single event loop.
|
||||
#http_header_max 4096
|
||||
#http_body_max 10240000
|
||||
#http_body_max 1024000
|
||||
#http_keepalive_time 0
|
||||
#http_hsts_enable 31536000
|
||||
#http_request_limit 1000
|
||||
#http_body_disk_offload 0
|
||||
#http_body_disk_path tmp_files
|
||||
|
||||
# Websocket specific settings.
|
||||
# websocket_maxframe Specifies the maximum frame size we can receive
|
||||
|
@ -109,8 +122,7 @@ validator v_session function v_session_validate
|
|||
# Specify the TLS ciphers that will be used.
|
||||
#tls_cipher ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!3DES:!MD5:!PSK:!kRSA:!kDSA
|
||||
|
||||
# If you wish to use EDH / ECDH specify a file containing
|
||||
# a generated DH key (See OpenSSL dhparam).
|
||||
# Required DH parameters for TLS.
|
||||
#tls_dhparam dh2048.pem
|
||||
|
||||
# Authentication configuration
|
||||
|
|
|
@ -5,6 +5,9 @@ load ./generic.so example_load
|
|||
|
||||
tls_dhparam dh2048.pem
|
||||
|
||||
http_body_max 1024000000
|
||||
http_body_disk_offload 1024000
|
||||
|
||||
validator v_example function v_example_func
|
||||
validator v_regex regex ^/test/[a-z]*$
|
||||
validator v_number regex ^[0-9]*$
|
||||
|
|
|
@ -17,6 +17,12 @@
|
|||
#include <kore/kore.h>
|
||||
#include <kore/http.h>
|
||||
|
||||
#include <openssl/sha.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "assets.h"
|
||||
|
||||
int example_load(int);
|
||||
|
@ -132,9 +138,9 @@ serve_b64test(struct http_request *req)
|
|||
int
|
||||
serve_file_upload(struct http_request *req)
|
||||
{
|
||||
int r;
|
||||
u_int8_t *d;
|
||||
struct kore_buf *b;
|
||||
struct http_file *f;
|
||||
u_int32_t len;
|
||||
char *name, buf[BUFSIZ];
|
||||
|
||||
|
@ -142,16 +148,20 @@ serve_file_upload(struct http_request *req)
|
|||
kore_buf_append(b, asset_upload_html, asset_len_upload_html);
|
||||
|
||||
if (req->method == HTTP_METHOD_POST) {
|
||||
http_populate_multipart_form(req, &r);
|
||||
if (http_argument_get_string("firstname", &name, &len)) {
|
||||
kore_buf_replace_string(b, "$firstname$", name, len);
|
||||
if (req->http_body_fd != -1)
|
||||
kore_log(LOG_NOTICE, "file is on disk");
|
||||
|
||||
http_populate_multipart_form(req);
|
||||
if (http_argument_get_string(req, "firstname", &name)) {
|
||||
kore_buf_replace_string(b, "$firstname$",
|
||||
name, strlen(name));
|
||||
} else {
|
||||
kore_buf_replace_string(b, "$firstname$", NULL, 0);
|
||||
}
|
||||
|
||||
if (http_file_lookup(req, "file", &name, &d, &len)) {
|
||||
if ((f = http_file_lookup(req, "file")) != NULL) {
|
||||
(void)snprintf(buf, sizeof(buf),
|
||||
"%s is %d bytes", name, len);
|
||||
"%s is %ld bytes", f->filename, f->length);
|
||||
kore_buf_replace_string(b,
|
||||
"$upload$", buf, strlen(buf));
|
||||
} else {
|
||||
|
@ -232,7 +242,10 @@ serve_params_test(struct http_request *req)
|
|||
int r, i;
|
||||
char *test, name[10];
|
||||
|
||||
http_populate_arguments(req);
|
||||
if (req->method == HTTP_METHOD_GET)
|
||||
http_populate_get(req);
|
||||
else if (req->method == HTTP_METHOD_POST)
|
||||
http_populate_post(req);
|
||||
|
||||
b = kore_buf_create(asset_len_params_html);
|
||||
kore_buf_append(b, asset_params_html, asset_len_params_html);
|
||||
|
@ -240,14 +253,14 @@ serve_params_test(struct http_request *req)
|
|||
/*
|
||||
* The GET parameters will be filtered out on POST.
|
||||
*/
|
||||
if (http_argument_get_string("arg1", &test, &len)) {
|
||||
kore_buf_replace_string(b, "$arg1$", test, len);
|
||||
if (http_argument_get_string(req, "arg1", &test)) {
|
||||
kore_buf_replace_string(b, "$arg1$", test, strlen(test));
|
||||
} else {
|
||||
kore_buf_replace_string(b, "$arg1$", NULL, 0);
|
||||
}
|
||||
|
||||
if (http_argument_get_string("arg2", &test, &len)) {
|
||||
kore_buf_replace_string(b, "$arg2$", test, len);
|
||||
if (http_argument_get_string(req, "arg2", &test)) {
|
||||
kore_buf_replace_string(b, "$arg2$", test, strlen(test));
|
||||
} else {
|
||||
kore_buf_replace_string(b, "$arg2$", NULL, 0);
|
||||
}
|
||||
|
@ -257,7 +270,7 @@ serve_params_test(struct http_request *req)
|
|||
kore_buf_replace_string(b, "$test2$", NULL, 0);
|
||||
kore_buf_replace_string(b, "$test3$", NULL, 0);
|
||||
|
||||
if (http_argument_get_uint16("id", &r))
|
||||
if (http_argument_get_uint16(req, "id", &r))
|
||||
kore_log(LOG_NOTICE, "id: %d", r);
|
||||
else
|
||||
kore_log(LOG_NOTICE, "No id set");
|
||||
|
@ -272,9 +285,9 @@ serve_params_test(struct http_request *req)
|
|||
|
||||
for (i = 1; i < 4; i++) {
|
||||
(void)snprintf(name, sizeof(name), "test%d", i);
|
||||
if (http_argument_get_string(name, &test, &len)) {
|
||||
if (http_argument_get_string(req, name, &test)) {
|
||||
(void)snprintf(name, sizeof(name), "$test%d$", i);
|
||||
kore_buf_replace_string(b, name, test, len);
|
||||
kore_buf_replace_string(b, name, test, strlen(test));
|
||||
} else {
|
||||
(void)snprintf(name, sizeof(name), "$test%d$", i);
|
||||
kore_buf_replace_string(b, name, NULL, 0);
|
||||
|
|
|
@ -15,28 +15,28 @@ page(struct http_request *req)
|
|||
u_int32_t u32, len;
|
||||
u_int8_t c, *data;
|
||||
|
||||
http_populate_arguments(req);
|
||||
http_populate_get(req);
|
||||
buf = kore_buf_create(128);
|
||||
|
||||
if (http_argument_get_byte("id", &c))
|
||||
if (http_argument_get_byte(req, "id", &c))
|
||||
kore_buf_appendf(buf, "byte\t%c\n", c);
|
||||
|
||||
if (http_argument_get_int16("id", &s16))
|
||||
if (http_argument_get_int16(req, "id", &s16))
|
||||
kore_buf_appendf(buf, "int16\t%d\n", s16);
|
||||
|
||||
if (http_argument_get_uint16("id", &u16))
|
||||
if (http_argument_get_uint16(req, "id", &u16))
|
||||
kore_buf_appendf(buf, "uint16\t%d\n", u16);
|
||||
|
||||
if (http_argument_get_int32("id", &s32))
|
||||
if (http_argument_get_int32(req, "id", &s32))
|
||||
kore_buf_appendf(buf, "int32\t%d\n", s32);
|
||||
|
||||
if (http_argument_get_uint32("id", &u32))
|
||||
if (http_argument_get_uint32(req, "id", &u32))
|
||||
kore_buf_appendf(buf, "uint32\t%d\n", u32);
|
||||
|
||||
if (http_argument_get_int64("id", &s64))
|
||||
if (http_argument_get_int64(req, "id", &s64))
|
||||
kore_buf_appendf(buf, "int64\t%ld\n", s64);
|
||||
|
||||
if (http_argument_get_uint64("id", &u64))
|
||||
if (http_argument_get_uint64(req, "id", &u64))
|
||||
kore_buf_appendf(buf, "uint64\t%lu\n", u64);
|
||||
|
||||
data = kore_buf_release(buf, &len);
|
||||
|
|
|
@ -1,3 +1,19 @@
|
|||
/*
|
||||
* Copyright (c) 2013-2016 Joris Vink <joris@coders.se>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <kore/kore.h>
|
||||
#include <kore/http.h>
|
||||
|
||||
|
@ -8,10 +24,12 @@ int page(struct http_request *);
|
|||
int
|
||||
page(struct http_request *req)
|
||||
{
|
||||
ssize_t ret;
|
||||
struct kore_buf *buf;
|
||||
char *body;
|
||||
yajl_val node, v;
|
||||
char eb[1024];
|
||||
u_int8_t data[BUFSIZ];
|
||||
const char *path[] = { "foo", "bar", NULL };
|
||||
|
||||
/* We only allow POST/PUT methods. */
|
||||
|
@ -23,14 +41,27 @@ page(struct http_request *req)
|
|||
}
|
||||
|
||||
/*
|
||||
* Grab the entire body we received as text (NUL-terminated).
|
||||
* Note: this can return NULL and the result MUST be freed.
|
||||
* Read the entire received body into a memory buffer.
|
||||
*/
|
||||
if ((body = http_body_text(req)) == NULL) {
|
||||
http_response(req, 400, NULL, 0);
|
||||
return (KORE_RESULT_OK);
|
||||
buf = kore_buf_create(128);
|
||||
for (;;) {
|
||||
ret = http_body_read(req, data, sizeof(data));
|
||||
if (ret == -1) {
|
||||
kore_buf_free(buf);
|
||||
kore_log(LOG_NOTICE, "error reading body");
|
||||
http_response(req, 500, NULL, 0);
|
||||
return (KORE_RESULT_OK);
|
||||
}
|
||||
|
||||
if (ret == 0)
|
||||
break;
|
||||
|
||||
kore_buf_append(buf, data, ret);
|
||||
}
|
||||
|
||||
/* Grab our body data as a NUL-terminated string. */
|
||||
body = kore_buf_stringify(buf);
|
||||
|
||||
/* Parse the body via yajl now. */
|
||||
node = yajl_tree_parse(body, eb, sizeof(eb));
|
||||
if (node == NULL) {
|
||||
|
@ -40,12 +71,13 @@ page(struct http_request *req)
|
|||
kore_log(LOG_NOTICE, "parse error: unknown");
|
||||
}
|
||||
|
||||
kore_mem_free(body);
|
||||
kore_buf_free(buf);
|
||||
http_response(req, 400, NULL, 0);
|
||||
return (KORE_RESULT_OK);
|
||||
}
|
||||
|
||||
buf = kore_buf_create(128);
|
||||
/* Reuse old buffer, don't need it anymore for body. */
|
||||
kore_buf_reset(buf);
|
||||
|
||||
/* Attempt to grab foo.bar from the JSON tree. */
|
||||
v = yajl_tree_get(node, path, yajl_t_string);
|
||||
|
|
|
@ -49,9 +49,9 @@ open_connection(struct http_request *req)
|
|||
}
|
||||
|
||||
/* Parse the query string and grab our arguments. */
|
||||
http_populate_arguments(req);
|
||||
if (!http_argument_get_string("host", &host, NULL) ||
|
||||
!http_argument_get_string("port", &port, NULL)) {
|
||||
http_populate_get(req);
|
||||
if (!http_argument_get_string(req, "host", &host) ||
|
||||
!http_argument_get_string(req, "port", &port)) {
|
||||
http_response(req, HTTP_STATUS_BAD_REQUEST, NULL, 0);
|
||||
return (KORE_RESULT_OK);
|
||||
}
|
||||
|
|
|
@ -22,9 +22,7 @@ int page(struct http_request *);
|
|||
int
|
||||
page(struct http_request *req)
|
||||
{
|
||||
int p;
|
||||
u_int16_t id;
|
||||
u_int32_t len;
|
||||
char *sid;
|
||||
struct kore_buf *buf;
|
||||
|
||||
|
@ -40,17 +38,8 @@ page(struct http_request *req)
|
|||
* See conf/parameters.conf on how that is done, this is an
|
||||
* important step as without the params block you will never
|
||||
* get any parameters returned from Kore.
|
||||
*
|
||||
* http_populate_arguments() returns the number of arguments
|
||||
* that were successfully processed and are available.
|
||||
*/
|
||||
p = http_populate_arguments(req);
|
||||
|
||||
/* If we had no arguments available what so ever, return 400. */
|
||||
if (p == 0) {
|
||||
http_response(req, 400, NULL, 0);
|
||||
return (KORE_RESULT_OK);
|
||||
}
|
||||
http_populate_get(req);
|
||||
|
||||
/*
|
||||
* Lets grab the "id" parameter if available. Kore can obtain
|
||||
|
@ -73,11 +62,11 @@ page(struct http_request *req)
|
|||
buf = kore_buf_create(128);
|
||||
|
||||
/* Grab it as a string, we shouldn't free the result in sid. */
|
||||
if (http_argument_get_string("id", &sid, &len))
|
||||
kore_buf_appendf(buf, "id as a string: '%s' (%d)\n", sid, len);
|
||||
if (http_argument_get_string(req, "id", &sid))
|
||||
kore_buf_appendf(buf, "id as a string: '%s'\n", sid);
|
||||
|
||||
/* Grab it as an actual u_int16_t. */
|
||||
if (http_argument_get_uint16("id", &id))
|
||||
if (http_argument_get_uint16(req, "id", &id))
|
||||
kore_buf_appendf(buf, "id as an u_int16_t: %d\n", id);
|
||||
|
||||
/* Now return the result to the client with a 200 status code. */
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
*.o
|
||||
.objs
|
||||
pgsql-sync.so
|
||||
assets.h
|
||||
cert
|
|
@ -0,0 +1,11 @@
|
|||
# Placeholder configuration
|
||||
|
||||
bind 127.0.0.1 8888
|
||||
load ./pgsql-sync.so init
|
||||
tls_dhparam dh2048.pem
|
||||
|
||||
domain 127.0.0.1 {
|
||||
certfile cert/server.crt
|
||||
certkey cert/server.key
|
||||
static / page
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
* Copyright (c) 2015 Joris Vink <joris@coders.se>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This example demonstrates how to use synchronous PGSQL queries
|
||||
* with Kore. For an asynchronous example see pgsql/ under examples/.
|
||||
*
|
||||
* This example does the same as the asynchronous one, select all entries
|
||||
* from a table called "coders".
|
||||
*/
|
||||
|
||||
#include <kore/kore.h>
|
||||
#include <kore/http.h>
|
||||
#include <kore/pgsql.h>
|
||||
|
||||
int init(int);
|
||||
int page(struct http_request *);
|
||||
|
||||
/* Called when our module is loaded (see config) */
|
||||
int
|
||||
init(int state)
|
||||
{
|
||||
/* Register our database. */
|
||||
kore_pgsql_register("db", "host=/tmp dbname=test");
|
||||
|
||||
return (KORE_RESULT_OK);
|
||||
}
|
||||
|
||||
/* Page handler entry point (see config) */
|
||||
int
|
||||
page(struct http_request *req)
|
||||
{
|
||||
struct kore_pgsql sql;
|
||||
char *name;
|
||||
int rows, i;
|
||||
|
||||
req->status = HTTP_STATUS_INTERNAL_ERROR;
|
||||
|
||||
/*
|
||||
* Initialise our kore_pgsql data structure with the database name
|
||||
* we want to connect to (note that we registered this earlier with
|
||||
* kore_pgsql_register()). We also say we will perform a synchronous
|
||||
* query (KORE_PGSQL_SYNC) and we do not need to pass our http_request
|
||||
* so we pass NULL instead.
|
||||
*/
|
||||
if (!kore_pgsql_query_init(&sql, NULL, "db", KORE_PGSQL_SYNC)) {
|
||||
kore_pgsql_logerror(&sql);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Now we can fire off the query, once it returns we either have
|
||||
* a result on which we can operate or an error occured.
|
||||
*/
|
||||
if (!kore_pgsql_query(&sql, "SELECT * FROM coders")) {
|
||||
kore_pgsql_logerror(&sql);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Iterate over the result and dump it to somewhere.
|
||||
*/
|
||||
rows = kore_pgsql_ntuples(&sql);
|
||||
for (i = 0; i < rows; i++) {
|
||||
name = kore_pgsql_getvalue(&sql, i, 0);
|
||||
kore_log(LOG_NOTICE, "name: '%s'", name);
|
||||
}
|
||||
|
||||
/* All good. */
|
||||
req->status = HTTP_STATUS_OK;
|
||||
|
||||
out:
|
||||
http_response(req, req->status, NULL, 0);
|
||||
|
||||
/* Don't forget to cleanup the kore_pgsql data structure. */
|
||||
kore_pgsql_cleanup(&sql);
|
||||
|
||||
return (KORE_RESULT_OK);
|
||||
}
|
|
@ -16,7 +16,8 @@
|
|||
|
||||
/*
|
||||
* This example demonstrates on how to use state machines and
|
||||
* asynchronous pgsql queries.
|
||||
* asynchronous pgsql queries. For a synchronous query example
|
||||
* see the pgsql-sync/ example under the examples/ directory.
|
||||
*
|
||||
* While this example might seem overly complex for a simple pgsql
|
||||
* query, there is a reason behind its complexity:
|
||||
|
@ -36,15 +37,17 @@
|
|||
#include <kore/http.h>
|
||||
#include <kore/pgsql.h>
|
||||
|
||||
#define REQ_STATE_QUERY 0
|
||||
#define REQ_STATE_DB_WAIT 1
|
||||
#define REQ_STATE_DB_READ 2
|
||||
#define REQ_STATE_ERROR 3
|
||||
#define REQ_STATE_DONE 4
|
||||
#define REQ_STATE_INIT 0
|
||||
#define REQ_STATE_QUERY 1
|
||||
#define REQ_STATE_DB_WAIT 2
|
||||
#define REQ_STATE_DB_READ 3
|
||||
#define REQ_STATE_ERROR 4
|
||||
#define REQ_STATE_DONE 5
|
||||
|
||||
int init(int);
|
||||
int page(struct http_request *);
|
||||
|
||||
static int request_perform_init(struct http_request *);
|
||||
static int request_perform_query(struct http_request *);
|
||||
static int request_db_wait(struct http_request *);
|
||||
static int request_db_read(struct http_request *);
|
||||
|
@ -52,6 +55,7 @@ static int request_error(struct http_request *);
|
|||
static int request_done(struct http_request *);
|
||||
|
||||
struct http_state mystates[] = {
|
||||
{ "REQ_STATE_INIT", request_perform_init },
|
||||
{ "REQ_STATE_QUERY", request_perform_query },
|
||||
{ "REQ_STATE_DB_WAIT", request_db_wait },
|
||||
{ "REQ_STATE_DB_READ", request_db_read },
|
||||
|
@ -62,6 +66,7 @@ struct http_state mystates[] = {
|
|||
#define mystates_size (sizeof(mystates) / sizeof(mystates[0]))
|
||||
|
||||
struct rstate {
|
||||
int cnt;
|
||||
struct kore_pgsql sql;
|
||||
};
|
||||
|
||||
|
@ -69,8 +74,8 @@ struct rstate {
|
|||
int
|
||||
init(int state)
|
||||
{
|
||||
/* Set our connection string. */
|
||||
pgsql_conn_string = "host=/var/run/postgresql/ dbname=test";
|
||||
/* Register our database. */
|
||||
kore_pgsql_register("db", "host=/tmp dbname=test");
|
||||
|
||||
return (KORE_RESULT_OK);
|
||||
}
|
||||
|
@ -84,29 +89,48 @@ page(struct http_request *req)
|
|||
return (http_state_run(mystates, mystates_size, req));
|
||||
}
|
||||
|
||||
/* The initial state, we setup our context and fire off the pgsql query. */
|
||||
/* Initialize our PGSQL data structure and prepare for an async query. */
|
||||
int
|
||||
request_perform_query(struct http_request *req)
|
||||
request_perform_init(struct http_request *req)
|
||||
{
|
||||
struct rstate *state;
|
||||
|
||||
/* Setup our state context. */
|
||||
state = kore_malloc(sizeof(*state));
|
||||
/* Setup our state context (if not yet set). */
|
||||
if (req->hdlr_extra == NULL) {
|
||||
state = kore_malloc(sizeof(*state));
|
||||
req->hdlr_extra = state;
|
||||
} else {
|
||||
state = req->hdlr_extra;
|
||||
}
|
||||
|
||||
/* Attach the state to our request. */
|
||||
req->hdlr_extra = state;
|
||||
/* Initialize our kore_pgsql data structure. */
|
||||
if (!kore_pgsql_query_init(&state->sql, req, "db", KORE_PGSQL_ASYNC)) {
|
||||
/* If the state was still INIT, we'll try again later. */
|
||||
if (state->sql.state == KORE_PGSQL_STATE_INIT) {
|
||||
req->fsm_state = REQ_STATE_INIT;
|
||||
return (HTTP_STATE_RETRY);
|
||||
}
|
||||
|
||||
kore_pgsql_logerror(&state->sql);
|
||||
req->fsm_state = REQ_STATE_ERROR;
|
||||
} else {
|
||||
req->fsm_state = REQ_STATE_QUERY;
|
||||
}
|
||||
|
||||
return (HTTP_STATE_CONTINUE);
|
||||
}
|
||||
|
||||
/* After setting everything up we will execute our async query. */
|
||||
int
|
||||
request_perform_query(struct http_request *req)
|
||||
{
|
||||
struct rstate *state = req->hdlr_extra;
|
||||
|
||||
/* We want to move to read result after this. */
|
||||
req->fsm_state = REQ_STATE_DB_WAIT;
|
||||
|
||||
/* Fire off the query. */
|
||||
if (!kore_pgsql_query(&state->sql, req, "SELECT * FROM coders")) {
|
||||
/* If the state was still INIT, we'll try again later. */
|
||||
if (state->sql.state == KORE_PGSQL_STATE_INIT) {
|
||||
req->fsm_state = REQ_STATE_QUERY;
|
||||
return (HTTP_STATE_RETRY);
|
||||
}
|
||||
|
||||
if (!kore_pgsql_query(&state->sql, "SELECT * FROM coders")) {
|
||||
/*
|
||||
* Let the state machine continue immediately since we
|
||||
* have an error anyway.
|
||||
|
|
|
@ -58,8 +58,8 @@ page_handler(struct http_request *req)
|
|||
*/
|
||||
if (req->hdlr_extra == NULL) {
|
||||
/* Grab the user argument */
|
||||
http_populate_arguments(req);
|
||||
if (!http_argument_get_string("user", &user, &len)) {
|
||||
http_populate_get(req);
|
||||
if (!http_argument_get_string(req, "user", &user)) {
|
||||
http_response(req, 500, "ERROR\n", 6);
|
||||
return (KORE_RESULT_OK);
|
||||
}
|
||||
|
@ -87,7 +87,7 @@ page_handler(struct http_request *req)
|
|||
* GET request to its channel.
|
||||
*/
|
||||
kore_task_run(&state->task);
|
||||
kore_task_channel_write(&state->task, user, len);
|
||||
kore_task_channel_write(&state->task, user, strlen(user));
|
||||
|
||||
/*
|
||||
* Tell Kore to retry us later.
|
||||
|
@ -142,7 +142,6 @@ page_handler(struct http_request *req)
|
|||
int
|
||||
post_back(struct http_request *req)
|
||||
{
|
||||
u_int32_t len;
|
||||
char *user;
|
||||
|
||||
if (req->method != HTTP_METHOD_POST) {
|
||||
|
@ -150,14 +149,14 @@ post_back(struct http_request *req)
|
|||
return (KORE_RESULT_OK);
|
||||
}
|
||||
|
||||
http_populate_arguments(req);
|
||||
if (!http_argument_get_string("user", &user, &len)) {
|
||||
http_populate_post(req);
|
||||
if (!http_argument_get_string(req, "user", &user)) {
|
||||
http_response(req, 500, NULL, 0);
|
||||
return (KORE_RESULT_OK);
|
||||
}
|
||||
|
||||
/* Simply echo the supplied user argument back. */
|
||||
http_response(req, 200, user, len);
|
||||
http_response(req, 200, user, strlen(user));
|
||||
|
||||
return (KORE_RESULT_OK);
|
||||
}
|
||||
|
|
|
@ -166,7 +166,8 @@ client_setup(struct connection *c)
|
|||
int
|
||||
backend_handle_connect(struct connection *c)
|
||||
{
|
||||
int ret;
|
||||
int ret;
|
||||
struct connection *src;
|
||||
|
||||
/* We will get a write notification when we can progress. */
|
||||
if (!(c->flags & CONN_WRITE_POSSIBLE))
|
||||
|
@ -208,7 +209,12 @@ backend_handle_connect(struct connection *c)
|
|||
kore_connection_start_idletimer(c);
|
||||
kore_platform_event_all(c->fd, c);
|
||||
|
||||
return (KORE_RESULT_OK);
|
||||
/* Allow events from source now. */
|
||||
src = c->hdlr_extra;
|
||||
kore_platform_event_all(src->fd, src);
|
||||
|
||||
/* Now lets start. */
|
||||
return (c->handle(c));
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
*.o
|
||||
.objs
|
||||
upload.so
|
||||
assets.h
|
||||
cert
|
|
@ -0,0 +1,16 @@
|
|||
# Placeholder configuration
|
||||
|
||||
bind 127.0.0.1 8888
|
||||
load ./upload.so
|
||||
|
||||
tls_dhparam dh2048.pem
|
||||
|
||||
http_body_max 1024000000
|
||||
http_body_disk_offload 4096
|
||||
|
||||
domain 127.0.0.1 {
|
||||
certfile cert/server.crt
|
||||
certkey cert/server.key
|
||||
|
||||
static / page
|
||||
}
|
|
@ -0,0 +1,118 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Joris Vink <joris@coders.se>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This example demonstrates how to properly deal with file uploads
|
||||
* coming from a multipart form.
|
||||
*
|
||||
* The basics are quite trivial:
|
||||
* 1) call http_populate_multipart_form()
|
||||
* 2) find the file using http_file_lookup().
|
||||
* 3) read the file data using http_file_read().
|
||||
*
|
||||
* In this example the contents is written to a newly created file
|
||||
* on the server that matches the naming given by the uploader.
|
||||
*
|
||||
* Note that the above is probably not what you want to do in real life.
|
||||
*/
|
||||
|
||||
#include <kore/kore.h>
|
||||
#include <kore/http.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int page(struct http_request *);
|
||||
|
||||
int
|
||||
page(struct http_request *req)
|
||||
{
|
||||
int fd;
|
||||
struct http_file *file;
|
||||
u_int8_t buf[BUFSIZ];
|
||||
ssize_t ret, written;
|
||||
|
||||
/* Only deal with POSTs. */
|
||||
if (req->method != HTTP_METHOD_POST) {
|
||||
http_response(req, 405, NULL, 0);
|
||||
return (KORE_RESULT_OK);
|
||||
}
|
||||
|
||||
/* Parse the multipart data that was present. */
|
||||
http_populate_multipart_form(req);
|
||||
|
||||
/* Find our file. */
|
||||
if ((file = http_file_lookup(req, "file")) == NULL) {
|
||||
http_response(req, 400, NULL, 0);
|
||||
return (KORE_RESULT_OK);
|
||||
}
|
||||
|
||||
/* Open dump file where we will write file contents. */
|
||||
fd = open(file->filename, O_CREAT | O_TRUNC | O_WRONLY, 0700);
|
||||
if (fd == -1) {
|
||||
http_response(req, 500, NULL, 0);
|
||||
return (KORE_RESULT_OK);
|
||||
}
|
||||
|
||||
/* While we have data from http_file_read(), write it. */
|
||||
/* Alternatively you could look at file->offset and file->length. */
|
||||
ret = KORE_RESULT_ERROR;
|
||||
for (;;) {
|
||||
ret = http_file_read(file, buf, sizeof(buf));
|
||||
if (ret == -1) {
|
||||
kore_log(LOG_ERR, "failed to read from file");
|
||||
http_response(req, 500, NULL, 0);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (ret == 0)
|
||||
break;
|
||||
|
||||
written = write(fd, buf, ret);
|
||||
if (written == -1) {
|
||||
kore_log(LOG_ERR,"write(%s): %s",
|
||||
file->filename, errno_s);
|
||||
http_response(req, 500, NULL, 0);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (written != ret) {
|
||||
kore_log(LOG_ERR, "partial write on %s",
|
||||
file->filename);
|
||||
http_response(req, 500, NULL, 0);
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
ret = KORE_RESULT_OK;
|
||||
http_response(req, 200, NULL, 0);
|
||||
kore_log(LOG_INFO, "file '%s' successfully received",
|
||||
file->filename);
|
||||
|
||||
cleanup:
|
||||
if (close(fd) == -1)
|
||||
kore_log(LOG_WARNING, "close(%s): %s", file->filename, errno_s);
|
||||
|
||||
if (ret == KORE_RESULT_ERROR) {
|
||||
if (unlink(file->filename) == -1) {
|
||||
kore_log(LOG_WARNING, "unlink(%s): %s",
|
||||
file->filename, errno_s);
|
||||
}
|
||||
ret = KORE_RESULT_OK;
|
||||
}
|
||||
|
||||
return (KORE_RESULT_OK);
|
||||
}
|
119
includes/http.h
119
includes/http.h
|
@ -26,13 +26,17 @@ extern "C" {
|
|||
#define HTTP_KEEPALIVE_TIME 20
|
||||
#define HTTP_HSTS_ENABLE 31536000
|
||||
#define HTTP_HEADER_MAX_LEN 4096
|
||||
#define HTTP_BODY_MAX_LEN 10240000
|
||||
#define HTTP_BODY_MAX_LEN 1024000
|
||||
#define HTTP_URI_LEN 2000
|
||||
#define HTTP_USERAGENT_LEN 256
|
||||
#define HTTP_REQ_HEADER_MAX 25
|
||||
#define HTTP_MAX_QUERY_ARGS 20
|
||||
#define HTTP_MAX_COOKIES 10
|
||||
#define HTTP_REQUEST_LIMIT 1000
|
||||
#define HTTP_BODY_DISK_PATH "tmp_files"
|
||||
#define HTTP_BODY_DISK_OFFLOAD 0
|
||||
#define HTTP_BODY_PATH_MAX 256
|
||||
#define HTTP_BOUNDARY_MAX 80
|
||||
|
||||
#define HTTP_ARG_TYPE_RAW 0
|
||||
#define HTTP_ARG_TYPE_BYTE 1
|
||||
|
@ -58,19 +62,13 @@ struct http_header {
|
|||
|
||||
struct http_arg {
|
||||
char *name;
|
||||
void *value;
|
||||
u_int32_t len;
|
||||
|
||||
char *s_value;
|
||||
u_int32_t s_len;
|
||||
|
||||
TAILQ_ENTRY(http_arg) list;
|
||||
};
|
||||
|
||||
#define COPY_ARG_TYPE(v, l, t) \
|
||||
#define COPY_ARG_TYPE(v, t) \
|
||||
do { \
|
||||
if (l != NULL) \
|
||||
*l = sizeof(t); \
|
||||
*(t *)nout = v; \
|
||||
} while (0);
|
||||
|
||||
|
@ -81,7 +79,7 @@ struct http_arg {
|
|||
nval = (type)kore_strtonum64(q->s_value, sign, &err); \
|
||||
if (err != KORE_RESULT_OK) \
|
||||
return (KORE_RESULT_ERROR); \
|
||||
COPY_ARG_TYPE(nval, len, type); \
|
||||
COPY_ARG_TYPE(nval, type); \
|
||||
} while (0);
|
||||
|
||||
#define COPY_ARG_INT(min, max, type) \
|
||||
|
@ -91,23 +89,13 @@ struct http_arg {
|
|||
nval = kore_strtonum(q->s_value, 10, min, max, &err); \
|
||||
if (err != KORE_RESULT_OK) \
|
||||
return (KORE_RESULT_ERROR); \
|
||||
COPY_ARG_TYPE(nval, len, type); \
|
||||
} while (0);
|
||||
|
||||
#define CACHE_STRING() \
|
||||
do { \
|
||||
if (q->s_value == NULL) { \
|
||||
q->s_len = q->len + 1; \
|
||||
q->s_value = kore_malloc(q->s_len); \
|
||||
kore_strlcpy(q->s_value, q->value, q->s_len); \
|
||||
} \
|
||||
COPY_ARG_TYPE(nval, type); \
|
||||
} while (0);
|
||||
|
||||
#define COPY_AS_INTTYPE_64(type, sign) \
|
||||
do { \
|
||||
if (nout == NULL) \
|
||||
return (KORE_RESULT_ERROR); \
|
||||
CACHE_STRING(); \
|
||||
COPY_ARG_INT64(type, sign); \
|
||||
} while (0);
|
||||
|
||||
|
@ -115,45 +103,44 @@ struct http_arg {
|
|||
do { \
|
||||
if (nout == NULL) \
|
||||
return (KORE_RESULT_ERROR); \
|
||||
CACHE_STRING(); \
|
||||
COPY_ARG_INT(min, max, type); \
|
||||
} while (0);
|
||||
|
||||
#define http_argument_type(r, n, so, no, l, t) \
|
||||
http_argument_get(r, n, so, no, l, t)
|
||||
#define http_argument_type(r, n, so, no, t) \
|
||||
http_argument_get(r, n, so, no, t)
|
||||
|
||||
#define http_argument_get_string(n, o, l) \
|
||||
http_argument_type(req, n, (void **)o, NULL, l, HTTP_ARG_TYPE_STRING)
|
||||
#define http_argument_get_string(r, n, o) \
|
||||
http_argument_type(r, n, (void **)o, NULL, HTTP_ARG_TYPE_STRING)
|
||||
|
||||
#define http_argument_get_byte(n, o) \
|
||||
http_argument_type(req, n, NULL, o, NULL, HTTP_ARG_TYPE_BYTE)
|
||||
#define http_argument_get_byte(r, n, o) \
|
||||
http_argument_type(r, n, NULL, o, HTTP_ARG_TYPE_BYTE)
|
||||
|
||||
#define http_argument_get_uint16(n, o) \
|
||||
http_argument_type(req, n, NULL, o, NULL, HTTP_ARG_TYPE_UINT16)
|
||||
#define http_argument_get_uint16(r, n, o) \
|
||||
http_argument_type(r, n, NULL, o, HTTP_ARG_TYPE_UINT16)
|
||||
|
||||
#define http_argument_get_int16(n, o) \
|
||||
http_argument_type(req, n, NULL, o, NULL, HTTP_ARG_TYPE_INT16)
|
||||
#define http_argument_get_int16(r, n, o) \
|
||||
http_argument_type(r, n, NULL, o, HTTP_ARG_TYPE_INT16)
|
||||
|
||||
#define http_argument_get_uint32(n, o) \
|
||||
http_argument_type(req, n, NULL, o, NULL, HTTP_ARG_TYPE_UINT32)
|
||||
#define http_argument_get_uint32(r, n, o) \
|
||||
http_argument_type(r, n, NULL, o, HTTP_ARG_TYPE_UINT32)
|
||||
|
||||
#define http_argument_get_int32(n, o) \
|
||||
http_argument_type(req, n, NULL, o, NULL, HTTP_ARG_TYPE_INT32)
|
||||
#define http_argument_get_int32(r, n, o) \
|
||||
http_argument_type(r, n, NULL, o, HTTP_ARG_TYPE_INT32)
|
||||
|
||||
#define http_argument_get_uint64(n, o) \
|
||||
http_argument_type(req, n, NULL, o, NULL, HTTP_ARG_TYPE_UINT64)
|
||||
#define http_argument_get_uint64(r, n, o) \
|
||||
http_argument_type(r, n, NULL, o, HTTP_ARG_TYPE_UINT64)
|
||||
|
||||
#define http_argument_get_int64(n, o) \
|
||||
http_argument_type(req, n, NULL, o, NULL, HTTP_ARG_TYPE_INT64)
|
||||
#define http_argument_get_int64(r, n, o) \
|
||||
http_argument_type(r, n, NULL, o, HTTP_ARG_TYPE_INT64)
|
||||
|
||||
|
||||
struct http_file {
|
||||
char *name;
|
||||
char *filename;
|
||||
|
||||
u_int8_t *data;
|
||||
u_int32_t len;
|
||||
|
||||
size_t position;
|
||||
size_t offset;
|
||||
size_t length;
|
||||
struct http_request *req;
|
||||
TAILQ_ENTRY(http_file) list;
|
||||
};
|
||||
|
||||
|
@ -163,20 +150,21 @@ struct http_file {
|
|||
#define HTTP_METHOD_DELETE 3
|
||||
#define HTTP_METHOD_HEAD 4
|
||||
|
||||
#define HTTP_REQUEST_COMPLETE 0x01
|
||||
#define HTTP_REQUEST_DELETE 0x02
|
||||
#define HTTP_REQUEST_SLEEPING 0x04
|
||||
#define HTTP_REQUEST_PGSQL_QUEUE 0x10
|
||||
#define HTTP_REQUEST_EXPECT_BODY 0x20
|
||||
#define HTTP_REQUEST_RETAIN_EXTRA 0x40
|
||||
#define HTTP_REQUEST_NO_CONTENT_LENGTH 0x80
|
||||
#define HTTP_REQUEST_COMPLETE 0x0001
|
||||
#define HTTP_REQUEST_DELETE 0x0002
|
||||
#define HTTP_REQUEST_SLEEPING 0x0004
|
||||
#define HTTP_REQUEST_PGSQL_QUEUE 0x0010
|
||||
#define HTTP_REQUEST_EXPECT_BODY 0x0020
|
||||
#define HTTP_REQUEST_RETAIN_EXTRA 0x0040
|
||||
#define HTTP_REQUEST_NO_CONTENT_LENGTH 0x0080
|
||||
#define HTTP_REQUEST_AUTHED 0x0100
|
||||
|
||||
struct kore_task;
|
||||
|
||||
struct http_request {
|
||||
u_int8_t method;
|
||||
u_int8_t flags;
|
||||
u_int8_t fsm_state;
|
||||
u_int16_t flags;
|
||||
u_int16_t status;
|
||||
u_int64_t start;
|
||||
u_int64_t end;
|
||||
|
@ -186,9 +174,13 @@ struct http_request {
|
|||
char *agent;
|
||||
struct connection *owner;
|
||||
struct kore_buf *http_body;
|
||||
int http_body_fd;
|
||||
char *http_body_path;
|
||||
size_t http_body_length;
|
||||
size_t http_body_offset;
|
||||
size_t content_length;
|
||||
void *hdlr_extra;
|
||||
char *query_string;
|
||||
u_int8_t *multipart_body;
|
||||
struct kore_module_handle *hdlr;
|
||||
|
||||
LIST_HEAD(, kore_task) tasks;
|
||||
|
@ -213,6 +205,10 @@ extern u_int64_t http_body_max;
|
|||
extern u_int64_t http_hsts_enable;
|
||||
extern u_int16_t http_keepalive_time;
|
||||
extern u_int32_t http_request_limit;
|
||||
extern u_int64_t http_body_disk_offload;
|
||||
extern char *http_body_disk_path;
|
||||
|
||||
void kore_accesslog(struct http_request *);
|
||||
|
||||
void http_init(void);
|
||||
void http_cleanup(void);
|
||||
|
@ -222,9 +218,8 @@ time_t http_date_to_time(char *);
|
|||
void http_request_free(struct http_request *);
|
||||
void http_request_sleep(struct http_request *);
|
||||
void http_request_wakeup(struct http_request *);
|
||||
char *http_body_text(struct http_request *);
|
||||
void http_process_request(struct http_request *, int);
|
||||
u_int8_t *http_body_bytes(struct http_request *, u_int32_t *);
|
||||
void http_process_request(struct http_request *);
|
||||
ssize_t http_body_read(struct http_request *, void *, size_t);
|
||||
void http_response(struct http_request *, int, void *, u_int32_t);
|
||||
void http_response_stream(struct http_request *, int, void *,
|
||||
u_int64_t, int (*cb)(struct netbuf *), void *);
|
||||
|
@ -240,15 +235,15 @@ int http_state_run(struct http_state *, u_int8_t,
|
|||
|
||||
int http_argument_urldecode(char *);
|
||||
int http_header_recv(struct netbuf *);
|
||||
int http_generic_404(struct http_request *);
|
||||
int http_populate_arguments(struct http_request *);
|
||||
int http_populate_multipart_form(struct http_request *, int *);
|
||||
void http_populate_get(struct http_request *);
|
||||
void http_populate_post(struct http_request *);
|
||||
void http_populate_multipart_form(struct http_request *);
|
||||
int http_argument_get(struct http_request *,
|
||||
const char *, void **, void *, u_int32_t *, int);
|
||||
int http_file_lookup(struct http_request *, const char *, char **,
|
||||
u_int8_t **, u_int32_t *);
|
||||
const char *, void **, void *, int);
|
||||
|
||||
void kore_accesslog(struct http_request *);
|
||||
void http_file_rewind(struct http_file *);
|
||||
ssize_t http_file_read(struct http_file *, void *, size_t);
|
||||
struct http_file *http_file_lookup(struct http_request *, const char *);
|
||||
|
||||
enum http_status_code {
|
||||
HTTP_STATUS_CONTINUE = 100,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2013-2015 Joris Vink <joris@coders.se>
|
||||
* Copyright (c) 2013-2016 Joris Vink <joris@coders.se>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
|
@ -22,17 +22,24 @@
|
|||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/queue.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#if !defined(KORE_NO_TLS)
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/dh.h>
|
||||
#include <openssl/ssl.h>
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
#include <regex.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <syslog.h>
|
||||
#include <unistd.h>
|
||||
#include <stdarg.h>
|
||||
|
@ -67,11 +74,11 @@ extern int daemon(int, int);
|
|||
#define KORE_DEFAULT_CIPHER_LIST "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!3DES:!MD5:!PSK:!kRSA:!kDSA"
|
||||
|
||||
#if defined(KORE_DEBUG)
|
||||
#define kore_debug(fmt, ...) \
|
||||
#define kore_debug(...) \
|
||||
if (kore_debug) \
|
||||
kore_debug_internal(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
|
||||
kore_debug_internal(__FILE__, __LINE__, ##__VA_ARGS__)
|
||||
#else
|
||||
#define kore_debug(fmt, ...)
|
||||
#define kore_debug(...)
|
||||
#endif
|
||||
|
||||
#define NETBUF_RECV 0
|
||||
|
@ -160,11 +167,13 @@ struct connection {
|
|||
u_int8_t state;
|
||||
u_int8_t proto;
|
||||
void *owner;
|
||||
#if !defined(KORE_NO_TLS)
|
||||
X509 *cert;
|
||||
SSL *ssl;
|
||||
int tls_reneg;
|
||||
#endif
|
||||
u_int8_t flags;
|
||||
void *hdlr_extra;
|
||||
X509 *cert;
|
||||
int tls_reneg;
|
||||
|
||||
int (*handle)(struct connection *);
|
||||
void (*disconnect)(struct connection *);
|
||||
|
@ -284,12 +293,14 @@ struct kore_worker {
|
|||
|
||||
struct kore_domain {
|
||||
char *domain;
|
||||
char *certfile;
|
||||
char *certkey;
|
||||
int accesslog;
|
||||
#if !defined(KORE_NO_TLS)
|
||||
char *cafile;
|
||||
char *crlfile;
|
||||
int accesslog;
|
||||
char *certfile;
|
||||
char *certkey;
|
||||
SSL_CTX *ssl_ctx;
|
||||
#endif
|
||||
TAILQ_HEAD(, kore_module_handle) handlers;
|
||||
TAILQ_ENTRY(kore_domain) list;
|
||||
};
|
||||
|
@ -312,8 +323,7 @@ struct kore_validator {
|
|||
};
|
||||
#endif
|
||||
|
||||
#define KORE_BUF_INITIAL 128
|
||||
#define KORE_BUF_INCREMENT KORE_BUF_INITIAL
|
||||
#define KORE_BUF_INCREMENT 4096
|
||||
|
||||
struct kore_buf {
|
||||
u_int8_t *data;
|
||||
|
@ -386,7 +396,10 @@ extern char *kore_pidfile;
|
|||
extern char *config_file;
|
||||
extern char *kore_tls_cipher_list;
|
||||
extern int tls_version;
|
||||
|
||||
#if !defined(KORE_NO_TLS)
|
||||
extern DH *tls_dhparam;
|
||||
#endif
|
||||
|
||||
extern u_int8_t nlisteners;
|
||||
extern u_int16_t cpu_count;
|
||||
|
@ -450,9 +463,11 @@ void kore_timer_remove(struct kore_timer *);
|
|||
struct kore_timer *kore_timer_add(void (*cb)(void *, u_int64_t),
|
||||
u_int64_t, void *, int);
|
||||
|
||||
int kore_tls_sni_cb(SSL *, int *, void *);
|
||||
int kore_server_bind(const char *, const char *, const char *);
|
||||
#if !defined(KORE_NO_TLS)
|
||||
int kore_tls_sni_cb(SSL *, int *, void *);
|
||||
void kore_tls_info_callback(const SSL *, int, int);
|
||||
#endif
|
||||
|
||||
void kore_connection_init(void);
|
||||
void kore_connection_cleanup(void);
|
||||
|
@ -581,8 +596,9 @@ void kore_buf_free(struct kore_buf *);
|
|||
struct kore_buf *kore_buf_create(u_int32_t);
|
||||
void kore_buf_append(struct kore_buf *, const void *, u_int32_t);
|
||||
u_int8_t *kore_buf_release(struct kore_buf *, u_int32_t *);
|
||||
void kore_buf_reset(struct kore_buf *);
|
||||
void kore_buf_reset(struct kore_buf *);
|
||||
|
||||
char *kore_buf_stringify(struct kore_buf *);
|
||||
void kore_buf_appendf(struct kore_buf *, const char *, ...);
|
||||
void kore_buf_appendv(struct kore_buf *, const char *, va_list);
|
||||
void kore_buf_appendb(struct kore_buf *, struct kore_buf *);
|
||||
|
|
|
@ -22,6 +22,9 @@
|
|||
#define KORE_PGSQL_FORMAT_TEXT 0
|
||||
#define KORE_PGSQL_FORMAT_BINARY 1
|
||||
|
||||
#define KORE_PGSQL_SYNC 0x0001
|
||||
#define KORE_PGSQL_ASYNC 0x0002
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
@ -29,14 +32,23 @@ extern "C" {
|
|||
struct pgsql_conn {
|
||||
u_int8_t type;
|
||||
u_int8_t flags;
|
||||
char *name;
|
||||
|
||||
PGconn *db;
|
||||
struct pgsql_job *job;
|
||||
TAILQ_ENTRY(pgsql_conn) list;
|
||||
};
|
||||
|
||||
struct pgsql_db {
|
||||
char *name;
|
||||
char *conn_string;
|
||||
|
||||
LIST_ENTRY(pgsql_db) rlist;
|
||||
};
|
||||
|
||||
struct kore_pgsql {
|
||||
u_int8_t state;
|
||||
int flags;
|
||||
char *error;
|
||||
PGresult *result;
|
||||
struct pgsql_conn *conn;
|
||||
|
@ -45,17 +57,17 @@ struct kore_pgsql {
|
|||
};
|
||||
|
||||
extern u_int16_t pgsql_conn_max;
|
||||
extern char *pgsql_conn_string;
|
||||
|
||||
void kore_pgsql_init(void);
|
||||
int kore_pgsql_query_init(struct kore_pgsql *, struct http_request *,
|
||||
const char *, int);
|
||||
void kore_pgsql_handle(void *, int);
|
||||
void kore_pgsql_cleanup(struct kore_pgsql *);
|
||||
void kore_pgsql_continue(struct http_request *, struct kore_pgsql *);
|
||||
int kore_pgsql_query(struct kore_pgsql *, struct http_request *,
|
||||
const char *);
|
||||
int kore_pgsql_query_params(struct kore_pgsql *, struct http_request *,
|
||||
int kore_pgsql_query(struct kore_pgsql *, const char *);
|
||||
int kore_pgsql_query_params(struct kore_pgsql *,
|
||||
const char *, int, u_int8_t, ...);
|
||||
|
||||
int kore_pgsql_register(const char *, const char *);
|
||||
int kore_pgsql_ntuples(struct kore_pgsql *);
|
||||
void kore_pgsql_logerror(struct kore_pgsql *);
|
||||
void kore_pgsql_queue_remove(struct http_request *);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2013-2015 Joris Vink <joris@coders.se>
|
||||
* Copyright (c) 2013-2016 Joris Vink <joris@coders.se>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
|
@ -17,6 +17,7 @@
|
|||
#include <sys/socket.h>
|
||||
|
||||
#include <poll.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "kore.h"
|
||||
#include "http.h"
|
||||
|
@ -32,7 +33,9 @@ struct kore_log_packet {
|
|||
char host[KORE_DOMAINNAME_LEN];
|
||||
char path[HTTP_URI_LEN];
|
||||
char agent[HTTP_USERAGENT_LEN];
|
||||
#if !defined(KORE_NO_TLS)
|
||||
char cn[X509_CN_LENGTH];
|
||||
#endif
|
||||
};
|
||||
|
||||
void
|
||||
|
@ -90,10 +93,11 @@ kore_accesslog_write(const void *data, u_int32_t len)
|
|||
break;
|
||||
}
|
||||
|
||||
cn = "none";
|
||||
#if !defined(KORE_NO_TLS)
|
||||
if (logpacket.cn[0] != '\0')
|
||||
cn = logpacket.cn;
|
||||
else
|
||||
cn = "none";
|
||||
#endif
|
||||
|
||||
if (inet_ntop(logpacket.addrtype, &(logpacket.addr),
|
||||
addr, sizeof(addr)) == NULL)
|
||||
|
@ -157,8 +161,8 @@ kore_accesslog(struct http_request *req)
|
|||
sizeof(logpacket.agent));
|
||||
}
|
||||
|
||||
memset(logpacket.cn, '\0', sizeof(logpacket.cn));
|
||||
#if !defined(KORE_NO_TLS)
|
||||
memset(logpacket.cn, '\0', sizeof(logpacket.cn));
|
||||
if (req->owner->cert != NULL) {
|
||||
if (X509_GET_CN(req->owner->cert,
|
||||
logpacket.cn, sizeof(logpacket.cn)) == -1) {
|
||||
|
|
|
@ -77,6 +77,7 @@ kore_auth_run(struct http_request *req, struct kore_auth *auth)
|
|||
|
||||
switch (r) {
|
||||
case KORE_RESULT_OK:
|
||||
req->flags |= HTTP_REQUEST_AUTHED;
|
||||
kore_debug("kore_auth_run() for %s successful", req->path);
|
||||
/* FALLTHROUGH */
|
||||
case KORE_RESULT_RETRY:
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2013-2015 Joris Vink <joris@coders.se>
|
||||
* Copyright (c) 2013-2016 Joris Vink <joris@coders.se>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
|
|
19
src/buf.c
19
src/buf.c
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2013-2015 Joris Vink <joris@coders.se>
|
||||
* Copyright (c) 2013-2016 Joris Vink <joris@coders.se>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
|
@ -37,7 +37,10 @@ kore_buf_create(u_int32_t initial)
|
|||
void
|
||||
kore_buf_append(struct kore_buf *buf, const void *d, u_int32_t len)
|
||||
{
|
||||
if ((buf->offset + len) >= buf->length) {
|
||||
if ((buf->offset + len) < len)
|
||||
fatal("overflow in kore_buf_append");
|
||||
|
||||
if ((buf->offset + len) > buf->length) {
|
||||
buf->length += len + KORE_BUF_INCREMENT;
|
||||
buf->data = kore_realloc(buf->data, buf->length);
|
||||
}
|
||||
|
@ -90,6 +93,16 @@ kore_buf_appendf(struct kore_buf *buf, const char *fmt, ...)
|
|||
va_end(args);
|
||||
}
|
||||
|
||||
char *
|
||||
kore_buf_stringify(struct kore_buf *buf)
|
||||
{
|
||||
char c;
|
||||
|
||||
c = '\0';
|
||||
kore_buf_append(buf, &c, sizeof(c));
|
||||
return ((char *)buf->data);
|
||||
}
|
||||
|
||||
u_int8_t *
|
||||
kore_buf_release(struct kore_buf *buf, u_int32_t *len)
|
||||
{
|
||||
|
@ -147,7 +160,7 @@ kore_buf_replace_string(struct kore_buf *b, char *src, void *dst, size_t len)
|
|||
}
|
||||
|
||||
void
|
||||
kore_buf_reset(struct kore_buf *buf)
|
||||
kore_buf_reset(struct kore_buf *buf)
|
||||
{
|
||||
buf->offset = 0;
|
||||
}
|
||||
|
|
|
@ -921,7 +921,9 @@ cli_compile_cfile(void *arg)
|
|||
#if defined(KORE_NO_HTTP)
|
||||
args[idx++] = "-DKORE_NO_HTTP";
|
||||
#endif
|
||||
|
||||
#if defined(KORE_NO_TLS)
|
||||
args[idx++] = "-DKORE_NO_TLS";
|
||||
#endif
|
||||
args[idx++] = "-Wall";
|
||||
args[idx++] = "-Wmissing-declarations";
|
||||
args[idx++] = "-Wshadow";
|
||||
|
|
41
src/config.c
41
src/config.c
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2013-2015 Joris Vink <joris@coders.se>
|
||||
* Copyright (c) 2013-2016 Joris Vink <joris@coders.se>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
|
@ -67,6 +67,8 @@ static int configure_http_body_max(char **);
|
|||
static int configure_http_hsts_enable(char **);
|
||||
static int configure_http_keepalive_time(char **);
|
||||
static int configure_http_request_limit(char **);
|
||||
static int configure_http_body_disk_offload(char **);
|
||||
static int configure_http_body_disk_path(char **);
|
||||
static int configure_validator(char **);
|
||||
static int configure_params(char **);
|
||||
static int configure_validate(char **);
|
||||
|
@ -124,6 +126,8 @@ static struct {
|
|||
{ "http_hsts_enable", configure_http_hsts_enable },
|
||||
{ "http_keepalive_time", configure_http_keepalive_time },
|
||||
{ "http_request_limit", configure_http_request_limit },
|
||||
{ "http_body_disk_offload", configure_http_body_disk_offload },
|
||||
{ "http_body_disk_path", configure_http_body_disk_path },
|
||||
{ "validator", configure_validator },
|
||||
{ "params", configure_params },
|
||||
{ "validate", configure_validate },
|
||||
|
@ -162,9 +166,6 @@ kore_parse_config(void)
|
|||
if (!kore_module_loaded())
|
||||
fatal("no site module was loaded");
|
||||
|
||||
if (LIST_EMPTY(&listeners))
|
||||
fatal("no listeners defined");
|
||||
|
||||
if (skip_chroot != 1 && chroot_path == NULL) {
|
||||
fatal("missing a chroot path");
|
||||
}
|
||||
|
@ -541,7 +542,7 @@ configure_http_body_max(char **argv)
|
|||
return (KORE_RESULT_ERROR);
|
||||
}
|
||||
|
||||
http_body_max = kore_strtonum(argv[1], 10, 1, LONG_MAX, &err);
|
||||
http_body_max = kore_strtonum(argv[1], 10, 0, LONG_MAX, &err);
|
||||
if (err != KORE_RESULT_OK) {
|
||||
printf("bad http_body_max value: %s\n", argv[1]);
|
||||
return (KORE_RESULT_ERROR);
|
||||
|
@ -550,6 +551,36 @@ configure_http_body_max(char **argv)
|
|||
return (KORE_RESULT_OK);
|
||||
}
|
||||
|
||||
static int
|
||||
configure_http_body_disk_offload(char **argv)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (argv[1] == NULL)
|
||||
return (KORE_RESULT_ERROR);
|
||||
|
||||
http_body_disk_offload = kore_strtonum(argv[1], 10, 0, LONG_MAX, &err);
|
||||
if (err != KORE_RESULT_OK) {
|
||||
printf("bad http_body_disk_offload value: %s\n", argv[1]);
|
||||
return (KORE_RESULT_ERROR);
|
||||
}
|
||||
|
||||
return (KORE_RESULT_OK);
|
||||
}
|
||||
|
||||
static int
|
||||
configure_http_body_disk_path(char **argv)
|
||||
{
|
||||
if (argv[1] == NULL)
|
||||
return (KORE_RESULT_ERROR);
|
||||
|
||||
if (strcmp(http_body_disk_path, HTTP_BODY_DISK_PATH))
|
||||
kore_mem_free(http_body_disk_path);
|
||||
|
||||
http_body_disk_path = kore_strdup(argv[1]);
|
||||
return (KORE_RESULT_OK);
|
||||
}
|
||||
|
||||
static int
|
||||
configure_http_hsts_enable(char **argv)
|
||||
{
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2013-2015 Joris Vink <joris@coders.se>
|
||||
* Copyright (c) 2013-2016 Joris Vink <joris@coders.se>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
|
@ -55,13 +55,15 @@ kore_connection_new(void *owner)
|
|||
|
||||
c = kore_pool_get(&connection_pool);
|
||||
|
||||
#if !defined(KORE_NO_TLS)
|
||||
c->ssl = NULL;
|
||||
c->cert = NULL;
|
||||
c->tls_reneg = 0;
|
||||
#endif
|
||||
c->flags = 0;
|
||||
c->rnb = NULL;
|
||||
c->snb = NULL;
|
||||
c->cert = NULL;
|
||||
c->owner = owner;
|
||||
c->tls_reneg = 0;
|
||||
c->handle = NULL;
|
||||
c->disconnect = NULL;
|
||||
c->hdlr_extra = NULL;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2013-2015 Joris Vink <joris@coders.se>
|
||||
* Copyright (c) 2013-2016 Joris Vink <joris@coders.se>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
|
@ -24,8 +24,11 @@
|
|||
|
||||
struct kore_domain_h domains;
|
||||
struct kore_domain *primary_dom = NULL;
|
||||
|
||||
#if !defined(KORE_NO_TLS)
|
||||
DH *tls_dhparam = NULL;
|
||||
int tls_version = KORE_TLS_VERSION_1_2;
|
||||
#endif
|
||||
|
||||
static void domain_load_crl(struct kore_domain *);
|
||||
|
||||
|
@ -51,11 +54,13 @@ kore_domain_new(char *domain)
|
|||
|
||||
dom = kore_malloc(sizeof(*dom));
|
||||
dom->accesslog = -1;
|
||||
#if !defined(KORE_NO_TLS)
|
||||
dom->cafile = NULL;
|
||||
dom->certkey = NULL;
|
||||
dom->ssl_ctx = NULL;
|
||||
dom->certfile = NULL;
|
||||
dom->crlfile = NULL;
|
||||
#endif
|
||||
dom->domain = kore_strdup(domain);
|
||||
TAILQ_INIT(&(dom->handlers));
|
||||
TAILQ_INSERT_TAIL(&domains, dom, list);
|
||||
|
|
1002
src/http.c
1002
src/http.c
File diff suppressed because it is too large
Load Diff
15
src/kore.c
15
src/kore.c
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2013-2015 Joris Vink <joris@coders.se>
|
||||
* Copyright (c) 2013-2016 Joris Vink <joris@coders.se>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
|
@ -15,6 +15,8 @@
|
|||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <sys/resource.h>
|
||||
|
||||
|
@ -24,6 +26,10 @@
|
|||
|
||||
#include "kore.h"
|
||||
|
||||
#if !defined(KORE_NO_HTTP)
|
||||
#include "http.h"
|
||||
#endif
|
||||
|
||||
volatile sig_atomic_t sig_recv;
|
||||
|
||||
struct listener_head listeners;
|
||||
|
@ -162,6 +168,13 @@ main(int argc, char *argv[])
|
|||
|
||||
#if !defined(KORE_NO_HTTP)
|
||||
kore_accesslog_init();
|
||||
if (http_body_disk_offload > 0) {
|
||||
if (mkdir(http_body_disk_path, 0700) == -1 && errno != EEXIST) {
|
||||
printf("can't create http_body_disk_path '%s': %s\n",
|
||||
http_body_disk_path, errno_s);
|
||||
return (KORE_RESULT_ERROR);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
sig_recv = 0;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2013-2015 Joris Vink <joris@coders.se>
|
||||
* Copyright (c) 2013-2016 Joris Vink <joris@coders.se>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2013-2015 Joris Vink <joris@coders.se>
|
||||
* Copyright (c) 2013-2016 Joris Vink <joris@coders.se>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2013-2015 Joris Vink <joris@coders.se>
|
||||
* Copyright (c) 2013-2016 Joris Vink <joris@coders.se>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2015 Joris Vink <joris@coders.se>
|
||||
* Copyright (c) 2016 Joris Vink <joris@coders.se>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
|
|
32
src/net.c
32
src/net.c
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2013-2015 Joris Vink <joris@coders.se>
|
||||
* Copyright (c) 2013-2016 Joris Vink <joris@coders.se>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
|
@ -293,6 +293,19 @@ net_write_ssl(struct connection *c, int len, int *written)
|
|||
c->snb->flags |= NETBUF_MUST_RESEND;
|
||||
c->flags &= ~CONN_WRITE_POSSIBLE;
|
||||
return (KORE_RESULT_OK);
|
||||
case SSL_ERROR_SYSCALL:
|
||||
switch (errno) {
|
||||
case EINTR:
|
||||
*written = 0;
|
||||
return (KORE_RESULT_OK);
|
||||
case EAGAIN:
|
||||
c->snb->flags |= NETBUF_MUST_RESEND;
|
||||
c->flags &= ~CONN_WRITE_POSSIBLE;
|
||||
return (KORE_RESULT_OK);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
/* FALLTHROUGH */
|
||||
default:
|
||||
kore_debug("SSL_write(): %s", ssl_errno_s);
|
||||
return (KORE_RESULT_ERROR);
|
||||
|
@ -321,6 +334,19 @@ net_read_ssl(struct connection *c, int *bytes)
|
|||
case SSL_ERROR_WANT_WRITE:
|
||||
c->flags &= ~CONN_READ_POSSIBLE;
|
||||
return (KORE_RESULT_OK);
|
||||
case SSL_ERROR_SYSCALL:
|
||||
switch (errno) {
|
||||
case EINTR:
|
||||
*bytes = 0;
|
||||
return (KORE_RESULT_OK);
|
||||
case EAGAIN:
|
||||
c->snb->flags |= NETBUF_MUST_RESEND;
|
||||
c->flags &= ~CONN_WRITE_POSSIBLE;
|
||||
return (KORE_RESULT_OK);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
/* FALLTHROUGH */
|
||||
default:
|
||||
kore_debug("SSL_read(): %s", ssl_errno_s);
|
||||
return (KORE_RESULT_ERROR);
|
||||
|
@ -341,6 +367,8 @@ net_write(struct connection *c, int len, int *written)
|
|||
if (r <= -1) {
|
||||
switch (errno) {
|
||||
case EINTR:
|
||||
*written = 0;
|
||||
return (KORE_RESULT_OK);
|
||||
case EAGAIN:
|
||||
c->flags &= ~CONN_WRITE_POSSIBLE;
|
||||
return (KORE_RESULT_OK);
|
||||
|
@ -364,6 +392,8 @@ net_read(struct connection *c, int *bytes)
|
|||
if (r <= 0) {
|
||||
switch (errno) {
|
||||
case EINTR:
|
||||
*bytes = 0;
|
||||
return (KORE_RESULT_OK);
|
||||
case EAGAIN:
|
||||
c->flags &= ~CONN_READ_POSSIBLE;
|
||||
return (KORE_RESULT_OK);
|
||||
|
|
273
src/pgsql.c
273
src/pgsql.c
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2014 Joris Vink <joris@coders.se>
|
||||
* Copyright (c) 2014-2016 Joris Vink <joris@coders.se>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
|
@ -25,7 +25,6 @@
|
|||
#include "pgsql.h"
|
||||
|
||||
struct pgsql_job {
|
||||
char *query;
|
||||
struct http_request *req;
|
||||
struct kore_pgsql *pgsql;
|
||||
|
||||
|
@ -37,28 +36,30 @@ struct pgsql_wait {
|
|||
TAILQ_ENTRY(pgsql_wait) list;
|
||||
};
|
||||
|
||||
#define PGSQL_IS_BLOCKING 0
|
||||
#define PGSQL_IS_ASYNC 1
|
||||
|
||||
#define PGSQL_CONN_MAX 2
|
||||
#define PGSQL_CONN_FREE 0x01
|
||||
#define PGSQL_LIST_INSERTED 0x0100
|
||||
|
||||
static void pgsql_queue_wakeup(void);
|
||||
static int pgsql_conn_create(struct kore_pgsql *);
|
||||
static void pgsql_set_error(struct kore_pgsql *, const char *);
|
||||
static void pgsql_queue_add(struct http_request *);
|
||||
static void pgsql_conn_release(struct kore_pgsql *);
|
||||
static void pgsql_conn_cleanup(struct pgsql_conn *);
|
||||
static void pgsql_read_result(struct kore_pgsql *, int);
|
||||
static void pgsql_schedule(struct kore_pgsql *, struct http_request *);
|
||||
static int pgsql_prepare(struct kore_pgsql *, struct http_request *,
|
||||
const char *);
|
||||
static void pgsql_read_result(struct kore_pgsql *);
|
||||
static void pgsql_schedule(struct kore_pgsql *);
|
||||
|
||||
static struct pgsql_conn *pgsql_conn_create(struct kore_pgsql *,
|
||||
struct pgsql_db *);
|
||||
static struct pgsql_conn *pgsql_conn_next(struct kore_pgsql *,
|
||||
struct pgsql_db *,
|
||||
struct http_request *);
|
||||
|
||||
static struct kore_pool pgsql_job_pool;
|
||||
static struct kore_pool pgsql_wait_pool;
|
||||
static TAILQ_HEAD(, pgsql_conn) pgsql_conn_free;
|
||||
static TAILQ_HEAD(, pgsql_wait) pgsql_wait_queue;
|
||||
static LIST_HEAD(, pgsql_db) pgsql_db_conn_strings;
|
||||
static u_int16_t pgsql_conn_count;
|
||||
char *pgsql_conn_string = NULL;
|
||||
u_int16_t pgsql_conn_max = PGSQL_CONN_MAX;
|
||||
|
||||
void
|
||||
|
@ -67,6 +68,7 @@ kore_pgsql_init(void)
|
|||
pgsql_conn_count = 0;
|
||||
TAILQ_INIT(&pgsql_conn_free);
|
||||
TAILQ_INIT(&pgsql_wait_queue);
|
||||
LIST_INIT(&pgsql_db_conn_strings);
|
||||
|
||||
kore_pool_init(&pgsql_job_pool, "pgsql_job_pool",
|
||||
sizeof(struct pgsql_job), 100);
|
||||
|
@ -75,32 +77,91 @@ kore_pgsql_init(void)
|
|||
}
|
||||
|
||||
int
|
||||
kore_pgsql_query(struct kore_pgsql *pgsql, struct http_request *req,
|
||||
const char *query)
|
||||
kore_pgsql_query_init(struct kore_pgsql *pgsql, struct http_request *req,
|
||||
const char *dbname, int flags)
|
||||
{
|
||||
if (!pgsql_prepare(pgsql, req, query))
|
||||
return (KORE_RESULT_ERROR);
|
||||
struct pgsql_db *db;
|
||||
|
||||
if (!PQsendQuery(pgsql->conn->db, query)) {
|
||||
pgsql_conn_cleanup(pgsql->conn);
|
||||
memset(pgsql, 0, sizeof(*pgsql));
|
||||
pgsql->flags = flags;
|
||||
pgsql->state = KORE_PGSQL_STATE_INIT;
|
||||
|
||||
if ((req == NULL && (flags & KORE_PGSQL_ASYNC)) ||
|
||||
((flags & KORE_PGSQL_ASYNC) && (flags & KORE_PGSQL_SYNC))) {
|
||||
pgsql_set_error(pgsql, "invalid query init parameters");
|
||||
return (KORE_RESULT_ERROR);
|
||||
}
|
||||
|
||||
pgsql_schedule(pgsql, req);
|
||||
db = NULL;
|
||||
LIST_FOREACH(db, &pgsql_db_conn_strings, rlist) {
|
||||
if (!strcmp(db->name, dbname))
|
||||
break;
|
||||
}
|
||||
|
||||
if (db == NULL) {
|
||||
pgsql_set_error(pgsql, "no database found");
|
||||
return (KORE_RESULT_ERROR);
|
||||
}
|
||||
|
||||
if ((pgsql->conn = pgsql_conn_next(pgsql, db, req)) == NULL)
|
||||
return (KORE_RESULT_ERROR);
|
||||
|
||||
if (pgsql->flags & KORE_PGSQL_ASYNC) {
|
||||
pgsql->conn->job = kore_pool_get(&pgsql_job_pool);
|
||||
pgsql->conn->job->req = req;
|
||||
pgsql->conn->job->pgsql = pgsql;
|
||||
|
||||
http_request_sleep(req);
|
||||
pgsql->flags |= PGSQL_LIST_INSERTED;
|
||||
LIST_INSERT_HEAD(&(req->pgsqls), pgsql, rlist);
|
||||
}
|
||||
|
||||
return (KORE_RESULT_OK);
|
||||
}
|
||||
|
||||
int
|
||||
kore_pgsql_query_params(struct kore_pgsql *pgsql, struct http_request *req,
|
||||
kore_pgsql_query(struct kore_pgsql *pgsql, const char *query)
|
||||
{
|
||||
if (pgsql->conn == NULL) {
|
||||
pgsql_set_error(pgsql, "no connection was set before query");
|
||||
return (KORE_RESULT_ERROR);
|
||||
}
|
||||
|
||||
if (pgsql->flags & KORE_PGSQL_SYNC) {
|
||||
pgsql->result = PQexec(pgsql->conn->db, query);
|
||||
|
||||
if ((PQresultStatus(pgsql->result) != PGRES_TUPLES_OK) &&
|
||||
(PQresultStatus(pgsql->result) != PGRES_COMMAND_OK)) {
|
||||
pgsql_set_error(pgsql, PQerrorMessage(pgsql->conn->db));
|
||||
return (KORE_RESULT_ERROR);
|
||||
}
|
||||
|
||||
pgsql->state = KORE_PGSQL_STATE_DONE;
|
||||
} else {
|
||||
if (!PQsendQuery(pgsql->conn->db, query)) {
|
||||
pgsql_set_error(pgsql, PQerrorMessage(pgsql->conn->db));
|
||||
return (KORE_RESULT_ERROR);
|
||||
}
|
||||
|
||||
pgsql_schedule(pgsql);
|
||||
}
|
||||
|
||||
return (KORE_RESULT_OK);
|
||||
}
|
||||
|
||||
int
|
||||
kore_pgsql_query_params(struct kore_pgsql *pgsql,
|
||||
const char *query, int result, u_int8_t count, ...)
|
||||
{
|
||||
u_int8_t i;
|
||||
va_list args;
|
||||
char **values;
|
||||
int *lengths, *formats;
|
||||
int *lengths, *formats, ret;
|
||||
|
||||
if (!pgsql_prepare(pgsql, req, query))
|
||||
if (pgsql->conn == NULL) {
|
||||
pgsql_set_error(pgsql, "no connection was set before query");
|
||||
return (KORE_RESULT_ERROR);
|
||||
}
|
||||
|
||||
if (count > 0) {
|
||||
va_start(args, count);
|
||||
|
@ -120,20 +181,55 @@ kore_pgsql_query_params(struct kore_pgsql *pgsql, struct http_request *req,
|
|||
values = NULL;
|
||||
}
|
||||
|
||||
if (!PQsendQueryParams(pgsql->conn->db, query, count, NULL,
|
||||
(const char * const *)values, lengths, formats, result)) {
|
||||
kore_mem_free(values);
|
||||
kore_mem_free(lengths);
|
||||
kore_mem_free(formats);
|
||||
pgsql_conn_cleanup(pgsql->conn);
|
||||
return (KORE_RESULT_ERROR);
|
||||
ret = KORE_RESULT_ERROR;
|
||||
|
||||
if (pgsql->flags & KORE_PGSQL_SYNC) {
|
||||
pgsql->result = PQexecParams(pgsql->conn->db, query, count,
|
||||
NULL, (const char * const *)values, lengths, formats,
|
||||
result);
|
||||
|
||||
if ((PQresultStatus(pgsql->result) != PGRES_TUPLES_OK) &&
|
||||
(PQresultStatus(pgsql->result) != PGRES_COMMAND_OK)) {
|
||||
pgsql_set_error(pgsql, PQerrorMessage(pgsql->conn->db));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
pgsql->state = KORE_PGSQL_STATE_DONE;
|
||||
} else {
|
||||
if (!PQsendQueryParams(pgsql->conn->db, query, count, NULL,
|
||||
(const char * const *)values, lengths, formats, result)) {
|
||||
pgsql_set_error(pgsql, PQerrorMessage(pgsql->conn->db));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
pgsql_schedule(pgsql);
|
||||
}
|
||||
|
||||
ret = KORE_RESULT_OK;
|
||||
|
||||
cleanup:
|
||||
kore_mem_free(values);
|
||||
kore_mem_free(lengths);
|
||||
kore_mem_free(formats);
|
||||
|
||||
pgsql_schedule(pgsql, req);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
int
|
||||
kore_pgsql_register(const char *dbname, const char *connstring)
|
||||
{
|
||||
struct pgsql_db *pgsqldb;
|
||||
|
||||
LIST_FOREACH(pgsqldb, &pgsql_db_conn_strings, rlist) {
|
||||
if (!strcmp(pgsqldb->name, dbname))
|
||||
return (KORE_RESULT_ERROR);
|
||||
}
|
||||
|
||||
pgsqldb = kore_malloc(sizeof(*pgsqldb));
|
||||
pgsqldb->name = kore_strdup(dbname);
|
||||
pgsqldb->conn_string = kore_strdup(connstring);
|
||||
LIST_INSERT_HEAD(&pgsql_db_conn_strings, pgsqldb, rlist);
|
||||
|
||||
return (KORE_RESULT_OK);
|
||||
}
|
||||
|
||||
|
@ -157,7 +253,7 @@ kore_pgsql_handle(void *c, int err)
|
|||
pgsql->state = KORE_PGSQL_STATE_ERROR;
|
||||
pgsql->error = kore_strdup(PQerrorMessage(conn->db));
|
||||
} else {
|
||||
pgsql_read_result(pgsql, PGSQL_IS_ASYNC);
|
||||
pgsql_read_result(pgsql);
|
||||
}
|
||||
|
||||
if (pgsql->state == KORE_PGSQL_STATE_WAIT) {
|
||||
|
@ -218,7 +314,10 @@ kore_pgsql_cleanup(struct kore_pgsql *pgsql)
|
|||
pgsql->error = NULL;
|
||||
pgsql->conn = NULL;
|
||||
|
||||
LIST_REMOVE(pgsql, rlist);
|
||||
if (pgsql->flags & PGSQL_LIST_INSERTED) {
|
||||
LIST_REMOVE(pgsql, rlist);
|
||||
pgsql->flags &= ~PGSQL_LIST_INSERTED;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -262,47 +361,55 @@ kore_pgsql_queue_remove(struct http_request *req)
|
|||
}
|
||||
}
|
||||
|
||||
static int
|
||||
pgsql_prepare(struct kore_pgsql *pgsql, struct http_request *req,
|
||||
const char *query)
|
||||
static struct pgsql_conn *
|
||||
pgsql_conn_next(struct kore_pgsql *pgsql, struct pgsql_db *db,
|
||||
struct http_request *req)
|
||||
{
|
||||
struct pgsql_conn *conn;
|
||||
|
||||
pgsql->state = KORE_PGSQL_STATE_INIT;
|
||||
pgsql->result = NULL;
|
||||
pgsql->error = NULL;
|
||||
pgsql->conn = NULL;
|
||||
conn = NULL;
|
||||
|
||||
if (TAILQ_EMPTY(&pgsql_conn_free)) {
|
||||
if (pgsql_conn_count >= pgsql_conn_max) {
|
||||
pgsql_queue_add(req);
|
||||
return (KORE_RESULT_ERROR);
|
||||
}
|
||||
|
||||
if (!pgsql_conn_create(pgsql))
|
||||
return (KORE_RESULT_ERROR);
|
||||
TAILQ_FOREACH(conn, &pgsql_conn_free, list) {
|
||||
if (!(conn->flags & PGSQL_CONN_FREE))
|
||||
fatal("got a pgsql connection that was not free?");
|
||||
if (!strcmp(conn->name, db->name))
|
||||
break;
|
||||
}
|
||||
|
||||
http_request_sleep(req);
|
||||
conn = TAILQ_FIRST(&pgsql_conn_free);
|
||||
if (!(conn->flags & PGSQL_CONN_FREE))
|
||||
fatal("received a pgsql conn that was not free?");
|
||||
if (conn == NULL) {
|
||||
if (pgsql_conn_count >= pgsql_conn_max) {
|
||||
if (pgsql->flags & KORE_PGSQL_ASYNC) {
|
||||
pgsql_queue_add(req);
|
||||
} else {
|
||||
pgsql_set_error(pgsql,
|
||||
"no available connection");
|
||||
}
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
if ((conn = pgsql_conn_create(pgsql, db)) == NULL)
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
conn->flags &= ~PGSQL_CONN_FREE;
|
||||
TAILQ_REMOVE(&pgsql_conn_free, conn, list);
|
||||
|
||||
pgsql->conn = conn;
|
||||
conn->job = kore_pool_get(&pgsql_job_pool);
|
||||
conn->job->query = kore_strdup(query);
|
||||
conn->job->pgsql = pgsql;
|
||||
conn->job->req = req;
|
||||
|
||||
LIST_INSERT_HEAD(&(req->pgsqls), pgsql, rlist);
|
||||
return (KORE_RESULT_OK);
|
||||
return (conn);
|
||||
}
|
||||
|
||||
static void
|
||||
pgsql_schedule(struct kore_pgsql *pgsql, struct http_request *req)
|
||||
pgsql_set_error(struct kore_pgsql *pgsql, const char *msg)
|
||||
{
|
||||
if (pgsql->error != NULL)
|
||||
kore_mem_free(pgsql->error);
|
||||
|
||||
pgsql->error = kore_strdup(msg);
|
||||
pgsql->state = KORE_PGSQL_STATE_ERROR;
|
||||
}
|
||||
|
||||
static void
|
||||
pgsql_schedule(struct kore_pgsql *pgsql)
|
||||
{
|
||||
int fd;
|
||||
|
||||
|
@ -347,33 +454,32 @@ pgsql_queue_wakeup(void)
|
|||
}
|
||||
}
|
||||
|
||||
static int
|
||||
pgsql_conn_create(struct kore_pgsql *pgsql)
|
||||
static struct pgsql_conn *
|
||||
pgsql_conn_create(struct kore_pgsql *pgsql, struct pgsql_db *db)
|
||||
{
|
||||
struct pgsql_conn *conn;
|
||||
|
||||
if (pgsql_conn_string == NULL)
|
||||
if (db == NULL || db->conn_string == NULL)
|
||||
fatal("pgsql_conn_create: no connection string");
|
||||
|
||||
pgsql_conn_count++;
|
||||
conn = kore_malloc(sizeof(*conn));
|
||||
kore_debug("pgsql_conn_create(): %p", conn);
|
||||
memset(conn, 0, sizeof(*conn));
|
||||
|
||||
conn->db = PQconnectdb(pgsql_conn_string);
|
||||
conn->db = PQconnectdb(db->conn_string);
|
||||
if (conn->db == NULL || (PQstatus(conn->db) != CONNECTION_OK)) {
|
||||
pgsql->state = KORE_PGSQL_STATE_ERROR;
|
||||
pgsql->error = kore_strdup(PQerrorMessage(conn->db));
|
||||
pgsql_set_error(pgsql, PQerrorMessage(conn->db));
|
||||
pgsql_conn_cleanup(conn);
|
||||
return (KORE_RESULT_ERROR);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
conn->job = NULL;
|
||||
conn->flags = PGSQL_CONN_FREE;
|
||||
conn->type = KORE_TYPE_PGSQL_CONN;
|
||||
conn->name = kore_strdup(db->name);
|
||||
TAILQ_INSERT_TAIL(&pgsql_conn_free, conn, list);
|
||||
|
||||
return (KORE_RESULT_OK);
|
||||
return (conn);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -384,8 +490,14 @@ pgsql_conn_release(struct kore_pgsql *pgsql)
|
|||
if (pgsql->conn == NULL)
|
||||
return;
|
||||
|
||||
kore_mem_free(pgsql->conn->job->query);
|
||||
kore_pool_put(&pgsql_job_pool, pgsql->conn->job);
|
||||
/* Async query cleanup */
|
||||
if (pgsql->flags & KORE_PGSQL_ASYNC) {
|
||||
if (pgsql->conn != NULL) {
|
||||
fd = PQsocket(pgsql->conn->db);
|
||||
kore_platform_disable_read(fd);
|
||||
kore_pool_put(&pgsql_job_pool, pgsql->conn->job);
|
||||
}
|
||||
}
|
||||
|
||||
/* Drain just in case. */
|
||||
while (PQgetResult(pgsql->conn->db) != NULL)
|
||||
|
@ -395,9 +507,6 @@ pgsql_conn_release(struct kore_pgsql *pgsql)
|
|||
pgsql->conn->flags |= PGSQL_CONN_FREE;
|
||||
TAILQ_INSERT_TAIL(&pgsql_conn_free, pgsql->conn, list);
|
||||
|
||||
fd = PQsocket(pgsql->conn->db);
|
||||
kore_platform_disable_read(fd);
|
||||
|
||||
pgsql->conn = NULL;
|
||||
pgsql->state = KORE_PGSQL_STATE_COMPLETE;
|
||||
|
||||
|
@ -421,10 +530,8 @@ pgsql_conn_cleanup(struct pgsql_conn *conn)
|
|||
http_request_wakeup(req);
|
||||
|
||||
pgsql->conn = NULL;
|
||||
pgsql->state = KORE_PGSQL_STATE_ERROR;
|
||||
pgsql->error = kore_strdup(PQerrorMessage(conn->db));
|
||||
pgsql_set_error(pgsql, PQerrorMessage(conn->db));
|
||||
|
||||
kore_mem_free(conn->job->query);
|
||||
kore_pool_put(&pgsql_job_pool, conn->job);
|
||||
conn->job = NULL;
|
||||
}
|
||||
|
@ -433,17 +540,16 @@ pgsql_conn_cleanup(struct pgsql_conn *conn)
|
|||
PQfinish(conn->db);
|
||||
|
||||
pgsql_conn_count--;
|
||||
kore_mem_free(conn->name);
|
||||
kore_mem_free(conn);
|
||||
}
|
||||
|
||||
static void
|
||||
pgsql_read_result(struct kore_pgsql *pgsql, int async)
|
||||
pgsql_read_result(struct kore_pgsql *pgsql)
|
||||
{
|
||||
if (async) {
|
||||
if (PQisBusy(pgsql->conn->db)) {
|
||||
pgsql->state = KORE_PGSQL_STATE_WAIT;
|
||||
return;
|
||||
}
|
||||
if (PQisBusy(pgsql->conn->db)) {
|
||||
pgsql->state = KORE_PGSQL_STATE_WAIT;
|
||||
return;
|
||||
}
|
||||
|
||||
pgsql->result = PQgetResult(pgsql->conn->db);
|
||||
|
@ -470,8 +576,7 @@ pgsql_read_result(struct kore_pgsql *pgsql, int async)
|
|||
case PGRES_EMPTY_QUERY:
|
||||
case PGRES_BAD_RESPONSE:
|
||||
case PGRES_FATAL_ERROR:
|
||||
pgsql->state = KORE_PGSQL_STATE_ERROR;
|
||||
pgsql->error = kore_strdup(PQresultErrorMessage(pgsql->result));
|
||||
pgsql_set_error(pgsql, PQresultErrorMessage(pgsql->result));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2013-2015 Joris Vink <joris@coders.se>
|
||||
* Copyright (c) 2013-2016 Joris Vink <joris@coders.se>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2015 Joris Vink <joris@coders.se>
|
||||
* Copyright (c) 2016 Joris Vink <joris@coders.se>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2013-2015 Joris Vink <joris@coders.se>
|
||||
* Copyright (c) 2013-2016 Joris Vink <joris@coders.se>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
|
@ -20,6 +20,7 @@
|
|||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "kore.h"
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2013-2015 Joris Vink <joris@coders.se>
|
||||
* Copyright (c) 2013-2016 Joris Vink <joris@coders.se>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
|
||||
#include <sys/param.h>
|
||||
|
||||
#include <openssl/sha.h>
|
||||
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2013-2015 Joris Vink <joris@coders.se>
|
||||
* Copyright (c) 2013-2016 Joris Vink <joris@coders.se>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
|
|
Loading…
Reference in New Issue