diff options
author | Oxore <oxore@protonmail.com> | 2023-12-28 00:04:20 +0300 |
---|---|---|
committer | Oxore <oxore@protonmail.com> | 2023-12-28 00:04:20 +0300 |
commit | 18893127524d87e47a948b9a92d8d8b2ab869852 (patch) | |
tree | 1491660a439221174a776b9c7f38f05234590cdb /client.c | |
parent | 4faf778b6ec4b9d8ab0c19e22d27c76f4c67ab28 (diff) |
WIP
Diffstat (limited to 'client.c')
-rw-r--r-- | client.c | 166 |
1 files changed, 136 insertions, 30 deletions
@@ -1,19 +1,71 @@ -// Initially based on https://stackoverflow.com/a/35570418 +/* SPDX-License-Identifier: Unlicense */ +#include "proto.h" +#include "proto_io.h" + +#include "timespec/timespec.h" + +#include <assert.h> +#include <errno.h> +#include <fcntl.h> +#include <inttypes.h> #include <netinet/in.h> +#include <poll.h> +#include <signal.h> #include <stdbool.h> #include <stdint.h> -#include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/socket.h> +#include <time.h> #include <unistd.h> -static unsigned char udp_buffer[UINT16_MAX]; +struct connection { + int fd; + uint16_t port; + uint32_t addr; + bool connected; + uint32_t connection_id; + struct timespec last_syn; + uint32_t server_roundtrip_prev; + uint32_t client_roundtrip_prev; +}; + +static volatile bool g_should_exit = false; +struct connection g_conn = { .fd = -1, }; static inline bool IsDigit(char c) { return c >= '0' && c <= '9'; } +static void HandleFrame( + struct connection *self, + struct frame const *frame, + struct timespec now) +{ + if (frame->type == FT_HANDSHAKE_RESP) { + self->connection_id = frame->connection_id; + self->connected = true; + } else if (frame->type == FT_SYN && self->connected) { + printf("client_rt %5" PRIu32 "\n", self->client_roundtrip_prev); + struct frame outgoing = *frame; + outgoing.type = FT_SYNACK, + outgoing.syn = (struct frame_data_syn){ + .tick = frame->syn.tick, + .roundtrip_prev = self->client_roundtrip_prev, + .prev_is_lost = false, + }; + SendFrame(self->fd, &outgoing); + self->last_syn = now; + self->server_roundtrip_prev = frame->syn.roundtrip_prev; + } else if (frame->type == FT_ACK && self->connected) { + long const ms = timespec_to_ms(timespec_sub(now, self->last_syn)); + assert(ms >= 0); + self->client_roundtrip_prev = ms; + } else if (frame->type == FT_RST) { + // TODO + } +} + static uint32_t ParseAddress(char const *str, FILE *log_stream) { uint32_t addr = 0; @@ -66,6 +118,11 @@ static uint32_t ParseAddress(char const *str, FILE *log_stream) return addr; } +static void sigintHandler(int a) +{ + (void) a; +} + int main(int const argc, char *const argv[]) { if (argc < 3) { @@ -86,34 +143,83 @@ int main(int const argc, char *const argv[]) perror("socket failed"); return 1; } - struct sockaddr_in const serveraddr = { - .sin_family = AF_INET, - .sin_port = htons(port), - .sin_addr.s_addr = htonl(addr), + fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK); + g_conn.addr = addr; + g_conn.port = port; + g_conn.fd = fd; + struct frame const handshake = { + .addr = addr, + .port = port, + .type = FT_HANDSHAKE, + .handshake = { + .tick_period = 200, + }, }; - ssize_t const ret = sendto( - fd, "\x2a", 1, 0, (struct sockaddr const *)&serveraddr, sizeof(serveraddr)); - if (ret < 0) { - perror("sendto failed"); - return 1; + SendFrame(fd, &handshake); + struct sigaction sa = { .sa_handler = sigintHandler, }; + sigaction(SIGINT, &sa, NULL); + struct pollfd fds[1] = { { .fd = fd, .events = POLLIN, }, }; + while (!g_should_exit) { + int const pollret = poll(fds, sizeof(fds)/sizeof(*fds), -1); + int const poll_err = errno; + struct timespec start; + if (-1 == clock_gettime(CLOCK_MONOTONIC, &start)) { + int const err = errno; + fprintf(stderr, + "clock_gettime(CLOCK_MONOTONIC, &start) failed (%d): \"%s\"", + err, strerror(err)); + } + if (pollret > 0) { + if (fds[0].revents & POLLIN) { + while (1) { + struct frame frame = { .type = FT_NONE, }; + int const ret = ReceiveFrame(fds[0].fd, &frame); + if (ret) { + break; + } + HandleFrame(&g_conn, &frame, start); + } + } + if (fds[0].revents & POLLRDNORM) { + fprintf(stderr, "POLLRDNORM, ignoring...\n"); + } + if (fds[0].revents & POLLRDBAND) { + fprintf(stderr, "POLLRDBAND, ignoring...\n"); + } + if (fds[0].revents & POLLPRI) { + fprintf(stderr, "POLLPRI, ignoring...\n"); + } + if (fds[0].revents & POLLPRI) { + fprintf(stderr, "POLLPRI, ignoring...\n"); + } + if (fds[0].revents & POLLHUP) { + fprintf(stderr, "POLLHUP, ignoring...\n"); + } + if (fds[0].revents & POLLERR) { + fprintf(stderr, "POLLERR, ignoring...\n"); + } + if (fds[0].revents & POLLNVAL) { + fprintf(stderr, "POLLNVAL, exiting...\n"); + return 1; + } + } else if (pollret < 0) { + if (poll_err == EINTR) { + fprintf(stderr, "SIGINT received\n"); + if (g_conn.connected) { + struct frame const rst = { + .addr = g_conn.addr, + .port = g_conn.port, + .type = FT_RST, + }; + SendFrame(g_conn.fd, &rst); + } + break; + } + fprintf(stderr, + "poll() failed (%d): \"%s\"", + poll_err, strerror(poll_err)); + } } - printf("message sent\n"); - struct sockaddr_in source_address; - socklen_t source_address_len = sizeof(source_address); - int const length = recvfrom( - fd, - udp_buffer, - sizeof(udp_buffer) - 1, - 0, - (struct sockaddr*)&source_address, - &source_address_len); - (void) length; - uint32_t const addr2 = ntohl(source_address.sin_addr.s_addr); - uint8_t const a0 = addr2 >> 24; - uint8_t const a1 = addr2 >> 16; - uint8_t const a2 = addr2 >> 8; - uint8_t const a3 = addr2; - uint16_t const port2 = ntohs(source_address.sin_port); - printf("Received: %u from %u.%u.%u.%u:%u\n", udp_buffer[0], a0, a1, a2, a3, port2); close(fd); } + |