Compare commits

..

2 Commits

Author SHA1 Message Date
Krzosa Karol
d62bebee78 add run_server and threading so both client and server are in same program 2026-01-27 21:19:42 +01:00
Krzosa Karol
d1304b64d4 refactor, bring back basic.h and Slice<T> 2026-01-27 20:33:23 +01:00
2 changed files with 190 additions and 122 deletions

View File

@@ -1,5 +1,8 @@
#define panicf(...) (fprintf(stderr, __VA_ARGS__), fprintf(stderr, "\n"), exit(1)) #define lengthof(x) (sizeof((x)) / sizeof((x)[0]))
#define panicf(...) (fprintf(stderr, "%s:%d: %s\n", __FILE__, __LINE__, strf(__VA_ARGS__)), exit(1))
#define debugf(...) printf("%s:%d: %s\n", __FILE__, __LINE__, strf(__VA_ARGS__))
#define assert(x) ((!(x)) && (panicf("%s:%d: assertion failed " #x, __FILE__, __LINE__), 0))
template <typename T> template <typename T>
struct DEFER_ExitScope { struct DEFER_ExitScope {
T lambda; T lambda;
@@ -20,3 +23,48 @@ class DEFER_ExitScopeHelp {
#define DEFER_CONCAT_INTERNAL(x, y) x##y #define DEFER_CONCAT_INTERNAL(x, y) x##y
#define DEFER_CONCAT(x, y) DEFER_CONCAT_INTERNAL(x, y) #define DEFER_CONCAT(x, y) DEFER_CONCAT_INTERNAL(x, y)
#define defer const auto DEFER_CONCAT(defer__, __LINE__) = DEFER_ExitScopeHelp() + [&]() #define defer const auto DEFER_CONCAT(defer__, __LINE__) = DEFER_ExitScopeHelp() + [&]()
char* strf(const char* format, ...) { // @leak
va_list args;
va_start(args, format);
va_list args_copy;
va_copy(args_copy, args);
int size = vsnprintf(NULL, 0, format, args_copy) + 1;
va_end(args_copy);
char* buffer = (char *)malloc(size);
assert(buffer);
vsnprintf(buffer, size, format, args);
va_end(args);
return buffer;
}
template<class T>
struct Slice {
T *data;
int len;
};
#define PLEN(x) {(x), lengthof(x)}
#define ENUM_VALUE(x) {x, #x}
struct Enum_Value {
int value;
const char *name;
};
const char *serialize(Slice<Enum_Value> table, int value) {
for (int i = 0; i < table.len; i += 1) {
Enum_Value *it = table.data + i;
if (it->value == value) return it->name;
}
return "";
}
char *serialize_flags(Slice<Enum_Value> table, int n) { // @leak
char *result = strf("%d", n);
for (int i = 0; i < table.len; i += 1) {
auto *it = table.data + i;
if (n & it->value) result = strf("%s %s", result, it->name);
}
return result;
}

View File

@@ -12,31 +12,40 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#pragma comment(lib, "ws2_32") #pragma comment(lib, "ws2_32")
#include "basic.cpp"
#define panicf(...) (fprintf(stderr, "%s:%d: ", __FILE__, __LINE__), fprintf(stderr, __VA_ARGS__), fprintf(stderr, "\n"), exit(1)) Enum_Value _ai_flags_table[] = {
#define debugf(...) (printf("%s:%d: ", __FILE__, __LINE__), printf(__VA_ARGS__), printf("\n")) ENUM_VALUE(AI_PASSIVE),
#define assert(x) ((!(x)) && (panicf("%s:%d: assertion failed " #x, __FILE__, __LINE__), 0)) ENUM_VALUE(AI_CANONNAME),
ENUM_VALUE(AI_NUMERICHOST),
template <typename T>
struct DEFER_ExitScope {
T lambda;
DEFER_ExitScope(T lambda) : lambda(lambda) {}
~DEFER_ExitScope() { lambda(); }
DEFER_ExitScope(const DEFER_ExitScope &i) : lambda(i.lambda){};
private:
DEFER_ExitScope &operator=(const DEFER_ExitScope &);
}; };
Slice<Enum_Value> ai_flags_table = PLEN(_ai_flags_table);
class DEFER_ExitScopeHelp { Enum_Value _ai_family_table[] = {
public: {0, "AF_UNSPEC"},
template <typename T> {2, "AF_INET"},
DEFER_ExitScope<T> operator+(T t) { return t; } {17, "AF_NETBIOS"},
{23, "AF_INET6"},
{26, "AF_IRDA"},
{32, "AF_BTH"},
}; };
Slice<Enum_Value> ai_family_table = PLEN(_ai_family_table);
#define DEFER_CONCAT_INTERNAL(x, y) x##y Enum_Value _ai_socktype_table[] = {
#define DEFER_CONCAT(x, y) DEFER_CONCAT_INTERNAL(x, y) ENUM_VALUE(SOCK_STREAM),
#define defer const auto DEFER_CONCAT(defer__, __LINE__) = DEFER_ExitScopeHelp() + [&]() ENUM_VALUE(SOCK_DGRAM),
ENUM_VALUE(SOCK_RAW),
ENUM_VALUE(SOCK_RDM),
ENUM_VALUE(SOCK_SEQPACKET),
};
Slice<Enum_Value> ai_socktype_table = PLEN(_ai_socktype_table);
Enum_Value _ai_protocol_table[] = {
ENUM_VALUE(IPPROTO_TCP),
ENUM_VALUE(IPPROTO_UDP),
ENUM_VALUE(IPPROTO_PGM),
};
Slice<Enum_Value> ai_protocol_table = PLEN(_ai_protocol_table);
char *serialize_error_code(DWORD errorCode) { char *serialize_error_code(DWORD errorCode) {
char* message = NULL; char* message = NULL;
@@ -58,98 +67,16 @@ char *serialize_error_code(DWORD errorCode) {
if (newline) *newline = '\0'; if (newline) *newline = '\0';
} }
return message; // Remember to LocalFree() this later! return message; // @leak - LocalFree
} }
char* strf(const char* format, ...) {
va_list args;
va_start(args, format);
va_list args_copy;
va_copy(args_copy, args);
int size = vsnprintf(NULL, 0, format, args_copy) + 1;
va_end(args_copy);
char* buffer = (char *)malloc(size);
assert(buffer);
vsnprintf(buffer, size, format, args);
va_end(args);
return buffer;
}
#define lengthof(x) (sizeof((x)) / sizeof((x)[0]))
struct EnumValue {
int value;
const char *name;
};
#define ENUM_VALUE(x) {x, #x}
const char *serialize(EnumValue *table, int table_size, int value) {
for (int i = 0; i < table_size; i += 1) {
EnumValue *it = table + i;
if (it->value == value) return it->name;
}
return "";
}
EnumValue ai_flag_table[] = {
ENUM_VALUE(AI_PASSIVE),
ENUM_VALUE(AI_CANONNAME),
ENUM_VALUE(AI_NUMERICHOST),
};
char *serialize_ai_flags(int n) {
char *result = strf("%d", n);
for (int i = 0; i < lengthof(ai_flag_table); i += 1) {
auto *it = ai_flag_table + i;
if (n & it->value) result = strf("%s %s", result, it->name);
}
return result;
}
struct {
const char *name;
int value;
const char *desc;
} ai_family_table[] = {
{"AF_UNSPEC", 0, "The address family is unspecified"},
{"AF_INET", 2, "The Internet Protocol version 4 (IPv4) address family."},
{"AF_NETBIOS", 17, "The NetBIOS address family. This address family is only supported if a Windows Sockets provider for NetBIOS is installed."},
{"AF_INET6", 23, "The Internet Protocol version 6 (IPv6) address family."},
{"AF_IRDA", 26, "The Infrared Data Association (IrDA) address family. This address family is only supported if the computer has an infrared port and driver installed."},
{"AF_BTH", 32, "The Bluetooth address family. This address family is only supported if a Bluetooth adapter is installed on Windows Server 2003 or later."},
};
const char *serialize_ai_family(int n) {
for (int i = 0; i < lengthof(ai_family_table); i += 1) {
auto *it = ai_family_table + i;
if (it->value == n) {
return it->name;
}
}
return "";
}
EnumValue ai_socktype_table[] = {
ENUM_VALUE(SOCK_STREAM),
ENUM_VALUE(SOCK_DGRAM),
ENUM_VALUE(SOCK_RAW),
ENUM_VALUE(SOCK_RDM),
ENUM_VALUE(SOCK_SEQPACKET),
};
EnumValue ai_protocol_table[] = {
ENUM_VALUE(IPPROTO_TCP),
ENUM_VALUE(IPPROTO_UDP),
ENUM_VALUE(IPPROTO_PGM),
};
void serialize_addrinfo(struct addrinfo* in) { void serialize_addrinfo(struct addrinfo* in) {
for (struct addrinfo* p = in; p != NULL; p = p->ai_next) { for (struct addrinfo* p = in; p != NULL; p = p->ai_next) {
printf("addrinfo %p {\n", p); printf("addrinfo %p {\n", p);
printf(" ai_flags = %s(%d)\n", serialize_ai_flags(p->ai_flags), p->ai_flags); printf(" ai_flags = %s(%d)\n", serialize_flags(ai_flags_table, p->ai_flags), p->ai_flags);
printf(" ai_family = %s(%d)\n", serialize_ai_family(p->ai_family), p->ai_family); printf(" ai_family = %s(%d)\n", serialize(ai_family_table, p->ai_family), p->ai_family);
printf(" ai_socktype = %s(%d)\n", serialize(ai_socktype_table, lengthof(ai_socktype_table), p->ai_socktype), p->ai_socktype); printf(" ai_socktype = %s(%d)\n", serialize(ai_socktype_table, p->ai_socktype), p->ai_socktype);
printf(" ai_protocol = %s(%d)\n", serialize(ai_protocol_table, lengthof(ai_protocol_table), p->ai_protocol), p->ai_protocol); printf(" ai_protocol = %s(%d)\n", serialize(ai_protocol_table, p->ai_protocol), p->ai_protocol);
printf(" ai_addrlen = %zu\n", p->ai_addrlen); printf(" ai_addrlen = %zu\n", p->ai_addrlen);
printf(" ai_canonname = \"%s\"\n", p->ai_canonname ? p->ai_canonname : ""); printf(" ai_canonname = \"%s\"\n", p->ai_canonname ? p->ai_canonname : "");
@@ -176,18 +103,6 @@ void serialize_addrinfo(struct addrinfo* in) {
#define PORT "8000" #define PORT "8000"
void run_server() { void run_server() {
WSADATA wsaData;
int err_wsa_startup = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (err_wsa_startup != 0) {
panicf("WSAStartup failed, error code: %d", err_wsa_startup);
}
defer { WSACleanup(); };
if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) {
panicf("Version 2.2 of Winsock not available");
}
struct addrinfo *servinfo = {}; struct addrinfo *servinfo = {};
struct addrinfo hints = {}; struct addrinfo hints = {};
hints.ai_family = AF_UNSPEC; hints.ai_family = AF_UNSPEC;
@@ -199,7 +114,7 @@ void run_server() {
panicf("getaddrinfo failed, error code: %s\n", gai_strerrorA(err)); panicf("getaddrinfo failed, error code: %s\n", gai_strerrorA(err));
} }
defer { freeaddrinfo(servinfo); }; defer { freeaddrinfo(servinfo); };
serialize_addrinfo(servinfo); // serialize_addrinfo(servinfo);
SOCKET socket_fd = -1; SOCKET socket_fd = -1;
for (addrinfo *it = servinfo; it; it = it->ai_next) { for (addrinfo *it = servinfo; it; it = it->ai_next) {
@@ -259,8 +174,113 @@ void run_server() {
} }
} }
int main() { void *get_in_addr(struct sockaddr *sa)
{
if (sa->sa_family == AF_INET) {
return &(((struct sockaddr_in*)sa)->sin_addr);
}
return &(((struct sockaddr_in6*)sa)->sin6_addr);
}
void run_client() {
struct addrinfo *servinfo = {};
struct addrinfo hints = {};
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM; // tcp
// hints.ai_flags = AI_PASSIVE;
// hints.ai_protocol = IPROTO_TCP; // tcp
INT err = getaddrinfo(NULL, PORT, &hints, &servinfo);
if (err != 0) {
panicf("client: getaddrinfo failed, error code: %s\n", gai_strerrorA(err));
}
defer { freeaddrinfo(servinfo); };
// serialize_addrinfo(servinfo);
SOCKET socket_fd = -1;
for (addrinfo *it = servinfo; it; it = it->ai_next) {
socket_fd = socket(it->ai_family, it->ai_socktype, it->ai_protocol);
if (socket_fd == -1) {
debugf("skipping socket call %s", serialize_error_code(WSAGetLastError()));
continue;
}
char s[INET6_ADDRSTRLEN];
inet_ntop(it->ai_family, get_in_addr(it->ai_addr), s, sizeof(s));
debugf("client: attempting connection to: %s", s);
if (connect(socket_fd, it->ai_addr, (int)it->ai_addrlen) != 0) {
debugf("client: failed to connect %s", serialize_error_code(WSAGetLastError()));
closesocket(socket_fd);
socket_fd = -1;
continue;
}
break;
}
if (socket_fd == -1) {
panicf("client: failed to connect");
} else {
debugf("client: connected!");
}
char buf[1024];
int numbytes = recv(socket_fd, buf, lengthof(buf) - 1, 0);
if (numbytes == -1) {
panicf("client: recv failed %s", serialize_error_code(WSAGetLastError()));
}
buf[numbytes] = '\0';
debugf("client: received '%s'",buf);
closesocket(socket_fd);
}
struct Thread_Data {
int idx;
};
DWORD thread_entry(LPVOID param) {
Thread_Data *thread_data = (Thread_Data *)param;
printf("thread %d, reporting in!\n", thread_data->idx);
if (thread_data->idx == 0) {
run_server(); run_server();
} else {
run_client();
}
printf("thread %d, exiting...\n", thread_data->idx);
return 0;
}
int main() {
WSADATA wsaData;
int err_wsa_startup = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (err_wsa_startup != 0) {
panicf("WSAStartup failed, error code: %d", err_wsa_startup);
}
defer { WSACleanup(); };
if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) {
panicf("Version 2.2 of Winsock not available");
}
constexpr int thread_count = 8;
HANDLE thread_handles[32];
Thread_Data thread_data[32];
DWORD thread_ids[32];
static_assert(thread_count < lengthof(thread_ids));
for (int i = 0; i < thread_count; i += 1) {
thread_data[i].idx = i;
LPSECURITY_ATTRIBUTES attribs = NULL;
SIZE_T stack_size = 0;
DWORD creation_flags = 0;
thread_handles[i] = CreateThread(attribs, stack_size, thread_entry, &thread_data[i], creation_flags, &thread_ids[i]);
}
WaitForMultipleObjects(thread_count, thread_handles, TRUE, INFINITE);
// run_server();
debugf("exiting..."); debugf("exiting...");
return 0; return 0;
} }