├── .gitignore ├── BEERS ├── LICENSE ├── Makefile ├── README.md ├── RELEASE.md ├── conf └── kore.conf.example ├── examples ├── Makefile ├── async-curl │ ├── .gitignore │ ├── README.md │ ├── conf │ │ ├── async-curl.conf │ │ └── build.conf │ └── src │ │ ├── ftp.c │ │ ├── http.c │ │ └── init.c ├── cookies │ ├── README.md │ ├── conf │ │ ├── build.conf │ │ └── cookies.conf │ └── src │ │ └── cookies.c ├── cpp │ ├── .gitignore │ ├── README.md │ ├── conf │ │ ├── build.conf │ │ └── cpp.conf │ └── src │ │ ├── cpp.cpp │ │ ├── example_class.cpp │ │ └── example_class.h ├── generic │ ├── README.md │ ├── assets │ │ ├── index.html │ │ ├── intro.jpg │ │ ├── params.html │ │ ├── private.html │ │ ├── private_test.html │ │ ├── style.css │ │ └── upload.html │ ├── conf │ │ ├── build.conf │ │ └── generic.conf │ └── src │ │ └── example.c ├── headers │ ├── .gitignore │ ├── README.md │ ├── conf │ │ ├── build.conf │ │ └── headers.conf │ └── src │ │ └── headers.c ├── integers │ ├── .gitignore │ ├── README.md │ ├── conf │ │ ├── build.conf │ │ └── integers.conf │ └── src │ │ └── check_integers.c ├── json │ ├── .gitignore │ ├── README.md │ ├── conf │ │ ├── build.conf │ │ └── json.conf │ └── src │ │ └── json.c ├── jsonrpc │ ├── .gitignore │ ├── README.md │ ├── conf │ │ ├── build.conf │ │ └── jsonrpc.conf │ ├── src │ │ ├── home.c │ │ └── v1.c │ └── test │ │ └── integ │ │ └── jsonrpc.bats ├── memtag │ ├── .gitignore │ ├── conf │ │ ├── build.conf │ │ └── memtag.conf │ └── src │ │ └── memtag.c ├── messaging │ ├── .gitignore │ ├── README.md │ ├── conf │ │ ├── build.conf │ │ └── messaging.conf │ └── src │ │ └── messaging.c ├── nohttp │ ├── .gitignore │ ├── README.md │ ├── conf │ │ ├── build.conf │ │ └── nohttp.conf │ └── src │ │ ├── init.c │ │ └── nohttp.c ├── parameters │ ├── .gitignore │ ├── README.md │ ├── conf │ │ ├── build.conf │ │ └── parameters.conf │ └── src │ │ └── parameters.c ├── pgsql-sync │ ├── .gitignore │ ├── conf │ │ ├── build.conf │ │ └── pgsql-sync.conf │ └── src │ │ └── pgsql-sync.c ├── pgsql │ ├── .gitignore │ ├── README.md │ ├── conf │ │ ├── build.conf │ │ └── pgsql.conf │ └── src │ │ ├── init.c │ │ ├── pgsql.c │ │ └── pgsql_cb.c ├── pipe_task │ ├── .gitignore │ ├── README.md │ ├── assets │ │ └── frontend.html │ ├── conf │ │ ├── build.conf │ │ └── pipe_task.conf │ └── src │ │ ├── init.c │ │ └── pipe_task.c ├── python-async │ ├── .gitignore │ ├── README.md │ ├── app.py │ ├── async_http.py │ ├── async_lock.py │ ├── async_process.py │ ├── async_queue.py │ └── async_socket.py ├── python-echo │ ├── .gitignore │ ├── README.md │ └── echo.py ├── python-pgsql │ ├── .gitignore │ ├── README.md │ ├── __init__.py │ ├── app.py │ └── kore.conf ├── sse │ ├── .gitignore │ ├── README.md │ ├── assets │ │ └── index.html │ ├── conf │ │ ├── build.conf │ │ └── sse.conf │ └── src │ │ └── sse.c ├── tasks │ ├── README.md │ ├── conf │ │ ├── build.conf │ │ └── tasks.conf │ └── src │ │ ├── init.c │ │ └── tasks.c ├── tls-proxy │ ├── .gitignore │ ├── README.md │ ├── conf │ │ ├── build.conf │ │ └── tls-proxy.conf │ └── src │ │ └── proxy.c ├── upload │ ├── .gitignore │ ├── conf │ │ ├── build.conf │ │ └── upload.conf │ └── src │ │ └── upload.c ├── video_stream │ ├── .gitignore │ ├── README.md │ ├── assets │ │ └── video.html │ ├── conf │ │ ├── build.conf │ │ └── video_stream.conf │ ├── src │ │ └── stream.c │ └── videos │ │ └── placeholder └── websocket │ ├── .gitignore │ ├── README.md │ ├── assets │ └── frontend.html │ ├── conf │ ├── build.conf │ └── websocket.conf │ └── src │ └── websocket.c ├── include └── kore │ ├── acme.h │ ├── curl.h │ ├── hooks.h │ ├── http.h │ ├── jsonrpc.h │ ├── kore.h │ ├── lua_api.h │ ├── lua_methods.h │ ├── pgsql.h │ ├── python_api.h │ ├── python_methods.h │ ├── seccomp.h │ ├── sha1.h │ ├── sha2.h │ └── tasks.h ├── kodev └── Makefile ├── minisign.pub ├── misc ├── curl-extract-opt.sh ├── curl │ └── python_curlopt.h ├── ffdhe4096.pem ├── hooks │ └── post-receive ├── linux-platform.sh ├── linux │ ├── aarch64_syscall.h.in │ ├── arm_syscall.h.in │ ├── i386_syscall.h.in │ └── x86_64_syscall.h.in └── python3-config.sh ├── src ├── accesslog.c ├── acme.c ├── auth.c ├── bsd.c ├── buf.c ├── cli.c ├── config.c ├── connection.c ├── curl.c ├── domain.c ├── filemap.c ├── fileref.c ├── http.c ├── json.c ├── jsonrpc.c ├── keymgr_openssl.c ├── kore.c ├── linux.c ├── log.c ├── lua.c ├── mem.c ├── module.c ├── msg.c ├── net.c ├── pgsql.c ├── pool.c ├── python.c ├── route.c ├── runtime.c ├── seccomp.c ├── sha1.c ├── sha2.c ├── tasks.c ├── timer.c ├── tls_none.c ├── tls_openssl.c ├── utils.c ├── validator.c ├── websocket.c └── worker.c └── tools └── kore-serve ├── .gitignore ├── conf ├── build.conf └── kore-serve.conf └── src └── kore-serve.c /.gitignore: -------------------------------------------------------------------------------- 1 | kore 2 | *.o 3 | *.swp 4 | *.swo 5 | *.module 6 | *.DSYM 7 | cert 8 | obj 9 | .lvimrc 10 | kodev/kodev 11 | kore.features 12 | src/version.c 13 | src/platform.h 14 | -------------------------------------------------------------------------------- /BEERS: -------------------------------------------------------------------------------- 1 | THE BEER LIST. 2 | 3 | Any contributer to Kore that submitted patches will be put on this list. 4 | 5 | If you are on this list, I owe you a beer if we ever run into 6 | each other at any time. 7 | 8 | It is however your responsibility to remind me ;) 9 | 10 | I will note down the beer of your choice between the brackets. 11 | 12 | [] Andreas Pfohl 13 | [] Ansen Dong 14 | [] Carl Ekerot 15 | [] Cleve Lendon 16 | [] Corbin Hughes 17 | [] Daniel Fahlgren x 6 18 | [] Daniel Melani 19 | [] Dmitrii Golub 20 | [] Elliot Schlegelmilch 21 | [] Erik Karlsson x 2 22 | [] Frederic Cambus 23 | [] Guy Nankivell 24 | [] James Turner 25 | [] Joel Arbring x 2 26 | [] Manuel Kniep 27 | [] Marcin Szczepaniak 28 | [] Matt Thompson 29 | [] Matthew Norström 30 | [] Nandor Kracser 31 | [] Pascal Borreli 32 | [] Quentin Perez 33 | [] Raphaël Monrouzeau 34 | [] Raymond Pasco 35 | [] Remy Noulin 36 | [] Rickard Lind x 3 37 | [] Shih-Yuan Lee 38 | [] Stanislav Yudin 39 | [] Stig Telfer 40 | [] Thordur Bjornsson 41 | [] Tobias Kortkamp 42 | [] Yorick de Wid 43 | [] Yvan Sraka 44 | [] Ángel González 45 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-2022 Joris Vink 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | About 2 | ----- 3 | 4 | Kore (https://kore.io) is a web application platform for writing scalable, 5 | concurrent web based processes in C or Python. 6 | 7 | It is built with a "secure by default" approach. It is fully privilege 8 | separated while using strong security features at the operating system level 9 | such as seccomp, pledge, unveil and more. 10 | 11 | Today Kore is used in a variety of applications ranging from high assurance 12 | cryptographic devices, machine-learning stacks and even in the aerospace 13 | industry. 14 | 15 | From embedded platforms all the way to high performance servers. *Kore scales.* 16 | 17 | Key Features 18 | ------------ 19 | * Supports SNI 20 | * Supports HTTP/1.1 21 | * Websocket support 22 | * Privseps by default 23 | * TLS enabled by default 24 | * Optional background tasks 25 | * Built-in parameter validation 26 | * Optional asynchronous PostgreSQL support 27 | * Optional support for page handlers in Python 28 | * Reload private keys and certificates on-the-fly 29 | * Automatic X509 certificates via ACME (with privsep) 30 | * Private keys isolated in separate process (RSA and ECDSA) 31 | * Default sane TLS ciphersuites (PFS in all major browsers) 32 | * Modules can be reloaded on-the-fly, even while serving content 33 | * Worker processes sandboxed on OpenBSD (pledge) and Linux (seccomp) 34 | * Event driven (epoll/kqueue) architecture with per CPU worker processes 35 | * Build your web application as a precompiled dynamic library or single binary 36 | 37 | And lots more. 38 | 39 | License 40 | ------- 41 | * Kore is licensed under the ISC license 42 | 43 | Documentation 44 | -------------- 45 | [Read the documentation](https://docs.kore.io/4.2.0/) 46 | 47 | Performance 48 | ----------- 49 | Read the [benchmarks](https://blog.kore.io/posts/benchmarks) blog post. 50 | 51 | Platforms supported 52 | ------------------- 53 | * Linux 54 | * OpenBSD 55 | * FreeBSD 56 | * MacOS 57 | 58 | Kore only supports x64, arm and aarch64 architectures. 59 | 60 | Building Kore 61 | ------------- 62 | Clone this repository or get the latest release at [https://kore.io/releases/4.2.3](https://kore.io/releases/4.2.3). 63 | 64 | Requirements 65 | * openssl 1.1.1, libressl 3.x or openssl 3. 66 | 67 | Requirement for asynchronous curl (optional) 68 | * libcurl (7.64.0 or higher) 69 | 70 | Requirements for background tasks (optional) 71 | * pthreads 72 | 73 | Requirements for pgsql (optional) 74 | * libpq 75 | 76 | Requirements for python (optional) 77 | * Python 3.6+ 78 | 79 | Requirements for lua support (optional) 80 | * Lua 5.4+ 81 | 82 | Normal compilation and installation: 83 | 84 | ``` 85 | $ cd kore 86 | $ make 87 | # make install 88 | ``` 89 | 90 | If you would like to build a specific flavor, you can enable 91 | those by setting a shell environment variable before running **_make_**. 92 | 93 | * LUA=1 (compiles in LUA support) 94 | * ACME=1 (compiles in ACME support) 95 | * CURL=1 (compiles in asynchronous curl support) 96 | * TASKS=1 (compiles in task support) 97 | * PGSQL=1 (compiles in pgsql support) 98 | * DEBUG=1 (enables use of -d for debug) 99 | * NOHTTP=1 (compiles Kore without HTTP support) 100 | * NOOPT=1 (disable compiler optimizations) 101 | * JSONRPC=1 (compiles in JSONRPC support) 102 | * PYTHON=1 (compiles in the Python support) 103 | * TLS_BACKEND=none (compiles Kore without any TLS backend) 104 | 105 | Note that certain build flavors cannot be mixed together and you will just 106 | be met with compilation errors. 107 | 108 | Example applications 109 | ----------------- 110 | You can find example applications under **_examples/_**. 111 | 112 | The examples contain a README file with instructions on how 113 | to build or use them. 114 | 115 | Mailing lists 116 | ------------- 117 | 118 | **patches@kore.io** - Send patches here, preferably inline. 119 | 120 | **users@kore.io** - Questions regarding kore. 121 | 122 | 123 | If you want to signup to those mailing lists send an empty email to 124 | listname+subscribe@kore.io 125 | 126 | 127 | Other mailboxes (these are **not** mailing lists): 128 | 129 | **security@kore.io** - Mail this email if you think you found a security problem. 130 | 131 | **sponsor@kore.io** - If your company would like to sponsor part of Kore development. 132 | 133 | More information can be found on https://kore.io/ 134 | -------------------------------------------------------------------------------- /RELEASE.md: -------------------------------------------------------------------------------- 1 | Kore release procedure: 2 | 3 | $next = next release 4 | $prev = previous release 5 | 6 | kore: 7 | $ git checkout 4.x-releng 8 | $ git merge master 9 | [update RELEASE, README.md] 10 | $ git commit -a -m "update for $next" 11 | $ git tag -a $next -m "Kore $next" 12 | $ git archive --format=tgz --prefix=kore-$next/ -o ~/kore-$next.tgz $next 13 | $ minisign -S -c "Kore $next release" -m kore-$next.tar.gz 14 | $ shasum -a256 kore-$next.tar.gz > kore-$next.tar.gz.sha256 15 | $ git push --tags origin 4.x-releng 16 | $ git push --tags github 4.x-releng 17 | 18 | kore-site: 19 | $ cp ~/kore-$next* webroot/releases 20 | $ cp webroot/releases/$prev.html webroot/releases/$next.html 21 | [update all relevant links] 22 | [write changelog on release page] 23 | $ git add webroot && git commit -a -m "update to $next" 24 | $ git push origin master 25 | 26 | [on nightfall] 27 | $ cd kore-site && git pull origin master && make install-docs 28 | 29 | kore-docker: 30 | $ cp -R $prev $next 31 | $ ./build.sh $next 32 | -------------------------------------------------------------------------------- /examples/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Build all relevant examples. 3 | # This only exists to quickly test building all examples. 4 | # 5 | # Kore must be built with PGSQL=1 TASKS=1 PYTHON=1 to get all 6 | # of the below examples to build correctly. 7 | # 8 | # Don't run this directly, run it from the top level as 9 | # $ make releng-build-examples 10 | # 11 | 12 | CURDIR= $(shell pwd) 13 | KODEV= /tmp/kore_releng/bin/kodev 14 | 15 | EXAMPLES= async-curl \ 16 | cookies \ 17 | cpp \ 18 | generic \ 19 | headers \ 20 | integers \ 21 | memtag \ 22 | messaging \ 23 | nohttp \ 24 | parameters \ 25 | pgsql \ 26 | pgsql-sync \ 27 | pipe_task \ 28 | sse \ 29 | tasks \ 30 | tls-proxy \ 31 | upload \ 32 | video_stream \ 33 | websocket \ 34 | 35 | all: 36 | @for example in $(EXAMPLES); do \ 37 | cd $$example; \ 38 | $(KODEV) clean && $(KODEV) build || exit 1; \ 39 | cd $(CURDIR); \ 40 | done 41 | 42 | clean: 43 | @for example in $(EXAMPLES); do \ 44 | cd $$example; \ 45 | $(KODEV) clean; \ 46 | cd $(CURDIR); \ 47 | done 48 | -------------------------------------------------------------------------------- /examples/async-curl/.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | .flavor 3 | .objs 4 | ht.so 5 | assets.h 6 | cert 7 | -------------------------------------------------------------------------------- /examples/async-curl/README.md: -------------------------------------------------------------------------------- 1 | Kore asynchronous libcurl integration example. 2 | 3 | This example demonstrates how you can use the asynchronous libcurl 4 | api from Kore to perform HTTP client requests, or FTP requests, or send 5 | emails all in an asynchronous fashion. 6 | 7 | Run: 8 | ``` 9 | $ kodev run 10 | $ curl https://127.0.0.1:8888 11 | $ curl https://127.0.0.1:8888/ftp 12 | ``` 13 | -------------------------------------------------------------------------------- /examples/async-curl/conf/async-curl.conf: -------------------------------------------------------------------------------- 1 | # ht configuration 2 | 3 | server tls { 4 | bind 127.0.0.1 8888 5 | } 6 | 7 | workers 1 8 | pledge dns 9 | 10 | domain * { 11 | attach tls 12 | 13 | certfile cert/server.pem 14 | certkey cert/key.pem 15 | 16 | route / { 17 | handler http 18 | } 19 | 20 | route /ftp { 21 | handler ftp 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /examples/async-curl/conf/build.conf: -------------------------------------------------------------------------------- 1 | # ht build config 2 | # You can switch flavors using: kodev flavor [newflavor] 3 | 4 | # Set to yes if you wish to produce a single binary instead 5 | # of a dynamic library. If you set this to yes you must also 6 | # set kore_source together with kore_flavor. 7 | single_binary=yes 8 | kore_source=../../ 9 | kore_flavor=CURL=1 10 | 11 | # The flags below are shared between flavors 12 | cflags=-Wall -Wmissing-declarations -Wshadow 13 | cflags=-Wstrict-prototypes -Wmissing-prototypes 14 | cflags=-Wpointer-arith -Wcast-qual -Wsign-compare 15 | 16 | cxxflags=-Wall -Wmissing-declarations -Wshadow 17 | cxxflags=-Wpointer-arith -Wcast-qual -Wsign-compare 18 | 19 | # Mime types for assets served via the builtin asset_serve_* 20 | #mime_add=txt:text/plain; charset=utf-8 21 | #mime_add=png:image/png 22 | #mime_add=html:text/html; charset=utf-8 23 | 24 | dev { 25 | # These flags are added to the shared ones when 26 | # you build the "dev" flavor. 27 | cflags=-g 28 | cxxflags=-g 29 | } 30 | 31 | #prod { 32 | # You can specify additional flags here which are only 33 | # included if you build with the "prod" flavor. 34 | #} 35 | -------------------------------------------------------------------------------- /examples/async-curl/src/ftp.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 Joris Vink 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | /* 18 | * This example is the same as the HTTP one (see src/http.c) except 19 | * we fetch an FTP URL. 20 | */ 21 | 22 | #include 23 | #include 24 | #include 25 | 26 | int ftp(struct http_request *); 27 | 28 | static int state_setup(struct http_request *); 29 | static int state_result(struct http_request *); 30 | 31 | static struct http_state states[] = { 32 | KORE_HTTP_STATE(state_setup), 33 | KORE_HTTP_STATE(state_result) 34 | }; 35 | 36 | int 37 | ftp(struct http_request *req) 38 | { 39 | return (http_state_run(states, 2, req)); 40 | } 41 | 42 | static int 43 | state_setup(struct http_request *req) 44 | { 45 | struct kore_curl *client; 46 | 47 | client = http_state_create(req, sizeof(*client)); 48 | 49 | if (!kore_curl_init(client, 50 | "http://ftp.eu.openbsd.org/pub/OpenBSD/README", KORE_CURL_ASYNC)) { 51 | http_response(req, 500, NULL, 0); 52 | return (HTTP_STATE_COMPLETE); 53 | } 54 | 55 | kore_curl_bind_request(client, req); 56 | kore_curl_run(client); 57 | 58 | req->fsm_state = 1; 59 | return (HTTP_STATE_RETRY); 60 | } 61 | 62 | static int 63 | state_result(struct http_request *req) 64 | { 65 | size_t len; 66 | const u_int8_t *body; 67 | struct kore_curl *client; 68 | 69 | client = http_state_get(req); 70 | 71 | if (!kore_curl_success(client)) { 72 | kore_curl_logerror(client); 73 | http_response(req, 500, NULL, 0); 74 | } else { 75 | kore_curl_response_as_bytes(client, &body, &len); 76 | http_response(req, HTTP_STATUS_OK, body, len); 77 | } 78 | 79 | kore_curl_cleanup(client); 80 | 81 | return (HTTP_STATE_COMPLETE); 82 | } 83 | -------------------------------------------------------------------------------- /examples/async-curl/src/http.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 Joris Vink 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | /* 18 | * This example demonstrates how easy it is to perform asynchronous 19 | * HTTP client requests using the integrated libcurl support. 20 | * 21 | * In this example we setup 2 states for an HTTP request: 22 | * 1) setup 23 | * We initialize the HTTP request and fire it off. 24 | * This will put our HTTP request to sleep and it be woken up 25 | * by Kore when a response is available or something went wrong. 26 | * 27 | * 2) result 28 | * After we have woken up we have access to the result. 29 | */ 30 | 31 | #include 32 | #include 33 | #include 34 | 35 | int http(struct http_request *); 36 | 37 | static int state_setup(struct http_request *); 38 | static int state_result(struct http_request *); 39 | 40 | /* Our states. */ 41 | static struct http_state states[] = { 42 | KORE_HTTP_STATE(state_setup), 43 | KORE_HTTP_STATE(state_result) 44 | }; 45 | 46 | /* Transcend into the HTTP state machine for a request. */ 47 | int 48 | http(struct http_request *req) 49 | { 50 | return (http_state_run(states, 2, req)); 51 | } 52 | 53 | /* 54 | * Setup the HTTP client request using the integrated curl API and the easy 55 | * to use HTTP client api. 56 | */ 57 | static int 58 | state_setup(struct http_request *req) 59 | { 60 | struct kore_curl *client; 61 | 62 | client = http_state_create(req, sizeof(*client)); 63 | 64 | /* Initialize curl. */ 65 | if (!kore_curl_init(client, "https://kore.io", KORE_CURL_ASYNC)) { 66 | http_response(req, 500, NULL, 0); 67 | return (HTTP_STATE_COMPLETE); 68 | } 69 | 70 | /* Setup our HTTP client request. */ 71 | kore_curl_http_setup(client, HTTP_METHOD_GET, NULL, 0); 72 | 73 | /* Add some headers. */ 74 | kore_curl_http_set_header(client, "x-source", "from-example"); 75 | 76 | /* We could opt to override some settings ourselves if we wanted. */ 77 | /* curl_easy_setopt(client->handle, CURLOPT_SSL_VERIFYHOST, 0); */ 78 | /* curl_easy_setopt(client->handle, CURLOPT_SSL_VERIFYPEER, 0); */ 79 | 80 | /* 81 | * Bind the HTTP client request to our HTTP request so we get woken 82 | * up once a response is available. 83 | * 84 | * This will put us to sleep. 85 | */ 86 | kore_curl_bind_request(client, req); 87 | 88 | /* 89 | * Now fire off the request onto the event loop. 90 | */ 91 | kore_curl_run(client); 92 | 93 | /* Make sure we go onto the next state once woken up. */ 94 | req->fsm_state = 1; 95 | 96 | /* Tell Kore we can't complete this immediately. */ 97 | return (HTTP_STATE_RETRY); 98 | } 99 | 100 | /* 101 | * This state is called when a result for the HTTP request call is 102 | * available to us. 103 | */ 104 | static int 105 | state_result(struct http_request *req) 106 | { 107 | size_t len; 108 | const u_int8_t *body; 109 | const char *header; 110 | struct kore_curl *client; 111 | 112 | /* Get the state attached to the HTTP request. */ 113 | client = http_state_get(req); 114 | 115 | /* Check if we were successful, if not log an error. */ 116 | if (!kore_curl_success(client)) { 117 | kore_curl_logerror(client); 118 | http_response(req, 500, NULL, 0); 119 | } else { 120 | /* 121 | * Success! We now have the body available to us. 122 | */ 123 | kore_curl_response_as_bytes(client, &body, &len); 124 | 125 | /* We could check the existence of a header: */ 126 | if (kore_curl_http_get_header(client, "server", &header)) 127 | printf("got server header: '%s'\n", header); 128 | 129 | /* 130 | * Respond to our client with the status and body from 131 | * the HTTP client request we did. 132 | */ 133 | http_response(req, client->http.status, body, len); 134 | } 135 | 136 | /* Cleanup. */ 137 | kore_curl_cleanup(client); 138 | 139 | /* State is now finished. */ 140 | return (HTTP_STATE_COMPLETE); 141 | } 142 | -------------------------------------------------------------------------------- /examples/async-curl/src/init.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Joris Vink 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include 18 | #include 19 | 20 | /* Let kore handle the default option parsing. */ 21 | void 22 | kore_parent_configure(int argc, char **argv) 23 | { 24 | kore_default_getopt(argc, argv); 25 | } 26 | -------------------------------------------------------------------------------- /examples/cookies/README.md: -------------------------------------------------------------------------------- 1 | This example shows cookies API usage 2 | 3 | * Simple key value cookie 4 | * Complex cookie with RFC 6265 features 5 | * Mix with cookie formatted in the header 6 | 7 | Run: 8 | ``` 9 | # kodev run 10 | ``` 11 | -------------------------------------------------------------------------------- /examples/cookies/conf/build.conf: -------------------------------------------------------------------------------- 1 | # generic build config 2 | # You can switch flavors using: kodev flavor [newflavor] 3 | 4 | # The cflags below are shared between flavors 5 | cflags=-Wall -Wmissing-declarations -Wshadow 6 | cflags=-Wstrict-prototypes -Wmissing-prototypes 7 | cflags=-Wpointer-arith -Wcast-qual -Wsign-compare 8 | 9 | dev { 10 | # These cflags are added to the shared ones when 11 | # you build the "dev" flavor. 12 | cflags=-g 13 | } 14 | 15 | #prod { 16 | # You can specify additional CFLAGS here which are only 17 | # included if you build with the "prod" flavor. 18 | #} 19 | -------------------------------------------------------------------------------- /examples/cookies/conf/cookies.conf: -------------------------------------------------------------------------------- 1 | # Placeholder configuration 2 | 3 | server tls { 4 | bind 127.0.0.1 8888 5 | } 6 | 7 | load ./cookies.so 8 | 9 | domain * { 10 | attach tls 11 | 12 | certfile cert/server.pem 13 | certkey cert/key.pem 14 | 15 | route / { 16 | handler serve_cookies 17 | } 18 | 19 | route /secure { 20 | handler serve_cookies 21 | } 22 | 23 | route /vault { 24 | handler serve_cookies 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /examples/cookies/src/cookies.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Stanislav Yudin 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include 18 | #include 19 | 20 | static char *html = "

Reload this page

"; 21 | 22 | int serve_cookies(struct http_request *); 23 | 24 | int 25 | serve_cookies(struct http_request *req) 26 | { 27 | char *value; 28 | struct http_cookie *cookie; 29 | 30 | http_populate_cookies(req); 31 | 32 | if (http_request_cookie(req, "Simple", &value)) 33 | kore_log(LOG_DEBUG, "Got simple: %s", value); 34 | if (http_request_cookie(req, "Complex", &value)) 35 | kore_log(LOG_DEBUG, "Got complex: %s", value); 36 | if (http_request_cookie(req, "Formatted", &value)) 37 | kore_log(LOG_DEBUG, "Got formatted: %s", value); 38 | 39 | /* no expire, no maxage for current path. */ 40 | http_response_cookie(req, "Simple", "Hello World!", 41 | req->path, 0, 0, NULL); 42 | 43 | /* expire, no maxage, for /secure. */ 44 | http_response_cookie(req, "Complex", "Secure Value!", "/secure", 45 | time(NULL) + (1 * 60 * 60), 0, NULL); 46 | 47 | /* maxage, no httponly, for current path. */ 48 | http_response_cookie(req, "key", "value", req->path, 0, 60, &cookie); 49 | cookie->flags &= ~HTTP_COOKIE_HTTPONLY; 50 | 51 | /* set formatted cookie via header directly. */ 52 | http_response_header(req, "set-cookie", 53 | "Formatted=TheValue; Path=/vault; HttpOnly"); 54 | 55 | http_response(req, 200, html, strlen(html)); 56 | 57 | return (KORE_RESULT_OK); 58 | } 59 | -------------------------------------------------------------------------------- /examples/cpp/.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | .objs 3 | cpp.so 4 | assets.h 5 | cert 6 | -------------------------------------------------------------------------------- /examples/cpp/README.md: -------------------------------------------------------------------------------- 1 | Kore example showing how to use C++ support! 2 | 3 | All functions accessible to kore must have their prototypes wrapped with the extern keyword like so: 4 | ``` 5 | extern “C” { 6 | int pageA(struct http_request *); 7 | int pageB(struct http_request *); 8 | int validatorA(struct http_request *, char *); 9 | } 10 | ``` 11 | In order to run this example with the default C++ settings (default compiler dialect, libstdc++): 12 | ``` 13 | # kodev run 14 | ``` 15 | 16 | In order to run with a specific dialect and C++ runtime: 17 | ``` 18 | # env CXXSTD=c++11 CXXLIB=c++ kodev run 19 | ``` 20 | 21 | You can also supply your own compiler combined with the above: 22 | ``` 23 | # env CC=clang++ CXXSTD=c++11 CXXLIB=c++ kodev run 24 | ``` 25 | -------------------------------------------------------------------------------- /examples/cpp/conf/build.conf: -------------------------------------------------------------------------------- 1 | # cpp build config 2 | # You can switch flavors using: kodev flavor [newflavor] 3 | 4 | # The cflags below are shared between flavors 5 | cflags=-Wall -Wmissing-declarations -Wshadow 6 | cflags=-Wstrict-prototypes -Wmissing-prototypes 7 | cflags=-Wpointer-arith -Wcast-qual -Wsign-compare 8 | 9 | cxxflags=-Wall -Wmissing-declarations -Wshadow 10 | cxxflags=-Wpointer-arith -Wcast-qual -Wsign-compare 11 | 12 | dev { 13 | # These cflags are added to the shared ones when 14 | # you build the "dev" flavor. 15 | cflags=-g 16 | cxxflags=-g 17 | } 18 | 19 | #prod { 20 | # You can specify additional CFLAGS here which are only 21 | # included if you build with the "prod" flavor. 22 | #} 23 | -------------------------------------------------------------------------------- /examples/cpp/conf/cpp.conf: -------------------------------------------------------------------------------- 1 | # Placeholder configuration 2 | 3 | server tls { 4 | bind 127.0.0.1 8888 5 | } 6 | 7 | load ./cpp.so 8 | 9 | domain * { 10 | attach tls 11 | 12 | certfile cert/server.pem 13 | certkey cert/key.pem 14 | 15 | route / { 16 | handler page 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /examples/cpp/src/cpp.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Jonathan Goodman 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include 18 | #include 19 | 20 | #include "example_class.h" 21 | 22 | extern "C" { 23 | int page(struct http_request *); 24 | } 25 | 26 | int 27 | page(struct http_request *req) 28 | { 29 | example_class example; 30 | const char *str = example.a(); 31 | 32 | http_response(req, 200, 33 | static_cast(const_cast(str)), strlen(str)); 34 | 35 | return (KORE_RESULT_OK); 36 | } 37 | -------------------------------------------------------------------------------- /examples/cpp/src/example_class.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Jonathan Goodman 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include "example_class.h" 18 | 19 | example_class::example_class() { 20 | } 21 | 22 | example_class::~example_class() { 23 | } 24 | 25 | const char * 26 | example_class::a() { 27 | return "Hello world!"; 28 | } 29 | -------------------------------------------------------------------------------- /examples/cpp/src/example_class.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Jonathan Goodman 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #ifndef ____example_class__ 18 | #define ____example_class__ 19 | 20 | #include 21 | 22 | class example_class { 23 | public: 24 | example_class(); 25 | ~example_class(); 26 | 27 | const char *a(); 28 | }; 29 | 30 | #endif /* defined(____example_class__) */ 31 | -------------------------------------------------------------------------------- /examples/generic/README.md: -------------------------------------------------------------------------------- 1 | Generic Kore application that shows off a few things: 2 | 3 | * File uploads (/upload) 4 | * Authentication blocks (/private) 5 | * base64 encoding tests (/b64test) 6 | * Parameter validator tests (/params-test) 7 | 8 | Run: 9 | ``` 10 | # kodev run 11 | ``` 12 | -------------------------------------------------------------------------------- /examples/generic/assets/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Your KORE module worked! 6 | 7 | 8 | 9 | 10 |
11 |

Your first Kore module worked.

12 |
13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /examples/generic/assets/intro.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jorisvink/kore/86b1408e2086047445731767ae921a073b97512b/examples/generic/assets/intro.jpg -------------------------------------------------------------------------------- /examples/generic/assets/params.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Kore params test 6 | 7 | 8 | 9 | 10 |
11 |

You can pass one GET parameter (arg1), any other GET parameter will 12 | be filtered out

13 |

Only two out of the three input fields will be visible to Kore.

14 |

The first field accepts the input "test"

15 |

The second field accepts anything like /test/[a-z]*

16 |

The third field will be removed by Kore, as it is not in the params 17 | block configured for this page.

18 |
19 | 20 | 21 | 22 | 23 |
24 | 25 |

GET param arg1: $arg1$

26 |

GET param arg2: $arg2$

27 |

test1: $test1$

28 |

test2: $test2$

29 |

test3: $test3$

30 |
31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /examples/generic/assets/private.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Kore Authentication tests 6 | 7 | 8 | 9 | 10 |
11 |

The cookie session_id should now be set.

12 |

You can continue to view page handler in auth block

13 |
14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /examples/generic/assets/private_test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Kore Authentication tests 6 | 7 | 8 | 9 | 10 |
11 |

If you see this, the authentication worked. This page should redirect back to /private once you remove your session_id cookie.

12 |
13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /examples/generic/assets/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | width: 100%; 3 | margin: 0px; 4 | color: #000; 5 | overflow: hidden; 6 | background-color: #fff; 7 | } 8 | 9 | .content { 10 | width: 800px; 11 | margin-left: auto; 12 | margin-right: auto; 13 | margin-top: 100px; 14 | font-size: 60px; 15 | text-align: center; 16 | } 17 | -------------------------------------------------------------------------------- /examples/generic/assets/upload.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Kore upload test 6 | 7 | 8 | 9 | 10 |
11 |
12 | 13 | 14 | 15 |
16 | 17 |

$upload$

18 |

$firstname$

19 |
20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /examples/generic/conf/build.conf: -------------------------------------------------------------------------------- 1 | # generic build config 2 | # You can switch flavors using: kodev flavor [newflavor] 3 | 4 | # The cflags below are shared between flavors 5 | cflags=-Wall -Wmissing-declarations -Wshadow 6 | cflags=-Wstrict-prototypes -Wmissing-prototypes 7 | cflags=-Wpointer-arith -Wcast-qual -Wsign-compare 8 | 9 | mime_add=jpg:image/jpg 10 | mime_add=css:text/css; charset=utf-8 11 | mime_add=html:text/html; charset=utf-8 12 | 13 | dev { 14 | # These cflags are added to the shared ones when 15 | # you build the "dev" flavor. 16 | cflags=-g 17 | } 18 | 19 | #prod { 20 | # You can specify additional CFLAGS here which are only 21 | # included if you build with the "prod" flavor. 22 | #} 23 | -------------------------------------------------------------------------------- /examples/generic/conf/generic.conf: -------------------------------------------------------------------------------- 1 | # Placeholder configuration 2 | 3 | server tls { 4 | bind 127.0.0.1 8888 5 | } 6 | 7 | load ./generic.so example_load 8 | 9 | http_body_max 1024000000 10 | http_body_disk_offload 1024000 11 | 12 | validator v_example function v_example_func 13 | validator v_regex regex ^/test/[a-z]*$ 14 | validator v_number regex ^[0-9]*$ 15 | validator v_session function v_session_validate 16 | 17 | authentication auth_example { 18 | authentication_type cookie 19 | authentication_value session_id 20 | authentication_validator v_session 21 | authentication_uri /private 22 | } 23 | 24 | domain * { 25 | attach tls 26 | 27 | certfile cert/server.pem 28 | certkey cert/key.pem 29 | accesslog kore_access.log 30 | 31 | route /css/style.css { 32 | handler asset_serve_style_css 33 | methods get 34 | } 35 | 36 | route / { 37 | handler asset_serve_index_html 38 | methods get 39 | } 40 | 41 | route /intro.jpg { 42 | handler asset_serve_intro_jpg 43 | methods get 44 | } 45 | 46 | route /b64test { 47 | handler serve_b64test 48 | methods get 49 | } 50 | 51 | route /upload { 52 | handler serve_file_upload 53 | methods get post 54 | } 55 | 56 | route /validator { 57 | handler serve_validator 58 | methods get 59 | } 60 | 61 | route /params-test { 62 | handler serve_params_test 63 | methods get post 64 | 65 | validate qs:get arg1 v_example 66 | validate qs:get id v_number 67 | 68 | validate post test1 v_example 69 | validate post test2 v_regex 70 | } 71 | 72 | route /private { 73 | handler serve_private 74 | methods get 75 | } 76 | 77 | route /private/test { 78 | handler asset_serve_private_test_html 79 | authenticate auth_example 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /examples/headers/.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | .objs 3 | headers.so 4 | assets.h 5 | cert 6 | -------------------------------------------------------------------------------- /examples/headers/README.md: -------------------------------------------------------------------------------- 1 | Example on how to read HTTP request headers and set your own custom ones. 2 | 3 | Run: 4 | ``` 5 | # kodev run 6 | ``` 7 | 8 | Test: 9 | ``` 10 | # curl -H "X-Custom-Header: testing" -i -k https://127.0.0.1:8888 11 | ``` 12 | 13 | If X-Custom-Header is given, it will be mirrored in the response. 14 | -------------------------------------------------------------------------------- /examples/headers/conf/build.conf: -------------------------------------------------------------------------------- 1 | # headers build config 2 | # You can switch flavors using: kodev flavor [newflavor] 3 | 4 | # The cflags below are shared between flavors 5 | cflags=-Wall -Wmissing-declarations -Wshadow 6 | cflags=-Wstrict-prototypes -Wmissing-prototypes 7 | cflags=-Wpointer-arith -Wcast-qual -Wsign-compare 8 | 9 | dev { 10 | # These cflags are added to the shared ones when 11 | # you build the "dev" flavor. 12 | cflags=-g 13 | } 14 | 15 | #prod { 16 | # You can specify additional CFLAGS here which are only 17 | # included if you build with the "prod" flavor. 18 | #} 19 | -------------------------------------------------------------------------------- /examples/headers/conf/headers.conf: -------------------------------------------------------------------------------- 1 | # Placeholder configuration 2 | 3 | server tls { 4 | bind 127.0.0.1 8888 5 | } 6 | 7 | load ./headers.so 8 | 9 | tls_dhparam dh2048.pem 10 | 11 | domain * { 12 | attach tls 13 | 14 | certfile cert/server.pem 15 | certkey cert/key.pem 16 | route / page 17 | } 18 | -------------------------------------------------------------------------------- /examples/headers/src/headers.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int page(struct http_request *); 5 | 6 | int 7 | page(struct http_request *req) 8 | { 9 | const char *custom; 10 | 11 | /* 12 | * We'll lookup if the X-Custom-Header is given in the request. 13 | * If it is we'll set it as a response header as well. 14 | * 15 | * The value returned by http_request_header() should not be freed. 16 | */ 17 | if (http_request_header(req, "x-custom-header", &custom)) 18 | http_response_header(req, "x-custom-header", custom); 19 | 20 | /* Return 200 with "ok\n" to the client. */ 21 | http_response(req, 200, "ok\n", 3); 22 | 23 | return (KORE_RESULT_OK); 24 | } 25 | -------------------------------------------------------------------------------- /examples/integers/.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | .objs 3 | integers.so 4 | static.h 5 | cert 6 | -------------------------------------------------------------------------------- /examples/integers/README.md: -------------------------------------------------------------------------------- 1 | Test parameter to integer conversions. 2 | 3 | Run: 4 | ``` 5 | $ kodev run 6 | ``` 7 | 8 | Test: 9 | ``` 10 | $ curl -i -k https://127.0.0.1:8888/?id=123123 11 | $ curl -i -k https://127.0.0.1:8888/?id=-123123 12 | ``` 13 | 14 | The correct integer types should only be represented in the output. 15 | -------------------------------------------------------------------------------- /examples/integers/conf/build.conf: -------------------------------------------------------------------------------- 1 | # integers build config 2 | # You can switch flavors using: kodev flavor [newflavor] 3 | 4 | # The cflags below are shared between flavors 5 | cflags=-Wall -Wmissing-declarations -Wshadow 6 | cflags=-Wstrict-prototypes -Wmissing-prototypes 7 | cflags=-Wpointer-arith -Wcast-qual -Wsign-compare 8 | 9 | dev { 10 | # These cflags are added to the shared ones when 11 | # you build the "dev" flavor. 12 | cflags=-g 13 | } 14 | 15 | #prod { 16 | # You can specify additional CFLAGS here which are only 17 | # included if you build with the "prod" flavor. 18 | #} 19 | -------------------------------------------------------------------------------- /examples/integers/conf/integers.conf: -------------------------------------------------------------------------------- 1 | # Placeholder configuration 2 | 3 | server tls { 4 | bind 127.0.0.1 8888 5 | } 6 | 7 | load ./integers.so 8 | 9 | workers 2 10 | worker_max_connections 5000 11 | 12 | validator v_id regex ^-?[0-9]*.?[0-9]+$ 13 | 14 | domain * { 15 | attach tls 16 | 17 | certfile cert/server.pem 18 | certkey cert/key.pem 19 | 20 | route / { 21 | handler page 22 | methods get 23 | 24 | # allowed parameters in the query string for GETs 25 | validate get id v_id 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /examples/integers/src/check_integers.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int page(struct http_request *); 5 | 6 | int 7 | page(struct http_request *req) 8 | { 9 | float fl; 10 | double dbl; 11 | int16_t s16; 12 | u_int16_t u16; 13 | int32_t s32; 14 | int64_t s64; 15 | u_int64_t u64; 16 | u_int32_t u32; 17 | size_t len; 18 | struct kore_buf *buf; 19 | u_int8_t c, *data; 20 | 21 | http_populate_get(req); 22 | buf = kore_buf_alloc(128); 23 | 24 | if (http_argument_get_byte(req, "id", &c)) 25 | kore_buf_appendf(buf, "byte\t%c\n", c); 26 | 27 | if (http_argument_get_int16(req, "id", &s16)) 28 | kore_buf_appendf(buf, "int16\t%d\n", s16); 29 | 30 | if (http_argument_get_uint16(req, "id", &u16)) 31 | kore_buf_appendf(buf, "uint16\t%d\n", u16); 32 | 33 | if (http_argument_get_int32(req, "id", &s32)) 34 | kore_buf_appendf(buf, "int32\t%d\n", s32); 35 | 36 | if (http_argument_get_uint32(req, "id", &u32)) 37 | kore_buf_appendf(buf, "uint32\t%d\n", u32); 38 | 39 | if (http_argument_get_int64(req, "id", &s64)) 40 | kore_buf_appendf(buf, "int64\t%ld\n", s64); 41 | 42 | if (http_argument_get_uint64(req, "id", &u64)) 43 | kore_buf_appendf(buf, "uint64\t%lu\n", u64); 44 | 45 | if (http_argument_get_float(req, "id", &fl)) 46 | kore_buf_appendf(buf, "float\t%g\n", fl); 47 | 48 | if (http_argument_get_double(req, "id", &dbl)) 49 | kore_buf_appendf(buf, "double\t%g\n", dbl); 50 | 51 | data = kore_buf_release(buf, &len); 52 | http_response(req, 200, data, len); 53 | kore_free(data); 54 | 55 | return (KORE_RESULT_OK); 56 | } 57 | -------------------------------------------------------------------------------- /examples/json/.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | .objs 3 | json.so 4 | assets.h 5 | cert 6 | -------------------------------------------------------------------------------- /examples/json/README.md: -------------------------------------------------------------------------------- 1 | Native Kore JSON parser example. 2 | 3 | Run: 4 | ``` 5 | $ kodev run 6 | ``` 7 | 8 | Test: 9 | ``` 10 | $ curl -i -k -d '{"foo":{"bar": "Hello world"}}' https://127.0.0.1:8888 11 | ``` 12 | 13 | The result should echo back the foo.bar JSON path value if it is a JSON string. 14 | -------------------------------------------------------------------------------- /examples/json/conf/build.conf: -------------------------------------------------------------------------------- 1 | # json build config 2 | # You can switch flavors using: kodev flavor [newflavor] 3 | 4 | # The cflags below are shared between flavors 5 | cflags=-Wall -Wmissing-declarations -Wshadow 6 | cflags=-Wstrict-prototypes -Wmissing-prototypes 7 | cflags=-Wpointer-arith -Wcast-qual -Wsign-compare 8 | 9 | dev { 10 | # These cflags are added to the shared ones when 11 | # you build the "dev" flavor. 12 | cflags=-g 13 | } 14 | 15 | #prod { 16 | # You can specify additional CFLAGS here which are only 17 | # included if you build with the "prod" flavor. 18 | #} 19 | -------------------------------------------------------------------------------- /examples/json/conf/json.conf: -------------------------------------------------------------------------------- 1 | # Placeholder configuration 2 | 3 | server tls { 4 | bind 127.0.0.1 8888 5 | } 6 | 7 | load ./json.so 8 | 9 | domain 127.0.0.1 { 10 | attach tls 11 | 12 | certfile cert/server.pem 13 | certkey cert/key.pem 14 | 15 | route / { 16 | handler page 17 | methods post 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /examples/json/src/json.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 Joris Vink 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include 18 | #include 19 | 20 | #include 21 | 22 | int page(struct http_request *); 23 | 24 | int 25 | page(struct http_request *req) 26 | { 27 | struct kore_buf buf; 28 | struct kore_json json; 29 | struct kore_json_item *item; 30 | 31 | kore_buf_init(&buf, 128); 32 | kore_json_init(&json, req->http_body->data, req->http_body->length); 33 | 34 | if (!kore_json_parse(&json)) { 35 | kore_buf_appendf(&buf, "%s\n", kore_json_strerror()); 36 | } else { 37 | item = kore_json_find_string(json.root, "foo/bar"); 38 | if (item != NULL) { 39 | kore_buf_appendf(&buf, 40 | "foo.bar = '%s'\n", item->data.string); 41 | } else { 42 | kore_buf_appendf(&buf, "foo.bar %s\n", 43 | kore_json_strerror()); 44 | } 45 | 46 | item = kore_json_find_integer_u64(json.root, "foo/integer"); 47 | if (item != NULL) { 48 | kore_buf_appendf(&buf, 49 | "foo.integer = '%" PRIu64 "'\n", item->data.u64); 50 | } else { 51 | kore_buf_appendf(&buf, "foo.integer %s\n", 52 | kore_json_strerror()); 53 | } 54 | } 55 | 56 | http_response(req, 200, buf.data, buf.offset); 57 | 58 | kore_buf_cleanup(&buf); 59 | kore_json_cleanup(&json); 60 | 61 | return (KORE_RESULT_OK); 62 | } 63 | -------------------------------------------------------------------------------- /examples/jsonrpc/.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | .objs 3 | jsonrpc.so 4 | assets.h 5 | cert 6 | .*.swp 7 | .*.swo 8 | -------------------------------------------------------------------------------- /examples/jsonrpc/README.md: -------------------------------------------------------------------------------- 1 | This example demonstrates how you can use the JSON-RPC module in your 2 | application. 3 | 4 | Note that the module depends upon the third-party library `yajl` (Yet Another 5 | JSON library) to parse and produce messages. 6 | 7 | As for the `yajl_json` example, conf/build.conf shows how to link to the 8 | library. 9 | 10 | This example needs kore having been compiled with `JSONRPC` (and so `HTTP`) 11 | activated. 12 | 13 | Run: 14 | ``` 15 | $ kodev run 16 | ``` 17 | 18 | Test: 19 | ``` 20 | $ curl -i -k \ 21 | -d '{"id":1,"jsonrpc":"2.0","method":"echo","params":["Hello world"]}' \ 22 | https://127.0.0.1:8888/v1 23 | ``` 24 | The result should echo back the string at `params`: Hello world. 25 | 26 | Alternatively, if you have bats installed: 27 | ``` 28 | $ bats test/integ/jsonrpc.bats 29 | ``` 30 | Will run a small test suite. 31 | 32 | 33 | The yajl repo is available @ https://github.com/lloyd/yajl 34 | 35 | 36 | JSONRPC Request Lifetime 37 | ------------------------ 38 | 39 | Currently, one HTTP request will (in most cases) provoke one and only one 40 | response. Batch mode is not supported yet, neither is websocket. 41 | 42 | As such `jsonrpc\_error` and `jsonrpc\_result` do clean the request after call. 43 | 44 | If however you want to abort the processed request, like by returning 45 | `KORE\_RESULT\_ERROR`, after it having been read, you need to clean it by 46 | calling `jsonrpc\_destroy\_request`. Other than that you shouldn't think about 47 | this function. 48 | 49 | 50 | Message Handling Log 51 | -------------------- 52 | 53 | The `jsonrpc\_request` keeps a log of messages with levels similar to those of 54 | syslog. Messages are added with jsonrpc_log(). 55 | 56 | By default messages of the log are added to the data member of the error 57 | responses if at levels EMERG, ERROR, WARNING and NOTICE. 58 | 59 | If you don't want log messages to be outputted zero the log_levels flag of the 60 | jsonrpc_request. 61 | 62 | 63 | Formatting responses 64 | -------------------- 65 | 66 | By default responses are not prettyfied. To do that set the appropriate flag in 67 | the jsonrpc_request structure. 68 | -------------------------------------------------------------------------------- /examples/jsonrpc/conf/build.conf: -------------------------------------------------------------------------------- 1 | # jsonrpc build config 2 | # You can switch flavors using: kodev flavor [newflavor] 3 | 4 | # The cflags below are shared between flavors 5 | cflags=-Wall -Wmissing-declarations -Wshadow 6 | cflags=-Wstrict-prototypes -Wmissing-prototypes 7 | cflags=-Wpointer-arith -Wcast-qual -Wsign-compare 8 | 9 | dev { 10 | # These cflags are added to the shared ones when 11 | # you build the "dev" flavor. 12 | cflags=-g 13 | ldflags=-lyajl 14 | } 15 | 16 | #prod { 17 | # You can specify additional CFLAGS here which are only 18 | # included if you build with the "prod" flavor. 19 | #} 20 | -------------------------------------------------------------------------------- /examples/jsonrpc/conf/jsonrpc.conf: -------------------------------------------------------------------------------- 1 | # Placeholder configuration 2 | 3 | server tls { 4 | bind 127.0.0.1 8888 5 | } 6 | 7 | load ./jsonrpc.so 8 | 9 | domain * { 10 | attach tls 11 | 12 | certfile cert/server.pem 13 | certkey cert/key.pem 14 | 15 | route / { 16 | handler homepage 17 | } 18 | 19 | route /v1 { 20 | handler v1 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /examples/jsonrpc/src/home.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int homepage(struct http_request *); 5 | 6 | int 7 | homepage(struct http_request *req) 8 | { 9 | static const char response_body[] = "JSON-RPC API\n"; 10 | 11 | http_response_header(req, "content-type", "text/plain"); 12 | http_response(req, 200, response_body, sizeof(response_body) - 1); 13 | return (KORE_RESULT_OK); 14 | } 15 | -------------------------------------------------------------------------------- /examples/jsonrpc/src/v1.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | int v1(struct http_request *); 10 | 11 | static int 12 | write_string(struct jsonrpc_request *req, void *ctx) 13 | { 14 | const unsigned char *str = (unsigned char *)ctx; 15 | 16 | return yajl_gen_string(req->gen, str, strlen((const char *)str)); 17 | } 18 | 19 | static int 20 | write_string_array_params(struct jsonrpc_request *req, void *ctx) 21 | { 22 | int status = 0; 23 | 24 | if (!YAJL_GEN_KO(status = yajl_gen_array_open(req->gen))) { 25 | for (size_t i = 0; i < req->params->u.array.len; i++) { 26 | yajl_val yajl_str = req->params->u.array.values[i]; 27 | char *str = YAJL_GET_STRING(yajl_str); 28 | 29 | if (YAJL_GEN_KO(status = yajl_gen_string(req->gen, 30 | (unsigned char *)str, strlen(str)))) 31 | break; 32 | } 33 | if (status == 0) 34 | status = yajl_gen_array_close(req->gen); 35 | } 36 | 37 | return status; 38 | } 39 | 40 | int 41 | v1(struct http_request *http_req) 42 | { 43 | struct jsonrpc_request req; 44 | int ret; 45 | 46 | /* We only allow POST/PUT methods. */ 47 | if (http_req->method != HTTP_METHOD_POST && 48 | http_req->method != HTTP_METHOD_PUT) { 49 | http_response_header(http_req, "allow", "POST, PUT"); 50 | http_response(http_req, HTTP_STATUS_METHOD_NOT_ALLOWED, NULL, 0); 51 | return (KORE_RESULT_OK); 52 | } 53 | 54 | /* Read JSON-RPC request. */ 55 | if ((ret = jsonrpc_read_request(http_req, &req)) != 0) 56 | return jsonrpc_error(&req, ret, NULL); 57 | 58 | /* Echo command takes and gives back params. */ 59 | if (strcmp(req.method, "echo") == 0) { 60 | if (!YAJL_IS_ARRAY(req.params)) { 61 | jsonrpc_log(&req, LOG_ERR, 62 | "Echo only accepts positional params"); 63 | return jsonrpc_error(&req, JSONRPC_INVALID_PARAMS, NULL); 64 | } 65 | for (size_t i = 0; i < req.params->u.array.len; i++) { 66 | yajl_val v = req.params->u.array.values[i]; 67 | if (!YAJL_IS_STRING(v)) { 68 | jsonrpc_log(&req, -3, 69 | "Echo only accepts strings"); 70 | return jsonrpc_error(&req, 71 | JSONRPC_INVALID_PARAMS, NULL); 72 | } 73 | } 74 | return jsonrpc_result(&req, write_string_array_params, NULL); 75 | } 76 | 77 | /* Date command displays date and time according to parameters. */ 78 | if (strcmp(req.method, "date") == 0) { 79 | time_t time_value; 80 | struct tm time_info; 81 | char timestamp[33]; 82 | struct tm *(*gettm)(const time_t *, struct tm *) = 83 | localtime_r; 84 | 85 | if (YAJL_IS_OBJECT(req.params)) { 86 | const char *path[] = {"local", NULL}; 87 | yajl_val bf; 88 | 89 | bf = yajl_tree_get(req.params, path, yajl_t_false); 90 | if (bf != NULL) 91 | gettm = gmtime_r; 92 | } else if (req.params != NULL) { 93 | jsonrpc_log(&req, LOG_ERR, 94 | "Date only accepts named params"); 95 | return jsonrpc_error(&req, JSONRPC_INVALID_PARAMS, NULL); 96 | } 97 | 98 | if ((time_value = time(NULL)) == -1) 99 | return jsonrpc_error(&req, -2, 100 | "Failed to get date time"); 101 | 102 | if (gettm(&time_value, &time_info) == NULL) 103 | return jsonrpc_error(&req, -3, 104 | "Failed to get date time info"); 105 | 106 | memset(timestamp, 0, sizeof(timestamp)); 107 | if (strftime_l(timestamp, sizeof(timestamp) - 1, "%c", 108 | &time_info, LC_GLOBAL_LOCALE) == 0) 109 | return jsonrpc_error(&req, -4, 110 | "Failed to get printable date time"); 111 | 112 | return jsonrpc_result(&req, write_string, timestamp); 113 | } 114 | 115 | return jsonrpc_error(&req, JSONRPC_METHOD_NOT_FOUND, NULL); 116 | } 117 | -------------------------------------------------------------------------------- /examples/jsonrpc/test/integ/jsonrpc.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | # Simple and non exhaustive test suite using bats: 4 | # https://github.com/sstephenson/bats 5 | 6 | PIDFILE=run/jsonrpc.pid 7 | CONFFILE=conf/jsonrpc.conf 8 | 9 | # Start and stop have to be tweaked before being used 10 | stop_app() { 11 | if [ -f "$PIDFILE" ]; then 12 | kill -QUIT `cat "$PIDFILE"` 13 | sleep 3 14 | fi 15 | if [ -f "$PIDFILE" ]; then 16 | kill -KILL `cat "$PIDFILE"` 17 | sleep 2 18 | fi 19 | } 20 | 21 | start_app() { 22 | stop_app 23 | kore -nrc "$CONFFILE" 24 | } 25 | 26 | query_with_content_type() { 27 | curl -q \ 28 | -H "Content-Type: $1" \ 29 | -X POST \ 30 | --raw \ 31 | -d "$2" \ 32 | -s -S \ 33 | --insecure \ 34 | "https://127.0.0.1:8888/v1" 35 | } 36 | 37 | query() { 38 | query_with_content_type "application/json" "$1" 39 | } 40 | 41 | grepstr() { 42 | declare result=$1 43 | shift 44 | printf "%s" "$result" | grep "$@" >/dev/null 45 | } 46 | 47 | printrep() { 48 | declare query=$1 49 | declare result=$2 50 | printf "Sent:\n" 51 | printf "%s\n" "$query" 52 | printf "Received:\n" 53 | printf "%s\n" "$result" 54 | } 55 | 56 | @test "requests with no protocol returns nothing" { 57 | query='{"method":"foo","id":"foo"}' 58 | result=`query "$query"` 59 | printrep "$query" "$result" 60 | [ "$result" = "" ] 61 | } 62 | @test "requests with invalid protocol (1) returns nothing" { 63 | query='{"jsonrpc":"1.0","method":"foo","id":"foo"}' 64 | result=`query "$query"` 65 | printrep "$query" "$result" 66 | [ "$result" = "" ] 67 | } 68 | @test "requests with invalid protocol (2) returns nothing" { 69 | query='{"jsonrpc":2.0,"method":"foo","id":"foo"}' 70 | result=`query "$query"` 71 | printrep "$query" "$result" 72 | [ "$result" = "" ] 73 | } 74 | 75 | @test "requests with no method raise errors" { 76 | query='{"jsonrpc":"2.0","id":"foo"}' 77 | result=`query "$query"` 78 | printrep "$query" "$result" 79 | grepstr "$result" '"error"[ \t\n]*:[ \t\n]*{[ \t\n]*"code"' 80 | } 81 | @test "requests with invalid method raise errors" { 82 | query='{"jsonrpc":"2.0","method":1,"id":"foo"}' 83 | result=`query "$query"` 84 | printrep "$query" "$result" 85 | grepstr "$result" '"error"[ \t\n]*:[ \t\n]*{[ \t\n]*"code"' 86 | } 87 | @test "requests with unknown method raise errors" { 88 | query='{"jsonrpc":"2.0","method":"foobar","id":"foo"}' 89 | result=`query "$query"` 90 | printrep "$query" "$result" 91 | grepstr "$result" '"error"[ \t\n]*:[ \t\n]*{[ \t\n]*"code"' 92 | } 93 | 94 | @test "error responses give back the string request id" { 95 | query='{"jsonrpc":"2.0","id":"foo"}' 96 | result=`query "$query"` 97 | printrep "$query" "$result" 98 | grepstr "$result" '"error"[ \t\n]*:[ \t\n]*{[ \t\n]*"code"' 99 | grepstr "$result" '"id"[ \t\n]*:[ \t\n]*"foo"' 100 | } 101 | @test "error responses give back the integer request id" { 102 | query='{"jsonrpc":"2.0","id":1}' 103 | result=`query "$query"` 104 | printrep "$query" "$result" 105 | grepstr "$result" '"error"[ \t\n]*:[ \t\n]*{[ \t\n]*"code"' 106 | grepstr "$result" '"id"[ \t\n]*:[ \t\n]*1' 107 | } 108 | @test "result responses give back the string request id" { 109 | query='{"jsonrpc":"2.0","method":"echo","params":["foobar"],"id":"tau"}' 110 | result=`query "$query"` 111 | printrep "$query" "$result" 112 | grepstr "$result" '"result"[ \t\n]*:[ \t\n]*[[ \t\n]*"foobar"[ \t\n]*]' 113 | grepstr "$result" '"id"[ \t\n]*:[ \t\n]*"tau"' 114 | } 115 | @test "result responses give back the integer request id" { 116 | query='{"jsonrpc":"2.0","method":"echo","params":["foobar"],"id":6}' 117 | result=`query "$query"` 118 | printrep "$query" "$result" 119 | grepstr "$result" '"result"[ \t\n]*:[ \t\n]*[[ \t\n]*"foobar"[ \t\n]*]' 120 | grepstr "$result" '"id"[ \t\n]*:[ \t\n]*6' 121 | } 122 | -------------------------------------------------------------------------------- /examples/memtag/.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | .flavor 3 | .objs 4 | memtag.so 5 | assets.h 6 | cert 7 | -------------------------------------------------------------------------------- /examples/memtag/conf/build.conf: -------------------------------------------------------------------------------- 1 | # memtag build config 2 | # You can switch flavors using: kodev flavor [newflavor] 3 | 4 | # Set to yes if you wish to produce a single binary instead 5 | # of a dynamic library. If you set this to yes you must also 6 | # set kore_source together with kore_flavor. 7 | #single_binary=no 8 | #kore_source=/home/joris/src/kore 9 | #kore_flavor= 10 | 11 | # The flags below are shared between flavors 12 | cflags=-Wall -Wmissing-declarations -Wshadow 13 | cflags=-Wstrict-prototypes -Wmissing-prototypes 14 | cflags=-Wpointer-arith -Wcast-qual -Wsign-compare 15 | 16 | cxxflags=-Wall -Wmissing-declarations -Wshadow 17 | cxxflags=-Wpointer-arith -Wcast-qual -Wsign-compare 18 | 19 | # Mime types for assets served via the builtin asset_serve_* 20 | #mime_add=txt:text/plain; charset=utf-8 21 | #mime_add=png:image/png 22 | #mime_add=html:text/html; charset=utf-8 23 | 24 | dev { 25 | # These flags are added to the shared ones when 26 | # you build the "dev" flavor. 27 | cflags=-g 28 | cxxflags=-g 29 | } 30 | 31 | #prod { 32 | # You can specify additional flags here which are only 33 | # included if you build with the "prod" flavor. 34 | #} 35 | -------------------------------------------------------------------------------- /examples/memtag/conf/memtag.conf: -------------------------------------------------------------------------------- 1 | # memtag configuration 2 | 3 | server tls { 4 | bind 127.0.0.1 8888 5 | } 6 | 7 | load ./memtag.so init 8 | 9 | domain * { 10 | attach tls 11 | 12 | certfile cert/server.pem 13 | certkey cert/key.pem 14 | 15 | route / { 16 | handler page 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /examples/memtag/src/memtag.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2018 Joris Vink 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include 18 | #include 19 | 20 | /* 21 | * This example demonstrates how dynamically reloadable modules 22 | * can use the memory tagging system in Kore in order to restore 23 | * the global pointers in the module. 24 | */ 25 | 26 | /* Some unique value. */ 27 | #define MEM_TAG_HELLO 100 28 | 29 | int init(int); 30 | int page(struct http_request *); 31 | 32 | /* Global pointer, gets initialized to NULL when module loads/reloads. */ 33 | char *fixed_ptr = NULL; 34 | 35 | int 36 | init(int state) 37 | { 38 | /* Ignore unload(s). */ 39 | if (state == KORE_MODULE_UNLOAD) 40 | return (KORE_RESULT_OK); 41 | 42 | printf("fixed_ptr: %p\n", (void *)fixed_ptr); 43 | 44 | /* Attempt to lookup the original pointer. */ 45 | if ((fixed_ptr = kore_mem_lookup(MEM_TAG_HELLO)) == NULL) { 46 | /* Failed, grab a new chunk of memory and tag it. */ 47 | printf(" allocating fixed_ptr for the first time\n"); 48 | fixed_ptr = kore_malloc_tagged(6, MEM_TAG_HELLO); 49 | kore_strlcpy(fixed_ptr, "hello", 6); 50 | } else { 51 | printf(" fixed_ptr address resolved\n"); 52 | } 53 | 54 | printf(" fixed_ptr: %p\n", (void *)fixed_ptr); 55 | printf(" value : %s\n", fixed_ptr); 56 | 57 | return (KORE_RESULT_OK); 58 | } 59 | 60 | int 61 | page(struct http_request *req) 62 | { 63 | http_response(req, 200, fixed_ptr, strlen(fixed_ptr)); 64 | return (KORE_RESULT_OK); 65 | } 66 | -------------------------------------------------------------------------------- /examples/messaging/.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | .objs 3 | messaging.so 4 | assets.h 5 | cert 6 | -------------------------------------------------------------------------------- /examples/messaging/README.md: -------------------------------------------------------------------------------- 1 | Kore message framework example 2 | 3 | Run: 4 | ``` 5 | # kodev run 6 | ``` 7 | 8 | Test: 9 | ``` 10 | Perform a simple GET request against the root page. 11 | This should trigger the example app to send a message 12 | to the other workers which will display it. 13 | 14 | # curl -k https://127.0.0.1:8888 15 | ``` 16 | -------------------------------------------------------------------------------- /examples/messaging/conf/build.conf: -------------------------------------------------------------------------------- 1 | # messaging build config 2 | # You can switch flavors using: kodev flavor [newflavor] 3 | 4 | # The cflags below are shared between flavors 5 | cflags=-Wall -Wmissing-declarations -Wshadow 6 | cflags=-Wstrict-prototypes -Wmissing-prototypes 7 | cflags=-Wpointer-arith -Wcast-qual -Wsign-compare 8 | 9 | dev { 10 | # These cflags are added to the shared ones when 11 | # you build the "dev" flavor. 12 | cflags=-g 13 | } 14 | 15 | #prod { 16 | # You can specify additional CFLAGS here which are only 17 | # included if you build with the "prod" flavor. 18 | #} 19 | -------------------------------------------------------------------------------- /examples/messaging/conf/messaging.conf: -------------------------------------------------------------------------------- 1 | # Placeholder configuration 2 | 3 | server tls { 4 | bind 127.0.0.1 8888 5 | } 6 | 7 | load ./messaging.so init 8 | 9 | domain * { 10 | attach tls 11 | 12 | certfile cert/server.pem 13 | certkey cert/key.pem 14 | 15 | route / { 16 | handler page 17 | } 18 | 19 | route /shutdown { 20 | handler page_shutdown 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /examples/messaging/src/messaging.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Joris Vink 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include 18 | #include 19 | 20 | /* 21 | * This example demonstrates how to use the messaging framework 22 | * in Kore. This framework allows you to send messages between 23 | * your workers with custom callbacks defined per message ID. 24 | */ 25 | 26 | /* Your code shouldn't use IDs <= KORE_MSG_APP_BASE. */ 27 | #define MY_MESSAGE_ID KORE_MSG_APP_BASE + 1 28 | 29 | int init(int); 30 | int page(struct http_request *); 31 | int page_shutdown(struct http_request *req); 32 | void received_message(struct kore_msg *, const void *); 33 | 34 | /* Initialization callback. */ 35 | int 36 | init(int state) 37 | { 38 | if (state == KORE_MODULE_UNLOAD) 39 | return (KORE_RESULT_OK); 40 | 41 | /* 42 | * Register our message callback when the module is initialized. 43 | * kore_msg_register() fails if the message ID already exists, 44 | * but in our case that is OK. 45 | */ 46 | (void)kore_msg_register(MY_MESSAGE_ID, received_message); 47 | 48 | return (KORE_RESULT_OK); 49 | } 50 | 51 | /* 52 | * Callback for receiving a message MY_MESSAGE_ID. 53 | */ 54 | void 55 | received_message(struct kore_msg *msg, const void *data) 56 | { 57 | kore_log(LOG_INFO, "got message from %u (%zu bytes): %.*s", msg->src, 58 | msg->length, (int)msg->length, (const char *)data); 59 | } 60 | 61 | /* 62 | * Page request which will send a message to all other workers 63 | * with the ID set to MY_MESSAGE_ID and a payload of "hello". 64 | */ 65 | int 66 | page(struct http_request *req) 67 | { 68 | /* Send to all workers first. */ 69 | kore_msg_send(KORE_MSG_WORKER_ALL, MY_MESSAGE_ID, "hello", 5); 70 | 71 | /* Now send something to worker number #2 only. */ 72 | kore_msg_send(2, MY_MESSAGE_ID, "hello number 2", 14); 73 | 74 | http_response(req, 200, NULL, 0); 75 | return (KORE_RESULT_OK); 76 | } 77 | 78 | /* 79 | * Page request which will send a message to the parent 80 | * requesting process shutdown. 81 | */ 82 | int 83 | page_shutdown(struct http_request *req) 84 | { 85 | /* Send shutdown request to parent. */ 86 | kore_msg_send(KORE_MSG_PARENT, KORE_MSG_SHUTDOWN, "1", 1); 87 | 88 | http_response(req, 200, NULL, 0); 89 | return (KORE_RESULT_OK); 90 | } 91 | -------------------------------------------------------------------------------- /examples/nohttp/.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | .objs 3 | nohttp.so 4 | assets.h 5 | cert 6 | -------------------------------------------------------------------------------- /examples/nohttp/README.md: -------------------------------------------------------------------------------- 1 | Kore NOHTTP example 2 | 3 | Run: 4 | ``` 5 | $ kodev run 6 | ``` 7 | 8 | Test: 9 | ``` 10 | Connect to the server using openssl s_client, you will notice 11 | that anything sent is submitted back to your client. 12 | 13 | $ openssl s_client -connect 127.0.0.1:8888 14 | ``` 15 | -------------------------------------------------------------------------------- /examples/nohttp/conf/build.conf: -------------------------------------------------------------------------------- 1 | # nohttp build config 2 | # You can switch flavors using: kodev flavor [newflavor] 3 | 4 | # Set to yes if you wish to produce a single binary instead 5 | # of a dynamic library. If you set this to yes you must also 6 | # set kore_source together with kore_flavor. 7 | single_binary=yes 8 | kore_source=../../ 9 | kore_flavor=NOHTTP=1 10 | 11 | # The cflags below are shared between flavors 12 | cflags=-Wall -Wmissing-declarations -Wshadow 13 | cflags=-Wstrict-prototypes -Wmissing-prototypes 14 | cflags=-Wpointer-arith -Wcast-qual -Wsign-compare 15 | 16 | dev { 17 | # These cflags are added to the shared ones when 18 | # you build the "dev" flavor. 19 | cflags=-g 20 | } 21 | 22 | #prod { 23 | # You can specify additional CFLAGS here which are only 24 | # included if you build with the "prod" flavor. 25 | #} 26 | -------------------------------------------------------------------------------- /examples/nohttp/conf/nohttp.conf: -------------------------------------------------------------------------------- 1 | # nohttp configuration 2 | 3 | server tls { 4 | bind 127.0.0.1 8888 connection_setup 5 | } 6 | 7 | domain * { 8 | attach tls 9 | 10 | certfile cert/server.pem 11 | certkey cert/key.pem 12 | } 13 | -------------------------------------------------------------------------------- /examples/nohttp/src/init.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Joris Vink 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include 18 | #include 19 | 20 | /* Let kore handle the default option parsing. */ 21 | void 22 | kore_parent_configure(int argc, char **argv) 23 | { 24 | kore_default_getopt(argc, argv); 25 | } 26 | -------------------------------------------------------------------------------- /examples/nohttp/src/nohttp.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Joris Vink 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | /* 18 | * Example of using Kore as a network application server. 19 | * 20 | * We will get called for every new connection that has been established. 21 | * For TLS connections we will get called after the TLS handshake completed. 22 | * 23 | * From the setup we can queue up our own read commands and do whatever we 24 | * like with the newly connected client. 25 | */ 26 | 27 | #include 28 | 29 | void connection_setup(struct connection *); 30 | int connection_handle(struct connection *); 31 | int connection_recv_data(struct netbuf *); 32 | 33 | void 34 | connection_setup(struct connection *c) 35 | { 36 | kore_log(LOG_NOTICE, "%p: new connection", c); 37 | 38 | /* 39 | * Setup a read command that will read up to 128 bytes and will 40 | * always call the callback connection_recv_data even if not all 41 | * 128 bytes were read. 42 | */ 43 | net_recv_queue(c, 128, NETBUF_CALL_CB_ALWAYS, connection_recv_data); 44 | 45 | /* We are responsible for setting the connection state. */ 46 | c->state = CONN_STATE_ESTABLISHED; 47 | 48 | /* Override the handle function, called when new events occur. */ 49 | c->handle = connection_handle; 50 | } 51 | 52 | /* 53 | * This function is called every time a new event is triggered on the 54 | * connection. In this demo we just use it as a stub for the normal 55 | * callback kore_connection_handle(). 56 | * 57 | * In this callback you would generally look at the state of the connection 58 | * in c->state and perform the required actions like writing / reading using 59 | * net_send_flush() or net_recv_flush() if KORE_EVENT_WRITE or 60 | * KORE_EVENT_READ are set respectively in c->evt.flags. 61 | * Returning KORE_RESULT_ERROR from this callback will disconnect the 62 | * connection altogether. 63 | */ 64 | int 65 | connection_handle(struct connection *c) 66 | { 67 | kore_log(LOG_NOTICE, "connection_handle: %p", c); 68 | return (kore_connection_handle(c)); 69 | } 70 | 71 | /* 72 | * This function is called every time we get up to 128 bytes of data. 73 | * The connection can be found under nb->owner. 74 | * The data received can be found under nb->buf. 75 | * The length of the received data can be found under s_off. 76 | */ 77 | int 78 | connection_recv_data(struct netbuf *nb) 79 | { 80 | struct connection *c = (struct connection *)nb->owner; 81 | 82 | kore_log(LOG_NOTICE, "%p: received %zu bytes", (void *)c, nb->s_off); 83 | 84 | /* We will just dump these back to the client. */ 85 | net_send_queue(c, nb->buf, nb->s_off); 86 | net_send_flush(c); 87 | 88 | /* Now reset the receive command for the next one. */ 89 | net_recv_reset(c, 128, connection_recv_data); 90 | 91 | return (KORE_RESULT_OK); 92 | } 93 | -------------------------------------------------------------------------------- /examples/parameters/.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | .objs 3 | parameters.so 4 | assets.h 5 | cert 6 | -------------------------------------------------------------------------------- /examples/parameters/README.md: -------------------------------------------------------------------------------- 1 | Example on how to handle GET/POST parameters in Kore. 2 | 3 | Run: 4 | ``` 5 | # kodev run 6 | ``` 7 | 8 | Test: 9 | ``` 10 | # curl -i -k https://127.0.0.1:8888/?id=123123 11 | ``` 12 | 13 | The output will differ based on whether or not id is a valid 14 | u_int16_t number or not. (the string should always be present). 15 | -------------------------------------------------------------------------------- /examples/parameters/conf/build.conf: -------------------------------------------------------------------------------- 1 | # parameters build config 2 | # You can switch flavors using: kodev flavor [newflavor] 3 | 4 | # The cflags below are shared between flavors 5 | cflags=-Wall -Wmissing-declarations -Wshadow 6 | cflags=-Wstrict-prototypes -Wmissing-prototypes 7 | cflags=-Wpointer-arith -Wcast-qual -Wsign-compare 8 | 9 | dev { 10 | # These cflags are added to the shared ones when 11 | # you build the "dev" flavor. 12 | cflags=-g 13 | } 14 | 15 | #prod { 16 | # You can specify additional CFLAGS here which are only 17 | # included if you build with the "prod" flavor. 18 | #} 19 | -------------------------------------------------------------------------------- /examples/parameters/conf/parameters.conf: -------------------------------------------------------------------------------- 1 | # Placeholder configuration 2 | 3 | server tls { 4 | bind 127.0.0.1 8888 5 | } 6 | 7 | load ./parameters.so 8 | 9 | # The validator used to validate the 'id' parameter 10 | # defined below. We'll use a simple regex to make sure 11 | # it only matches positive numbers. 12 | validator v_id regex ^[0-9]*$ 13 | 14 | domain * { 15 | attach tls 16 | 17 | certfile cert/server.pem 18 | certkey cert/key.pem 19 | 20 | route / { 21 | handler page 22 | methods get 23 | 24 | validate qs:get id v_id 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /examples/parameters/src/parameters.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014 Joris Vink 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include 18 | #include 19 | 20 | int page(struct http_request *); 21 | 22 | int 23 | page(struct http_request *req) 24 | { 25 | u_int16_t id; 26 | char *sid; 27 | struct kore_buf *buf; 28 | 29 | /* 30 | * Before we are able to obtain any parameters given to 31 | * us via the query string we must tell Kore to parse and 32 | * validate them. 33 | * 34 | * NOTE: All parameters MUST be declared in a params {} block 35 | * inside the configuration for Kore! Kore will filter out 36 | * any parameters not explicitly defined. 37 | * 38 | * See conf/parameters.conf on how that is done, this is an 39 | * important step as without the params block you will never 40 | * get any parameters returned from Kore. 41 | */ 42 | http_populate_get(req); 43 | 44 | /* 45 | * Lets grab the "id" parameter if available. Kore can obtain 46 | * parameters in different data types native to C. 47 | * 48 | * In this scenario, lets grab it both as an actual string and 49 | * as an u_int16_t (unsigned short). 50 | * 51 | * When trying to obtain a parameter as something else then 52 | * a string, Kore will automatically check if the value fits 53 | * in said data type. 54 | * 55 | * For example if id is 65536 it won't fit in an u_int16_t 56 | * and Kore will return an error when trying to read it as such. 57 | */ 58 | 59 | buf = kore_buf_alloc(128); 60 | 61 | /* Grab it as a string, we shouldn't free the result in sid. */ 62 | if (http_argument_get_string(req, "id", &sid)) 63 | kore_buf_appendf(buf, "id as a string: '%s'\n", sid); 64 | 65 | /* Grab it as an actual u_int16_t. */ 66 | if (http_argument_get_uint16(req, "id", &id)) 67 | kore_buf_appendf(buf, "id as an u_int16_t: %d\n", id); 68 | 69 | /* Now return the result to the client with a 200 status code. */ 70 | http_response(req, 200, buf->data, buf->offset); 71 | kore_buf_free(buf); 72 | 73 | return (KORE_RESULT_OK); 74 | } 75 | -------------------------------------------------------------------------------- /examples/pgsql-sync/.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | .objs 3 | pgsql-sync.so 4 | assets.h 5 | cert 6 | -------------------------------------------------------------------------------- /examples/pgsql-sync/conf/build.conf: -------------------------------------------------------------------------------- 1 | # pgsql-sync build config 2 | # You can switch flavors using: kodev flavor [newflavor] 3 | 4 | # The cflags below are shared between flavors 5 | cflags=-Wall -Wmissing-declarations -Wshadow 6 | cflags=-Wstrict-prototypes -Wmissing-prototypes 7 | cflags=-Wpointer-arith -Wcast-qual -Wsign-compare 8 | 9 | dev { 10 | # These cflags are added to the shared ones when 11 | # you build the "dev" flavor. 12 | cflags=-g 13 | } 14 | 15 | #prod { 16 | # You can specify additional CFLAGS here which are only 17 | # included if you build with the "prod" flavor. 18 | #} 19 | -------------------------------------------------------------------------------- /examples/pgsql-sync/conf/pgsql-sync.conf: -------------------------------------------------------------------------------- 1 | # Placeholder configuration 2 | 3 | server tls { 4 | bind 127.0.0.1 8888 5 | } 6 | 7 | load ./pgsql-sync.so init 8 | 9 | domain * { 10 | attach tls 11 | 12 | certfile cert/server.pem 13 | certkey cert/key.pem 14 | 15 | route / { 16 | handler page 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /examples/pgsql-sync/src/pgsql-sync.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Joris Vink 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | /* 18 | * This example demonstrates how to use synchronous PGSQL queries 19 | * with Kore. For an asynchronous example see pgsql/ under examples/. 20 | * 21 | * This example does the same as the asynchronous one, select all entries 22 | * from a table called "coders". 23 | */ 24 | 25 | #include 26 | #include 27 | #include 28 | 29 | int init(int); 30 | int page(struct http_request *); 31 | 32 | /* Called when our module is loaded (see config) */ 33 | int 34 | init(int state) 35 | { 36 | /* Register our database. */ 37 | kore_pgsql_register("db", "host=/tmp dbname=test"); 38 | 39 | return (KORE_RESULT_OK); 40 | } 41 | 42 | /* Page handler entry point (see config) */ 43 | int 44 | page(struct http_request *req) 45 | { 46 | struct kore_pgsql sql; 47 | char *name; 48 | int rows, i; 49 | 50 | req->status = HTTP_STATUS_INTERNAL_ERROR; 51 | 52 | kore_pgsql_init(&sql); 53 | 54 | /* 55 | * Initialise our kore_pgsql data structure with the database name 56 | * we want to connect to (note that we registered this earlier with 57 | * kore_pgsql_register()). We also say we will perform a synchronous 58 | * query (KORE_PGSQL_SYNC). 59 | */ 60 | if (!kore_pgsql_setup(&sql, "db", KORE_PGSQL_SYNC)) { 61 | kore_pgsql_logerror(&sql); 62 | goto out; 63 | } 64 | 65 | /* 66 | * Now we can fire off the query, once it returns we either have 67 | * a result on which we can operate or an error occurred. 68 | */ 69 | if (!kore_pgsql_query(&sql, "SELECT * FROM coders")) { 70 | kore_pgsql_logerror(&sql); 71 | goto out; 72 | } 73 | 74 | /* 75 | * Iterate over the result and dump it to somewhere. 76 | */ 77 | rows = kore_pgsql_ntuples(&sql); 78 | for (i = 0; i < rows; i++) { 79 | name = kore_pgsql_getvalue(&sql, i, 0); 80 | kore_log(LOG_NOTICE, "name: '%s'", name); 81 | } 82 | 83 | /* All good. */ 84 | req->status = HTTP_STATUS_OK; 85 | 86 | out: 87 | http_response(req, req->status, NULL, 0); 88 | 89 | /* Don't forget to cleanup the kore_pgsql data structure. */ 90 | kore_pgsql_cleanup(&sql); 91 | 92 | return (KORE_RESULT_OK); 93 | } 94 | -------------------------------------------------------------------------------- /examples/pgsql/.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | .objs 3 | pgsql.so 4 | assets.h 5 | cert 6 | -------------------------------------------------------------------------------- /examples/pgsql/README.md: -------------------------------------------------------------------------------- 1 | Kore pgsql example. 2 | 3 | This example demonstrates how one can use Kore state machines and the 4 | pgsql api to make fully asynchronous SQL queries. 5 | 6 | Asynchronous in this case meaning, without interrupting a Kore worker its 7 | other clients their I/O or http requests. 8 | 9 | Tons of comments inside on how everything works. 10 | 11 | Run: 12 | ``` 13 | # kodev run 14 | ``` 15 | -------------------------------------------------------------------------------- /examples/pgsql/conf/build.conf: -------------------------------------------------------------------------------- 1 | # pgsql build config 2 | # You can switch flavors using: kodev flavor [newflavor] 3 | 4 | # The cflags below are shared between flavors 5 | cflags=-Wall -Wmissing-declarations -Wshadow 6 | cflags=-Wstrict-prototypes -Wmissing-prototypes 7 | cflags=-Wpointer-arith -Wcast-qual -Wsign-compare 8 | 9 | dev { 10 | # These cflags are added to the shared ones when 11 | # you build the "dev" flavor. 12 | cflags=-g 13 | } 14 | 15 | #prod { 16 | # You can specify additional CFLAGS here which are only 17 | # included if you build with the "prod" flavor. 18 | #} 19 | -------------------------------------------------------------------------------- /examples/pgsql/conf/pgsql.conf: -------------------------------------------------------------------------------- 1 | # Placeholder configuration 2 | 3 | load ./pgsql.so init 4 | 5 | server tls { 6 | bind 127.0.0.1 8888 7 | } 8 | 9 | server other { 10 | bind 127.0.0.1 8889 connection_new 11 | } 12 | 13 | http_keepalive_time 0 14 | 15 | domain * { 16 | attach tls 17 | 18 | certfile cert/server.pem 19 | certkey cert/key.pem 20 | 21 | route / { 22 | handler page 23 | } 24 | 25 | route /hello { 26 | handler hello 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /examples/pgsql/src/init.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2018 Joris Vink 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include 18 | #include 19 | 20 | #if !defined(KORE_NO_HTTP) 21 | #include 22 | #endif 23 | 24 | int init(int); 25 | 26 | #if !defined(KORE_NO_HTTP) 27 | int hello(struct http_request *); 28 | #endif 29 | 30 | /* Called when our module is loaded (see config) */ 31 | int 32 | init(int state) 33 | { 34 | /* Register our database. */ 35 | kore_pgsql_register("db", "host=/tmp dbname=test"); 36 | 37 | return (KORE_RESULT_OK); 38 | } 39 | 40 | #if !defined(KORE_NO_HTTP) 41 | int 42 | hello(struct http_request *req) 43 | { 44 | http_response(req, HTTP_STATUS_OK, "hello", 5); 45 | return (KORE_RESULT_OK); 46 | } 47 | #endif 48 | -------------------------------------------------------------------------------- /examples/pgsql/src/pgsql_cb.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 Joris Vink 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | /* 18 | * This is the same as pgsql.c except the query is fired off when 19 | * a new connection is made to Kore on port 8889. 20 | * 21 | * Instead of binding an http_request to the pgsql data structure we 22 | * use a callback function that is called for every state change. 23 | * 24 | * We pass the connection as an argument to this function. 25 | */ 26 | 27 | #include 28 | #include 29 | #include 30 | 31 | void connection_del(struct connection *c); 32 | void connection_new(struct connection *); 33 | 34 | void db_state_change(struct kore_pgsql *, void *); 35 | void db_init(struct connection *, struct kore_pgsql *); 36 | void db_results(struct kore_pgsql *, struct connection *); 37 | 38 | void 39 | connection_new(struct connection *c) 40 | { 41 | struct kore_pgsql *pgsql; 42 | 43 | c->disconnect = connection_del; 44 | c->proto = CONN_PROTO_UNKNOWN; 45 | c->state = CONN_STATE_ESTABLISHED; 46 | 47 | pgsql = kore_calloc(1, sizeof(*pgsql)); 48 | 49 | kore_pgsql_init(pgsql); 50 | kore_pgsql_bind_callback(pgsql, db_state_change, c); 51 | 52 | c->hdlr_extra = pgsql; 53 | printf("new connection %p\n", (void *)c); 54 | 55 | db_init(c, pgsql); 56 | } 57 | 58 | void 59 | db_init(struct connection *c, struct kore_pgsql *pgsql) 60 | { 61 | if (!kore_pgsql_setup(pgsql, "db", KORE_PGSQL_ASYNC)) { 62 | if (pgsql->state == KORE_PGSQL_STATE_INIT) { 63 | printf("\twaiting for available pgsql connection\n"); 64 | return; 65 | } 66 | 67 | kore_pgsql_logerror(pgsql); 68 | kore_connection_disconnect(c); 69 | return; 70 | } 71 | 72 | printf("\tgot pgsql connection\n"); 73 | if (!kore_pgsql_query(pgsql, "SELECT * FROM coders, pg_sleep(5)")) { 74 | kore_pgsql_logerror(pgsql); 75 | kore_connection_disconnect(c); 76 | return; 77 | } 78 | printf("\tquery fired off!\n"); 79 | } 80 | 81 | void 82 | connection_del(struct connection *c) 83 | { 84 | printf("%p: disconnecting\n", (void *)c); 85 | 86 | if (c->hdlr_extra != NULL) 87 | kore_pgsql_cleanup(c->hdlr_extra); 88 | 89 | kore_free(c->hdlr_extra); 90 | c->hdlr_extra = NULL; 91 | } 92 | 93 | void 94 | db_state_change(struct kore_pgsql *pgsql, void *arg) 95 | { 96 | struct connection *c = arg; 97 | 98 | printf("%p: state change on pgsql %d\n", arg, pgsql->state); 99 | 100 | switch (pgsql->state) { 101 | case KORE_PGSQL_STATE_INIT: 102 | db_init(c, pgsql); 103 | break; 104 | case KORE_PGSQL_STATE_WAIT: 105 | break; 106 | case KORE_PGSQL_STATE_COMPLETE: 107 | kore_connection_disconnect(c); 108 | break; 109 | case KORE_PGSQL_STATE_ERROR: 110 | kore_pgsql_logerror(pgsql); 111 | kore_connection_disconnect(c); 112 | break; 113 | case KORE_PGSQL_STATE_RESULT: 114 | db_results(pgsql, c); 115 | break; 116 | default: 117 | kore_pgsql_continue(pgsql); 118 | break; 119 | } 120 | } 121 | 122 | void 123 | db_results(struct kore_pgsql *pgsql, struct connection *c) 124 | { 125 | char *name; 126 | int i, rows; 127 | 128 | rows = kore_pgsql_ntuples(pgsql); 129 | for (i = 0; i < rows; i++) { 130 | name = kore_pgsql_getvalue(pgsql, i, 0); 131 | net_send_queue(c, name, strlen(name)); 132 | } 133 | 134 | net_send_flush(c); 135 | kore_pgsql_continue(pgsql); 136 | } 137 | -------------------------------------------------------------------------------- /examples/pipe_task/.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | .objs 3 | websocket.so 4 | assets.h 5 | cert 6 | -------------------------------------------------------------------------------- /examples/pipe_task/README.md: -------------------------------------------------------------------------------- 1 | Kore example of tasks and websockets. 2 | 3 | This example connects Kore via task to a named unix pipe and 4 | spews out any output to all connected websocket clients. 5 | 6 | Before you run this make the pipe: 7 | $ mkfifo /tmp/pipe 8 | 9 | Run: 10 | ``` 11 | $ kodev run 12 | ``` 13 | 14 | Test: 15 | ``` 16 | Open a browser that does websockets, surf to https://127.0.0.1:8888 17 | or whatever configured IP you have in the config. 18 | 19 | Hit the connect button to open a websocket session. 20 | 21 | Now connect a writer endpoint to the named pipe (/tmp/pipe): 22 | $ echo "hello" > /tmp/pipe 23 | 24 | You should see the result in your browser. 25 | ``` 26 | -------------------------------------------------------------------------------- /examples/pipe_task/assets/frontend.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 30 | 31 | 32 | 33 | 34 |
35 | 36 |
37 | 38 |
39 |
40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /examples/pipe_task/conf/build.conf: -------------------------------------------------------------------------------- 1 | # pipe_task build config 2 | # You can switch flavors using: kodev flavor [newflavor] 3 | 4 | # Set to yes if you wish to produce a single binary instead 5 | # of a dynamic library. If you set this to yes you must also 6 | # set kore_source together with kore_flavor. 7 | single_binary=yes 8 | kore_source=../../ 9 | kore_flavor=TASKS=1 10 | 11 | # The cflags below are shared between flavors 12 | cflags=-Wall -Wmissing-declarations -Wshadow 13 | cflags=-Wstrict-prototypes -Wmissing-prototypes 14 | cflags=-Wpointer-arith -Wcast-qual -Wsign-compare 15 | 16 | dev { 17 | # These cflags are added to the shared ones when 18 | # you build the "dev" flavor. 19 | cflags=-g 20 | } 21 | 22 | #prod { 23 | # You can specify additional CFLAGS here which are only 24 | # included if you build with the "prod" flavor. 25 | #} 26 | -------------------------------------------------------------------------------- /examples/pipe_task/conf/pipe_task.conf: -------------------------------------------------------------------------------- 1 | # Kore pipe_task example 2 | 3 | server tls { 4 | bind 127.0.0.1 8888 5 | } 6 | 7 | websocket_maxframe 65536 8 | websocket_timeout 10000 9 | 10 | domain * { 11 | attach tls 12 | 13 | certfile cert/server.pem 14 | certkey cert/key.pem 15 | 16 | route / { 17 | handler page 18 | } 19 | 20 | route /connect { 21 | handler page_ws_connect 22 | methods get 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /examples/pipe_task/src/init.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Joris Vink 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include 18 | #include 19 | 20 | /* Let kore handle the default option parsing. */ 21 | void 22 | kore_parent_configure(int argc, char **argv) 23 | { 24 | kore_default_getopt(argc, argv); 25 | } 26 | -------------------------------------------------------------------------------- /examples/pipe_task/src/pipe_task.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Joris Vink 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | /* 18 | * This example demos Kore its task and websocket capabilities. 19 | * 20 | * It will spawn a task which connects to a named pipe and writes 21 | * responses to all connected websocket clients. 22 | */ 23 | 24 | #include 25 | #include 26 | #include 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | #include 34 | #include 35 | 36 | #include "assets.h" 37 | 38 | int init(int); 39 | int page(struct http_request *); 40 | int page_ws_connect(struct http_request *); 41 | 42 | void websocket_connect(struct connection *); 43 | void websocket_disconnect(struct connection *); 44 | void websocket_message(struct connection *, 45 | u_int8_t, void *, size_t); 46 | 47 | int pipe_reader(struct kore_task *); 48 | void pipe_data_available(struct kore_task *); 49 | 50 | /* Our pipe reader. */ 51 | struct kore_task pipe_task; 52 | 53 | void 54 | kore_worker_configure(void) 55 | { 56 | /* Only do this on a dedicated worker. */ 57 | if (worker->id != 1) 58 | return; 59 | 60 | /* Create our task. */ 61 | kore_task_create(&pipe_task, pipe_reader); 62 | 63 | /* Bind a callback whenever data is available from task. */ 64 | kore_task_bind_callback(&pipe_task, pipe_data_available); 65 | 66 | /* Start the task. */ 67 | kore_task_run(&pipe_task); 68 | } 69 | 70 | /* Called whenever we get a new websocket connection. */ 71 | void 72 | websocket_connect(struct connection *c) 73 | { 74 | kore_log(LOG_NOTICE, "%p: connected", c); 75 | } 76 | 77 | /* Called whenever we receive a websocket message from a client. */ 78 | void 79 | websocket_message(struct connection *c, u_int8_t op, void *data, size_t len) 80 | { 81 | /* Not doing anything with this. */ 82 | } 83 | 84 | /* Called whenever a websocket goes away. */ 85 | void 86 | websocket_disconnect(struct connection *c) 87 | { 88 | kore_log(LOG_NOTICE, "%p: disconnecting", c); 89 | } 90 | 91 | /* The / page. */ 92 | int 93 | page(struct http_request *req) 94 | { 95 | http_response_header(req, "content-type", "text/html"); 96 | http_response(req, 200, asset_frontend_html, asset_len_frontend_html); 97 | 98 | return (KORE_RESULT_OK); 99 | } 100 | 101 | /* The /connect page. */ 102 | int 103 | page_ws_connect(struct http_request *req) 104 | { 105 | kore_websocket_handshake(req, "websocket_connect", 106 | "websocket_message", "websocket_disconnect"); 107 | return (KORE_RESULT_OK); 108 | } 109 | 110 | /* 111 | * The pipe reader task. This task simply waits for a writer end 112 | * on a named pipe and reads from it. The bytes read are written 113 | * on the task channel because the task does not own any connection 114 | * data structures and shouldn't reference them directly. 115 | */ 116 | int 117 | pipe_reader(struct kore_task *t) 118 | { 119 | int fd; 120 | ssize_t ret; 121 | u_int8_t buf[BUFSIZ]; 122 | 123 | fd = -1; 124 | 125 | kore_log(LOG_INFO, "pipe_reader starting"); 126 | 127 | /* Just run forever. */ 128 | for (;;) { 129 | /* Attempt to open the pipe if needed. */ 130 | if (fd == -1) { 131 | kore_log(LOG_NOTICE, "waiting for writer"); 132 | 133 | if ((fd = open("/tmp/pipe", O_RDONLY)) == -1) { 134 | kore_log(LOG_NOTICE, "failed to open pipe"); 135 | sleep(1); 136 | continue; 137 | } 138 | 139 | kore_log(LOG_NOTICE, "writer connected"); 140 | } 141 | 142 | /* Got a writer on the other end so start reading. */ 143 | ret = read(fd, buf, sizeof(buf)); 144 | if (ret == -1) { 145 | kore_log(LOG_ERR, "read error on pipe"); 146 | (void)close(fd); 147 | fd = -1; 148 | continue; 149 | } 150 | 151 | if (ret == 0) { 152 | kore_log(LOG_NOTICE, "writer disconnected"); 153 | (void)close(fd); 154 | fd = -1; 155 | continue; 156 | } 157 | 158 | kore_log(LOG_NOTICE, "got %ld bytes from pipe", ret); 159 | 160 | /* 161 | * Write data on the task channel so our main event loop 162 | * will call the registered callback. 163 | */ 164 | kore_task_channel_write(t, buf, ret); 165 | } 166 | 167 | return (KORE_RESULT_OK); 168 | } 169 | 170 | /* Called on the main event loop whenever a task event fires. */ 171 | void 172 | pipe_data_available(struct kore_task *t) 173 | { 174 | size_t len; 175 | u_int8_t buf[BUFSIZ]; 176 | 177 | /* Deal with the task finishing, we could restart it from here. */ 178 | if (kore_task_finished(t)) { 179 | kore_log(LOG_WARNING, "task finished"); 180 | return; 181 | } 182 | 183 | /* Read data from the task channel. */ 184 | len = kore_task_channel_read(t, buf, sizeof(buf)); 185 | if (len > sizeof(buf)) 186 | kore_log(LOG_WARNING, "truncated data from task"); 187 | 188 | /* Broadcast it to all connected websocket clients. */ 189 | kore_log(LOG_NOTICE, "got %zu bytes from task", len); 190 | 191 | kore_websocket_broadcast(NULL, WEBSOCKET_OP_TEXT, 192 | buf, len, WEBSOCKET_BROADCAST_GLOBAL); 193 | } 194 | -------------------------------------------------------------------------------- /examples/python-async/.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | .flavor 3 | .objs 4 | python-async.so 5 | assets.h 6 | cert 7 | -------------------------------------------------------------------------------- /examples/python-async/README.md: -------------------------------------------------------------------------------- 1 | Kore python async/await examples. 2 | 3 | This example also shows off the asynchronous HTTP client support 4 | and requires libcurl on your machine. 5 | 6 | Requires that Kore is built with PYTHON=1 CURL=1 7 | 8 | Run: 9 | ``` 10 | $ kore app.py 11 | ``` 12 | 13 | Test: 14 | ``` 15 | $ curl -k http://127.0.0.1:8888/queue 16 | $ curl -k http://127.0.0.1:8888/lock 17 | $ curl -k http://127.0.0.1:8888/proc 18 | $ curl -k http://127.0.0.1:8888/socket 19 | $ curl -k http://127.0.0.1:8888/httpclient 20 | ``` 21 | -------------------------------------------------------------------------------- /examples/python-async/app.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2018 Joris Vink 3 | # 4 | # Permission to use, copy, modify, and distribute this software for any 5 | # purpose with or without fee is hereby granted, provided that the above 6 | # copyright notice and this permission notice appear in all copies. 7 | # 8 | # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | # 16 | 17 | import kore 18 | 19 | import async_http 20 | import async_queue 21 | import async_socket 22 | import async_process 23 | import async_process 24 | 25 | kore.server(ip="127.0.0.1", port="8888", tls=False) 26 | kore.domain("*") 27 | 28 | kore.task_create(async_queue.queue_helper()) 29 | -------------------------------------------------------------------------------- /examples/python-async/async_http.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2019 Joris Vink 3 | # 4 | # Permission to use, copy, modify, and distribute this software for any 5 | # purpose with or without fee is hereby granted, provided that the above 6 | # copyright notice and this permission notice appear in all copies. 7 | # 8 | # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | # 16 | 17 | # 18 | # Asynchronous HTTP client example. 19 | # 20 | 21 | import kore 22 | 23 | # Handler called for /httpclient 24 | @kore.route("/httpclient", methods=["get"]) 25 | async def httpclient(req): 26 | # Create an httpclient. 27 | client = kore.httpclient("https://kore.io") 28 | 29 | # Do a simple GET request. 30 | print("firing off request") 31 | status, body = await client.get() 32 | print("status: %d, body: '%s'" % (status, body)) 33 | 34 | # Reuse and perform another GET request, returning headers too this time. 35 | status, headers, body = await client.get(return_headers=True) 36 | print("status: %d, headers: '%s'" % (status, headers)) 37 | 38 | # What happens if we post something? 39 | status, body = await client.post(body=b"hello world") 40 | print("status: %d, body: '%s'" % (status, body)) 41 | 42 | # Add some custom headers to our requests. 43 | status, body = await client.get( 44 | headers={ 45 | "x-my-header": "async-http" 46 | } 47 | ) 48 | 49 | req.response(200, b'async done') 50 | -------------------------------------------------------------------------------- /examples/python-async/async_lock.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2018 Joris Vink 3 | # 4 | # Permission to use, copy, modify, and distribute this software for any 5 | # purpose with or without fee is hereby granted, provided that the above 6 | # copyright notice and this permission notice appear in all copies. 7 | # 8 | # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | # 16 | 17 | # 18 | # Locking example. 19 | # 20 | # The handler for /lock will grab the shared lock, suspend itself for 21 | # 5 seconds before releasing the lock and responding. 22 | # 23 | # While the lock is held, other requests to /lock will block until it 24 | # is released. 25 | 26 | import kore 27 | 28 | # The shared lock 29 | lock = kore.lock() 30 | 31 | @kore.route("/lock", methods=["get"]) 32 | async def async_lock(req): 33 | # A kore.lock should be used with the "async with" syntax. 34 | async with lock: 35 | # Suspend for 5 seconds. 36 | await kore.suspend(5000) 37 | 38 | # Now respond. 39 | req.response(200, b'') 40 | -------------------------------------------------------------------------------- /examples/python-async/async_process.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2018 Joris Vink 3 | # 4 | # Permission to use, copy, modify, and distribute this software for any 5 | # purpose with or without fee is hereby granted, provided that the above 6 | # copyright notice and this permission notice appear in all copies. 7 | # 8 | # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | # 16 | 17 | # 18 | # Asynchronous process example. 19 | # 20 | # Wait for the result of an external process asynchronously. 21 | # The handler will execute "/bin/ls" on the current directory and 22 | # read the result. 23 | # 24 | 25 | import kore 26 | import json 27 | 28 | @kore.route("/proc", methods=["get"]) 29 | async def async_proc(req): 30 | # 31 | # You may specify a timeout when creating the kore.proc object. 32 | # If the timeout is reached before the process exits kore will 33 | # raise a TimeoutError exception. 34 | # 35 | # Ex: set timeout to 100ms: 36 | # proc = kore.proc("/bin/ls -lR", 100) 37 | 38 | proc = kore.proc("/bin/ls -lR") 39 | 40 | try: 41 | stdout = "" 42 | 43 | # Read until EOF (None is returned) 44 | while True: 45 | try: 46 | # Read from the process, with an optional 1 second timeout. 47 | # The recv() call will throw a TimeoutError exception if 48 | # the timeout has elapsed before any data was read. 49 | chunk = await proc.recv(1024, 1000) 50 | if chunk is None: 51 | break 52 | except TimeoutError as e: 53 | print("recv() timed out: %s" % e) 54 | continue 55 | stdout += chunk.decode() 56 | 57 | # Reap the process. 58 | retcode = await proc.reap() 59 | 60 | # Respond with the return code + the result as JSON. 61 | payload = { 62 | "retcode": retcode, 63 | "stdout": stdout 64 | } 65 | 66 | data = json.dumps(payload, indent=4) 67 | req.response(200, data.encode()) 68 | except Exception as e: 69 | # If an exception occurs we must kill the process first. 70 | proc.kill() 71 | errmsg = "Exception: %s" % e 72 | req.response(500, errmsg.encode()) 73 | -------------------------------------------------------------------------------- /examples/python-async/async_queue.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2018 Joris Vink 3 | # 4 | # Permission to use, copy, modify, and distribute this software for any 5 | # purpose with or without fee is hereby granted, provided that the above 6 | # copyright notice and this permission notice appear in all copies. 7 | # 8 | # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | # 16 | 17 | # 18 | # Asynchronous queue example. 19 | # 20 | 21 | import kore 22 | 23 | # The shared queue. 24 | tq = kore.queue() 25 | 26 | # Entry point for our independent coroutine that is created when kore starts. 27 | async def queue_helper(): 28 | while True: 29 | # Wait for a dictionary to arrive. 30 | obj = await tq.pop() 31 | kore.log(kore.LOG_INFO, "coro(): received %s" % obj) 32 | 33 | # Create a message to send back. 34 | msg = "%d = %s" % (kore.time(), obj["msg"]) 35 | 36 | # Send it on the received queue. 37 | obj["rq"].push(msg) 38 | 39 | @kore.route("/queue", methods=["get"]) 40 | async def async_queue(req): 41 | # Create our own queue. 42 | rq = kore.queue() 43 | 44 | # The dictionary we are going to send. 45 | obj = { 46 | # Receive queue object. 47 | "rq": rq, 48 | "msg": "hello" 49 | } 50 | 51 | # Push it onto the tq queue now, which will wake up the other coroutine. 52 | tq.push(obj) 53 | 54 | # Wait for a response. 55 | response = await rq.pop() 56 | 57 | # Send the response to the client. 58 | req.response(200, response.encode()) 59 | -------------------------------------------------------------------------------- /examples/python-async/async_socket.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2018 Joris Vink 3 | # 4 | # Permission to use, copy, modify, and distribute this software for any 5 | # purpose with or without fee is hereby granted, provided that the above 6 | # copyright notice and this permission notice appear in all copies. 7 | # 8 | # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | # 16 | 17 | # 18 | # Simple socket example. 19 | # 20 | # The handler will asynchronously connect to the kore app itself and 21 | # send an GET request to /socket-test and read the response. 22 | 23 | import kore 24 | import socket 25 | 26 | @kore.route("/socket", methods=["get"]) 27 | async def async_socket(req): 28 | # Create the socket using Pythons built-in socket class. 29 | sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 30 | 31 | # Set it to nonblocking. 32 | sock.setblocking(False) 33 | 34 | # Create a kore.socket with kore.socket_wrap(). 35 | conn = kore.socket_wrap(sock) 36 | 37 | # Asynchronously connect to 127.0.0.1 port 8888 38 | await conn.connect("127.0.0.1", 8888) 39 | kore.log(kore.LOG_INFO, "connected!") 40 | 41 | # Now send the GET request 42 | msg = "GET /socket-test HTTP/1.1\r\nHost: 127.0.0.1\r\n\r\n" 43 | await conn.send(msg.encode()) 44 | kore.log(kore.LOG_INFO, "request sent!") 45 | 46 | # Read the response. 47 | data = await conn.recv(8192) 48 | kore.log(kore.LOG_INFO, "got response!") 49 | 50 | # Respond with the response from /socket-test. 51 | req.response(200, data) 52 | 53 | conn.close() 54 | 55 | @kore.route("/socket-test", methods=["get"]) 56 | async def socket_test(req): 57 | # Delay response a bit, just cause we can. 58 | await kore.suspend(5000) 59 | req.response(200, b'response from /socket-test') 60 | -------------------------------------------------------------------------------- /examples/python-echo/.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | .flavor 3 | .objs 4 | python-echo 5 | assets.h 6 | cert 7 | -------------------------------------------------------------------------------- /examples/python-echo/README.md: -------------------------------------------------------------------------------- 1 | Example of using the asynchronous python api to create a simple 2 | echo server. 3 | 4 | Kore must have been built with PYTHON=1. 5 | 6 | On the command-line run the following 7 | 8 | $ kore echo.py 9 | 10 | Then connect to 127.0.0.1 port 6969 using netcat or so and you'll 11 | see it echo back everything you send it. 12 | -------------------------------------------------------------------------------- /examples/python-echo/echo.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2013-2018 Joris Vink 3 | # 4 | # Permission to use, copy, modify, and distribute this software for any 5 | # purpose with or without fee is hereby granted, provided that the above 6 | # copyright notice and this permission notice appear in all copies. 7 | # 8 | # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | # 16 | 17 | import kore 18 | import socket 19 | 20 | class EchoServer: 21 | # Setup socket + wrap it inside of a kore socket so we can use it. 22 | def __init__(self): 23 | sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 24 | sock.setblocking(False) 25 | sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 26 | sock.bind(("127.0.0.1", 6969)) 27 | sock.listen() 28 | 29 | self.conn = kore.socket_wrap(sock) 30 | 31 | # Wait for a new client to connect, then create a new task 32 | # that calls handle_client with the ocnnected client as 33 | # the argument. 34 | async def run(self): 35 | while True: 36 | try: 37 | client = await self.conn.accept() 38 | kore.task_create(self.handle_client(client)) 39 | client = None 40 | except Exception as e: 41 | kore.fatal("exception %s" % e) 42 | 43 | # Each client will run as this co-routine. 44 | # In this case we pass a timeout of 1 second to the recv() call 45 | # which will throw a TimeoutError exception in case the timeout 46 | # is hit before data is read from the socket. 47 | # 48 | # This timeout argument is optional. If none is specified the call 49 | # will wait until data becomes available. 50 | async def handle_client(self, client): 51 | while True: 52 | try: 53 | data = await client.recv(1024, 1000) 54 | if data is None: 55 | break 56 | await client.send(data) 57 | except TimeoutError as e: 58 | print("timed out reading (%s)" % e) 59 | except Exception as e: 60 | print("client got exception %s" % e) 61 | client.close() 62 | 63 | # Setup the server object. 64 | server = EchoServer() 65 | 66 | # Create a task that will execute inside of Kore as a co-routine. 67 | kore.task_create(server.run()) 68 | -------------------------------------------------------------------------------- /examples/python-pgsql/.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | .flavor 3 | .objs 4 | python-pgsql.so 5 | assets.h 6 | cert 7 | -------------------------------------------------------------------------------- /examples/python-pgsql/README.md: -------------------------------------------------------------------------------- 1 | Kore pgsql python module example. 2 | 3 | This application requires kore to be built with PYTHON=1 PGSQL=1. 4 | 5 | Run: 6 | ``` 7 | $ kodev run 8 | ``` 9 | 10 | Test: 11 | ``` 12 | $ curl -k https://127.0.0.1:8888 13 | $ curl -k https://127.0.0.1:8888/hello 14 | $ curl -k https://127.0.0.1:8888/slow 15 | ``` 16 | -------------------------------------------------------------------------------- /examples/python-pgsql/__init__.py: -------------------------------------------------------------------------------- 1 | from .app import koreapp 2 | 3 | def kore_parent_configure(args): 4 | koreapp.configure(args) 5 | 6 | def kore_worker_configure(): 7 | return 8 | -------------------------------------------------------------------------------- /examples/python-pgsql/app.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2017-2018 Joris Vink 3 | # 4 | # Permission to use, copy, modify, and distribute this software for any 5 | # purpose with or without fee is hereby granted, provided that the above 6 | # copyright notice and this permission notice appear in all copies. 7 | # 8 | # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | # 16 | 17 | # Asynchronous postgresql queries with Python. 18 | 19 | import json 20 | import kore 21 | 22 | class KoreApp: 23 | def configure(self, args): 24 | # Register the path to our database when Kore starts. 25 | kore.dbsetup("db", "host=/tmp dbname=test") 26 | 27 | # A handler that returns 200 OK with hello as body. 28 | def hello(self, req): 29 | req.response(200, b'hello\n') 30 | 31 | # 32 | # The query handler that fires of the query and returns a coroutine. 33 | # 34 | # Kore will resume this handler when the query returns a result or 35 | # is successful. 36 | # 37 | # The kore.pgsql() method can throw exceptions, most notably a 38 | # GeneratorExit in case the client connection went away before 39 | # the query was able to be completed. 40 | # 41 | # In this example we're not doing any exception handling. 42 | # 43 | async def query(self, req): 44 | result = await kore.dbquery("db", "SELECT * FROM coders") 45 | req.response(200, json.dumps(result).encode("utf-8")) 46 | 47 | # 48 | # A slow query that returns after 10 seconds. 49 | # 50 | async def slow(self, req): 51 | result = await kore.dbquery("db", "SELECT * FROM pg_sleep(10)") 52 | req.response(200, json.dumps(result).encode("utf-8")) 53 | 54 | # Set the application Kore will run to our class. 55 | koreapp = KoreApp() 56 | -------------------------------------------------------------------------------- /examples/python-pgsql/kore.conf: -------------------------------------------------------------------------------- 1 | # sql configuration 2 | 3 | server tls { 4 | bind 127.0.0.1 8888 5 | } 6 | 7 | tls_dhparam dh2048.pem 8 | 9 | domain * { 10 | attach tls 11 | 12 | certfile cert/server.pem 13 | certkey cert/key.pem 14 | 15 | route / koreapp.query 16 | route /hello koreapp.hello 17 | route /slow koreapp.slow 18 | } 19 | -------------------------------------------------------------------------------- /examples/sse/.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | .objs 3 | sse.so 4 | assets.h 5 | cert 6 | -------------------------------------------------------------------------------- /examples/sse/README.md: -------------------------------------------------------------------------------- 1 | This example demonstrates SSE (Server Side Events) in Kore. 2 | 3 | Run: 4 | ``` 5 | $ kodev run 6 | ``` 7 | 8 | Test (run different times to see the events broadcast): 9 | ``` 10 | curl -H 'accept: text/event-stream' -ik https://127.0.0.1:8888/subscribe 11 | ``` 12 | 13 | If you point a browser to https://127.0.0.1:8888 you will see 14 | a small log of what events are arriving. 15 | -------------------------------------------------------------------------------- /examples/sse/assets/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 47 | 48 | 49 |

events

50 |
51 |
52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /examples/sse/conf/build.conf: -------------------------------------------------------------------------------- 1 | # sse build config 2 | # You can switch flavors using: kodev flavor [newflavor] 3 | 4 | # The cflags below are shared between flavors 5 | cflags=-Wall -Wmissing-declarations -Wshadow 6 | cflags=-Wstrict-prototypes -Wmissing-prototypes 7 | cflags=-Wpointer-arith -Wcast-qual -Wsign-compare 8 | 9 | dev { 10 | # These cflags are added to the shared ones when 11 | # you build the "dev" flavor. 12 | cflags=-g 13 | } 14 | 15 | #prod { 16 | # You can specify additional CFLAGS here which are only 17 | # included if you build with the "prod" flavor. 18 | #} 19 | -------------------------------------------------------------------------------- /examples/sse/conf/sse.conf: -------------------------------------------------------------------------------- 1 | # Placeholder configuration 2 | 3 | server tls { 4 | bind 127.0.0.1 8888 5 | } 6 | 7 | load ./sse.so 8 | http_keepalive_time 600 9 | 10 | workers 1 11 | 12 | domain * { 13 | attach tls 14 | 15 | certfile cert/server.pem 16 | certkey cert/key.pem 17 | 18 | route / { 19 | handler page 20 | } 21 | 22 | route /subscribe { 23 | handler subscribe 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /examples/sse/src/sse.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Joris Vink 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | /* 18 | * Simple example of how SSE (Server Side Events) could be used in Kore. 19 | * 20 | * Upon new arrivals, a join event is broadcast to all clients. 21 | * If a client goes away a leave event is broadcasted. 22 | * Each connection gets its own 10 second ping timer which will emit 23 | * a ping event to the connection endpoint. 24 | */ 25 | 26 | #include 27 | #include 28 | 29 | #include "assets.h" 30 | 31 | void sse_ping(void *, u_int64_t); 32 | int page(struct http_request *); 33 | int subscribe(struct http_request *); 34 | void sse_disconnect(struct connection *); 35 | void sse_send(struct connection *, void *, size_t); 36 | void sse_broadcast(struct connection *, void *, size_t); 37 | int check_header(struct http_request *, const char *, const char *); 38 | 39 | /* 40 | * Each client subscribed to our SSE gets a state attached 41 | * to their hdlr_extra pointer member. 42 | */ 43 | struct sse_state { 44 | struct kore_timer *timer; 45 | }; 46 | 47 | int 48 | page(struct http_request *req) 49 | { 50 | if (req->method != HTTP_METHOD_GET) { 51 | http_response_header(req, "allow", "get"); 52 | http_response(req, 405, NULL, 0); 53 | return (KORE_RESULT_OK); 54 | } 55 | 56 | http_response_header(req, "content-type", "text/html"); 57 | http_response(req, 200, asset_index_html, asset_len_index_html); 58 | return (KORE_RESULT_OK); 59 | } 60 | 61 | int 62 | subscribe(struct http_request *req) 63 | { 64 | struct connection *c; 65 | struct sse_state *state; 66 | char *hello = "event:join\ndata: client\n\n"; 67 | 68 | /* Preventive paranoia. */ 69 | if (req->hdlr_extra != NULL) { 70 | kore_log(LOG_ERR, "%p: already subscribed", req->owner); 71 | http_response(req, 500, NULL, 0); 72 | return (KORE_RESULT_OK); 73 | } 74 | 75 | /* Only allow GET methods. */ 76 | if (req->method != HTTP_METHOD_GET) { 77 | http_response_header(req, "allow", "get"); 78 | http_response(req, 405, NULL, 0); 79 | return (KORE_RESULT_OK); 80 | } 81 | 82 | /* Only do SSE if the client told us it wanted too. */ 83 | if (!check_header(req, "accept", "text/event-stream")) 84 | return (KORE_RESULT_OK); 85 | 86 | /* Do not include content-length in our response. */ 87 | req->flags |= HTTP_REQUEST_NO_CONTENT_LENGTH; 88 | 89 | /* Notify existing clients of our new client now. */ 90 | sse_broadcast(req->owner, hello, strlen(hello)); 91 | 92 | /* Set a disconnection method so we know when this client goes away. */ 93 | req->owner->disconnect = sse_disconnect; 94 | 95 | /* Allocate a state to be carried by our connection. */ 96 | state = kore_malloc(sizeof(*state)); 97 | req->owner->hdlr_extra = state; 98 | 99 | /* Now start a timer to send a ping back every 10 second. */ 100 | state->timer = kore_timer_add(sse_ping, 10000, req->owner, 0); 101 | 102 | /* Respond that the SSE channel is now open. */ 103 | kore_log(LOG_NOTICE, "%p: connected for SSE", req->owner); 104 | http_response_header(req, "content-type", "text/event-stream"); 105 | http_response(req, 200, NULL, 0); 106 | 107 | /* Kill HTTP timeouts. */ 108 | c = req->owner; 109 | c->http_timeout = 0; 110 | 111 | return (KORE_RESULT_OK); 112 | } 113 | 114 | void 115 | sse_broadcast(struct connection *src, void *data, size_t len) 116 | { 117 | struct connection *c; 118 | 119 | /* Broadcast the message to all other clients. */ 120 | TAILQ_FOREACH(c, &connections, list) { 121 | if (c == src) 122 | continue; 123 | sse_send(c, data, len); 124 | } 125 | } 126 | 127 | void 128 | sse_send(struct connection *c, void *data, size_t len) 129 | { 130 | struct sse_state *state = c->hdlr_extra; 131 | 132 | /* Do not send to clients that do not have a state. */ 133 | if (state == NULL) 134 | return; 135 | 136 | /* Queue outgoing data now. */ 137 | net_send_queue(c, data, len); 138 | net_send_flush(c); 139 | } 140 | 141 | void 142 | sse_ping(void *arg, u_int64_t now) 143 | { 144 | struct connection *c = arg; 145 | char *ping = "event:ping\ndata:\n\n"; 146 | 147 | /* Send our ping to the client. */ 148 | sse_send(c, ping, strlen(ping)); 149 | } 150 | 151 | void 152 | sse_disconnect(struct connection *c) 153 | { 154 | struct sse_state *state = c->hdlr_extra; 155 | char *leaving = "event: leave\ndata: client\n\n"; 156 | 157 | kore_log(LOG_NOTICE, "%p: disconnecting for SSE", c); 158 | 159 | /* Tell others we are leaving. */ 160 | sse_broadcast(c, leaving, strlen(leaving)); 161 | 162 | /* Kill our timer and free/remove the state. */ 163 | kore_timer_remove(state->timer); 164 | kore_free(state); 165 | 166 | /* Prevent us to be called again. */ 167 | c->hdlr_extra = NULL; 168 | c->disconnect = NULL; 169 | } 170 | 171 | int 172 | check_header(struct http_request *req, const char *name, const char *value) 173 | { 174 | const char *hdr; 175 | 176 | if (!http_request_header(req, name, &hdr)) { 177 | http_response(req, 400, NULL, 0); 178 | return (KORE_RESULT_ERROR); 179 | } 180 | 181 | if (strcmp(hdr, value)) { 182 | http_response(req, 400, NULL, 0); 183 | return (KORE_RESULT_ERROR); 184 | } 185 | 186 | return (KORE_RESULT_OK); 187 | } 188 | -------------------------------------------------------------------------------- /examples/tasks/README.md: -------------------------------------------------------------------------------- 1 | Kore task example. 2 | 3 | This example creates an asynchronous task from the page handler 4 | that performs a POST to the same server and fetches its data 5 | before returning to the client. 6 | 7 | Build: 8 | ``` 9 | $ kodev build 10 | ``` 11 | 12 | Run: 13 | ``` 14 | $ kodev run 15 | ``` 16 | 17 | Test: 18 | ``` 19 | $ curl -i -k https://127.0.0.1:8888/?user=astring 20 | The returned data must match what you supplied in user ([a-z] string) 21 | ``` 22 | -------------------------------------------------------------------------------- /examples/tasks/conf/build.conf: -------------------------------------------------------------------------------- 1 | # tasks build config 2 | # You can switch flavors using: kodev flavor [newflavor] 3 | 4 | # Set to yes if you wish to produce a single binary instead 5 | # of a dynamic library. If you set this to yes you must also 6 | # set kore_source together with kore_flavor. 7 | single_binary=yes 8 | kore_source=../../ 9 | kore_flavor=TASKS=1 10 | 11 | # The cflags below are shared between flavors 12 | cflags=-Wall -Wmissing-declarations -Wshadow 13 | cflags=-Wstrict-prototypes -Wmissing-prototypes 14 | cflags=-Wpointer-arith -Wcast-qual -Wsign-compare 15 | 16 | cflags=-I/usr/local/include 17 | 18 | dev { 19 | # These cflags are added to the shared ones when 20 | # you build the "dev" flavor. 21 | cflags=-g 22 | ldflags=-L/usr/local/lib -lcurl 23 | } 24 | 25 | #prod { 26 | # You can specify additional CFLAGS here which are only 27 | # included if you build with the "prod" flavor. 28 | #} 29 | -------------------------------------------------------------------------------- /examples/tasks/conf/tasks.conf: -------------------------------------------------------------------------------- 1 | # Kore config for tasks example 2 | 3 | server tls { 4 | bind 127.0.0.1 8888 5 | } 6 | 7 | task_threads 4 8 | worker_max_connections 1000 9 | http_keepalive_time 0 10 | 11 | validator v_user regex ^[a-z]*$ 12 | 13 | domain * { 14 | attach tls 15 | 16 | certfile cert/server.pem 17 | certkey cert/key.pem 18 | accesslog kore_access.log 19 | 20 | route / { 21 | handler page_handler 22 | validate qs:get user v_user 23 | } 24 | 25 | route /post_back { 26 | handler post_back 27 | methods post 28 | validate post user v_user 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /examples/tasks/src/init.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Joris Vink 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include 18 | #include 19 | 20 | /* Let kore handle the default option parsing. */ 21 | void 22 | kore_parent_configure(int argc, char **argv) 23 | { 24 | kore_default_getopt(argc, argv); 25 | } 26 | -------------------------------------------------------------------------------- /examples/tls-proxy/.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | .objs 3 | tls-proxy.so 4 | assets.h 5 | cert 6 | -------------------------------------------------------------------------------- /examples/tls-proxy/README.md: -------------------------------------------------------------------------------- 1 | Kore as a TLS-proxy. 2 | 3 | Edit src/proxy.c and add your backends to the backends[] data structure. 4 | 5 | If you want to reduce attack surface you can build Kore with NOHTTP=1 to 6 | completely remove the HTTP component and only run the net code. 7 | 8 | Run: 9 | ``` 10 | $ kodev run 11 | ``` 12 | 13 | Test: 14 | ``` 15 | Connect to the server and notice that it proxies data between you 16 | and your destination. 17 | 18 | $ openssl s_client -connect 127.0.0.1:8888 19 | ``` 20 | -------------------------------------------------------------------------------- /examples/tls-proxy/conf/build.conf: -------------------------------------------------------------------------------- 1 | # tls-proxy build config 2 | # You can switch flavors using: kodev flavor [newflavor] 3 | 4 | # The cflags below are shared between flavors 5 | cflags=-Wall -Wmissing-declarations -Wshadow 6 | cflags=-Wstrict-prototypes -Wmissing-prototypes 7 | cflags=-Wpointer-arith -Wcast-qual -Wsign-compare 8 | 9 | dev { 10 | # These cflags are added to the shared ones when 11 | # you build the "dev" flavor. 12 | cflags=-g 13 | } 14 | 15 | #prod { 16 | # You can specify additional CFLAGS here which are only 17 | # included if you build with the "prod" flavor. 18 | #} 19 | -------------------------------------------------------------------------------- /examples/tls-proxy/conf/tls-proxy.conf: -------------------------------------------------------------------------------- 1 | # Kore as a TLS proxy configuration. 2 | 3 | load ./tls-proxy.so 4 | 5 | # 6 | # Bind the proxy to a given IP and port. For every 7 | # connection we receive we will call client_setup 8 | # so it can kick things in action. 9 | # 10 | server tls { 11 | bind 127.0.0.1 8888 client_setup 12 | } 13 | 14 | # Setup domain for TLS usage. 15 | domain * { 16 | attach tls 17 | 18 | certfile cert/server.pem 19 | certkey cert/key.pem 20 | } 21 | -------------------------------------------------------------------------------- /examples/upload/.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | .objs 3 | upload.so 4 | assets.h 5 | cert 6 | -------------------------------------------------------------------------------- /examples/upload/conf/build.conf: -------------------------------------------------------------------------------- 1 | # upload build config 2 | # You can switch flavors using: kodev flavor [newflavor] 3 | 4 | # The cflags below are shared between flavors 5 | cflags=-Wall -Wmissing-declarations -Wshadow 6 | cflags=-Wstrict-prototypes -Wmissing-prototypes 7 | cflags=-Wpointer-arith -Wcast-qual -Wsign-compare 8 | 9 | dev { 10 | # These cflags are added to the shared ones when 11 | # you build the "dev" flavor. 12 | cflags=-g 13 | } 14 | 15 | #prod { 16 | # You can specify additional CFLAGS here which are only 17 | # included if you build with the "prod" flavor. 18 | #} 19 | -------------------------------------------------------------------------------- /examples/upload/conf/upload.conf: -------------------------------------------------------------------------------- 1 | # Placeholder configuration 2 | 3 | server tls { 4 | bind 127.0.0.1 8888 5 | } 6 | 7 | load ./upload.so 8 | 9 | http_body_max 1024000000 10 | http_body_disk_offload 4096 11 | 12 | domain * { 13 | attach tls 14 | 15 | certfile cert/server.pem 16 | certkey cert/key.pem 17 | 18 | route / { 19 | handler page 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /examples/upload/src/upload.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016-2018 Joris Vink 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | /* 18 | * This example demonstrates how to properly deal with file uploads 19 | * coming from a multipart form. 20 | * 21 | * The basics are quite trivial: 22 | * 1) call http_populate_multipart_form() 23 | * 2) find the file using http_file_lookup(). 24 | * 3) read the file data using http_file_read(). 25 | * 26 | * In this example the contents is written to a newly created file 27 | * on the server that matches the naming given by the uploader. 28 | * 29 | * Note that the above is probably not what you want to do in real life. 30 | */ 31 | 32 | #include 33 | #include 34 | 35 | #include 36 | #include 37 | 38 | int page(struct http_request *); 39 | 40 | int 41 | page(struct http_request *req) 42 | { 43 | int fd; 44 | struct http_file *file; 45 | u_int8_t buf[BUFSIZ]; 46 | ssize_t ret, written; 47 | 48 | /* Only deal with POSTs. */ 49 | if (req->method != HTTP_METHOD_POST) { 50 | http_response(req, 405, NULL, 0); 51 | return (KORE_RESULT_OK); 52 | } 53 | 54 | /* Parse the multipart data that was present. */ 55 | http_populate_multipart_form(req); 56 | 57 | /* Find our file. */ 58 | if ((file = http_file_lookup(req, "file")) == NULL) { 59 | http_response(req, 400, NULL, 0); 60 | return (KORE_RESULT_OK); 61 | } 62 | 63 | /* Open dump file where we will write file contents. */ 64 | fd = open(file->filename, O_CREAT | O_TRUNC | O_WRONLY, 0700); 65 | if (fd == -1) { 66 | http_response(req, 500, NULL, 0); 67 | return (KORE_RESULT_OK); 68 | } 69 | 70 | /* While we have data from http_file_read(), write it. */ 71 | /* Alternatively you could look at file->offset and file->length. */ 72 | ret = KORE_RESULT_ERROR; 73 | for (;;) { 74 | ret = http_file_read(file, buf, sizeof(buf)); 75 | if (ret == -1) { 76 | kore_log(LOG_ERR, "failed to read from file"); 77 | http_response(req, 500, NULL, 0); 78 | goto cleanup; 79 | } 80 | 81 | if (ret == 0) 82 | break; 83 | 84 | written = write(fd, buf, ret); 85 | if (written == -1) { 86 | kore_log(LOG_ERR,"write(%s): %s", 87 | file->filename, errno_s); 88 | http_response(req, 500, NULL, 0); 89 | goto cleanup; 90 | } 91 | 92 | if (written != ret) { 93 | kore_log(LOG_ERR, "partial write on %s", 94 | file->filename); 95 | http_response(req, 500, NULL, 0); 96 | goto cleanup; 97 | } 98 | } 99 | 100 | ret = KORE_RESULT_OK; 101 | http_response(req, 200, NULL, 0); 102 | kore_log(LOG_INFO, "file '%s' successfully received", 103 | file->filename); 104 | 105 | cleanup: 106 | if (close(fd) == -1) 107 | kore_log(LOG_WARNING, "close(%s): %s", file->filename, errno_s); 108 | 109 | if (ret == KORE_RESULT_ERROR) { 110 | if (unlink(file->filename) == -1) { 111 | kore_log(LOG_WARNING, "unlink(%s): %s", 112 | file->filename, errno_s); 113 | } 114 | ret = KORE_RESULT_OK; 115 | } 116 | 117 | return (KORE_RESULT_OK); 118 | } 119 | -------------------------------------------------------------------------------- /examples/video_stream/.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | .objs 3 | stream.so 4 | assets.h 5 | cert 6 | -------------------------------------------------------------------------------- /examples/video_stream/README.md: -------------------------------------------------------------------------------- 1 | A simple HTML5 video streaming service using Kore. 2 | 3 | Building: 4 | ``` 5 | You must first place a test video inside the videos/ folder. I tested 6 | this using Big Buck Bunny (ogg version) on Chrome. But any video that 7 | can be played with HTML5 works. 8 | 9 | If you did not save your video as videos/video.ogg make sure you 10 | update the assets/video.html file to point to the right video. 11 | 12 | When done, run a kodev build. 13 | ``` 14 | 15 | Run: 16 | ``` 17 | kodev run 18 | ``` 19 | 20 | Visit the URI and you should see a video stream. 21 | 22 | Frontend parts from video.js: http://www.videojs.com/ 23 | -------------------------------------------------------------------------------- /examples/video_stream/assets/video.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Video stream over Kore 7 | 8 | 9 | 10 | 11 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /examples/video_stream/conf/build.conf: -------------------------------------------------------------------------------- 1 | # video_stream build config 2 | # You can switch flavors using: kodev flavor [newflavor] 3 | 4 | # The cflags below are shared between flavors 5 | cflags=-Wall -Wmissing-declarations -Wshadow 6 | cflags=-Wstrict-prototypes -Wmissing-prototypes 7 | cflags=-Wpointer-arith -Wcast-qual -Wsign-compare 8 | 9 | mime_add=html:text/html; charset=utf-8 10 | 11 | dev { 12 | # These cflags are added to the shared ones when 13 | # you build the "dev" flavor. 14 | cflags=-g 15 | } 16 | 17 | #prod { 18 | # You can specify additional CFLAGS here which are only 19 | # included if you build with the "prod" flavor. 20 | #} 21 | -------------------------------------------------------------------------------- /examples/video_stream/conf/video_stream.conf: -------------------------------------------------------------------------------- 1 | # Placeholder configuration 2 | 3 | server tls { 4 | bind 127.0.0.1 8888 5 | } 6 | 7 | load ./video_stream.so init 8 | 9 | http_keepalive_time 600 10 | 11 | domain * { 12 | attach tls 13 | 14 | certfile cert/server.pem 15 | certkey cert/key.pem 16 | accesslog access.log 17 | 18 | route / { 19 | handler asset_serve_video_html 20 | } 21 | 22 | route ^/[a-z]*.[a-z0-9]{3}$ { 23 | handler video_stream 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /examples/video_stream/videos/placeholder: -------------------------------------------------------------------------------- 1 | Drop your HTML5 videos in here 2 | -------------------------------------------------------------------------------- /examples/websocket/.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | .objs 3 | websocket.so 4 | assets.h 5 | cert 6 | -------------------------------------------------------------------------------- /examples/websocket/README.md: -------------------------------------------------------------------------------- 1 | Kore example websocket server 2 | 3 | Run: 4 | ``` 5 | # kodev run 6 | ``` 7 | 8 | Test: 9 | ``` 10 | Open a browser that does websockets, surf to https://127.0.0.1:8888 11 | or whatever configured IP you have in the config. 12 | 13 | Hit the connect button to open a websocket session, open a second 14 | tab and surf to the same address and hit the connection button there 15 | as well. This should cause the number of messages sent/recv to keep 16 | incrementing as each message is broadcast to the other connection. 17 | ``` 18 | -------------------------------------------------------------------------------- /examples/websocket/assets/frontend.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 48 | 49 | 50 | 51 | 52 |
53 | 54 |
55 | 56 |
57 |
58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /examples/websocket/conf/build.conf: -------------------------------------------------------------------------------- 1 | # websocket build config 2 | # You can switch flavors using: kodev flavor [newflavor] 3 | 4 | # The cflags below are shared between flavors 5 | cflags=-Wall -Wmissing-declarations -Wshadow 6 | cflags=-Wstrict-prototypes -Wmissing-prototypes 7 | cflags=-Wpointer-arith -Wcast-qual -Wsign-compare 8 | 9 | dev { 10 | # These cflags are added to the shared ones when 11 | # you build the "dev" flavor. 12 | cflags=-g 13 | } 14 | 15 | #prod { 16 | # You can specify additional CFLAGS here which are only 17 | # included if you build with the "prod" flavor. 18 | #} 19 | -------------------------------------------------------------------------------- /examples/websocket/conf/websocket.conf: -------------------------------------------------------------------------------- 1 | # Kore websocket example 2 | 3 | server tls { 4 | bind 127.0.0.1 8888 5 | } 6 | 7 | load ./websocket.so 8 | 9 | # Increase workers so connections are spread 10 | # across them to demonstrate WEBSOCKET_BROADCAST_GLOBAL. 11 | workers 4 12 | 13 | websocket_maxframe 65536 14 | websocket_timeout 20 15 | 16 | domain * { 17 | attach tls 18 | 19 | certfile cert/server.pem 20 | certkey cert/key.pem 21 | 22 | route / { 23 | handler page 24 | } 25 | 26 | route /connect { 27 | handler page_ws_connect 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /examples/websocket/src/websocket.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014 Joris Vink 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include 18 | #include 19 | 20 | #include "assets.h" 21 | 22 | int page(struct http_request *); 23 | int page_ws_connect(struct http_request *); 24 | 25 | void websocket_connect(struct connection *); 26 | void websocket_disconnect(struct connection *); 27 | void websocket_message(struct connection *, 28 | u_int8_t, void *, size_t); 29 | 30 | /* Called whenever we get a new websocket connection. */ 31 | void 32 | websocket_connect(struct connection *c) 33 | { 34 | kore_log(LOG_NOTICE, "%p: connected", c); 35 | } 36 | 37 | void 38 | websocket_message(struct connection *c, u_int8_t op, void *data, size_t len) 39 | { 40 | kore_websocket_broadcast(c, op, data, len, WEBSOCKET_BROADCAST_GLOBAL); 41 | } 42 | 43 | void 44 | websocket_disconnect(struct connection *c) 45 | { 46 | kore_log(LOG_NOTICE, "%p: disconnecting", c); 47 | } 48 | 49 | int 50 | page(struct http_request *req) 51 | { 52 | http_response_header(req, "content-type", "text/html"); 53 | http_response(req, 200, asset_frontend_html, asset_len_frontend_html); 54 | 55 | return (KORE_RESULT_OK); 56 | } 57 | 58 | int 59 | page_ws_connect(struct http_request *req) 60 | { 61 | /* Perform the websocket handshake, passing our callbacks. */ 62 | kore_websocket_handshake(req, "websocket_connect", 63 | "websocket_message", "websocket_disconnect"); 64 | 65 | return (KORE_RESULT_OK); 66 | } 67 | -------------------------------------------------------------------------------- /include/kore/acme.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019-2022 Joris Vink 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #ifndef __H_ACME_H 18 | #define __H_ACME_H 19 | 20 | #if defined(__cplusplus) 21 | extern "C" { 22 | #endif 23 | 24 | /* 25 | * All acme paths are relative to the keymgr_root directory. 26 | */ 27 | #define KORE_ACME_ACCOUNT_KEY "account-key.pem" 28 | #define KORE_ACME_CERTDIR "certificates" 29 | 30 | #define KORE_ACME_RSAKEY_E (KORE_MSG_ACME_BASE + 1) 31 | #define KORE_ACME_RSAKEY_N (KORE_MSG_ACME_BASE + 2) 32 | #define KORE_ACME_SIGN (KORE_MSG_ACME_BASE + 3) 33 | #define KORE_ACME_SIGN_RESULT (KORE_MSG_ACME_BASE + 4) 34 | #define KORE_ACME_PROC_READY (KORE_MSG_ACME_BASE + 5) 35 | #define KORE_ACME_ACCOUNT_CREATE (KORE_MSG_ACME_BASE + 10) 36 | #define KORE_ACME_ACCOUNT_RESOLVE (KORE_MSG_ACME_BASE + 11) 37 | #define KORE_ACME_ORDER_CREATE (KORE_MSG_ACME_BASE + 12) 38 | #define KORE_ACME_CSR_REQUEST (KORE_MSG_ACME_BASE + 13) 39 | #define KORE_ACME_CSR_RESPONSE (KORE_MSG_ACME_BASE + 14) 40 | #define KORE_ACME_INSTALL_CERT (KORE_MSG_ACME_BASE + 15) 41 | #define KORE_ACME_ORDER_FAILED (KORE_MSG_ACME_BASE + 16) 42 | 43 | #define KORE_ACME_CHALLENGE_CERT (KORE_MSG_ACME_BASE + 20) 44 | #define KORE_ACME_CHALLENGE_SET_CERT (KORE_MSG_ACME_BASE + 21) 45 | #define KORE_ACME_CHALLENGE_CLEAR_CERT (KORE_MSG_ACME_BASE + 22) 46 | 47 | void kore_acme_init(void); 48 | void kore_acme_run(void); 49 | void kore_acme_setup(void); 50 | void kore_acme_get_paths(const char *, char **, char **); 51 | 52 | extern char *acme_email; 53 | extern int acme_domains; 54 | extern char *acme_provider; 55 | 56 | #if defined(__cplusplus) 57 | } 58 | #endif 59 | 60 | #endif 61 | -------------------------------------------------------------------------------- /include/kore/curl.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019-2022 Joris Vink 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #ifndef __H_CURL_H 18 | #define __H_CURL_H 19 | 20 | #if defined(__cplusplus) 21 | extern "C" { 22 | #endif 23 | 24 | #include 25 | 26 | #include "http.h" 27 | 28 | #define KORE_CURL_TIMEOUT 60 29 | #define KORE_CURL_RECV_MAX (1024 * 1024 * 2) 30 | 31 | #define KORE_CURL_FLAG_HTTP_PARSED_HEADERS 0x0001 32 | #define KORE_CURL_FLAG_BOUND 0x0002 33 | 34 | #define KORE_CURL_SYNC 0x1000 35 | #define KORE_CURL_ASYNC 0x2000 36 | 37 | #define KORE_CURL_TYPE_CUSTOM 1 38 | #define KORE_CURL_TYPE_HTTP_CLIENT 2 39 | 40 | struct kore_curl { 41 | int type; 42 | int flags; 43 | CURLcode result; 44 | 45 | char *url; 46 | CURL *handle; 47 | struct kore_buf *response; 48 | 49 | struct http_request *req; 50 | void *arg; 51 | void (*cb)(struct kore_curl *, void *); 52 | 53 | char errbuf[CURL_ERROR_SIZE]; 54 | 55 | /* For the simplified HTTP api. */ 56 | struct { 57 | long status; 58 | struct curl_slist *hdrlist; 59 | 60 | struct kore_buf *tosend; 61 | struct kore_buf *headers; 62 | 63 | TAILQ_HEAD(, http_header) resp_hdrs; 64 | } http; 65 | 66 | LIST_ENTRY(kore_curl) list; 67 | }; 68 | 69 | extern u_int16_t kore_curl_timeout; 70 | extern u_int64_t kore_curl_recv_max; 71 | 72 | void kore_curl_sysinit(void); 73 | void kore_curl_do_timeout(void); 74 | void kore_curl_run_scheduled(void); 75 | void kore_curl_run(struct kore_curl *); 76 | void kore_curl_cleanup(struct kore_curl *); 77 | int kore_curl_success(struct kore_curl *); 78 | void kore_curl_run_sync(struct kore_curl *); 79 | void kore_curl_logerror(struct kore_curl *); 80 | int kore_curl_init(struct kore_curl *, const char *, int); 81 | 82 | size_t kore_curl_tobuf(char *, size_t, size_t, void *); 83 | size_t kore_curl_frombuf(char *, size_t, size_t, void *); 84 | 85 | void kore_curl_http_parse_headers(struct kore_curl *); 86 | void kore_curl_http_set_header(struct kore_curl *, const char *, 87 | const char *); 88 | int kore_curl_http_get_header(struct kore_curl *, const char *, 89 | const char **); 90 | void kore_curl_http_setup(struct kore_curl *, int, const void *, size_t); 91 | 92 | char *kore_curl_response_as_string(struct kore_curl *); 93 | void kore_curl_response_as_bytes(struct kore_curl *, 94 | const u_int8_t **, size_t *); 95 | 96 | void kore_curl_bind_request(struct kore_curl *, struct http_request *); 97 | void kore_curl_bind_callback(struct kore_curl *, 98 | void (*cb)(struct kore_curl *, void *), void *); 99 | 100 | const char *kore_curl_strerror(struct kore_curl *); 101 | 102 | #if defined(__cplusplus) 103 | } 104 | #endif 105 | 106 | #endif 107 | -------------------------------------------------------------------------------- /include/kore/hooks.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 Joris Vink 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #ifndef __H_HOOKS_H 18 | #define __H_HOOKS_H 19 | 20 | #define KORE_CONFIG_HOOK "kore_parent_configure" 21 | #define KORE_TEARDOWN_HOOK "kore_parent_teardown" 22 | #define KORE_DAEMONIZED_HOOK "kore_parent_daemonized" 23 | 24 | void kore_seccomp_hook(void); 25 | void kore_worker_signal(int); 26 | void kore_worker_teardown(void); 27 | void kore_parent_teardown(void); 28 | void kore_worker_configure(void); 29 | void kore_parent_daemonized(void); 30 | void kore_parent_configure(int, char **); 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /include/kore/jsonrpc.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Raphaël Monrouzeau 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #if !defined(KORE_NO_HTTP) 18 | 19 | #ifndef __H_JSONRPC_H 20 | #define __H_JSONRPC_H 21 | 22 | #if defined(__cplusplus) 23 | extern "C" { 24 | #endif 25 | 26 | /* JSON RPC request handling log entry. */ 27 | struct jsonrpc_log 28 | { 29 | char *msg; 30 | struct jsonrpc_log *next, *prev; 31 | int lvl; 32 | }; 33 | 34 | /* JSON RPC request. */ 35 | struct jsonrpc_request 36 | { 37 | struct jsonrpc_log log; 38 | struct kore_buf buf; 39 | struct http_request *http; 40 | yajl_gen gen; 41 | yajl_val json; 42 | yajl_val id; 43 | char *method; 44 | yajl_val params; 45 | unsigned int flags; 46 | int log_levels; 47 | }; 48 | 49 | #define YAJL_GEN_CONST_STRING(CTX, STR) \ 50 | yajl_gen_string((CTX), (unsigned char *)(STR), sizeof (STR) - 1) 51 | 52 | #define YAJL_GEN_CONST_NUMBER(CTX, STR) \ 53 | yajl_gen_number((CTX), (unsigned char *)(STR), sizeof (STR) - 1) 54 | 55 | #define YAJL_GEN_KO(OPERATION) \ 56 | ((OPERATION) != yajl_gen_status_ok) 57 | 58 | enum jsonrpc_error_code 59 | { 60 | #define JSONRPC_PARSE_ERROR_MSG "Parse error" 61 | JSONRPC_PARSE_ERROR = -32700, 62 | #define JSONRPC_INVALID_REQUEST_MSG "Invalid Request" 63 | JSONRPC_INVALID_REQUEST = -32600, 64 | #define JSONRPC_METHOD_NOT_FOUND_MSG "Method not found" 65 | JSONRPC_METHOD_NOT_FOUND = -32601, 66 | #define JSONRPC_INVALID_PARAMS_MSG "Invalid params" 67 | JSONRPC_INVALID_PARAMS = -32602, 68 | #define JSONRPC_INTERNAL_ERROR_MSG "Internal error" 69 | JSONRPC_INTERNAL_ERROR = -32603, 70 | #define JSONRPC_SERVER_ERROR_MSG "Server error" 71 | JSONRPC_SERVER_ERROR = -32000, 72 | #define JSONRPC_LIMIT_REACHED_MSG "Limit reached" 73 | JSONRPC_LIMIT_REACHED = -31997 74 | }; 75 | 76 | void jsonrpc_log(struct jsonrpc_request *, int, const char *, ...) 77 | __attribute__((format (printf, 3, 4))); 78 | int jsonrpc_read_request(struct http_request *, struct jsonrpc_request *); 79 | void jsonrpc_destroy_request(struct jsonrpc_request *); 80 | int jsonrpc_error(struct jsonrpc_request *, int, const char *); 81 | int jsonrpc_result(struct jsonrpc_request *, 82 | int (*)(struct jsonrpc_request *, void *), void *); 83 | #if defined(__cplusplus) 84 | } 85 | #endif 86 | #endif /* !__H_JSONRPC_H */ 87 | 88 | #endif /* ! KORE_NO_HTTP */ 89 | -------------------------------------------------------------------------------- /include/kore/lua_api.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 Joris Vink 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #ifndef __H_LUA_API_H 18 | #define __H_LUA_API_H 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | void kore_lua_init(void); 25 | void kore_lua_cleanup(void); 26 | 27 | extern struct kore_module_functions kore_lua_module; 28 | extern struct kore_runtime kore_lua_runtime; 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /include/kore/lua_methods.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 Joris Vink 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #ifndef __H_LUA_METHODS_H 18 | #define __H_LUA_METHODS_H 19 | 20 | static int lua_http_request_gc(lua_State *); 21 | static int lua_http_request_index(lua_State *); 22 | 23 | static int lua_http_response(lua_State *); 24 | static int lua_http_request_header(lua_State *); 25 | static int lua_http_response_header(lua_State *); 26 | 27 | static const luaL_Reg lua_http_request_meta[] = { 28 | { "__gc", lua_http_request_gc }, 29 | { "__index", lua_http_request_index }, 30 | { NULL, NULL }, 31 | }; 32 | 33 | static const luaL_Reg lua_http_request_methods[] = { 34 | { "response", lua_http_response }, 35 | { "request_header", lua_http_request_header }, 36 | { "response_header", lua_http_response_header }, 37 | { NULL, NULL }, 38 | }; 39 | 40 | static int lua_kore_config(lua_State *); 41 | static int lua_kore_server(lua_State *); 42 | 43 | static const luaL_Reg lua_kore_functions[] = { 44 | { "config", lua_kore_config }, 45 | { "server", lua_kore_server }, 46 | { NULL, NULL }, 47 | }; 48 | 49 | #endif 50 | -------------------------------------------------------------------------------- /include/kore/pgsql.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014-2022 Joris Vink 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #ifndef _H_KORE_PGSQL 18 | #define _H_KORE_PGSQL 19 | 20 | #include 21 | 22 | #define KORE_PGSQL_FORMAT_TEXT 0 23 | #define KORE_PGSQL_FORMAT_BINARY 1 24 | 25 | #define KORE_PGSQL_SYNC 0x0001 26 | #define KORE_PGSQL_ASYNC 0x0002 27 | #define KORE_PGSQL_SCHEDULED 0x0004 28 | 29 | #define KORE_PGSQL_PARAM_BINARY(v, l) v, l, 1 30 | #define KORE_PGSQL_PARAM_TEXT_LEN(v, l) v, l, 0 31 | #define KORE_PGSQL_PARAM_TEXT(v) v, strlen(v), 0 32 | 33 | #if defined(__cplusplus) 34 | extern "C" { 35 | #endif 36 | 37 | struct pgsql_conn { 38 | struct kore_event evt; 39 | u_int8_t flags; 40 | char *name; 41 | 42 | PGconn *db; 43 | struct pgsql_job *job; 44 | TAILQ_ENTRY(pgsql_conn) list; 45 | }; 46 | 47 | struct pgsql_db { 48 | char *name; 49 | char *conn_string; 50 | u_int16_t conn_max; 51 | u_int16_t conn_count; 52 | 53 | LIST_ENTRY(pgsql_db) rlist; 54 | }; 55 | 56 | struct kore_pgsql { 57 | u_int8_t state; 58 | int flags; 59 | char *error; 60 | PGresult *result; 61 | struct pgsql_conn *conn; 62 | 63 | struct { 64 | char *channel; 65 | char *extra; 66 | } notify; 67 | 68 | struct http_request *req; 69 | void *arg; 70 | void (*cb)(struct kore_pgsql *, void *); 71 | 72 | LIST_ENTRY(kore_pgsql) rlist; 73 | }; 74 | 75 | extern u_int16_t pgsql_conn_max; 76 | extern u_int32_t pgsql_queue_limit; 77 | 78 | void kore_pgsql_sys_init(void); 79 | void kore_pgsql_sys_cleanup(void); 80 | void kore_pgsql_init(struct kore_pgsql *); 81 | void kore_pgsql_bind_request(struct kore_pgsql *, struct http_request *); 82 | void kore_pgsql_bind_callback(struct kore_pgsql *, 83 | void (*cb)(struct kore_pgsql *, void *), void *); 84 | int kore_pgsql_setup(struct kore_pgsql *, const char *, int); 85 | void kore_pgsql_handle(void *, int); 86 | void kore_pgsql_cleanup(struct kore_pgsql *); 87 | void kore_pgsql_continue(struct kore_pgsql *); 88 | int kore_pgsql_query(struct kore_pgsql *, const void *); 89 | int kore_pgsql_query_params(struct kore_pgsql *, 90 | const void *, int, int, ...); 91 | int kore_pgsql_v_query_params(struct kore_pgsql *, 92 | const void *, int, int, va_list); 93 | int kore_pgsql_query_param_fields(struct kore_pgsql *, const void *, 94 | int, int, const char **, int *, int *); 95 | int kore_pgsql_register(const char *, const char *); 96 | int kore_pgsql_ntuples(struct kore_pgsql *); 97 | int kore_pgsql_nfields(struct kore_pgsql *); 98 | void kore_pgsql_logerror(struct kore_pgsql *); 99 | char *kore_pgsql_fieldname(struct kore_pgsql *, int); 100 | char *kore_pgsql_getvalue(struct kore_pgsql *, int, int); 101 | int kore_pgsql_getlength(struct kore_pgsql *, int, int); 102 | int kore_pgsql_column_binary(struct kore_pgsql *, int); 103 | 104 | #if defined(__cplusplus) 105 | } 106 | #endif 107 | 108 | #define KORE_PGSQL_STATE_INIT 1 109 | #define KORE_PGSQL_STATE_WAIT 2 110 | #define KORE_PGSQL_STATE_RESULT 3 111 | #define KORE_PGSQL_STATE_ERROR 4 112 | #define KORE_PGSQL_STATE_DONE 5 113 | #define KORE_PGSQL_STATE_COMPLETE 6 114 | #define KORE_PGSQL_STATE_NOTIFY 7 115 | 116 | #endif 117 | -------------------------------------------------------------------------------- /include/kore/python_api.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Stanislav Yudin 3 | * Copyright (c) 2017-2022 Joris Vink 4 | * 5 | * Permission to use, copy, modify, and distribute this software for any 6 | * purpose with or without fee is hereby granted, provided that the above 7 | * copyright notice and this permission notice appear in all copies. 8 | * 9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | */ 17 | 18 | #ifndef __H_PYTHON_H 19 | #define __H_PYTHON_H 20 | 21 | #undef _POSIX_C_SOURCE 22 | #undef _XOPEN_SOURCE 23 | 24 | #define PY_SSIZE_T_CLEAN 1 25 | 26 | #include 27 | #include 28 | 29 | void kore_python_init(void); 30 | void kore_python_preinit(void); 31 | void kore_python_cleanup(void); 32 | void kore_python_coro_run(void); 33 | void kore_python_proc_reap(void); 34 | int kore_python_coro_pending(void); 35 | void kore_python_path(const char *); 36 | void kore_python_coro_delete(void *); 37 | void kore_python_routes_resolve(void); 38 | void kore_python_log_error(const char *); 39 | 40 | PyObject *kore_python_callable(PyObject *, const char *); 41 | 42 | #if defined(__linux__) 43 | void kore_python_seccomp_cleanup(void); 44 | void kore_python_seccomp_hook(const char *); 45 | #endif 46 | 47 | extern struct kore_module_functions kore_python_module; 48 | extern struct kore_runtime kore_python_runtime; 49 | 50 | #define KORE_PYTHON_SIGNAL_HOOK "koreapp.signal" 51 | #define KORE_PYTHON_TEARDOWN_HOOK "koreapp.cleanup" 52 | #define KORE_PYTHON_CONFIG_HOOK "koreapp.configure" 53 | #define KORE_PYTHON_DAEMONIZED_HOOK "koreapp.daemonized" 54 | #define KORE_PYTHON_WORKER_STOP_HOOK "koreapp.workerstop" 55 | #define KORE_PYTHON_WORKER_START_HOOK "koreapp.workerstart" 56 | 57 | #endif 58 | -------------------------------------------------------------------------------- /include/kore/sha1.h: -------------------------------------------------------------------------------- 1 | /* $OpenBSD: sha1.h,v 1.24 2012/12/05 23:19:57 deraadt Exp $ */ 2 | 3 | /* 4 | * SHA-1 in C 5 | * By Steve Reid 6 | * 100% Public Domain 7 | */ 8 | 9 | #ifndef _SHA1_H 10 | #define _SHA1_H 11 | 12 | #ifndef WITH_OPENSSL 13 | 14 | #define SHA1_BLOCK_LENGTH 64 15 | #define SHA1_DIGEST_LENGTH 20 16 | #define SHA1_DIGEST_STRING_LENGTH (SHA1_DIGEST_LENGTH * 2 + 1) 17 | 18 | typedef struct { 19 | u_int32_t state[5]; 20 | u_int64_t count; 21 | u_int8_t buffer[SHA1_BLOCK_LENGTH]; 22 | } SHA1_CTX; 23 | 24 | void SHA1Init(SHA1_CTX *); 25 | void SHA1Pad(SHA1_CTX *); 26 | void SHA1Transform(u_int32_t [5], const u_int8_t [SHA1_BLOCK_LENGTH]); 27 | void SHA1Update(SHA1_CTX *, const u_int8_t *, size_t); 28 | void SHA1Final(u_int8_t [SHA1_DIGEST_LENGTH], SHA1_CTX *); 29 | char *SHA1End(SHA1_CTX *, char *); 30 | char *SHA1File(const char *, char *); 31 | char *SHA1FileChunk(const char *, char *, off_t, off_t); 32 | char *SHA1Data(const u_int8_t *, size_t, char *); 33 | 34 | #define HTONDIGEST(x) do { \ 35 | x[0] = htonl(x[0]); \ 36 | x[1] = htonl(x[1]); \ 37 | x[2] = htonl(x[2]); \ 38 | x[3] = htonl(x[3]); \ 39 | x[4] = htonl(x[4]); } while (0) 40 | 41 | #define NTOHDIGEST(x) do { \ 42 | x[0] = ntohl(x[0]); \ 43 | x[1] = ntohl(x[1]); \ 44 | x[2] = ntohl(x[2]); \ 45 | x[3] = ntohl(x[3]); \ 46 | x[4] = ntohl(x[4]); } while (0) 47 | 48 | #endif /* !WITH_OPENSSL */ 49 | #endif /* _SHA1_H */ 50 | -------------------------------------------------------------------------------- /include/kore/sha2.h: -------------------------------------------------------------------------------- 1 | /* $OpenBSD: sha2.h,v 1.10 2016/09/03 17:00:29 tedu Exp $ */ 2 | 3 | /* 4 | * FILE: sha2.h 5 | * AUTHOR: Aaron D. Gifford 6 | * 7 | * Copyright (c) 2000-2001, Aaron D. Gifford 8 | * All rights reserved. 9 | * 10 | * Redistribution and use in source and binary forms, with or without 11 | * modification, are permitted provided that the following conditions 12 | * are met: 13 | * 1. Redistributions of source code must retain the above copyright 14 | * notice, this list of conditions and the following disclaimer. 15 | * 2. Redistributions in binary form must reproduce the above copyright 16 | * notice, this list of conditions and the following disclaimer in the 17 | * documentation and/or other materials provided with the distribution. 18 | * 3. Neither the name of the copyright holder nor the names of contributors 19 | * may be used to endorse or promote products derived from this software 20 | * without specific prior written permission. 21 | * 22 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTOR(S) ``AS IS'' AND 23 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTOR(S) BE LIABLE 26 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 | * SUCH DAMAGE. 33 | * 34 | * $From: sha2.h,v 1.1 2001/11/08 00:02:01 adg Exp adg $ 35 | */ 36 | 37 | /* OPENBSD ORIGINAL: include/sha2.h */ 38 | 39 | #ifndef _SSHSHA2_H 40 | #define _SSHSHA2_H 41 | 42 | /*** SHA-256/384/512 Various Length Definitions ***********************/ 43 | #define SHA256_BLOCK_LENGTH 64 44 | #define SHA256_DIGEST_LENGTH 32 45 | #define SHA256_DIGEST_STRING_LENGTH (SHA256_DIGEST_LENGTH * 2 + 1) 46 | #define SHA384_BLOCK_LENGTH 128 47 | #define SHA384_DIGEST_LENGTH 48 48 | #define SHA384_DIGEST_STRING_LENGTH (SHA384_DIGEST_LENGTH * 2 + 1) 49 | #define SHA512_BLOCK_LENGTH 128 50 | #define SHA512_DIGEST_LENGTH 64 51 | #define SHA512_DIGEST_STRING_LENGTH (SHA512_DIGEST_LENGTH * 2 + 1) 52 | 53 | /*** SHA-224/256/384/512 Context Structure *******************************/ 54 | typedef struct _SHA2_CTX { 55 | union { 56 | u_int32_t st32[8]; 57 | u_int64_t st64[8]; 58 | } state; 59 | u_int64_t bitcount[2]; 60 | u_int8_t buffer[SHA512_BLOCK_LENGTH]; 61 | } SHA2_CTX; 62 | 63 | void SHA256Init(SHA2_CTX *); 64 | void SHA256Transform(u_int32_t state[8], const u_int8_t [SHA256_BLOCK_LENGTH]); 65 | void SHA256Update(SHA2_CTX *, const u_int8_t *, size_t); 66 | void SHA256Pad(SHA2_CTX *); 67 | void SHA256Final(u_int8_t [SHA256_DIGEST_LENGTH], SHA2_CTX *); 68 | char *SHA256End(SHA2_CTX *, char *); 69 | 70 | void SHA384Init(SHA2_CTX *); 71 | void SHA384Transform(u_int64_t state[8], const u_int8_t [SHA384_BLOCK_LENGTH]); 72 | void SHA384Update(SHA2_CTX *, const u_int8_t *, size_t); 73 | void SHA384Pad(SHA2_CTX *); 74 | void SHA384Final(u_int8_t [SHA384_DIGEST_LENGTH], SHA2_CTX *); 75 | char *SHA384End(SHA2_CTX *, char *); 76 | 77 | void SHA512Init(SHA2_CTX *); 78 | void SHA512Transform(u_int64_t state[8], const u_int8_t [SHA512_BLOCK_LENGTH]); 79 | void SHA512Update(SHA2_CTX *, const u_int8_t *, size_t); 80 | void SHA512Pad(SHA2_CTX *); 81 | void SHA512Final(u_int8_t [SHA512_DIGEST_LENGTH], SHA2_CTX *); 82 | char *SHA512End(SHA2_CTX *, char *); 83 | 84 | #endif /* _SSHSHA2_H */ 85 | -------------------------------------------------------------------------------- /include/kore/tasks.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014 Joris Vink 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #ifndef __H_KORE_TASKS 18 | #define __H_KORE_TASKS 19 | 20 | #include 21 | 22 | #define KORE_TASK_STATE_CREATED 1 23 | #define KORE_TASK_STATE_RUNNING 2 24 | #define KORE_TASK_STATE_FINISHED 3 25 | #define KORE_TASK_STATE_ABORT 4 26 | 27 | #define KORE_TASK_THREADS 2 28 | 29 | #if defined(__cplusplus) 30 | extern "C" { 31 | #endif 32 | 33 | #if !defined(KORE_NO_HTTP) 34 | struct http_request; 35 | #endif 36 | 37 | struct kore_task { 38 | struct kore_event evt; 39 | int state; 40 | int result; 41 | pthread_rwlock_t lock; 42 | 43 | #if !defined(KORE_NO_HTTP) 44 | struct http_request *req; 45 | #endif 46 | 47 | int fds[2]; 48 | int (*entry)(struct kore_task *); 49 | void (*cb)(struct kore_task *); 50 | 51 | struct kore_task_thread *thread; 52 | 53 | TAILQ_ENTRY(kore_task) list; 54 | LIST_ENTRY(kore_task) rlist; 55 | }; 56 | 57 | struct kore_task_thread { 58 | u_int8_t idx; 59 | pthread_t tid; 60 | pthread_mutex_t lock; 61 | pthread_cond_t cond; 62 | TAILQ_HEAD(, kore_task) tasks; 63 | 64 | TAILQ_ENTRY(kore_task_thread) list; 65 | }; 66 | 67 | void kore_task_init(void); 68 | void kore_task_handle(void *, int); 69 | void kore_task_run(struct kore_task *); 70 | void kore_task_finish(struct kore_task *); 71 | void kore_task_destroy(struct kore_task *); 72 | int kore_task_finished(struct kore_task *); 73 | 74 | #if !defined(KORE_NO_HTTP) 75 | void kore_task_bind_request(struct kore_task *, 76 | struct http_request *); 77 | #endif 78 | void kore_task_bind_callback(struct kore_task *, 79 | void (*cb)(struct kore_task *)); 80 | void kore_task_create(struct kore_task *, 81 | int (*entry)(struct kore_task *)); 82 | 83 | u_int32_t kore_task_channel_read(struct kore_task *, void *, u_int32_t); 84 | void kore_task_channel_write(struct kore_task *, void *, u_int32_t); 85 | 86 | void kore_task_set_state(struct kore_task *, int); 87 | void kore_task_set_result(struct kore_task *, int); 88 | 89 | int kore_task_state(struct kore_task *); 90 | int kore_task_result(struct kore_task *); 91 | 92 | extern u_int16_t kore_task_threads; 93 | 94 | #if defined(__cplusplus) 95 | } 96 | #endif 97 | 98 | #endif 99 | -------------------------------------------------------------------------------- /kodev/Makefile: -------------------------------------------------------------------------------- 1 | # kodev Makefile 2 | 3 | CC?=cc 4 | PREFIX?=/usr/local 5 | OBJDIR?=obj 6 | KODEV=kodev 7 | DESTDIR?= 8 | INSTALL_DIR=$(PREFIX)/bin 9 | 10 | S_SRC= ../src/cli.c 11 | 12 | CFLAGS+=-Wall -Werror -Wstrict-prototypes -Wmissing-prototypes 13 | CFLAGS+=-Wmissing-declarations -Wshadow -Wpointer-arith -Wcast-qual 14 | CFLAGS+=-Wsign-compare -Iincludes -std=c99 -pedantic 15 | CFLAGS+=-DPREFIX='"$(PREFIX)"' 16 | LDFLAGS=-lcrypto 17 | 18 | ifneq ("$(NOOPT)", "") 19 | CFLAGS+=-O0 20 | else 21 | CFLAGS+=-O2 22 | endif 23 | 24 | ifneq ("$(MINIMAL)", "") 25 | CFLAGS+=-DKODEV_MINIMAL 26 | LDFLAGS= 27 | endif 28 | 29 | OSNAME=$(shell uname -s | sed -e 's/[-_].*//g' | tr A-Z a-z) 30 | ifeq ("$(OSNAME)", "darwin") 31 | CFLAGS+=$(shell pkg-config openssl --cflags) 32 | LDFLAGS+=$(shell pkg-config openssl --libs) 33 | else ifeq ("$(OSNAME)", "linux") 34 | CFLAGS+=-D_GNU_SOURCE=1 35 | endif 36 | 37 | S_OBJS= $(S_SRC:../src/%.c=$(OBJDIR)/%.o) 38 | 39 | $(KODEV): $(OBJDIR) $(S_OBJS) 40 | $(CC) $(S_OBJS) $(LDFLAGS) -o $(KODEV) 41 | 42 | $(OBJDIR): 43 | @mkdir -p $(OBJDIR) 44 | 45 | install: $(KODEV) 46 | mkdir -p $(DESTDIR)$(INSTALL_DIR) 47 | install -m 555 $(KODEV) $(DESTDIR)$(INSTALL_DIR)/$(KODEV) 48 | 49 | uninstall: 50 | rm -f $(DESTDIR)$(INSTALL_DIR)/$(KODEV) 51 | 52 | $(OBJDIR)/%.o: ../src/%.c 53 | $(CC) $(CFLAGS) -c $< -o $@ 54 | 55 | clean: 56 | find . -type f -name \*.o -exec rm {} \; 57 | rm -rf $(KODEV) $(OBJDIR) 58 | 59 | .PHONY: all clean 60 | -------------------------------------------------------------------------------- /minisign.pub: -------------------------------------------------------------------------------- 1 | untrusted comment: Kore minisign public key 2 | RWSxkEDc2y+whfKTmvhqs/YaFmEwblmvar7l6RXMjnu6o9tZW3LC0Hc9 3 | -------------------------------------------------------------------------------- /misc/curl-extract-opt.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | if [ $# -ne 1 ]; then 4 | echo "Usage: curl-extract-opt.sh /path/to/include/curl" 5 | exit 1 6 | fi 7 | 8 | if [ ! -d $1 ]; then 9 | echo "given argument is not a directory" 10 | exit 1 11 | fi 12 | 13 | if [ ! -f "$1/curl.h" ]; then 14 | echo "$1 does not contain curl.h" 15 | exit 1 16 | fi 17 | 18 | if [ ! -f "$1/curlver.h" ]; then 19 | echo "$1 does not contain curlver.h" 20 | fi 21 | 22 | version=`egrep "#define LIBCURL_VERSION " "$1/curlver.h" | awk '{ print $3 }' | sed s/\"//g` 23 | 24 | echo "/* Auto generated on `date` from $version */" 25 | 26 | cat << __EOF 27 | 28 | struct { 29 | const char *name; 30 | int value; 31 | PyObject *(*cb)(struct pycurl_handle *, int, PyObject *); 32 | } py_curlopt[] = { 33 | __EOF 34 | 35 | egrep "^.*CURLOPT\(.*\),$" "$1/curl.h" | \ 36 | cut -d'(' -f 2 | cut -d ')' -f 1 | sed 's/,/ /g' | \ 37 | sed 's/CURLOPTTYPE_OBJECTPOINT/NULL/g' | \ 38 | sed 's/CURLOPTTYPE_STRINGPOINT/pycurl_handle_setopt_string/g' | \ 39 | sed 's/CURLOPTTYPE_LONG/pycurl_handle_setopt_long/g' | \ 40 | sed 's/CURLOPTTYPE_SLISTPOINT/pycurl_handle_setopt_slist/g' | \ 41 | sed 's/CURLOPTTYPE_FUNCTIONPOINT/NULL/g' | \ 42 | sed 's/CURLOPTTYPE_OFF_T/NULL/g' | \ 43 | sed 's/CURLOPTTYPE_BLOB/NULL/g' | \ 44 | awk '{ printf "\t{ \"%s\", %s, %s },\n", $1, $3, $2 } ' 45 | 46 | echo "\t{ NULL, 0, 0 }" 47 | echo "};" 48 | -------------------------------------------------------------------------------- /misc/ffdhe4096.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN DH PARAMETERS----- 2 | MIICCAKCAgEA//////////+t+FRYortKmq/cViAnPTzx2LnFg84tNpWp4TZBFGQz 3 | +8yTnc4kmz75fS/jY2MMddj2gbICrsRhetPfHtXV/WVhJDP1H18GbtCFY2VVPe0a 4 | 87VXE15/V8k1mE8McODmi3fipona8+/och3xWKE2rec1MKzKT0g6eXq8CrGCsyT7 5 | YdEIqUuyyOP7uWrat2DX9GgdT0Kj3jlN9K5W7edjcrsZCwenyO4KbXCeAvzhzffi 6 | 7MA0BM0oNC9hkXL+nOmFg/+OTxIy7vKBg8P+OxtMb61zO7X8vC7CIAXFjvGDfRaD 7 | ssbzSibBsu/6iGtCOGEfz9zeNVs7ZRkDW7w09N75nAI4YbRvydbmyQd62R0mkff3 8 | 7lmMsPrBhtkcrv4TCYUTknC0EwyTvEN5RPT9RFLi103TZPLiHnH1S/9croKrnJ32 9 | nuhtK8UiNjoNq8Uhl5sN6todv5pC1cRITgq80Gv6U93vPBsg7j/VnXwl5B0rZp4e 10 | 8W5vUsMWTfT7eTDp5OWIV7asfV9C1p9tGHdjzx1VA0AEh/VbpX4xzHpxNciG77Qx 11 | iu1qHgEtnmgyqQdgCpGBMMRtx3j5ca0AOAkpmaMzy4t6Gh25PXFAADwqTs6p+Y0K 12 | zAqCkc3OyX3Pjsm1Wn+IpGtNtahR9EGC4caKAH5eZV9q//////////8CAQI= 13 | -----END DH PARAMETERS----- 14 | -------------------------------------------------------------------------------- /misc/hooks/post-receive: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/bash 2 | 3 | set -x 4 | set -e 5 | 6 | URL=discord-hook 7 | 8 | while read oldrev newrev ref; do 9 | if [[ $ref =~ .*/master$ ]]; then 10 | logmsg="" 11 | commits=$(git rev-list ${oldrev}..${newrev}) 12 | for commit in $commits; do 13 | log=$(git log -1 --pretty=format:'[%h](https://git.kore.io/kore/commit/%H) %cn: %s' $commit) 14 | logmsg="$logmsg $log\\n" 15 | done 16 | 17 | curl -i \ 18 | -H "Accept: application/json" \ 19 | -H "Content-type: application/json" \ 20 | -X POST \ 21 | -d "{\"content\": \"${logmsg}\"}" \ 22 | $URL 23 | fi 24 | done 25 | 26 | git update-server-info 27 | 28 | ROOT=/var/chroot/kore-site 29 | TARGET=$ROOT/stagit 30 | STATIC=$HOME/src/stagit_static 31 | export TMPDIR=$ROOT/.tmp 32 | 33 | STAGING=`mktemp -d` 34 | 35 | function update_stagit { 36 | mkdir -p $STAGING/$1 37 | pushd $STAGING/$1 38 | stagit $2 39 | cp log.html index.html 40 | cp -R $2 ${STAGING}/${1}.git 41 | rm ${STAGING}/${1}.git/hooks/post-receive 42 | chmod -R +rx ${STAGING}/${1}.git 43 | popd 44 | 45 | } 46 | 47 | update_stagit kore /home/git/kore.git 48 | 49 | cp -R $STATIC/* $STAGING 50 | chmod -R o+rx $STAGING 51 | 52 | rm -rf $ROOT/.old 53 | mv $TARGET $ROOT/.old 54 | mv $STAGING $TARGET 55 | rm -rf $ROOT/.old 56 | -------------------------------------------------------------------------------- /misc/linux-platform.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Linux specific defines and system call maps. 4 | 5 | if [ -z "$TARGET_PLATFORM" ]; then 6 | PLATFORM=$(uname -m) 7 | else 8 | PLATFORM=$TARGET_PLATFORM 9 | fi 10 | 11 | BASE=$(dirname $0) 12 | 13 | case "$PLATFORM" in 14 | x86_64*) 15 | seccomp_audit_arch=AUDIT_ARCH_X86_64 16 | syscall_file=$BASE/linux/x86_64_syscall.h.in 17 | ;; 18 | i386) 19 | seccomp_audit_arch=AUDIT_ARCH_I386 20 | syscall_file=$BASE/linux/i386_syscall.h.in 21 | ;; 22 | arm*) 23 | seccomp_audit_arch=AUDIT_ARCH_ARM 24 | syscall_file=$BASE/linux/arm_syscall.h.in 25 | ;; 26 | aarch64*) 27 | seccomp_audit_arch=AUDIT_ARCH_AARCH64 28 | syscall_file=$BASE/linux/aarch64_syscall.h.in 29 | ;; 30 | *) 31 | >&2 echo "$PLATFORM not supported" 32 | exit 1 33 | ;; 34 | esac 35 | 36 | cat << __EOF 37 | /* Auto generated by linux-platform.sh - DO NOT EDIT */ 38 | 39 | #include 40 | 41 | #define SECCOMP_AUDIT_ARCH $seccomp_audit_arch 42 | 43 | struct { 44 | const char *name; 45 | int nr; 46 | } kore_syscall_map [] = { 47 | __EOF 48 | 49 | sed 's/__NR_//' $syscall_file | awk '/#define/ { syscall = $2; number = $3; printf " { \"%s\", %d },\n", syscall, number }' 50 | 51 | cat << __EOF 52 | { NULL, 0 } 53 | }; 54 | __EOF 55 | -------------------------------------------------------------------------------- /misc/python3-config.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | if [ $# -ne 1 ]; then 4 | echo "python3-flags.sh [--ldflags|--includes]" 5 | exit 1 6 | fi 7 | 8 | if [ ! -z "$PYTHON_CONFIG" ]; then 9 | BIN=$PYTHON_CONFIG 10 | else 11 | BIN=python3-config 12 | fi 13 | 14 | $BIN $1 --embed > /dev/null 2>&1 15 | 16 | if [ $? -eq 0 ]; then 17 | $BIN $1 --embed 18 | else 19 | $BIN $1 20 | fi 21 | -------------------------------------------------------------------------------- /src/auth.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014 Joris Vink 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include 18 | #include 19 | 20 | #include 21 | 22 | #include "kore.h" 23 | #include "http.h" 24 | 25 | TAILQ_HEAD(, kore_auth) auth_list; 26 | 27 | void 28 | kore_auth_init(void) 29 | { 30 | TAILQ_INIT(&auth_list); 31 | } 32 | 33 | int 34 | kore_auth_new(const char *name) 35 | { 36 | struct kore_auth *auth; 37 | 38 | if (kore_auth_lookup(name) != NULL) 39 | return (KORE_RESULT_ERROR); 40 | 41 | auth = kore_malloc(sizeof(*auth)); 42 | auth->type = 0; 43 | auth->value = NULL; 44 | auth->redirect = NULL; 45 | auth->validator = NULL; 46 | auth->name = kore_strdup(name); 47 | 48 | TAILQ_INSERT_TAIL(&auth_list, auth, list); 49 | 50 | return (KORE_RESULT_OK); 51 | } 52 | 53 | int 54 | kore_auth_run(struct http_request *req, struct kore_auth *auth) 55 | { 56 | int r; 57 | 58 | switch (auth->type) { 59 | case KORE_AUTH_TYPE_COOKIE: 60 | r = kore_auth_cookie(req, auth); 61 | break; 62 | case KORE_AUTH_TYPE_HEADER: 63 | r = kore_auth_header(req, auth); 64 | break; 65 | case KORE_AUTH_TYPE_REQUEST: 66 | r = kore_auth_request(req, auth); 67 | break; 68 | default: 69 | kore_log(LOG_NOTICE, "unknown auth type %d", auth->type); 70 | return (KORE_RESULT_ERROR); 71 | } 72 | 73 | switch (r) { 74 | case KORE_RESULT_OK: 75 | req->flags |= HTTP_REQUEST_AUTHED; 76 | /* FALLTHROUGH */ 77 | case KORE_RESULT_RETRY: 78 | return (r); 79 | default: 80 | break; 81 | } 82 | 83 | /* Authentication types of "request" send their own HTTP responses. */ 84 | if (auth->type == KORE_AUTH_TYPE_REQUEST) 85 | return (r); 86 | 87 | if (auth->redirect == NULL) { 88 | http_response(req, HTTP_STATUS_FORBIDDEN, NULL, 0); 89 | return (KORE_RESULT_ERROR); 90 | } 91 | 92 | http_response_header(req, "location", auth->redirect); 93 | http_response(req, HTTP_STATUS_FOUND, NULL, 0); 94 | 95 | return (KORE_RESULT_ERROR); 96 | } 97 | 98 | int 99 | kore_auth_cookie(struct http_request *req, struct kore_auth *auth) 100 | { 101 | const char *hdr; 102 | int i, v; 103 | size_t len, slen; 104 | char *value, *c, *cookie, *cookies[HTTP_MAX_COOKIES]; 105 | 106 | if (!http_request_header(req, "cookie", &hdr)) 107 | return (KORE_RESULT_ERROR); 108 | 109 | cookie = kore_strdup(hdr); 110 | 111 | slen = strlen(auth->value); 112 | v = kore_split_string(cookie, ";", cookies, HTTP_MAX_COOKIES); 113 | for (i = 0; i < v; i++) { 114 | for (c = cookies[i]; isspace(*(unsigned char *)c); c++) 115 | ; 116 | 117 | len = MIN(slen, strlen(cookies[i])); 118 | if (!strncmp(c, auth->value, len)) 119 | break; 120 | } 121 | 122 | if (i == v) { 123 | kore_free(cookie); 124 | return (KORE_RESULT_ERROR); 125 | } 126 | 127 | c = cookies[i]; 128 | if ((value = strchr(c, '=')) == NULL) { 129 | kore_free(cookie); 130 | return (KORE_RESULT_ERROR); 131 | } 132 | 133 | i = kore_validator_check(req, auth->validator, ++value); 134 | kore_free(cookie); 135 | 136 | return (i); 137 | } 138 | 139 | int 140 | kore_auth_header(struct http_request *req, struct kore_auth *auth) 141 | { 142 | const char *header; 143 | 144 | if (!http_request_header(req, auth->value, &header)) 145 | return (KORE_RESULT_ERROR); 146 | 147 | return (kore_validator_check(req, auth->validator, header)); 148 | } 149 | 150 | int 151 | kore_auth_request(struct http_request *req, struct kore_auth *auth) 152 | { 153 | int ret; 154 | 155 | req->flags |= HTTP_VALIDATOR_IS_REQUEST; 156 | ret = kore_validator_check(req, auth->validator, req); 157 | req->flags &= ~HTTP_VALIDATOR_IS_REQUEST; 158 | 159 | return (ret); 160 | } 161 | 162 | struct kore_auth * 163 | kore_auth_lookup(const char *name) 164 | { 165 | struct kore_auth *auth; 166 | 167 | TAILQ_FOREACH(auth, &auth_list, list) { 168 | if (!strcmp(auth->name, name)) 169 | return (auth); 170 | } 171 | 172 | return (NULL); 173 | } 174 | -------------------------------------------------------------------------------- /src/buf.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-2022 Joris Vink 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #include "kore.h" 25 | 26 | struct kore_buf * 27 | kore_buf_alloc(size_t initial) 28 | { 29 | struct kore_buf *buf; 30 | 31 | buf = kore_malloc(sizeof(*buf)); 32 | kore_buf_init(buf, initial); 33 | buf->flags = KORE_BUF_OWNER_API; 34 | 35 | return (buf); 36 | } 37 | 38 | void 39 | kore_buf_init(struct kore_buf *buf, size_t initial) 40 | { 41 | if (initial > 0) 42 | buf->data = kore_malloc(initial); 43 | else 44 | buf->data = NULL; 45 | 46 | buf->length = initial; 47 | buf->offset = 0; 48 | buf->flags = 0; 49 | } 50 | 51 | void 52 | kore_buf_cleanup(struct kore_buf *buf) 53 | { 54 | kore_free(buf->data); 55 | buf->data = NULL; 56 | buf->offset = 0; 57 | buf->length = 0; 58 | } 59 | 60 | void 61 | kore_buf_free(struct kore_buf *buf) 62 | { 63 | kore_buf_cleanup(buf); 64 | if (buf->flags & KORE_BUF_OWNER_API) 65 | kore_free(buf); 66 | } 67 | 68 | void 69 | kore_buf_append(struct kore_buf *buf, const void *data, size_t len) 70 | { 71 | if ((buf->offset + len) < len) 72 | fatal("overflow in kore_buf_append"); 73 | 74 | if ((buf->offset + len) > buf->length) { 75 | buf->length += len; 76 | buf->data = kore_realloc(buf->data, buf->length); 77 | } 78 | 79 | memcpy((buf->data + buf->offset), data, len); 80 | buf->offset += len; 81 | } 82 | 83 | void 84 | kore_buf_appendv(struct kore_buf *buf, const char *fmt, va_list args) 85 | { 86 | int l; 87 | va_list copy; 88 | char *b, sb[BUFSIZ]; 89 | 90 | va_copy(copy, args); 91 | 92 | l = vsnprintf(sb, sizeof(sb), fmt, args); 93 | if (l == -1) 94 | fatal("kore_buf_appendv(): vsnprintf error"); 95 | 96 | if ((size_t)l >= sizeof(sb)) { 97 | l = vasprintf(&b, fmt, copy); 98 | if (l == -1) 99 | fatal("kore_buf_appendv(): error or truncation"); 100 | } else { 101 | b = sb; 102 | } 103 | 104 | kore_buf_append(buf, b, l); 105 | if (b != sb) 106 | free(b); 107 | 108 | va_end(copy); 109 | } 110 | 111 | void 112 | kore_buf_appendf(struct kore_buf *buf, const char *fmt, ...) 113 | { 114 | va_list args; 115 | 116 | va_start(args, fmt); 117 | kore_buf_appendv(buf, fmt, args); 118 | va_end(args); 119 | } 120 | 121 | char * 122 | kore_buf_stringify(struct kore_buf *buf, size_t *len) 123 | { 124 | char c; 125 | 126 | if (len != NULL) 127 | *len = buf->offset; 128 | 129 | c = '\0'; 130 | kore_buf_append(buf, &c, sizeof(c)); 131 | 132 | return ((char *)buf->data); 133 | } 134 | 135 | u_int8_t * 136 | kore_buf_release(struct kore_buf *buf, size_t *len) 137 | { 138 | u_int8_t *p; 139 | 140 | p = buf->data; 141 | *len = buf->offset; 142 | 143 | buf->data = NULL; 144 | kore_buf_free(buf); 145 | 146 | return (p); 147 | } 148 | 149 | void 150 | kore_buf_replace_string(struct kore_buf *b, const char *src, 151 | const void *dst, size_t len) 152 | { 153 | char *key, *end, *tmp, *p; 154 | size_t blen, off, off2, nlen, klen; 155 | 156 | off = 0; 157 | klen = strlen(src); 158 | for (;;) { 159 | blen = b->offset; 160 | nlen = blen + len; 161 | p = (char *)b->data; 162 | 163 | key = kore_mem_find(p + off, b->offset - off, src, klen); 164 | if (key == NULL) 165 | break; 166 | 167 | end = key + klen; 168 | off = key - p; 169 | off2 = ((char *)(b->data + b->offset) - end); 170 | 171 | tmp = kore_malloc(nlen); 172 | memcpy(tmp, p, off); 173 | if (dst != NULL) 174 | memcpy((tmp + off), dst, len); 175 | memcpy((tmp + off + len), end, off2); 176 | 177 | kore_free(b->data); 178 | b->data = (u_int8_t *)tmp; 179 | b->offset = off + len + off2; 180 | b->length = nlen; 181 | 182 | off = off + len; 183 | } 184 | } 185 | 186 | void 187 | kore_buf_reset(struct kore_buf *buf) 188 | { 189 | buf->offset = 0; 190 | } 191 | -------------------------------------------------------------------------------- /src/domain.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-2022 Joris Vink 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include 18 | #include 19 | 20 | #include 21 | 22 | #include "kore.h" 23 | 24 | #if !defined(KORE_NO_HTTP) 25 | #include "http.h" 26 | #endif 27 | 28 | #if defined(KORE_USE_ACME) 29 | #include "acme.h" 30 | #endif 31 | 32 | #define KORE_DOMAIN_CACHE 16 33 | 34 | static u_int16_t domain_id = 0; 35 | struct kore_domain *primary_dom = NULL; 36 | static struct kore_domain *cached[KORE_DOMAIN_CACHE]; 37 | 38 | void 39 | kore_domain_init(void) 40 | { 41 | int i; 42 | 43 | for (i = 0; i < KORE_DOMAIN_CACHE; i++) 44 | cached[i] = NULL; 45 | } 46 | 47 | void 48 | kore_domain_cleanup(void) 49 | { 50 | } 51 | 52 | struct kore_domain * 53 | kore_domain_new(const char *domain) 54 | { 55 | struct kore_domain *dom; 56 | 57 | dom = kore_calloc(1, sizeof(*dom)); 58 | dom->id = domain_id++; 59 | 60 | dom->accesslog = -1; 61 | dom->x509_verify_depth = 1; 62 | 63 | dom->domain = kore_strdup(domain); 64 | 65 | #if !defined(KORE_NO_HTTP) 66 | TAILQ_INIT(&dom->routes); 67 | TAILQ_INIT(&dom->redirects); 68 | #endif 69 | 70 | if (dom->id < KORE_DOMAIN_CACHE) { 71 | if (cached[dom->id] != NULL) 72 | fatal("non free domain cache slot"); 73 | cached[dom->id] = dom; 74 | } 75 | 76 | if (primary_dom == NULL) 77 | primary_dom = dom; 78 | 79 | return (dom); 80 | } 81 | 82 | int 83 | kore_domain_attach(struct kore_domain *dom, struct kore_server *server) 84 | { 85 | struct kore_domain *d; 86 | 87 | if (dom->server != NULL) 88 | return (KORE_RESULT_ERROR); 89 | 90 | TAILQ_FOREACH(d, &server->domains, list) { 91 | if (!strcmp(d->domain, dom->domain)) 92 | return (KORE_RESULT_ERROR); 93 | } 94 | 95 | dom->server = server; 96 | TAILQ_INSERT_TAIL(&server->domains, dom, list); 97 | 98 | /* The primary domain should be attached to a TLS context. */ 99 | if (server->tls == 0 && dom == primary_dom) 100 | primary_dom = NULL; 101 | 102 | return (KORE_RESULT_OK); 103 | } 104 | 105 | void 106 | kore_domain_free(struct kore_domain *dom) 107 | { 108 | #if !defined(KORE_NO_HTTP) 109 | struct kore_route *rt; 110 | struct http_redirect *rdr; 111 | #endif 112 | if (dom == NULL) 113 | return; 114 | 115 | if (primary_dom == dom) 116 | primary_dom = NULL; 117 | 118 | TAILQ_REMOVE(&dom->server->domains, dom, list); 119 | 120 | if (dom->domain != NULL) 121 | kore_free(dom->domain); 122 | 123 | kore_tls_domain_cleanup(dom); 124 | 125 | kore_free(dom->cafile); 126 | kore_free(dom->certkey); 127 | kore_free(dom->certfile); 128 | kore_free(dom->crlfile); 129 | 130 | #if !defined(KORE_NO_HTTP) 131 | /* Drop all handlers associated with this domain */ 132 | while ((rt = TAILQ_FIRST(&dom->routes)) != NULL) { 133 | TAILQ_REMOVE(&dom->routes, rt, list); 134 | kore_route_free(rt); 135 | } 136 | 137 | while ((rdr = TAILQ_FIRST(&(dom->redirects))) != NULL) { 138 | TAILQ_REMOVE(&(dom->redirects), rdr, list); 139 | regfree(&rdr->rctx); 140 | kore_free(rdr->target); 141 | kore_free(rdr); 142 | } 143 | #endif 144 | kore_free(dom); 145 | } 146 | 147 | void 148 | kore_domain_callback(void (*cb)(struct kore_domain *)) 149 | { 150 | struct kore_server *srv; 151 | struct kore_domain *dom; 152 | 153 | LIST_FOREACH(srv, &kore_servers, list) { 154 | TAILQ_FOREACH(dom, &srv->domains, list) { 155 | cb(dom); 156 | } 157 | } 158 | } 159 | 160 | struct kore_domain * 161 | kore_domain_lookup(struct kore_server *srv, const char *domain) 162 | { 163 | struct kore_domain *dom; 164 | 165 | TAILQ_FOREACH(dom, &srv->domains, list) { 166 | if (!strcmp(dom->domain, domain)) 167 | return (dom); 168 | if (!fnmatch(dom->domain, domain, FNM_CASEFOLD)) 169 | return (dom); 170 | } 171 | 172 | return (NULL); 173 | } 174 | 175 | struct kore_domain * 176 | kore_domain_byid(u_int16_t id) 177 | { 178 | struct kore_server *srv; 179 | struct kore_domain *dom; 180 | 181 | if (id < KORE_DOMAIN_CACHE) 182 | return (cached[id]); 183 | 184 | LIST_FOREACH(srv, &kore_servers, list) { 185 | TAILQ_FOREACH(dom, &srv->domains, list) { 186 | if (dom->id == id) 187 | return (dom); 188 | } 189 | } 190 | 191 | return (NULL); 192 | } 193 | 194 | /* 195 | * Called by the worker processes to close the file descriptor towards 196 | * the accesslog as they do not need it locally. 197 | */ 198 | void 199 | kore_domain_closelogs(void) 200 | { 201 | struct kore_server *srv; 202 | struct kore_domain *dom; 203 | 204 | LIST_FOREACH(srv, &kore_servers, list) { 205 | TAILQ_FOREACH(dom, &srv->domains, list) { 206 | if (dom->accesslog != -1) { 207 | (void)close(dom->accesslog); 208 | /* 209 | * Turn into flag to indicate accesslogs 210 | * are active. 211 | */ 212 | dom->accesslog = 1; 213 | } else { 214 | dom->accesslog = 0; 215 | } 216 | } 217 | } 218 | } 219 | -------------------------------------------------------------------------------- /src/log.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 Joris Vink 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include 18 | 19 | #include 20 | #include 21 | 22 | #include "kore.h" 23 | 24 | struct kore_wlog { 25 | int prio; 26 | u_int16_t wid; 27 | size_t loglen; 28 | char logmsg[]; 29 | }; 30 | 31 | static void log_print(int, const char *, ...) 32 | __attribute__((format (printf, 2, 3))); 33 | static void log_from_worker(struct kore_msg *, const void *); 34 | 35 | static FILE *fp = NULL; 36 | 37 | void 38 | kore_log_init(void) 39 | { 40 | #if defined(KORE_SINGLE_BINARY) 41 | extern const char *__progname; 42 | const char *name = kore_strdup(__progname); 43 | #else 44 | const char *name = "kore"; 45 | #endif 46 | 47 | fp = stdout; 48 | 49 | if (!kore_foreground) 50 | openlog(name, LOG_NDELAY | LOG_PID, LOG_DAEMON); 51 | 52 | kore_msg_register(KORE_MSG_WORKER_LOG, log_from_worker); 53 | } 54 | 55 | void 56 | kore_log_file(const char *path) 57 | { 58 | if ((fp = fopen(path, "a")) == NULL) { 59 | fp = stdout; 60 | fatal("fopen(%s): %s", path, errno_s); 61 | } 62 | } 63 | 64 | void 65 | kore_log(int prio, const char *fmt, ...) 66 | { 67 | va_list args; 68 | const char *str; 69 | struct kore_wlog wlog; 70 | struct kore_buf buf, pkt; 71 | 72 | kore_buf_init(&buf, 128); 73 | 74 | va_start(args, fmt); 75 | kore_buf_appendv(&buf, fmt, args); 76 | va_end(args); 77 | 78 | if (worker != NULL) { 79 | kore_buf_init(&pkt, sizeof(wlog) + buf.offset); 80 | 81 | memset(&wlog, 0, sizeof(wlog)); 82 | 83 | wlog.prio = prio; 84 | wlog.wid = worker->id; 85 | wlog.loglen = buf.offset; 86 | 87 | kore_buf_append(&pkt, &wlog, sizeof(wlog)); 88 | kore_buf_append(&pkt, buf.data, buf.offset); 89 | 90 | kore_msg_send(KORE_MSG_PARENT, KORE_MSG_WORKER_LOG, 91 | pkt.data, pkt.offset); 92 | 93 | kore_buf_cleanup(&pkt); 94 | } else { 95 | str = kore_buf_stringify(&buf, NULL); 96 | 97 | if (kore_foreground || fp != stdout) 98 | log_print(prio, "proc=[parent] log=[%s]\n", str); 99 | else 100 | syslog(prio, "proc=[parent] log=[%s]", str); 101 | } 102 | 103 | kore_buf_cleanup(&buf); 104 | } 105 | 106 | static void 107 | log_from_worker(struct kore_msg *msg, const void *data) 108 | { 109 | const char *name; 110 | const struct kore_wlog *wlog; 111 | 112 | if (msg->length < sizeof(*wlog)) { 113 | kore_log(LOG_NOTICE, 114 | "too short worker log received (%zu < %zu)", 115 | msg->length, sizeof(*wlog)); 116 | return; 117 | } 118 | 119 | wlog = data; 120 | name = kore_worker_name(wlog->wid); 121 | 122 | if (kore_foreground || fp != stdout) { 123 | log_print(wlog->prio, "proc=%s log=[%.*s]\n", 124 | name, (int)wlog->loglen, wlog->logmsg); 125 | } else { 126 | syslog(wlog->prio, "proc=%s log=[%.*s]", 127 | name, (int)wlog->loglen, wlog->logmsg); 128 | } 129 | } 130 | 131 | static void 132 | log_print(int prio, const char *fmt, ...) 133 | { 134 | struct tm *t; 135 | struct timespec ts; 136 | va_list args; 137 | char tbuf[32]; 138 | 139 | va_start(args, fmt); 140 | 141 | switch (prio) { 142 | case LOG_ERR: 143 | case LOG_WARNING: 144 | case LOG_NOTICE: 145 | case LOG_INFO: 146 | case LOG_DEBUG: 147 | break; 148 | } 149 | 150 | (void)clock_gettime(CLOCK_REALTIME, &ts); 151 | t = gmtime(&ts.tv_sec); 152 | 153 | if (strftime(tbuf, sizeof(tbuf), "%Y-%m-%d %H:%M:%S", t) > 0) 154 | fprintf(fp, "%s.%03ld UTC ", tbuf, ts.tv_nsec / 1000000); 155 | 156 | vfprintf(fp, fmt, args); 157 | fflush(fp); 158 | 159 | va_end(args); 160 | } 161 | -------------------------------------------------------------------------------- /src/route.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 Joris Vink 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include 18 | #include 19 | 20 | #include 21 | 22 | #include "kore.h" 23 | #include "http.h" 24 | 25 | struct kore_route * 26 | kore_route_create(struct kore_domain *dom, const char *path, int type) 27 | { 28 | struct kore_route *rt; 29 | 30 | rt = kore_calloc(1, sizeof(*rt)); 31 | rt->dom = dom; 32 | rt->type = type; 33 | rt->path = kore_strdup(path); 34 | rt->methods = HTTP_METHOD_ALL; 35 | 36 | TAILQ_INIT(&rt->params); 37 | 38 | if (rt->type == HANDLER_TYPE_DYNAMIC) { 39 | if (regcomp(&rt->rctx, rt->path, REG_EXTENDED | REG_NOSUB)) { 40 | kore_route_free(rt); 41 | return (NULL); 42 | } 43 | } 44 | 45 | TAILQ_INSERT_TAIL(&dom->routes, rt, list); 46 | 47 | return (rt); 48 | } 49 | 50 | void 51 | kore_route_free(struct kore_route *rt) 52 | { 53 | struct kore_route_params *param; 54 | 55 | if (rt == NULL) 56 | return; 57 | 58 | kore_free(rt->func); 59 | kore_free(rt->path); 60 | 61 | if (rt->type == HANDLER_TYPE_DYNAMIC) 62 | regfree(&rt->rctx); 63 | 64 | /* Drop all validators associated with this handler */ 65 | while ((param = TAILQ_FIRST(&rt->params)) != NULL) { 66 | TAILQ_REMOVE(&rt->params, param, list); 67 | kore_free(param->name); 68 | kore_free(param); 69 | } 70 | 71 | kore_free(rt); 72 | } 73 | 74 | void 75 | kore_route_callback(struct kore_route *rt, const char *func) 76 | { 77 | if ((rt->rcall = kore_runtime_getcall(func)) == NULL) 78 | fatal("callback '%s' for '%s' not found", func, rt->path); 79 | 80 | kore_free(rt->func); 81 | rt->func = kore_strdup(func); 82 | } 83 | 84 | int 85 | kore_route_lookup(struct http_request *req, struct kore_domain *dom, 86 | int method, struct kore_route **out) 87 | { 88 | struct kore_route *rt; 89 | int exists; 90 | 91 | exists = 0; 92 | *out = NULL; 93 | 94 | TAILQ_FOREACH(rt, &dom->routes, list) { 95 | if (rt->type == HANDLER_TYPE_STATIC) { 96 | if (!strcmp(rt->path, req->path)) { 97 | if (rt->methods & method) { 98 | *out = rt; 99 | return (1); 100 | } 101 | exists++; 102 | } 103 | } else { 104 | if (!regexec(&rt->rctx, req->path, 105 | HTTP_CAPTURE_GROUPS, req->cgroups, 0)) { 106 | if (rt->methods & method) { 107 | *out = rt; 108 | return (1); 109 | } 110 | exists++; 111 | } 112 | } 113 | } 114 | 115 | return (exists); 116 | } 117 | 118 | void 119 | kore_route_reload(void) 120 | { 121 | struct kore_route *rt; 122 | struct kore_server *srv; 123 | struct kore_domain *dom; 124 | 125 | LIST_FOREACH(srv, &kore_servers, list) { 126 | TAILQ_FOREACH(dom, &srv->domains, list) { 127 | TAILQ_FOREACH(rt, &dom->routes, list) { 128 | kore_free(rt->rcall); 129 | rt->rcall = kore_runtime_getcall(rt->func); 130 | if (rt->rcall == NULL) { 131 | fatal("no function '%s' for route '%s'", 132 | rt->func, rt->path); 133 | } 134 | rt->errors = 0; 135 | } 136 | } 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /src/timer.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016-2022 Joris Vink 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | 21 | #include "kore.h" 22 | 23 | TAILQ_HEAD(timerlist, kore_timer) kore_timers; 24 | 25 | void 26 | kore_timer_init(void) 27 | { 28 | TAILQ_INIT(&kore_timers); 29 | } 30 | 31 | struct kore_timer * 32 | kore_timer_add(void (*cb)(void *, u_int64_t), u_int64_t interval, 33 | void *arg, int flags) 34 | { 35 | struct kore_timer *timer, *t; 36 | 37 | timer = kore_malloc(sizeof(*timer)); 38 | 39 | timer->cb = cb; 40 | timer->arg = arg; 41 | timer->flags = flags; 42 | timer->interval = interval; 43 | timer->nextrun = kore_time_ms() + timer->interval; 44 | 45 | TAILQ_FOREACH(t, &kore_timers, list) { 46 | if (t->nextrun > timer->nextrun) { 47 | TAILQ_INSERT_BEFORE(t, timer, list); 48 | return (timer); 49 | } 50 | } 51 | 52 | TAILQ_INSERT_TAIL(&kore_timers, timer, list); 53 | return (timer); 54 | } 55 | 56 | void 57 | kore_timer_remove(struct kore_timer *timer) 58 | { 59 | TAILQ_REMOVE(&kore_timers, timer, list); 60 | kore_free(timer); 61 | } 62 | 63 | u_int64_t 64 | kore_timer_next_run(u_int64_t now) 65 | { 66 | struct kore_timer *timer; 67 | 68 | if ((timer = TAILQ_FIRST(&kore_timers)) != NULL) { 69 | if (timer->nextrun > now) 70 | return (timer->nextrun - now); 71 | return (0); 72 | } 73 | 74 | return (KORE_WAIT_INFINITE); 75 | } 76 | 77 | void 78 | kore_timer_run(u_int64_t now) 79 | { 80 | struct kore_timer *timer, *t, *prev; 81 | 82 | prev = NULL; 83 | 84 | while ((timer = TAILQ_FIRST(&kore_timers)) != NULL) { 85 | if (timer == prev) 86 | break; 87 | 88 | if (timer->nextrun > now) 89 | break; 90 | 91 | TAILQ_REMOVE(&kore_timers, timer, list); 92 | timer->cb(timer->arg, now); 93 | 94 | if (timer->flags & KORE_TIMER_ONESHOT) { 95 | kore_free(timer); 96 | } else { 97 | prev = timer; 98 | timer->nextrun = now + timer->interval; 99 | TAILQ_FOREACH(t, &kore_timers, list) { 100 | if (t->nextrun > timer->nextrun) { 101 | TAILQ_INSERT_BEFORE(t, timer, list); 102 | break; 103 | } 104 | } 105 | 106 | if (t == NULL) 107 | TAILQ_INSERT_TAIL(&kore_timers, timer, list); 108 | } 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /src/tls_none.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 Joris Vink 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | /* 18 | * An empty TLS backend that does nothing, useful if you do 19 | * not require any TLS stuff in Kore. 20 | */ 21 | 22 | #include 23 | 24 | #include "kore.h" 25 | 26 | struct kore_privsep keymgr_privsep; 27 | char *kore_rand_file = NULL; 28 | int kore_keymgr_active = 0; 29 | 30 | int 31 | kore_tls_supported(void) 32 | { 33 | return (KORE_RESULT_ERROR); 34 | } 35 | 36 | void 37 | kore_keymgr_cleanup(int final) 38 | { 39 | } 40 | 41 | void 42 | kore_tls_init(void) 43 | { 44 | } 45 | 46 | void 47 | kore_tls_log_version(void) 48 | { 49 | kore_log(LOG_NOTICE, "No compiled in TLS backend"); 50 | } 51 | 52 | void 53 | kore_tls_cleanup(void) 54 | { 55 | } 56 | 57 | void 58 | kore_tls_dh_check(void) 59 | { 60 | } 61 | 62 | void 63 | kore_tls_keymgr_init(void) 64 | { 65 | } 66 | 67 | void 68 | kore_tls_connection_cleanup(struct connection *c) 69 | { 70 | } 71 | 72 | void 73 | kore_tls_domain_cleanup(struct kore_domain *dom) 74 | { 75 | } 76 | 77 | void 78 | kore_tls_seed(const void *data, size_t len) 79 | { 80 | } 81 | 82 | void 83 | kore_keymgr_run(void) 84 | { 85 | fatal("%s: not supported", __func__); 86 | } 87 | 88 | void 89 | kore_tls_version_set(int version) 90 | { 91 | fatal("%s: not supported", __func__); 92 | } 93 | 94 | int 95 | kore_tls_dh_load(const char *path) 96 | { 97 | fatal("%s: not supported", __func__); 98 | } 99 | 100 | int 101 | kore_tls_ciphersuite_set(const char *list) 102 | { 103 | fatal("%s: not supported", __func__); 104 | } 105 | 106 | void 107 | kore_tls_domain_setup(struct kore_domain *dom, int type, 108 | const void *data, size_t datalen) 109 | { 110 | fatal("%s: not supported", __func__); 111 | } 112 | 113 | void 114 | kore_tls_domain_crl(struct kore_domain *dom, const void *pem, size_t pemlen) 115 | { 116 | fatal("%s: not supported", __func__); 117 | } 118 | 119 | int 120 | kore_tls_connection_accept(struct connection *c) 121 | { 122 | fatal("%s: not supported", __func__); 123 | } 124 | 125 | int 126 | kore_tls_read(struct connection *c, size_t *bytes) 127 | { 128 | fatal("%s: not supported", __func__); 129 | } 130 | 131 | int 132 | kore_tls_write(struct connection *c, size_t len, size_t *written) 133 | { 134 | fatal("%s: not supported", __func__); 135 | } 136 | 137 | KORE_PRIVATE_KEY * 138 | kore_tls_rsakey_load(const char *path) 139 | { 140 | fatal("%s: not supported", __func__); 141 | } 142 | 143 | KORE_PRIVATE_KEY * 144 | kore_tls_rsakey_generate(const char *path) 145 | { 146 | fatal("%s: not supported", __func__); 147 | } 148 | 149 | KORE_X509_NAMES * 150 | kore_tls_x509_subject_name(struct connection *c) 151 | { 152 | fatal("%s: not supported", __func__); 153 | } 154 | 155 | KORE_X509_NAMES * 156 | kore_tls_x509_issuer_name(struct connection *c) 157 | { 158 | fatal("%s: not supported", __func__); 159 | } 160 | 161 | int 162 | kore_tls_x509name_foreach(KORE_X509_NAMES *name, int flags, void *udata, 163 | int (*cb)(void *, int, int, const char *, const void *, size_t, int)) 164 | { 165 | fatal("%s: not supported", __func__); 166 | } 167 | 168 | int 169 | kore_tls_x509_data(struct connection *c, u_int8_t **ptr, size_t *olen) 170 | { 171 | fatal("%s: not supported", __func__); 172 | } 173 | -------------------------------------------------------------------------------- /src/validator.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-2022 Joris Vink 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include 18 | 19 | #include "kore.h" 20 | 21 | TAILQ_HEAD(, kore_validator) validators; 22 | 23 | void 24 | kore_validator_init(void) 25 | { 26 | TAILQ_INIT(&validators); 27 | } 28 | 29 | int 30 | kore_validator_add(const char *name, u_int8_t type, const char *arg) 31 | { 32 | int ret; 33 | struct kore_validator *val; 34 | 35 | val = kore_malloc(sizeof(*val)); 36 | val->type = type; 37 | 38 | switch (val->type) { 39 | case KORE_VALIDATOR_TYPE_REGEX: 40 | ret = regcomp(&(val->rctx), arg, REG_EXTENDED | REG_NOSUB); 41 | if (ret) { 42 | kore_free(val); 43 | kore_log(LOG_NOTICE, 44 | "validator %s has bad regex %s (%d)", 45 | name, arg, ret); 46 | return (KORE_RESULT_ERROR); 47 | } 48 | break; 49 | case KORE_VALIDATOR_TYPE_FUNCTION: 50 | val->rcall = kore_runtime_getcall(arg); 51 | if (val->rcall == NULL) { 52 | kore_free(val); 53 | kore_log(LOG_NOTICE, 54 | "validator %s has undefined callback %s", 55 | name, arg); 56 | return (KORE_RESULT_ERROR); 57 | } 58 | break; 59 | default: 60 | kore_free(val); 61 | return (KORE_RESULT_ERROR); 62 | } 63 | 64 | val->arg = kore_strdup(arg); 65 | val->name = kore_strdup(name); 66 | TAILQ_INSERT_TAIL(&validators, val, list); 67 | 68 | return (KORE_RESULT_OK); 69 | } 70 | 71 | int 72 | kore_validator_run(struct http_request *req, const char *name, char *data) 73 | { 74 | struct kore_validator *val; 75 | 76 | TAILQ_FOREACH(val, &validators, list) { 77 | if (strcmp(val->name, name)) 78 | continue; 79 | 80 | return (kore_validator_check(req, val, data)); 81 | } 82 | 83 | return (KORE_RESULT_ERROR); 84 | } 85 | 86 | int 87 | kore_validator_check(struct http_request *req, struct kore_validator *val, 88 | const void *data) 89 | { 90 | int r; 91 | 92 | switch (val->type) { 93 | case KORE_VALIDATOR_TYPE_REGEX: 94 | if (!regexec(&(val->rctx), data, 0, NULL, 0)) 95 | r = KORE_RESULT_OK; 96 | else 97 | r = KORE_RESULT_ERROR; 98 | break; 99 | case KORE_VALIDATOR_TYPE_FUNCTION: 100 | r = kore_runtime_validator(val->rcall, req, data); 101 | break; 102 | default: 103 | r = KORE_RESULT_ERROR; 104 | kore_log(LOG_NOTICE, "invalid type %d for validator %s", 105 | val->type, val->name); 106 | break; 107 | } 108 | 109 | return (r); 110 | } 111 | 112 | void 113 | kore_validator_reload(void) 114 | { 115 | struct kore_validator *val; 116 | 117 | TAILQ_FOREACH(val, &validators, list) { 118 | if (val->type != KORE_VALIDATOR_TYPE_FUNCTION) 119 | continue; 120 | 121 | kore_free(val->rcall); 122 | val->rcall = kore_runtime_getcall(val->arg); 123 | if (val->rcall == NULL) 124 | fatal("no function for validator %s found", val->arg); 125 | } 126 | } 127 | 128 | struct kore_validator * 129 | kore_validator_lookup(const char *name) 130 | { 131 | struct kore_validator *val; 132 | 133 | TAILQ_FOREACH(val, &validators, list) { 134 | if (!strcmp(val->name, name)) 135 | return (val); 136 | } 137 | 138 | return (NULL); 139 | } 140 | -------------------------------------------------------------------------------- /tools/kore-serve/.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | .flavor 3 | .objs 4 | kore-serve.so 5 | assets.h 6 | cert 7 | -------------------------------------------------------------------------------- /tools/kore-serve/conf/build.conf: -------------------------------------------------------------------------------- 1 | single_binary=yes 2 | kore_source=../../ 3 | kore_flavor=NOTLS=1 4 | 5 | cflags=-std=c99 -Werror 6 | cflags=-Wall -Wmissing-declarations -Wshadow 7 | cflags=-Wstrict-prototypes -Wmissing-prototypes 8 | cflags=-Wpointer-arith -Wcast-qual -Wsign-compare 9 | 10 | dev { 11 | } 12 | 13 | darwin { 14 | } 15 | 16 | openbsd { 17 | } 18 | 19 | netbsd { 20 | } 21 | 22 | freebsd { 23 | } 24 | 25 | linux { 26 | cflags=-D_GNU_SOURCE 27 | } 28 | -------------------------------------------------------------------------------- /tools/kore-serve/conf/kore-serve.conf: -------------------------------------------------------------------------------- 1 | # kore-serve configuration 2 | # empty 3 | -------------------------------------------------------------------------------- /tools/kore-serve/src/kore-serve.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Joris Vink 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | /* 18 | * Simple static file serving over non TLS. Heavily used by myself 19 | * when working on kore-site. 20 | */ 21 | 22 | #include 23 | #include 24 | #include 25 | 26 | #include 27 | 28 | static void 29 | usage(void) 30 | { 31 | fprintf(stderr, 32 | "Usage: kore-serve [-i ip] [-p port] [-r root]\n"); 33 | 34 | exit(1); 35 | } 36 | 37 | void 38 | kore_parent_configure(int argc, char *argv[]) 39 | { 40 | int ch; 41 | struct kore_domain *dom; 42 | struct kore_server *srv; 43 | char *rpath; 44 | const char *ip, *port, *root; 45 | 46 | root = "."; 47 | port = "8888"; 48 | ip = "127.0.0.1"; 49 | 50 | kore_quiet = 1; 51 | kore_foreground = 1; 52 | 53 | skip_runas = 1; 54 | skip_chroot = 1; 55 | 56 | kore_filemap_ext = kore_strdup(".html"); 57 | 58 | while ((ch = getopt(argc, argv, "hi:p:r:")) != -1) { 59 | switch (ch) { 60 | case 'i': 61 | ip = optarg; 62 | break; 63 | case 'h': 64 | usage(); 65 | break; 66 | case 'p': 67 | port = optarg; 68 | break; 69 | case 'r': 70 | root = optarg; 71 | break; 72 | default: 73 | usage(); 74 | } 75 | } 76 | 77 | if ((rpath = realpath(root, NULL)) == NULL) 78 | fatal("realpath(%s): %s", root, errno_s); 79 | 80 | kore_log(LOG_INFO, "%s -> http://%s:%s", rpath, ip, port); 81 | 82 | srv = kore_server_create("kore-serve"); 83 | srv->tls = 0; 84 | 85 | if (!kore_server_bind(srv, ip, port, NULL)) 86 | fatal("Failed to bind to %s:%s (%s)", ip, port, errno_s); 87 | 88 | kore_server_finalize(srv); 89 | 90 | dom = kore_domain_new("*"); 91 | kore_domain_attach(dom, srv); 92 | 93 | if (kore_filemap_create(dom, rpath, "/", NULL) == NULL) 94 | fatal("failed to create filemap for %s", rpath); 95 | } 96 | --------------------------------------------------------------------------------