#include "server.h"
#include <stdlib.h>
#include <stdio.h>
void
server_add_socket(struct server *server, struct ood_inet_socket *socket) {
if (!ood_ptr_array_add(server->sockets, socket)) {
ood_halt("unable to add socket");
}
}
enum ood_result
server_add_listener(struct server *server,
in_addr_t in_addr,
in_port_t in_port,
int backlog,
ood_inet_socket_fn *on_read,
ood_inet_socket_fn *on_error)
{
struct ood_inet_socket *listener = ood_inet_socket_alloc(in_addr, in_port);
if (!listener) {
return ood_error;
}
listener->data = server;
listener->on_error = on_error;
listener->on_read = on_read;
ood_ptr_array_add(server->sockets, listener);
if (!ood_inet_socket_listen(listener, backlog)) {
return ood_error;
}
printf("dood: listening on %s\n", listener->address->formatted);
return ood_okay;
}
void
server_add_sockets_to_select_sets(struct server *server,
struct ood_select_sets *select_sets)
{
ood_select_sets_clear(select_sets);
int i = 0;
struct ood_inet_socket *socket;
while ((socket = ood_ptr_array_next(server->sockets, &i))) {
if (socket->on_error) ood_select_sets_add_errorable(select_sets, socket->fd);
if (socket->on_read) ood_select_sets_add_reader(select_sets, socket->fd);
if (socket->on_write) ood_select_sets_add_writer(select_sets, socket->fd);
}
}
struct server *
server_alloc(int socket_capacity)
{
struct server *server = calloc(1, sizeof(struct server));
if (!server) return NULL;
server->sockets = ood_ptr_array_alloc(socket_capacity);
if (!server->sockets) {
free(server);
return NULL;
}
return server;
}
bool
server_can_accept_connections(struct server *server)
{
return ood_ptr_array_has_capacity(server->sockets);
}
void
server_close_all_listeners(struct server *server)
{
for (int i = 0; i < server->sockets->capacity; ++i) {
if (!server->sockets->items[i]) continue;
struct ood_inet_socket *socket = (struct ood_inet_socket *)server->sockets->items[i];
if (OOD_INET_SOCKET_FLAGS_LISTENING & socket->flags) {
printf("dood: no longer listening on %s\n", socket->address->formatted);
ood_inet_socket_free(socket);
server->sockets->items = NULL;
--server->sockets->count;
}
}
}
void
server_close_socket(struct server *server, struct ood_inet_socket *socket) {
if (!ood_ptr_array_clear(server->sockets, socket)) {
ood_halt("unable to close socket");
}
ood_inet_socket_free(socket);
}
void
server_free(struct server *server)
{
if (server) {
ood_ptr_array_free(server->sockets);
free(server);
}
}
void
server_handle_events_in_select_sets(struct server *server,
struct ood_select_sets *select_sets)
{
int i = 0;
struct ood_inet_socket *socket;
while ((socket = ood_ptr_array_next(server->sockets, &i))) {
if (socket->on_error && ood_select_sets_has_error(select_sets, socket->fd)) {
socket->on_error(socket);
continue;
}
if (socket->on_read && ood_select_sets_is_readable(select_sets, socket->fd)) {
socket->on_read(socket);
}
if (socket->on_write && ood_select_sets_is_writable(select_sets, socket->fd)) {
socket->on_write(socket);
}
}
}
bool
server_is_running(struct server *server)
{
return server->sockets->count > 0;
}