coldforce
1.0.0
Coldforce is a library written in C that supports various network protocols. With the asynchronous API of this library You can easily develop event-driven network applications. The currently supported protocols are as follows. All of these support clients and servers (multi-client, C10K).
C99 or later
Use -pthread
-lm
OpenSSL or wolfSSL (only when using TLS, https and wss)
wolfSSL build options
IDE
#define OPENSSL_EXTRA
#define OPENSSL_ALL
#define HAVE_ALPN
#define HAVE_SNI
#define WOLFSSL_SYS_CA_CERTS
#define WOLFSSL_DTLS
#define WOLFSSL_DTLS13
mkdir inc/wolfssl
copy your user_settings.h to inc/wolfssl/.
configure
--enable-opensslextra --enable-opensslall --enable-alpn --enable-sni --enable-sys-ca-certs --enable-dtls --enable-dtls13
co_core.dll
/ libco_core.a
co_net.dll
/ libco_net.a
co_tls.dll
/ libco_tls.a
co_http.dll
/ libco_http.a
co_http2.dll
/ libco_http2.a
co_ws.dll
, co_ws_http2.dll
/ libco_ws.a
, libco_ws_http2.a
Windows Visual Studio (prj/msvc/coldforce.sln)
for wolfSSL
Add CO_USE_WOLFSSL
to C/C++ Preprocessor Definitions
in both co_tls and your project property.
Linux cmake
cd build
cmake ..
make
for wolfSSL
...
cmake .. -DTLS_LIB=wolfssl
...
macOS cmake (same way as Linux)
WebSocket client
#include <coldforce.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
co_app_t base_app;
co_ws_client_t* ws_client;
co_url_st* url;
} app_st;
void
app_on_ws_receive_frame(
app_st* self,
co_ws_client_t* ws_client,
const co_ws_frame_t* frame,
int error_code
)
{
if (error_code == 0)
{
bool fin = co_ws_frame_get_fin(frame);
uint8_t opcode = co_ws_frame_get_opcode(frame);
size_t data_size = (size_t)co_ws_frame_get_payload_size(frame);
const uint8_t* data = co_ws_frame_get_payload_data(frame);
switch (opcode)
{
case CO_WS_OPCODE_TEXT:
{
printf("receive text(%d): %*.*sn", fin,
(int)data_size, (int)data_size, (char*)data);
break;
}
case CO_WS_OPCODE_BINARY:
{
printf("receive binary(%d): %zu bytesn",
fin, data_size);
break;
}
case CO_WS_OPCODE_CONTINUATION:
{
printf("receive continuation(%d): %zu bytesn",
fin, data_size);
break;
}
default:
{
co_ws_default_handler(ws_client, frame);
break;
}
}
}
else
{
co_ws_client_destroy(ws_client);
self->ws_client = NULL;
}
}
void
app_on_ws_close(
app_st* self,
co_ws_client_t* ws_client
)
{
co_ws_client_destroy(ws_client);
self->ws_client = NULL;
co_app_stop();
}
void
app_on_ws_upgrade(
app_st* self,
co_ws_client_t* ws_client,
const co_http_response_t* response,
int error_code
)
{
if (error_code == 0)
{
co_ws_send_text(ws_client, "hello");
}
else
{
co_ws_client_destroy(ws_client);
self->ws_client = NULL;
co_app_stop();
}
}
void
app_on_ws_connect(
app_st* self,
co_ws_client_t* ws_client,
int error_code
)
{
if (error_code == 0)
{
co_http_request_t* request =
co_http_request_create_ws_upgrade(self->url->path_and_query, NULL, NULL);
co_ws_send_upgrade_request(self->ws_client, request);
}
else
{
co_ws_client_destroy(ws_client);
self->ws_client = NULL;
co_app_stop();
}
}
bool
app_on_create(
app_st* self
)
{
self->url = co_url_create("ws://127.0.0.1:8080/");
co_net_addr_t local_net_addr = { 0 };
co_net_addr_set_family(&local_net_addr, CO_NET_ADDR_FAMILY_IPV4);
self->ws_client = co_ws_client_create(self->url->origin, &local_net_addr, NULL);
if (self->ws_client == NULL)
{
return false;
}
co_ws_callbacks_st* callbacks = co_ws_get_callbacks(self->ws_client);
callbacks->on_connect = (co_ws_connect_fn)app_on_ws_connect;
callbacks->on_upgrade = (co_ws_upgrade_fn)app_on_ws_upgrade;
callbacks->on_receive_frame = (co_ws_receive_frame_fn)app_on_ws_receive_frame;
callbacks->on_close = (co_ws_close_fn)app_on_ws_close;
co_ws_start_connect(self->ws_client);
return true;
}
void
app_on_destroy(
app_st* self
)
{
co_ws_client_destroy(self->ws_client);
co_url_destroy(self->url);
}
int
main(
int argc,
char* argv[]
)
{
app_st self = { 0 };
return co_net_app_start(
(co_app_t*)&self, "ws-client-app",
(co_app_create_fn)app_on_create,
(co_app_destroy_fn)app_on_destroy,
argc, argv);
}
WebSocket echo server -> ws://127.0.0.1:8080
#include <coldforce.h>
typedef struct {
co_app_t base_app;
co_tcp_server_t* tcp_server;
co_list_t* ws_clients;
} app_st;
void
app_on_ws_receive_frame(
app_st* self,
co_ws_client_t* ws_client,
const co_ws_frame_t* frame,
int error_code
)
{
if (error_code == 0)
{
bool fin = co_ws_frame_get_fin(frame);
uint8_t opcode = co_ws_frame_get_opcode(frame);
size_t data_size = (size_t)co_ws_frame_get_payload_size(frame);
const uint8_t* data = co_ws_frame_get_payload_data(frame);
switch (opcode)
{
case CO_WS_OPCODE_TEXT:
case CO_WS_OPCODE_BINARY:
case CO_WS_OPCODE_CONTINUATION:
{
co_ws_send(ws_client, fin, opcode, data, data_size);
break;
}
default:
{
co_ws_default_handler(ws_client, frame);
break;
}
}
}
else
{
co_list_remove(self->ws_clients, ws_client);
}
}
void
app_on_ws_close(
app_st* self,
co_ws_client_t* ws_client
)
{
co_list_remove(self->ws_clients, ws_client);
}
void
app_on_ws_upgrade(
app_st* self,
co_ws_client_t* ws_client,
const co_http_request_t* http_request,
int error_code
)
{
if (error_code == 0)
{
co_http_response_t* http_response =
co_http_response_create_ws_upgrade(http_request, NULL, NULL);
co_http_connection_send_response(
(co_http_connection_t*)ws_client, http_response);
co_http_response_destroy(http_response);
}
else
{
co_list_remove(self->ws_clients, ws_client);
}
}
void
app_on_tcp_accept(
app_st* self,
co_tcp_server_t* tcp_server,
co_tcp_client_t* tcp_client
)
{
co_tcp_accept((co_thread_t*)self, tcp_client);
co_ws_client_t* ws_client = co_tcp_upgrade_to_ws(tcp_client, NULL);
co_ws_callbacks_st* callbacks = co_ws_get_callbacks(ws_client);
callbacks->on_upgrade = (co_ws_upgrade_fn)app_on_ws_upgrade;
callbacks->on_receive_frame = (co_ws_receive_frame_fn)app_on_ws_receive_frame;
callbacks->on_close = (co_ws_close_fn)app_on_ws_close;
co_list_add_tail(self->ws_clients, ws_client);
}
bool
app_on_create(
app_st* self
)
{
uint16_t port = 8080;
co_list_ctx_st list_ctx = { 0 };
list_ctx.destroy_value = (co_item_destroy_fn)co_ws_client_destroy;
self->ws_clients = co_list_create(&list_ctx);
co_net_addr_t local_net_addr = { 0 };
co_net_addr_set_family(&local_net_addr, CO_NET_ADDR_FAMILY_IPV4);
co_net_addr_set_port(&local_net_addr, port);
self->tcp_server = co_tcp_server_create(&local_net_addr);
co_socket_option_set_reuse_addr(
co_tcp_server_get_socket(self->tcp_server), true);
co_tcp_server_callbacks_st* callbacks =
co_tcp_server_get_callbacks(self->tcp_server);
callbacks->on_accept = (co_tcp_accept_fn)app_on_tcp_accept;
return co_tcp_server_start(self->tcp_server, SOMAXCONN);
}
void
app_on_destroy(
app_st* self
)
{
co_tcp_server_destroy(self->tcp_server);
co_list_destroy(self->ws_clients);
}
int
main(
int argc,
char* argv[]
)
{
app_st self = { 0 };
return co_net_app_start(
(co_app_t*)&self, "ws-server-app",
(co_app_create_fn)app_on_create,
(co_app_destroy_fn)app_on_destroy,
argc, argv);
}
more examples here