This library includes a linux server implementation, and a client one.
It uses my other libraries (socket
, buffer
and lvector
) to run.
Each lclient_t
is usable in each index of server.clients.arr[i]
.
Each struct poll_event::data.ptr
member is a client_t *
You can use the lvector_foreach
API to loop in it
Everything is readable in it. The buffer is writeable using the cbuffer_t API
on client->buffer
.
Lserver example:
#include <stdlib.h>
#include <stdio.h>
#include <lserver.h>
static void say_hi(lserver_t *server, lclient_t *client, uint16_t port, void *userdata)
{
printf("Say hi to '%s' who joined the server on port %u\n", inet_ntoa(client->socket.saddr.sin_addr), port);
}
static void say_goodbye(lserver_t *server, lclient_t *client, void *userdata)
{
printf("'%s' left the server, goodbye !\n", inet_ntoa(client->socket.saddr.sin_addr));
}
int main(void)
{
lserver_t server = {0};
uint16_t ports[] = {
2121,
5555,
};
struct lserver_config config = {
.ports = ports,
.ports_count = 2,
.client_buffer_size = 65536,
.cbs.on_connect_callback = &say_hi,
.cbs.on_connect_userdata = NULL,
.cbs.on_disconnect_callback = &say_goodbye,
.cbs.on_disconnect_userdata = NULL,
.backlog = 5
};
lclient_t *ptr;
char *line;
/* Start the server on port 2121 and 5555, each client will have a circular buffer of 65536 bytes */
if (lserver_create(&server, &config) == -1) {
fprintf(stderr, "Failed to start server\n");
return (-1);
}
while (1) {
/* Gives 100 miliseconds to the server to update */
lserver_update(&server, 100);
/* For each event in the server read events */
lvector_foreach(evt, server.revents) {
/* implicit cast of the union in 'struct poll_event' into a 'lclient_t *' */
ptr = evt->data.ptr;
/* Read from the client buffer and store each byte into <line> until a "\n" is encountered */
ssize_t rd = lbuffer_getbytes(&ptr->buffer, &line, "\n");
/* on 'lbuffer_getbytes()' success */
if (rd > 0) {
/* removes the \n */
rd -= 1;
line[rd] = '\0';
/* print the length of the line and the line itself */
printf("Client: [%zd] \"%s\"\n", rd, line);
/* answer to the client */
dprintf(ptr->socket.fd, "Hello !");
}
/* Since 'lbuffer_getbytes()' uses MALLOC(3) to set 'line' value, it needs to be freed */
free(line);
}
}
/* Destroy the server, eject all clients, close all listeners, clean all buffers, free all memory */
lserver_destroy(&server);
return (0);
}
The other part of the library, which is partially used in the server part, includes a client implementation.
int main(void)
{
lclient_t client;
char *output;
/* Connect the client on the address specified as 3rd parameter on port `2121`, with a circular buffer of `4096` bytes
** an other function: `lclient_connect32()`, takes a `uint32_t` as ip address
*/
lclient_create(&client, 4096, "localhost", 2121);
/* Reads from the server and store the read bytes into the client's circular buffer and returns the amount of bytes read */
lclient_update(&client, 100); /* We give 100 milliseconds as timeout to the function */
/* Retrieve each bytes of the buffer, allocate enough space and copy them into the given pointer */
lbuffer_retrieve(&client.buffer, &output);
/* simply printf the output, we expect a human readable null-terminated string */
printf("%s\n", output);
/* `lbuffer_retrieve()` uses MALLOC(3), we need to `free()` it */
free(output);
/* destroy the client, close the connection and free allocated memory */
lclient_destroy(&client);
return (0);
}