Program Listing for File client_manager.c¶
↰ Return to documentation for file (server/client/client_manager.c)
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/poll.h>
#include <unistd.h>
#include "client.h"
#include "client_manager.h"
#include "utils/resizable_array.h"
enum {
SECTION_SERVER = 0,
SECTION_UNASSIGNED = 1,
SECTION_GRAPHIC = 2,
SECTION_PLAYER = 3
};
static
client_state_t *swap_clients(client_manager_t *cm, size_t i, size_t j)
{
client_state_t tmp;
struct pollfd tmpfd;
if (i == j)
return &cm->clients[j];
tmp = cm->clients[i];
cm->clients[i] = cm->clients[j];
cm->clients[j] = tmp;
tmpfd = cm->server_pfds[i];
cm->server_pfds[i] = cm->server_pfds[j];
cm->server_pfds[j] = tmpfd;
return &cm->clients[i];
}
static
bool client_manager_ensure_capacity(client_manager_t *cm, size_t request)
{
resizable_array_t arr = {
.buff = (char *)cm->server_pfds,
.nmemb = cm->count,
.capacity = cm->capacity,
};
if (!sized_struct_ensure_capacity(&arr, request, sizeof *cm->server_pfds)
|| !sized_struct_ensure_capacity(
(resizable_array_t *)cm, request, sizeof *cm->clients))
return false;
cm->server_pfds = (struct pollfd *)(void *)arr.buff;
return true;
}
bool client_manager_init(client_manager_t *cm)
{
struct pollfd srv_pollfd = { .events = POLLIN };
client_state_t srv_client = {
.team_id = TEAM_ID_SERVER,
.id = 0,
0,
};
if (!client_manager_ensure_capacity(cm, 1))
return perror("can't allocate memory for clients"), false;
cm->count = 1;
*cm->server_pfds = srv_pollfd;
*cm->clients = srv_client;
cm->idx_of_gui++;
cm->idx_of_players++;
return true;
}
client_state_t *client_manager_add(client_manager_t *cm)
{
if (!client_manager_ensure_capacity(cm, 1))
return perror("can't reallocate memory for clients"), nullptr;
memset(cm->clients + cm->count, 0, sizeof *cm->clients);
memset(cm->server_pfds + cm->count, 0, sizeof *cm->server_pfds);
cm->clients[cm->count].fd = -1;
cm->server_pfds[cm->count].fd = -1;
cm->clients[cm->count].team_id = SECTION_UNASSIGNED;
swap_clients(cm, cm->count, cm->idx_of_gui);
if (cm->idx_of_gui != cm->idx_of_players)
swap_clients(cm, cm->count, cm->idx_of_players);
cm->count++;
cm->idx_of_players++;
cm->idx_of_gui++;
return &cm->clients[cm->idx_of_gui - 1];
}
client_state_t *client_manager_promote(
client_manager_t *cm, size_t idx)
{
if (idx >= cm->count)
return nullptr;
if (cm->clients[idx].team_id == SECTION_GRAPHIC) {
swap_clients(cm, idx, cm->idx_of_gui - 1);
cm->idx_of_gui--;
return cm->clients + cm->idx_of_gui;
}
if (cm->clients[idx].team_id > SECTION_GRAPHIC) {
swap_clients(cm, idx, cm->idx_of_gui - 1);
swap_clients(cm, cm->idx_of_gui - 1, cm->idx_of_players - 1);
cm->idx_of_players--;
cm->idx_of_gui--;
return cm->clients + cm->idx_of_players;
}
return nullptr;
}
static
void client_manager_remove_gui(client_manager_t *cm, size_t idx)
{
swap_clients(cm, idx, cm->idx_of_players - 1);
swap_clients(cm, cm->idx_of_players - 1, cm->count - 1);
cm->idx_of_players--;
}
static
void client_manager_remove_unassigned(client_manager_t *cm, size_t idx)
{
swap_clients(cm, idx, cm->idx_of_gui - 1);
swap_clients(cm, cm->idx_of_gui - 1, cm->count - 1);
if (cm->clients[cm->idx_of_gui - 1].team_id > SECTION_GRAPHIC)
swap_clients(cm, cm->idx_of_gui - 1, cm->idx_of_players - 1);
cm->idx_of_gui--;
cm->idx_of_players--;
}
void client_manager_remove(client_manager_t *cm, size_t idx)
{
if (idx >= cm->count)
return;
switch (cm->clients[idx].team_id) {
case SECTION_SERVER:
break;
case SECTION_UNASSIGNED:
client_manager_remove_unassigned(cm, idx);
cm->count--;
break;
case SECTION_GRAPHIC:
client_manager_remove_gui(cm, idx);
cm->count--;
break;
default:
swap_clients(cm, idx, cm->count - 1);
cm->count--;
break;
}
}