commit 3579fe196cf9399a86a275fa264bd0c0f7d5d44b
parent 894daa68c1e86b41d03d041bd550eef059fcfb52
Author: Henry Wilson <henry@henryandlizzy.uk>
Date: Wed, 30 Aug 2023 17:54:29 +0000
General improvements to protohack-0
Diffstat:
3 files changed, 54 insertions(+), 32 deletions(-)
diff --git a/fd.hpp b/fd.hpp
@@ -1,7 +1,9 @@
#pragma once
#include <unistd.h>
+#include <err.h>
#include <string>
+#include <span>
struct descriptor
{
@@ -59,9 +61,11 @@ private:
int fd;
};
-int write(descriptor& d, std::string_view s)
+ssize_t write(int d, std::string_view s)
{
- return ::write(d, s.data(), s.size());
+ if (ssize_t n = ::write(d, s.data(), s.size()); n != -1)
+ return n;
+ ::err(1, "write");
}
std::string read(descriptor& d)
@@ -73,3 +77,14 @@ std::string read(descriptor& d)
else
return {};
}
+
+std::string_view read(int d, std::span<char> buf)
+{
+ ssize_t n = ::read(d, buf.data(), buf.size());
+ if ((n < 0) or ((size_t)n > buf.size()))
+ err(1, "read");
+ else if (n)
+ return {buf.data(), (size_t)n};
+ else
+ return {};
+}
diff --git a/inet.hpp b/inet.hpp
@@ -14,7 +14,7 @@ namespace inet {
descriptor listen(int type)
{
- struct sockaddr_in addr {sizeof addr, AF_INET, htons(1337), INADDR_ANY};
+ struct sockaddr_in addr {sizeof addr, AF_INET, htons(1337), {INADDR_ANY}, {}};
int reuseaddr = 1;
descriptor incoming{::socket(AF_INET, type, 0)};
diff --git a/protohack-0.cpp b/protohack-0.cpp
@@ -2,61 +2,68 @@
#include <poll.h>
+#include <algorithm>
#include <iostream>
-#include <sstream>
-#include <span>
#include <map>
-#include <vector>
-struct client
+int poll(std::span<struct pollfd> pfds, int timeout = INFTIM)
{
- descriptor socket;
- std::string buffer;
-};
+ if (int n = ::poll(pfds.data(), pfds.size(), timeout); n != -1)
+ return n;
+ err(1, "poll");
+}
int main()
{
- std::map<int, client> clients;
- std::vector<pollfd> awaitables;
- auto incoming = inet::listen(SOCK_STREAM);
+ std::map<int, descriptor> clients;
+ auto incoming_socket = inet::listen(SOCK_STREAM);
+ std::cout << "Protohack 0: Smoke Test\n";
for (;;)
{
- awaitables.clear();
- awaitables.push_back(pollfd{incoming, POLLIN, 0});
+ size_t const pollen = clients.size() + 1;
+ pollfd events_buf[pollen];
+ std::span events{events_buf, pollen};
+
+ auto& socket_event = events.front();
+ auto client_events = events.subspan(1);
+
+ socket_event = pollfd{incoming_socket, POLLIN, 0};
- for (auto const& c : clients)
- awaitables.push_back(pollfd{c.second.socket, POLLIN, 0});
+ std::transform(clients.cbegin(), clients.cend(), client_events.begin(), [](auto& c) {
+ return pollfd{c.second, POLLIN, 0};
+ });
- if (::poll(awaitables.data(), awaitables.size(), INFTIM) == -1)
- err(1, "poll");
+ int ready = poll(events);
- if (awaitables.front().revents & POLLIN) // incoming
+ if (socket_event.revents & POLLIN)
{
- auto conn = inet::accept(incoming);
- clients[conn] = {std::move(conn), {}};
+ auto conn = inet::accept(incoming_socket);
+ clients[conn] = std::move(conn);
+ if (not --ready)
+ continue;
}
- for (auto& ev : std::span{awaitables}.subspan(1))
+ for (auto& ev : client_events)
{
if (~ev.revents & POLLIN)
continue;
- char buf[0x1000];
- int n = ::read(ev.fd, buf, sizeof buf);
- if (not n)
+ char data_buf[0x1000];
+ auto data = read(ev.fd, std::span{data_buf});
+
+ if (data.empty())
{
std::cout << "* " << ev.fd << " disconnected\n";
clients.erase(ev.fd);
continue;
}
- if (n < 0 or n > sizeof buf)
- err(1, "read");
- std::cout << "* " << ev.fd << ": " << n << " bytes\n";
- ::write(1, buf, n);
- //if (n != ::write(ev.fd, buf, n))
- // err(1, "write");
+ std::cout << "* " << ev.fd << ": " << data.size() << " bytes\n";
+ write(ev.fd, data);
+
+ if (not --ready)
+ break;
}
}
}