It's ugly, but it passes
This commit is contained in:
parent
d96ad07cdb
commit
9c1a81caab
2
.clang-format
Normal file
2
.clang-format
Normal file
@ -0,0 +1,2 @@
|
||||
---
|
||||
BasedOnStyle: Google
|
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
cmake-build-*
|
1
0_smoketest/CMakeLists.txt
Normal file
1
0_smoketest/CMakeLists.txt
Normal file
@ -0,0 +1 @@
|
||||
add_executable(0_smoketest main.cpp)
|
97
0_smoketest/main.cpp
Normal file
97
0_smoketest/main.cpp
Normal file
@ -0,0 +1,97 @@
|
||||
//
|
||||
// Created by bspeice on 10/5/24.
|
||||
//
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/epoll.h>
|
||||
#include <ifaddrs.h>
|
||||
#include <netdb.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <array>
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
|
||||
#define CHECK_SYSCALL(expr) [&](){ const auto ret = expr; if (ret < 0) { throw std::runtime_error(#expr); } else { return ret; } }()
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
if (argc != 2) {
|
||||
throw std::runtime_error("Usage: ./0_smoketest <interface>");
|
||||
}
|
||||
|
||||
// Get the address tied to our intended interface
|
||||
const auto interface = std::string_view(argv[1]);
|
||||
|
||||
ifaddrs* interface_addrs{};
|
||||
CHECK_SYSCALL(getifaddrs(&interface_addrs));
|
||||
|
||||
while (interface_addrs) {
|
||||
if (interface == interface_addrs->ifa_name && interface_addrs->ifa_addr->sa_family == AF_INET) {
|
||||
break;
|
||||
}
|
||||
interface_addrs = interface_addrs->ifa_next;
|
||||
}
|
||||
|
||||
if (!interface_addrs) {
|
||||
throw std::runtime_error("Expected interface not found");
|
||||
}
|
||||
|
||||
std::array<char, 1024> name_buffer{};
|
||||
getnameinfo(interface_addrs->ifa_addr, sizeof(sockaddr_in), name_buffer.data(), name_buffer.size(), nullptr, 0, NI_NUMERICHOST);
|
||||
|
||||
auto* address = reinterpret_cast<sockaddr_in*>(interface_addrs->ifa_addr);
|
||||
address->sin_port = htons(3490); // Port must be in network byte order
|
||||
|
||||
std::cout << "Address: " << std::string(name_buffer.data()) << ' ' << ntohs(address->sin_port) << '\n';
|
||||
|
||||
// Set up a socket
|
||||
const auto socket_fd = CHECK_SYSCALL(socket(AF_INET, SOCK_STREAM, 0));
|
||||
int enable = 1;
|
||||
setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable));
|
||||
|
||||
CHECK_SYSCALL(bind(socket_fd, reinterpret_cast<sockaddr*>(address), sizeof(sockaddr_in)));
|
||||
CHECK_SYSCALL(listen(socket_fd, 10));
|
||||
|
||||
// Set up epoll
|
||||
const auto epoll_fd = CHECK_SYSCALL(epoll_create(10));
|
||||
|
||||
epoll_event event{EPOLLIN};
|
||||
event.data.fd = socket_fd;
|
||||
CHECK_SYSCALL(epoll_ctl(epoll_fd, EPOLL_CTL_ADD, socket_fd, &event));
|
||||
|
||||
std::vector<epoll_event> events{10};
|
||||
std::vector<std::byte> buffer(1024);
|
||||
|
||||
while (true) {
|
||||
std::cout << "Waiting for events..." << '\n';
|
||||
const auto num_fds = CHECK_SYSCALL(epoll_wait(epoll_fd, events.data(), events.size(), -1));
|
||||
std::cout << "Received events=" << num_fds << '\n';
|
||||
|
||||
for (auto i = 0; i < num_fds; i++) {
|
||||
if (events[i].data.fd == socket_fd) {
|
||||
// Connection attempt; add to the interest list and continue
|
||||
const auto connection_fd = CHECK_SYSCALL(accept(socket_fd, nullptr, nullptr));
|
||||
event.data.fd = connection_fd;
|
||||
CHECK_SYSCALL(epoll_ctl(epoll_fd, EPOLL_CTL_ADD, connection_fd, &event));
|
||||
std::cout << "Adding connection=" << connection_fd << '\n';
|
||||
continue;
|
||||
}
|
||||
|
||||
// Received data on a connection socket, read it and send it back
|
||||
const auto bytes_read = CHECK_SYSCALL(read(events[i].data.fd, buffer.data(), buffer.size()));
|
||||
std::cout << "Received bytes=" << bytes_read << '\n';
|
||||
|
||||
if (bytes_read == 0) {
|
||||
// Connection closed
|
||||
std::cout << "Closing fd=" << events[i].data.fd << '\n';
|
||||
CHECK_SYSCALL(epoll_ctl(epoll_fd, EPOLL_CTL_DEL, events[i].data.fd, &event));
|
||||
CHECK_SYSCALL(close(events[i].data.fd));
|
||||
continue;
|
||||
}
|
||||
|
||||
// Blocking I/O, I know, it's bad
|
||||
std::cout << "Sending bytes=" << bytes_read << '\n';
|
||||
CHECK_SYSCALL(write(events[i].data.fd, buffer.data(), bytes_read));
|
||||
}
|
||||
}
|
||||
}
|
4
CMakeLists.txt
Normal file
4
CMakeLists.txt
Normal file
@ -0,0 +1,4 @@
|
||||
cmake_minimum_required(VERSION 3.29)
|
||||
project(solar_hackers)
|
||||
|
||||
add_subdirectory(0_smoketest)
|
Loading…
Reference in New Issue
Block a user