add run_server and threading so both client and server are in same program
This commit is contained in:
@@ -1,9 +1,8 @@
|
||||
#define lengthof(x) (sizeof((x)) / sizeof((x)[0]))
|
||||
|
||||
#define panicf(...) (fprintf(stderr, "%s:%d: ", __FILE__, __LINE__), fprintf(stderr, __VA_ARGS__), fprintf(stderr, "\n"), exit(1))
|
||||
#define debugf(...) (printf("%s:%d: ", __FILE__, __LINE__), printf(__VA_ARGS__), printf("\n"))
|
||||
#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>
|
||||
struct DEFER_ExitScope {
|
||||
T lambda;
|
||||
@@ -46,22 +45,22 @@ struct Slice {
|
||||
};
|
||||
|
||||
#define PLEN(x) {(x), lengthof(x)}
|
||||
#define ENUM_VALUE(x) {x, #x}
|
||||
|
||||
struct EnumValue {
|
||||
struct Enum_Value {
|
||||
int value;
|
||||
const char *name;
|
||||
};
|
||||
|
||||
#define ENUM_VALUE(x) {x, #x}
|
||||
const char *serialize(Slice<EnumValue> table, int value) {
|
||||
const char *serialize(Slice<Enum_Value> table, int value) {
|
||||
for (int i = 0; i < table.len; i += 1) {
|
||||
EnumValue *it = table.data + i;
|
||||
Enum_Value *it = table.data + i;
|
||||
if (it->value == value) return it->name;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
char *serialize_flags(Slice<EnumValue> table, int n) { // @leak
|
||||
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;
|
||||
|
||||
187
src/main.cpp
187
src/main.cpp
@@ -14,6 +14,39 @@
|
||||
#pragma comment(lib, "ws2_32")
|
||||
#include "basic.cpp"
|
||||
|
||||
Enum_Value _ai_flags_table[] = {
|
||||
ENUM_VALUE(AI_PASSIVE),
|
||||
ENUM_VALUE(AI_CANONNAME),
|
||||
ENUM_VALUE(AI_NUMERICHOST),
|
||||
};
|
||||
Slice<Enum_Value> ai_flags_table = PLEN(_ai_flags_table);
|
||||
|
||||
Enum_Value _ai_family_table[] = {
|
||||
{0, "AF_UNSPEC"},
|
||||
{2, "AF_INET"},
|
||||
{17, "AF_NETBIOS"},
|
||||
{23, "AF_INET6"},
|
||||
{26, "AF_IRDA"},
|
||||
{32, "AF_BTH"},
|
||||
};
|
||||
Slice<Enum_Value> ai_family_table = PLEN(_ai_family_table);
|
||||
|
||||
Enum_Value _ai_socktype_table[] = {
|
||||
ENUM_VALUE(SOCK_STREAM),
|
||||
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* message = NULL;
|
||||
|
||||
@@ -37,39 +70,6 @@ char *serialize_error_code(DWORD errorCode) {
|
||||
return message; // @leak - LocalFree
|
||||
}
|
||||
|
||||
EnumValue _ai_flags_table[] = {
|
||||
ENUM_VALUE(AI_PASSIVE),
|
||||
ENUM_VALUE(AI_CANONNAME),
|
||||
ENUM_VALUE(AI_NUMERICHOST),
|
||||
};
|
||||
Slice<EnumValue> ai_flags_table = PLEN(_ai_flags_table);
|
||||
|
||||
EnumValue _ai_family_table[] = {
|
||||
{0, "AF_UNSPEC"},
|
||||
{2, "AF_INET"},
|
||||
{17, "AF_NETBIOS"},
|
||||
{23, "AF_INET6"},
|
||||
{26, "AF_IRDA"},
|
||||
{32, "AF_BTH"},
|
||||
};
|
||||
Slice<EnumValue> ai_family_table = PLEN(_ai_family_table);
|
||||
|
||||
EnumValue _ai_socktype_table[] = {
|
||||
ENUM_VALUE(SOCK_STREAM),
|
||||
ENUM_VALUE(SOCK_DGRAM),
|
||||
ENUM_VALUE(SOCK_RAW),
|
||||
ENUM_VALUE(SOCK_RDM),
|
||||
ENUM_VALUE(SOCK_SEQPACKET),
|
||||
};
|
||||
Slice<EnumValue> ai_socktype_table = PLEN(_ai_socktype_table);
|
||||
|
||||
EnumValue _ai_protocol_table[] = {
|
||||
ENUM_VALUE(IPPROTO_TCP),
|
||||
ENUM_VALUE(IPPROTO_UDP),
|
||||
ENUM_VALUE(IPPROTO_PGM),
|
||||
};
|
||||
Slice<EnumValue> ai_protocol_table = PLEN(_ai_protocol_table);
|
||||
|
||||
void serialize_addrinfo(struct addrinfo* in) {
|
||||
for (struct addrinfo* p = in; p != NULL; p = p->ai_next) {
|
||||
printf("addrinfo %p {\n", p);
|
||||
@@ -103,18 +103,6 @@ void serialize_addrinfo(struct addrinfo* in) {
|
||||
#define PORT "8000"
|
||||
|
||||
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 hints = {};
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
@@ -126,7 +114,7 @@ void run_server() {
|
||||
panicf("getaddrinfo failed, error code: %s\n", gai_strerrorA(err));
|
||||
}
|
||||
defer { freeaddrinfo(servinfo); };
|
||||
serialize_addrinfo(servinfo);
|
||||
// serialize_addrinfo(servinfo);
|
||||
|
||||
SOCKET socket_fd = -1;
|
||||
for (addrinfo *it = servinfo; it; it = it->ai_next) {
|
||||
@@ -186,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();
|
||||
} 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...");
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user