Embeddable Event-based Asynchronous Message/HTTP Server library for C/C++

Overview

libasyncd

Embeddable Event-based Asynchronous Message/HTTP Server library for C/C++.

What is libasyncd?

Libasyncd is an embeddable event-driven asynchronous message server for C/C++. It supports HTTP protocol by default and you can add your own protocol handler(hook) to build your own high performance server.

Asynchronous way of programming can easily go quite complicated since you need to handle every thing in non-blocking way. So the goal of Libasyncd project is to make a flexible and fast asynchronous server framework with nice abstraction that can cut down the complexity.

Why libasyncd?

libasyncd is a light-weight single-threaded asynchronous RPC server. It is efficient especially when server needs to handle a large number of concurrent connections where connection-per-thread or connection-per-process model is not appropriate to consider.

  • Stands as a generic event-based server library. (single-thread)
  • Embeddable library module - you write main().
  • Pluggable protocol handlers.
  • Complete HTTP protocol handler. (support chunked transfer-encoding)
  • Support request pipelining.
  • Support multiple hooks.
  • Support SSL - Just flip the switch on.
  • Support IPv4, IPv6 and Unix Socket.
  • Simple to use - Check out examples.

Compile & Install.

$ git clone https://github.com/wolkykim/libasyncd
$ cd libasyncd
$ ./configure
# If using system wide install of qlibc, add QLIBC=system to make install command
$ make install

API Reference

"Hello World", Asynchronous Socket Server example.

int my_conn_handler(short event, ad_conn_t *conn, void *userdata) {
    if (event & AD_EVENT_WRITE) {
        evbuffer_add_printf(conn->out, "Hello World.");
        return AD_CLOSE;
    }
    return AD_OK;
}

int main(int argc, char **argv) {
    ad_log_level(AD_LOG_DEBUG);
    ad_server_t *server = ad_server_new();
    ad_server_set_option(server, "server.port", "2222");
    ad_server_register_hook(server, my_conn_handler, NULL);
    return ad_server_start(server);
}

"Hello World", Asynchronous HTTPS Server example.

int my_http_get_handler(short event, ad_conn_t *conn, void *userdata) {
    if (event & AD_EVENT_READ) {
        if (ad_http_get_status(conn) == AD_HTTP_REQ_DONE) {
            ad_http_response(conn, 200, "text/html", "Hello World", 11);
            return ad_http_is_keepalive_request(conn) ? AD_DONE : AD_CLOSE;
        }
    }
    return AD_OK;
}

int my_http_default_handler(short event, ad_conn_t *conn, void *userdata) {
    if (event & AD_EVENT_READ) {
        if (ad_http_get_status(conn) == AD_HTTP_REQ_DONE) {
            ad_http_response(conn, 501, "text/html", "Not implemented", 15);
            return AD_CLOSE; // Close connection.
        }
    }
    return AD_OK;
}

int main(int argc, char **argv) {

    SSL_load_error_strings();
    SSL_library_init();

    ad_log_level(AD_LOG_DEBUG);
    ad_server_t *server = ad_server_new();
    ad_server_set_option(server, "server.port", "8888");
    ad_server_set_ssl_ctx(server, ad_server_ssl_ctx_create_simple("ssl.cert", "ssl.pkey"));
    ad_server_register_hook(server, ad_http_handler, NULL); // HTTP Parser is also a hook.
    ad_server_register_hook_on_method(server, "GET", my_http_get_handler, NULL);
    ad_server_register_hook(server, my_http_default_handler, NULL);

    return ad_server_start(server);
}

Please refer sample codes such as echo example in examples directory for more details.

References

Contributors

The following people have helped with suggestions, ideas, code or fixing bugs: (in alphabetical order by first name)

Please send a PR for adding your name here, so we know whom to appreciate. Thanks to all the contributors.

