impl tcp.cpp

This commit is contained in:
Theis Pieter Hollebeek 2026-03-23 13:17:41 +01:00
parent ac8d2f2013
commit fca446d8e9
6 changed files with 147 additions and 79 deletions

View File

@ -1,54 +1,54 @@
MAKEFLAGS += -j16
CC=gcc
LD=gcc
CXX=g++
LD=g++
CLANG_FORMAT=clang-format
CFLAGS = -std=c23 -pedantic-errors -Wall -Wextra -Wconversion
CXXFLAGS = -std=c++23 -pedantic-errors -Wall -Wextra -Wconversion
LDFLAGS =
libraries = libmicrohttpd
# libraries = ""
CFLAGS += $(shell pkg-config $(libraries) --cflags)
LDFLAGS += $(shell pkg-config $(libraries) --libs)
# CXXFLAGS += $(shell pkg-config $(libraries) --cflags)
# LDFLAGS += $(shell pkg-config $(libraries) --libs)
RELEASE = 0
GDB = 0
ifeq ($(RELEASE),1)
CFLAGS += -O3
CXXFLAGS += -O3
else
CFLAGS += -g -Wno-unused
CXXFLAGS += -g -Wno-unused
ifeq ($(GDB),1)
CFLAGS += -ggdb
CXXFLAGS += -ggdb
else
CFLAGS += -fsanitize=address
CXXFLAGS += -fsanitize=address
endif
endif
NO_MAIN = 0
ifeq ($(NO_MAIN),1)
CFLAGS += -Dmain="not_main"
CXXFLAGS += -Dmain="not_main"
endif
build_dir = build
obj_dir = $(build_dir)/obj
sources = \
src/main.c
src/main.cpp
target=$(build_dir)/backend
all: $(target)
$(target): $(sources:%.c=$(obj_dir)/%.o)
$(LD) -o $@ $(CFLAGS) $(LDFLAGS) $^
$(target): $(sources:%.cpp=$(obj_dir)/%.o)
$(LD) -o $@ $(CXXFLAGS) $(LDFLAGS) $^
$(obj_dir)/%.o: %.c
$(obj_dir)/%.o: %.cpp
@mkdir -p $(dir $@)
$(CC) $< -c -o $@ -MMD -MP $(CFLAGS)
$(CXX) $< -c -o $@ -MMD -MP $(CXXFLAGS)
format:
$(CLANG_FORMAT) -style=file -i src/*
@ -59,5 +59,5 @@ check:
clean:
rm -rf $(build_dir)
-include $(sources:%.c=$(obj_dir)/%.d)
-include $(sources:%.cpp=$(obj_dir)/%.d)

View File

@ -1,5 +1,5 @@
-xc
-std=c23
-xc++
-std=c++23
-pedantic-errors
-Wall
-Wextra

View File

@ -1,60 +0,0 @@
#include <microhttpd.h>
#include <stdio.h>
#include <string.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <sys/types.h>
#define PORT 8888
int print_out_key(
void* cls, enum MHD_ValueKind kind, const char* key, const char* value)
{
printf("%s: %s\n", key, value);
return MHD_YES;
}
int answer_to_connection(void* cls, struct MHD_Connection* connection,
const char* url, const char* method, const char* version,
const char* upload_data, size_t* upload_data_size, void** req_cls)
{
const char* page = "<html><body>Hello, browser!</body></html>";
struct MHD_Response* response;
int ret;
MHD_get_connection_values(connection,
MHD_HEADER_KIND,
(MHD_KeyValueIterator)&print_out_key,
NULL);
printf("New %s request for %s using version %s\n", method, url, version);
response = MHD_create_response_from_buffer(
strlen(page), (void*)page, MHD_RESPMEM_PERSISTENT);
ret = (int)MHD_queue_response(connection, MHD_HTTP_OK, response);
MHD_destroy_response(response);
return ret;
}
int main(void)
{
printf("hello\n");
struct MHD_Daemon* daemon;
daemon = MHD_start_daemon(MHD_USE_INTERNAL_POLLING_THREAD,
PORT,
NULL,
NULL,
(MHD_AccessHandlerCallback)&answer_to_connection,
NULL,
MHD_OPTION_END);
if (NULL == daemon)
return 1;
getchar();
MHD_stop_daemon(daemon);
return 0;
}

12
backend/src/main.cpp Normal file
View File

@ -0,0 +1,12 @@
#include <stdio.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <sys/types.h>
#define PORT 8888
int main(void)
{
printf("hello\n");
return 0;
}

78
backend/src/tcp.cpp Normal file
View File

@ -0,0 +1,78 @@
#include "tcp.hpp"
#include <arpa/inet.h>
#include <errno.h>
#include <expected>
#include <format>
#include <netdb.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string>
#include <string_view>
#include <sys/socket.h>
#include <unistd.h>
namespace mst {
auto errno_shim(std::string_view message) -> std::string
{
auto x = strerror(errno);
return std::format("{} ({})", message, x);
}
auto TcpConnection::write(uint8_t* buffer, size_t len) -> Result<size_t>
{
ssize_t bytes_written = ::write(this->fd, buffer, len);
if (bytes_written < 0) {
return std::unexpected(errno_shim("could not write bytes"));
}
return bytes_written;
}
auto TcpConnection::read(uint8_t* buffer, size_t len) -> Result<size_t>
{
ssize_t bytes_read = ::recv(this->fd, buffer, len, 0);
if (bytes_read < 0) {
return std::unexpected(errno_shim("could not read bytes"));
}
return bytes_read;
}
auto TcpListener::bind(const std::string& host, uint16_t port)
-> Result<TcpListener>
{
int socket_fd = 0;
if ((socket_fd = ::socket(AF_INET, SOCK_STREAM, 0)) < 0) {
return std::unexpected(errno_shim("could not get socket"));
}
struct sockaddr_in address = {
.sin_family = AF_INET,
.sin_port = htons(port),
.sin_addr = in_addr { .s_addr = inet_addr(host.c_str()) },
.sin_zero = { },
};
if (::bind(socket_fd, (struct sockaddr*)&address, sizeof(address)) < 0) {
return std::unexpected(errno_shim("could not bind"));
}
if (::listen(socket_fd, 0) < 0) {
return std::unexpected(errno_shim("could not listen"));
}
return TcpListener(socket_fd, address);
}
auto TcpListener::accept() -> Result<TcpConnection>
{
socklen_t size = sizeof(address);
int socket = ::accept(this->fd, (struct sockaddr*)&address, &size);
if (socket < 0) {
return std::unexpected(errno_shim("could not accept"));
}
return TcpConnection(*this, socket);
}
}

38
backend/src/tcp.hpp Normal file
View File

@ -0,0 +1,38 @@
#pragma once
#include <cstdint>
#include <expected>
#include <netinet/in.h>
#include <string>
namespace mst {
template <typename T> using Result = std::expected<T, std::string>;
class TcpListener;
class TcpConnection {
public:
auto write(uint8_t* buffer, size_t len) -> Result<size_t>;
auto read(uint8_t* buffer, size_t len) -> Result<size_t>;
TcpConnection(TcpListener&, int fd)
: fd(fd) { };
private:
int fd;
};
class TcpListener {
public:
static auto bind(const std::string& host, uint16_t port)
-> Result<TcpListener>;
auto accept() -> Result<TcpConnection>;
private:
TcpListener(int fd, sockaddr_in address)
: fd(fd)
, address(address) { };
int fd;
sockaddr_in address;
};
}