Program Listing for File server.h

Return to documentation for file (server/server.h)

#ifndef SERVER_H
    #define SERVER_H

    #include <limits.h>
    #include <stdbool.h>
    #include <stddef.h>
    #include <stdint.h>
    #include <sys/time.h>

    #include "server_args_parser.h"
    #include "client/client_manager.h"
    #include "utils/debug.h"

    #include "event.h"

    #define MAP_MAX_SIDE_SIZE 42

    #define LIKELY(cond) (__builtin_expect(!!(cond), 1))
    #define UNLIKELY(cond) (__builtin_expect(!!(cond), 0))

enum {
    RES_FOOD,
    RES_LINEMATE,
    RES_DERAUMERE,
    RES_SIBUR,
    RES_MENDIANE,
    RES_PHIRAS,
    RES_THYSTAME,

    RES_COUNT
};

typedef struct pollfd pollfd_t;

typedef union {
    struct {
        uint32_t food;
        uint32_t linemate;
        uint32_t deraumere;
        uint32_t sibur;
        uint32_t mendiane;
        uint32_t phiras;
        uint32_t thystame;
    };
    uint32_t qnts[RES_COUNT];
} inventory_t;

typedef struct {
    uint32_t hatch;
    uint8_t team_id;
    uint8_t id;
    uint8_t x;
    uint8_t y;
} egg_t;

// For the next 3 structures, we use a resizable array pattern
// to manage dynamic arrays of client states, eggs, and poll file descriptors.
// It requires the following memory layout in order to work:
// - buff: pointer to the allocated memory
// - nmemb: number of elements currently in the array
// - capacity: total capacity of the allocated memory
// This allows us to use the same functions for all three types of arrays.

typedef struct {
    client_state_t *buff;
    size_t nmemb;
    size_t capacity;
} client_state_array_t;

typedef struct {
    egg_t *buff;
    size_t nmemb;
    size_t capacity;
} egg_array_t;

typedef struct {
    pollfd_t *buff;
    size_t nmemb;
    size_t capacity;
} pollfd_array_t;

typedef struct server_s {
    int self_fd;
    volatile bool is_running;
    egg_array_t eggs;
    client_manager_t cm;
    char *team_names[TEAM_COUNT_LIMIT];
    uint8_t map_height;
    uint8_t map_width;
    inventory_t total_item_in_map;
    inventory_t map[MAP_MAX_SIDE_SIZE][MAP_MAX_SIDE_SIZE];
    event_heap_t events;
    uint64_t start_time;
    uint16_t frequency; // reciprocal of time unit
    uint8_t last_egg_id;
} server_t;

bool server_run(params_t *p, uint64_t timestamp);
void server_handle_events(server_t *srv);
void handle_poll(server_t *srv, uint64_t timeout);
void handle_fds_revents(server_t *srv);
void handle_client_disconnection(server_t *srv);
void process_clients_buff(server_t *srv);

static constexpr const int MICROSEC_IN_SEC = 1000000;
static constexpr const int MILISEC_IN_SEC = 1000;

static inline uint64_t get_timestamp(void)
{
    struct timeval tv;

    gettimeofday(&tv, NULL);
    return (uint64_t)((tv.tv_sec * MICROSEC_IN_SEC) + tv.tv_usec);
}

static inline int32_t compute_timeout(server_t *srv)
{
    int64_t current_time = get_timestamp();
    int64_t next_event_time = event_heap_peek(&srv->events)->timestamp;
    int32_t diff = (next_event_time - current_time);
    int32_t ms = diff / MILISEC_IN_SEC;

    if (ms > 0) {
        DEBUG("Timeout for next event: %u ms; diff µs: %d",
            ms, diff - (MILISEC_IN_SEC * ms));
    }
    return ms;
}
#endif