diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..68740ba --- /dev/null +++ b/.clang-format @@ -0,0 +1,2 @@ +--- +BasedOnStyle: Google \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4d0826a --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +cmake-build-* \ No newline at end of file diff --git a/0_smoketest/CMakeLists.txt b/0_smoketest/CMakeLists.txt new file mode 100644 index 0000000..a57c5d6 --- /dev/null +++ b/0_smoketest/CMakeLists.txt @@ -0,0 +1 @@ +add_executable(0_smoketest main.cpp) \ No newline at end of file diff --git a/0_smoketest/main.cpp b/0_smoketest/main.cpp new file mode 100644 index 0000000..5a38195 --- /dev/null +++ b/0_smoketest/main.cpp @@ -0,0 +1,97 @@ +// +// Created by bspeice on 10/5/24. +// +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#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 "); + } + + // 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 name_buffer{}; + getnameinfo(interface_addrs->ifa_addr, sizeof(sockaddr_in), name_buffer.data(), name_buffer.size(), nullptr, 0, NI_NUMERICHOST); + + auto* address = reinterpret_cast(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(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 events{10}; + std::vector 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)); + } + } +} \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..cf10837 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,4 @@ +cmake_minimum_required(VERSION 3.29) +project(solar_hackers) + +add_subdirectory(0_smoketest) \ No newline at end of file