summaryrefslogtreecommitdiff
path: root/client.c
diff options
context:
space:
mode:
Diffstat (limited to 'client.c')
-rw-r--r--client.c166
1 files changed, 136 insertions, 30 deletions
diff --git a/client.c b/client.c
index 8f4d5ff..11f6156 100644
--- a/client.c
+++ b/client.c
@@ -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);
}
+