ToyWS

Since there is some demand to support a client, 'ToyWS' is a response to those requests: ToyWS is a toy WebSocket client, meaning that it's quite simple and made to work (guaranteed) only with wsServer.

Limitations:

  • Fixed handshake header
  • Fixed frame mask (it should be random)
  • No PING/PONG frame support
  • No close handshake support: although it can identify CLOSE frames, it does not send the response, only aborts the connection.
  • No support for CONT frames, that is, the entire content of a frame (TXT or BIN) must be contained within a single frame.
  • Possibly other things too.

Although extremely limited, ToyWS was designed for those who want to also have a C client that is lightweight and compatible with wsServer, thus, freeing the need for a browser and/or third-party libraries to test and use wsServer.

Maybe this client will evolve into something more complete and general in the future, but that's not in the roadmap at the moment.

API

The API is quite simple and is summarized in 4 routines, to connect, disconnect, send and receive frame, as follows:

int tws_connect(struct tws_ctx *ctx, const char *ip, uint16_t port);

Connect to a given ip address and port.

Return: Returns a positive number if success, otherwise, a negative number.

Note: struct tws_ctx *ctx is for internal usage and initialized within this function. There is no need to access this structure or modify its values, ToyWS just needs it to maintain the consistent client state.


void tws_close(struct tws_ctx *ctx);

Close the connection for the given ctx.


int tws_sendframe(struct tws_ctx *ctx, uint8_t *msg, uint64_t size, int type);

Send a frame of type type with content msg and size size for a given context ctx.

Valid frame types are:

  • FRM_TXT
  • FRM_BIN

Return: Returns 0 if success, otherwise, a negative number.


int tws_receiveframe(struct tws_ctx *ctx, char **buff, size_t *buff_size,
    int *frm_type);

Receive a frame and save it on buff.

Parameters:

**buff:**

Pointer to the target buffer. If NULL, ToyWS will allocate a new buffer that is capable to hold the frame and save into buff.

If already exists: the function will try to fill the buffer with the frame content, if the frame size is bigger than buff_size, the function will reallocate buff and update buff_size with the new size.

**buff_size:**

Current buffer size. Must point the a valid memory region. If *buff points to NULL, *buff_size must be equals to 0.

**frm_type:**

Frame type read. The frame type received will be reflected into the contents of this pointer.

Return: Returns 0 if success, a negative number otherwise.

Note:

  • This routine is blocking, that is, it will only return if it manages to read a frame or if there is an error during the reading (such as invalid (or unsupported) frame or server disconnection).
  • At the end of everything, don't forget to free the buffer!. Once its size is relocated, a single call to 'free' is sufficient.

Example

The example below illustrates the usage (also available at (extra/toyws/tws_test.c)):

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "toyws.h"

int main(void)
{
    struct tws_ctx ctx;
    char msg[] = "Hello";

    /* Buffer/frame params. */
    char *buff;
    int frm_type;
    size_t buff_size;

    buff      = NULL;
    buff_size = 0;
    frm_type  = 0;

    if (tws_connect(&ctx, "127.0.0.1", 8080) < 0)
        fprintf(stderr, "Unable to connect!\n");

    /* Send message. */
    printf("Send: %s\n",
        (tws_sendframe(&ctx, msg, strlen(msg), FRM_TXT) >= 0 ?
            "Success" : "Failed"));

    /* Blocks until receive a single message. */
    if (tws_receiveframe(&ctx, &buff, &buff_size, &frm_type) < 0)
        fprintf(stderr, "Unable to receive message!\n");

    printf("I received: (%s) (type: %s)\n", buff,
        (frm_type == FRM_TXT ? "Text" : "Binary"));

    tws_close(&ctx);

    free(buff);
    return (0);
}