From 6543fecd7b45cc0232aa4148d0a7be125f4c49ea Mon Sep 17 00:00:00 2001 From: "Anna (navi) Figueiredo Gomes" Date: Mon, 17 Jun 2024 00:03:18 +0200 Subject: *: restructure into subdirectoires and add REUSE --- src/peer.c | 156 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 156 insertions(+) create mode 100644 src/peer.c (limited to 'src/peer.c') diff --git a/src/peer.c b/src/peer.c new file mode 100644 index 0000000..f719622 --- /dev/null +++ b/src/peer.c @@ -0,0 +1,156 @@ +// SPDX-FileCopyrightText: 2024 Lizzy Fleckenstein +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +#include +#include +#include +#include +#include +#include +#include "peer.h" + +void peer_init(peer *p, int socket) +{ + p->socket = socket; + p->disco = false; + + p->in.header = true; + p->in.len = 0; + p->in.promised = 0; + p->in.buffer = malloc(PEER_INBUFFER_SIZE); + + p->out.cursor = 0; + p->out.avail = 0; + p->out.buffer = malloc(PEER_OUTBUFFER_SIZE); +} + +void peer_free(peer *p) +{ + close(p->socket); + free(p->in.buffer); + free(p->out.buffer); +} + +// in + +static void next_in(peer *p, bool header, size_t len) +{ + p->in.header = header; + p->in.len = 0; + p->in.buffer = malloc(p->in.promised = len); +} + +static bool peer_in_ready(peer *p) +{ + ssize_t got = read(p->socket, p->in.buffer + p->in.len, p->in.promised - p->in.len); + if (got < 0) { + switch (errno) { + case ECONNRESET: + p->disco = true; + return true; + case EINTR: + return peer_in_ready(p); // retry + default: + perror("read"); + return false; + } + } + + p->in.len += got; + if (p->in.len == p->in.promised && p->in.len != 0) { + if (!p->in.header) + return true; + + size_t len = *(pkt_header *) p->in.buffer; + if (len > PEER_INBUFFER_SIZE) + // TODO: figure out what to do if packet too large (disconnect?) + next_in(p, true, sizeof(pkt_header)); + else + next_in(p, false, len); + } + + return false; +} + +// out + +static void send_raw(peer *p, uint8_t *data, size_t len) +{ + memcpy(p->out.buffer + p->out.cursor + p->out.avail, data, len); + p->out.avail += len; +} + +static bool out_space(peer *p, size_t len) +{ + if (len + p->out.avail > PEER_OUTBUFFER_SIZE) + return false; + + if (p->out.cursor + p->out.avail + len > PEER_OUTBUFFER_SIZE) { + memmove(p->out.buffer, p->out.buffer + p->out.cursor, p->out.avail); + p->out.cursor = 0; + } + + return true; +} + +bool peer_send(peer *p, uint8_t *data, size_t len) +{ + if (len > PEER_INBUFFER_SIZE) + return false; + + pkt_header hdr = (pkt_header) len; + + if (!out_space(p, sizeof hdr + len)) + return false; + + send_raw(p, (uint8_t *) &hdr, sizeof hdr); + send_raw(p, data, len); + + return true; +} + +static bool peer_out_ready(peer *p) +{ + ssize_t written = write(p->socket, p->out.buffer + p->out.cursor, p->out.avail); + if (written < 0) { + switch (errno) { + case ECONNRESET: + p->disco = true; + return true; + case EINTR: + return peer_out_ready(p); + default: + perror("write"); + return false; + } + } + + p->out.avail -= written; + if (p->out.avail == 0) + p->out.cursor = 0; + + return false; +} + +// poll + +short peer_prepare(peer *p) +{ + if (p->in.len == p->in.promised) + next_in(p, true, sizeof(pkt_header)); + + return POLLIN | (p->out.avail ? POLLOUT : 0); +} + +bool peer_ready(peer *p, short revents) +{ + bool x = false; + + if (revents & POLLIN) + x = x || peer_in_ready(p); + if (revents & POLLOUT) + x = x || peer_out_ready(p); + + return x; +} -- cgit v1.2.3