-
Notifications
You must be signed in to change notification settings - Fork 1
These docs are hastily thrown together as a temporary help to any who might use this library.
First, I will go over a very basic echo server using libwebsock. The echo server simply accepts WebSocket clients and replies to any text messages sent by the client with the exact same message that was sent.
After installing the library (covered in INSTALL.txt), we must make sure to include <websock/websock.h> in our server program.
The most minimalistic echo server follows:
#include <stdio.h>
#include <websock/websock.h>
int main(int argc, char **argv) {
libwebsock_context *ctx = NULL;
ctx = libwebsock_init();
if(ctx == NULL) {
fprintf(stderr, "Error during libwebsock_init.\n");
exit(1);
}
libwebsock_bind(ctx, "0.0.0.0", "8080");
libwebsock_wait(ctx);
}
First we define a pointer to a libwebsock_context named 'ctx'. libwebsock_init allocates memory for the actual structure and sets up a basic context with some default callbacks. We check for NULL, to see if libwebsock_init failed or not. Then, we must tell libwebsock to bind itself to a certain IP address and port. If your server has only one IP address or you want to listen on all IP addresses, just use "0.0.0.0" for the address. In this instance, I've used "8080" as the port number. Finally, we call libwebsock_wait supplying the context as a parameter and libwebsock will take over from there. libwebsock uses libevent to monitor sockets and perform it's work when data is available to be read or written.
The above isn't very useful if you'd like to actually like to do something useful with your WebSocket server. In order to allow the programmer some flexibility, libwebsock allows you to set callbacks to be executed when certain events occur. For example, you might receive a WebSocket message from one of your connected clients or you might like to perform some work each time a new client connects.
Let's take a look at the onmessage callback prototype and how to register a new one. The prototype for the receive callback follows:
int some_callback_name(libwebsock_client_state *state, libwebsock_message *msg);
So the function you define will accept a pointer to a libwebsock_client_state and a pointer to libwebsock_message. When a new message is received by libwebsock, it generates these structures in memory and will then call the registered callback supplying them as arguments.
Useful fields in libwebsock_client_state are int sockfd and void *data. sockfd is the socket descriptor for this connection. The void pointer data can be used by your code to store a pointer to your own structure that will be available in your callbacks. libwebsock_message has an unsigned int opcode which contains the opcode for the message. The opcode is usually 1 which means it's a text message and not binary). It also has an unsigned long long payload_len and char *payload. payload_len tells you how much data was actually received and payload contains the message received from the client as a character array. So, let's look at the default receive callback which just echoes the received message.
int libwebsock_default_receive_callback(libwebsock_client_state *state, libwebsock_message *msg) {
libwebsock_send_text(state, msg->payload);
return 0;
}
This callback is taken straight out of default_callbacks.c and is what gets registered in libwebsock_init(). It simply calls libwebsock_send_text with the libwebsock_client_state structure of the client to send the message to and the character array of the message to send.
If you define your own receive callback named my_receive_callback.
You would then have to tell libwebsock about it before calling
libwebsock_wait(). You would do so by setting the context's
onmessage pointer, like so:
libwebsock_context *ctx = libwebsock_init();
ctx->onmessage = my_receive_callback; //my_receive_callback points to your callback function
libwebsock_bind(ctx, "0.0.0.0", "8080");
libwebsock_wait(ctx);
There are a couple of other callbacks which are useful:
The connect callback which gets fired every time a new client connects.
int some_connect_cb(libwebsock_client_state *state) {
fprintf(stderr, "New connection with socket descriptor: %d\n", state->sockfd);
return 0;
}
ctx->onopen = some_connect_cb;
The close callback which gets fired when a connected client closes the connection.
int some_close_cb(libwebsock_client_state *state) {
fprintf(stderr, "Client closed connection: %d\n",state->sockfd);
return 0;
}
ctx->onclose = some_close_cb;
It should also be noted that during the close callback, one can check for the existence of a close_info structure belonging to the libwebsock_client_state. See the following example:
int some_close_cb(libwebsock_client_state *state) {
fprintf(stderr, "Client closed connection: %d\n", state->sockfd);
if(state->close_info) {
fprintf(stderr, "We received a code and/or reason for close from client.\n");
fprintf(stderr, "Code: %hi\n", state->close_info->code);
fprintf(stderr, "Reason: %s\n", state->close_info->reason);
}
return 0;
}
There is also a control callback which deals with handling control frames, but that can get a little dicey and you'd probably want to study the source code and RFC 6455 before tackling that one. The default control callback just responds to close frames in the appropriate manner and you can view it in default_callbacks.c.
Okay, now the rest of this is only going to be technical information about the functions exported by the library that can be used by your program.
void libwebsock_dump_frame(libwebsock_frame *frame);
Dumps information about the supplied libwebsock_frame to stderr.
int libwebsock_close(libwebsock_client_state *state);
Sends close frame to client and closes underlying TCP connection. The code sent in the close frame is 1000 which is a code stating that the WebSocket has performed its function and is closing normally. In libwebsock, WS_CLOSE_NORMAL is defined as 1000. You can see other close codes in websock.h. libwebsock_close is a wrapper function and calls libwebsock_close_with_reason(state, WS_CLOSE_NORMAL, NULL).
int libwebsock_close_with_reason(libwebsock_client_state *state, unsigned short code, const char *reason);
Sends close frame to client and closes underlying TCP connection. The code sent in the close frame is specified by the unsigned short integer 'code'. If reason is not NULL, it is also sent in the close frame as the close reason.
int libwebsock_send_binary(libwebsock_client_state *state, char *in_data, unsigned long long payload_len);
Sends a binary type message to socket descriptor sockfd of length payload_len with data being in_data.
int libwebsock_send_text(libwebsock_client_state *state, char *strdata);
Sends a text type message to socket descriptor sockfd with text from strdata.
int libwebsock_send_all_text(libwebsock_context *ctx, char *strdata);
Sends a text type message to all currently connected clients with text from strdata.
void libwebsock_wait(libwebsock_context *ctx);
Endless loop function that uses libevent to handle incoming data and process it appropriately. This function is called last and is what makes libwebsock tick.
void libwebsock_bind(libwebsock_context *ctx, char *listen_host, char *port);
This function is called prior to libwebsock_wait and binds a listening socket to the supplied ip address and port. It also adds this socket to the list of sockets that will be monitored by libevent in libwebsock_wait.
void libwebsock_bind_ssl(libwebsock_context *ctx, char *listen_host,
char *port, char *keyfile, char *certfile);
This function is called prior to libwebsock_wait and binds a listening socket to the supplied ip address and port. It also adds this socket to the list of sockets that will be monitored by libevent in libwebsock_wait. This function also flags the listener as SSL enabled and only SSL clients should connect to this port.
void libwebsock_bind_ssl_real(libwebsock_context *ctx,
char *listen_host, char *port, char *keyfile,
char *certfile, char *chainfile);
This is the real function behind libwebsock_bind_ssl. This function accepts the same parameters plus chainfile for certificate bundles. libwebsock_bind_ssl simply calls libwebsock_bind_ssl_real with chainfile set to NULL.
libwebsock_context *libwebsock_init(void);
This functions allocates memory for a libwebsock_context and initializes it with some defaults. It registers the default callbacks to be associated with this context. It also creates the libevent event_base which we add events to later.