Comments
  • Access to SSL_CTX

    Access to SSL_CTX

    Hi,

    I'm trying to write SSL server using your library and I intend to heavily customize SSL context. The issue I'm having is that SSL_CTX is only available when server is started. This poses two issues for me:

    • SSL server starts with some default configuration and will run with configuration for a brief moment meaning it in theory will be able to accept SSL connections before all security settings are applied. This is miniscule but still security flaw in the design.
    • OpenSSL documentation is explicitly suggest against modifying SSL_CTX after it had been used to create SSL sessions, which is always a possibility with the current API.

    Here are some suggestions you may consider:

    • leave it to the API user to create an SSL_CTX of their liking.
    • pass the SSL_CTX to ad_server_start() or as an option of ad_server (or NULL if no SSL support is needed).
    • remove server.enable_ssl, server.ssl_cert, server.ssl_pkey server options
    • optionally, provide an utility method to create simple SSL_CTX as a starting point for simple applications, something along these lines SSL_CTX *ad_create_ssl_context (const char *cert_path, const char *priv_key_path).
    opened by dtoubelis 5
  • Install does not install transitively-required headers

    Install does not install transitively-required headers

    When including asyncd/ad_server.h it complains about qlibc's headers. Can you also install qlibc if it is not already there, when you do make install? Otherwise you get an unusable install.

    opened by dascandy 4
  • libasyncd + Free Pascal, is it possible?

    libasyncd + Free Pascal, is it possible?

    Hello,

    Firstly, thanks for share this nice library, I did some tests (using helloworld_http_server demo) with JMeter and I'm impressed with libasyncd performance, it's so fast like Civetweb HTTP server and NodeJS! =)

    However, I don't know C, so I can't understand libasyncd sources to check about this possibility: to use the libasyncd.so/dll to create a HTTP/HTTPS server with Free Pascal [¹].

    [¹] Creating bindings for C libraries.

    opened by silvioprog 4
  • segfault on ad_server_free()

    segfault on ad_server_free()

    Hello, to make a simple testcase, modify helloworld_http_server.c:

    int my_http_get_handler(short event, ad_conn_t *conn, void *userdata) {
        struct ad_http_s *http;
        if (ad_http_get_status(conn) == AD_HTTP_REQ_DONE) {
            // get the http struct pointer
            http = ad_conn_get_extra(conn);
            // check if the request matches our shutdown command
            if (strcmp("/SHUTDOWN",http->request.path) == 0) {
              ad_http_set_response_header(conn,"Content-Length","13");
              ad_http_response(conn, 200, "text/plain", "Shutting down", 13);
              ad_server_stop(conn->server);
            } else {
              ad_http_response(conn, 200, "text/html", "Hello World", 11);
            }
            return ad_http_is_keepalive_request(conn) ? AD_DONE : AD_CLOSE;
        }
        return AD_OK;
    }
    

    and in main:

    int main(int argc, char **argv) {
        int rc;
        ad_log_level(AD_LOG_DEBUG);
        ad_server_t *server = ad_server_new();
        ad_server_set_option(server, "server.port", "8888");
        // set a timeout, so the client actually renders the content
        ad_server_set_option(server, "server.timeout", "2");
        ad_server_register_hook(server, ad_http_handler, NULL); // HTTP Parser is also a hook.
        ad_server_register_hook_on_method(server, "GET", my_http_get_handler, NULL);
        ad_server_register_hook(server, my_http_default_handler, NULL);
        rc = ad_server_start(server);
        ad_server_free(server);
        return rc;
    }
    

    Start the server. Issue a test request for '/'. Get 'Hello World'. Issue a request for '/SHUTDOWN'. Get 'Shutting down'. Here's the last few lines of the log output:

    [DEBUG] Connection closed. [conn_cb(),ad_server.c:751]
    [DEBUG] Existing loop. [notify_cb(),ad_server.c:503]
    [DEBUG] Loop finished [server_loop(),ad_server.c:512]
    [DEBUG] Closing server. [close_server(),ad_server.c:519]
    [INFO] Server closed.
    [DEBUG] Server terminated. [ad_server_free(),ad_server.c:330]
    Segmentation fault
    

    uname -a: Linux sgmtech 3.2.0-4-686-pae #1 SMP Debian 3.2.65-1+deb7u2 i686 GNU/Linux distro : Debian 7, stock kernel. Libevent version: 2.0.19-stable

    opened by tarkin000 4
  • possible memory leak in ad_http_get_content

    possible memory leak in ad_http_get_content

    I am occasionally getting extra characters when using ad_http_get_content.

    post = ad_http_get_content(conn, http->request.contentlength, 0);

    Below is a screenshot. Also, that is not a real API key.

    image

    Most of the time it is just gibberish. I have seen the domain name appended to post. See screenshot below:

    image

    I'm afraid there is a memory leak in my code or the ad_http_get_content function.

    I am using SSL. If you need to see my code, it's currently in a private repo, but I can add you to it.

    Thanks!

    opened by levidurfee 3
  • Update ad_server_ssl_ctx_create_simple()

    Update ad_server_ssl_ctx_create_simple()

    SSL_CTX_use_certificate_chain_file() should be used instead of the SSL_CTX_use_certificate_file() function in order to allow the use of complete certificate chains even when no trusted CA storage is used or when the CA issuing the certificate shall not be added to the trusted CA storage.

    According to OpenSSL docs.

    opened by levidurfee 2
  • Trying asyncd on Windows

    Trying asyncd on Windows

    Hello,

    Is asyncd library compilable on Windows? I'm trying to compile it, but:

    fatal error: arpa/inet.h: No such file or directory
    

    Based in this error, so I believe that it is only for Unix systems.

    Thank you!

    opened by silvioprog 2
  • Segfault when using OpenSSL with HTTP handler

    Segfault when using OpenSSL with HTTP handler

    I'm getting a segfault when using SSL mode. Here is a trace from gdb:

    ...
    [DEBUG] conn_cb: status:0x0, event:0x4 [conn_cb(),ad_server.c:724]
    [DEBUG] call_hooks: event 0x4 [call_hooks(),ad_server.c:758]
    [DEBUG] ==> HTTP WRITE [ad_http_handler(),ad_http_handler.c:101]
    [DEBUG] call_hooks: event 0x8 [call_hooks(),ad_server.c:758]
    [DEBUG] ==> HTTP CLOSE=8 (TIMEOUT=0, SHUTDOWN=0) [ad_http_handler(),ad_http_handler.c:105]
    [DEBUG] Connection closed. [conn_cb(),ad_server.c:751]
    
    Program received signal SIGSEGV, Segmentation fault.
    [Switching to Thread 0x7fffb3fff700 (LWP 21411)]
    0x00007ffff672e9e6 in evbuffer_get_length () from /usr/lib/libevent-2.0.so.5
    (gdb) bt
    #0  0x00007ffff672e9e6 in evbuffer_get_length () from /usr/lib/libevent-2.0.so.5
    #1  0x0000000000421dbc in ad_http_send_header (conn=<optimized out>) at ad_http_handler.c:345
    #2  0x0000000000422078 in ad_http_send_data (conn=0x7fffac006160, data=0x42b17a, size=11) at ad_http_handler.c:367
    #3  0x000000000040d51f in _http_get_handler (event=2, conn=0x7fffac006160, userdata=0x0) at ak-http-connector.c:80
    #4  0x000000000041f6f6 in call_hooks (event=2, conn=0x7fffac006160) at ad_server.c:769
    #5  0x00000000004204ec in conn_cb (conn=0x7fffac006160, event=2) at ad_server.c:726
    #6  0x00007ffff6963369 in ?? () from /usr/lib/libevent_openssl-2.0.so.5
    #7  0x00007ffff696397a in ?? () from /usr/lib/libevent_openssl-2.0.so.5
    #8  0x00007ffff6963a08 in ?? () from /usr/lib/libevent_openssl-2.0.so.5
    #9  0x00007ffff67299cc in event_base_loop () from /usr/lib/libevent-2.0.so.5
    #10 0x000000000041f5b1 in server_loop (instance=0x650700) at ad_server.c:511
    #11 0x00007ffff6145e9a in start_thread () from /lib/x86_64-linux-gnu/libpthread.so.0
    #12 0x00007ffff644e8bd in clone () from /lib/x86_64-linux-gnu/libc.so.6
    #13 0x0000000000000000 in ?? ()
    

    The test program is the one from README.md with minor tweaks to SSL_CTX_*. The code is executed on Ubuntu 12.04. And requests are generated from https://www.ssllabs.com/ssltest/index.html.

    Any ideas?

    opened by dtoubelis 2
  • Added rudimentary support for the BSD and Mac OS family of operating …

    Added rudimentary support for the BSD and Mac OS family of operating …

    …systems. Currently uses ifdef's; future revisions may abstract into an interface.

    This change was tested on FreeBSD and Arch Linux. The Linux version still uses eventfd as before, but the BSD version uses kqueue, which in theory is supported across FreeBSD, NetBSD and OpenBSD as well as Mac OS X.

    opened by spbruner 1
  • Add -D_FILE_OFFSET_BITS=64 flag to Makefile

    Add -D_FILE_OFFSET_BITS=64 flag to Makefile

    Some places like https://github.com/wolkykim/libasyncd/blob/40768e1adc67c9fc700541a9a69166b45e78f403/src/ad_http_handler.c#L279 are assuming that off_t is 64bits which by default is not the case when compiling on 32 bits. Adding -D_FILE_OFFSET_BITS=64 to the Makefile.in.

    Without it, Content-Length (to name one) is broken:

    $ curl -I http://localhost:1337
    HTTP/1.1 200 OK
    Content-Length: 47244640258
    Content-Type: text/plain
    Connection: Keep-Alive
    
    opened by Reflejo 1
  • fix makefile

    fix makefile

    • fix submake calls
    • fix missing DESTDIR
    • adding makefile option QLIBC to wether or not recover qlibc at compile time (call "make QLIBC=system" to NOT recover qlibc)
    • modifying README concequently
    opened by kakwa 1
  • Use Libasyncd in more then one thread

    Use Libasyncd in more then one thread

    Hello there! I'm currently trying to write multithreaded servers in C++ and decided to use Libasyncd, as it seemed simple and straightforward to work with. I already managed to write a simple http server following the examples, but it looks like your library only allows it to work in one thread. I also tried changing the "server.thread" setting to "1", but this just caused the server to stop working without any errors. Apparently, it is not sent to a separate thread, as well as it is not launched in several threads, since when sending a request into the url of my server, I get "Connection refused". So, my question is:

    1. (most importantly) is it possible to use this library to start the server in several(let's say in 4) threads, without running the code 4 times in 4 different sessions?
    2. what is the "server.thread" parameter responsible for, how should it work, and when should it be used? This was not clear from the documentation.
    3. if you can't use multithreading using the library, can you suggest different ways to solve this problem?

    I would be very grateful if I get answers to these questions! Thank you!

    opened by Roma004 0
  • crash while calling ad_server_stop

    crash while calling ad_server_stop

    Hi, i have started 6 server threads which are running independantly, and there is a need for me to stop them at some instance of execution. while i was invoking the function ad_server_stop(server*) the code was getting stuck at : pthread_join function. "Waiting server's last loop to finish"

    But after modifying the code like below it started working. if (server->thread) { void *retval = NULL; DEBUG("Waiting server's last loop to finish."); pthread_join((server->thread), &retval); //// earlier the argument to this function was (*pthread_t) which is wrong , it should be just pthread_t. free(retval); free(server->thread); server->thread = NULL; }

    opened by manjunathkokhle 1
  • Can you add a https file server example?

    Can you add a https file server example?

    Hey.

    I've been looking for a c/c++ library that can be used to make a https web server.

    How do I combine the SSL and http server examples so that I can make an https server?

    Best,

    Rick

    opened by ClemsonCoder 2
  • Vulnerability: Define a maximum length for requests

    Vulnerability: Define a maximum length for requests

    I was starting to implement a simple HTTP application using libsyncd when I noticed currently there seems to be no mechanism to limit the size of requests. This can be exploited by an attacker by sending an arbitrary amount of data to a server. While the user may provide code to impose a limit for simple TCP it seems to me that is not the case for HTTP requests using ad_http_handler().

    Explanation

    To process a HTTP request ad_http_handler() can be used. This function calls http_parser(), which returns AD_TAKEOVER except when the request is complete (both header and body have been received). Therefore, the user's callbacks are not called while the request is not complete, which means

    • the user cannot verify how much data has been received;
    • all the received data will stay in the RAM while the request is not complete (since the user's callbacks aren't called to process the data).

    This leads to a simple attack vector enabling to exhaust the memory of a server.

    Mitigation

    The best way I could think of to mitigate this vulnerability (of course you might have a better one) is to define a maximum request length per server. A default value should be provided (for example 10 MB) which the user could override with ad_server_set_option(). This would "protect" both raw TCP and HTTP(S) applications.

    At first I thought of rejecting requests based on the Content-Length header, but

    • raw TCP would be left unprotected (unless the user implemented a limit, which he might not do because he did not thing about this type of attack)
    • Content-Length refers only to the body of the request, meaning the headers would still be vulnerable
    • Content-Length is not absolutely required by HTTP/1.1

    However, using the content length header might still be useful for early rejections: for example if Content-Length states the body will contain 1 GB but our server only accepts 10 MB then the request could be rejected right away.

    As a last note: when refusing a HTTP request for being too long, a response with a HTTP 413 status code could be sent before closing the connection (so that the client is not left in the dark as to why it was closed).


    I hope this can help improving the security of libasyncd :)

    opened by goncalor 0
  • Are more than one protocol without threads possible?

    Are more than one protocol without threads possible?

    Is it (somewhat easily) possible to have different callbacks registered on different ports (e.g.because the implement different protocols) without threads? And for this, one needs to (also) hook some buffer transfer logic as the daemon mustn't block.

    So the basic idea is:

    • register various callbacks to various (different) ports
    • the callbacks are called if data is available. the callback functions buffer the data and handle it, if enough data is here (e.a. a complete request).
    • the response is constructed (non-blocking) and stored in some buffer (and is gradually transmitted).

    Using threads just adds the complexity for internal explicit synchronization ....

    opened by berndpetrovitsch 1
  • How to close a connection in a seperate thread

    How to close a connection in a seperate thread

    Hello,

    I'm using this library in a multithreaded environment. When a new request arrives I add a new thread in a Thread pool. I managed to write from here using evbuffer_add.

    I managed to do something by setting userdata. and at every event I check the content to know if I should return AD_CLOSE.

    Is there a better way to do this ?

    Thanks a lot

    opened by GuillaumeLeclerc 2
Releases(v1.0.2)
  • v1.0.2(Jan 23, 2017)

    v1.0.2 is a maintenance release with following updates.

    • support of ssl cert chain file
    • support of bsd system

    Thanks a lot!

    Seungyoung "Steve" Kim

    Source code(tar.gz)
    Source code(zip)
  • v1.0.1(Dec 16, 2015)

    Hi,

    I'm pleased to announce v1.0.1 of libasyncd. Thank you all the contributors who helped improving libasyncd.

    Changes

    • fix memory leak
    • improve with sample codes.
    • improve SSL_CTX handling
    • improve makefile
    • add sub-library installation support

    Merry Christmas & Happy New Year 2016. Thank you.

    Seungyoung "Steve" Kim

    Source code(tar.gz)
    Source code(zip)
  • v1.0.0(Apr 18, 2014)

  • v0.9.0(Apr 6, 2014)

cserv is an event-driven and non-blocking web server

cserv is an event-driven and non-blocking web server. It ideally has one worker process per cpu or processor core, and each one is capable of handling thousands of incoming network connections per worker. There is no need to create new threads or processes for each connection.

null 43 Nov 6, 2022
Experimental, scalable, high performance HTTP server

Lwan Web Server Lwan is a high-performance & scalable web server. The project web site contains more details. Build status OS Arch Release Debug Stati

Leandro A. F. Pereira 5.7k Jan 9, 2023
A http/websocket server framework on linux.

The framework is a Web-Server on unix based system. Without using any third-party libraries, the framework writes from unix system calls and standard C library functions.

xingyuuchen 17 Oct 15, 2022
Corvusoft's Restbed framework brings asynchronous RESTful functionality to C++14 applications.

Restbed Restbed is a comprehensive and consistent programming model for building applications that require seamless and secure communication over HTTP

Corvusoft 1.8k Jan 7, 2023
C++ Parallel Computing and Asynchronous Networking Engine

中文版入口 Sogou C++ Workflow As Sogou`s C++ server engine, Sogou C++ Workflow supports almost all back-end C++ online services of Sogou, including all sea

Sogou-inc 9.7k Dec 29, 2022
Drogon: A C++14/17 based HTTP web application framework running on Linux/macOS/Unix/Windows

English | 简体中文 | 繁體中文 Overview Drogon is a C++14/17-based HTTP application framework. Drogon can be used to easily build various types of web applicat

An Tao 8.5k Dec 31, 2022
C library to create simple HTTP servers and Web Applications.

Onion http server library Travis status Coverity status Onion is a C library to create simple HTTP servers and Web Applications. master the developmen

David Moreno Montero 1.9k Dec 31, 2022
bittyhttp - A threaded HTTP library for building REST services in C.

bittyhttp - A threaded HTTP library for building REST services in C.

Colin Luoma 12 Nov 29, 2021
A high performance, middleware oriented C++14 http web framework please use matt-42/lithium instead

A high performance, middleware oriented C++14 http web framework please use matt-42/lithium instead

Matthieu Garrigues 1.7k Dec 17, 2022
Pistache is a modern and elegant HTTP and REST framework for C++

Pistache is a modern and elegant HTTP and REST framework for C++. It is entirely written in pure-C++17* and provides a clear and pleasant API.

null 2.8k Jan 4, 2023
A C++11 RESTful web server library

Served Overview Served is a C++ library for building high performance RESTful web servers. Served builds upon Boost.ASIO to provide a simple API for d

Meltwater 696 Dec 28, 2022
Embedded C/C++ web server

CivetWeb The official home of CivetWeb is https://github.com/civetweb/civetweb Continuous integration for Linux and macOS (Travis CI): Continuous inte

null 2.3k Jan 8, 2023
A lightweight Bedorck Dedicated Server Plugin Loader

LiteLoader 简体中文 A lightweight Bedorck Dedicated Server Plugin Loader Based on BedrockX Install Download LiteLoader from Releases or Actions, unzip it

null 572 Dec 31, 2022
Tntnet is a web application server for web applications written in C++.

Tntnet is a web application server for web applications written in C++.

Tommi Mäkitalo 73 Sep 26, 2022
QDjango, a Qt-based C++ web framework

QDjango - a Qt-based C++ web framework Copyright (c) 2010-2015 Jeremy Lainé About QDjango is a web framework written in C++ and built on top of the Qt

Jeremy Lainé 249 Dec 22, 2022
a very based, minimal, and flexible static site generator written in pure C89 with no external deps.

based-ssg is a very based, minimal, and flexible static site generator written in pure C89 with no external deps.

null 15 Dec 22, 2022
Support for multiple RPC protocols in a single library

AnyRPC A multiprotocol remote procedure call system for C++ Overview AnyRPC provides a common system to work with a number of different remote procedu

Steve Gieseking 56 Nov 17, 2022