Initial commit

This commit is contained in:
seajee
2025-04-25 01:52:14 +02:00
commit 04c671220e
11 changed files with 690 additions and 0 deletions

74
examples/chat_client.c Normal file
View File

@@ -0,0 +1,74 @@
#include <stdio.h>
#include <stdbool.h>
#include <pthread.h>
#define SOCK_IMPLEMENTATION
#include "sock.h"
#define DEFAULT_ADDRESS "127.0.0.1"
#define PORT 6969
#define BUFFER_CAPACITY 4096
bool disconnected = false;
void *listen_thread(void *user_data)
{
Sock *server = (Sock*) user_data;
char buffer[BUFFER_CAPACITY];
ssize_t received = 0;
while ((received = sock_recv(server, buffer, sizeof(buffer))) > 0) {
printf("%.*s\n", (int)received, buffer);
}
disconnected = true;
return NULL;
}
int main(int argc, char **argv)
{
const char *address = DEFAULT_ADDRESS;
if (argc > 1) {
address = argv[1];
}
Sock *client = sock_create(SOCK_IPV4, SOCK_TCP);
if (client == NULL) {
fprintf(stderr, "ERROR: Could not create socket\n");
return EXIT_FAILURE;
}
if (!sock_connect(client, sock_addr(address, PORT))) {
fprintf(stderr, "ERROR: Could not connect to server\n");
sock_close(client);
return EXIT_FAILURE;
}
pthread_t ltid;
if (pthread_create(&ltid, NULL, &listen_thread, client) != 0) {
fprintf(stderr, "ERROR: Could not create listening thread\n");
sock_close(client);
return EXIT_FAILURE;
}
pthread_detach(ltid);
printf("INFO: Connected to the server\n");
printf("INFO: Type `disconnect` to disconnect from the server\n");
char buffer[BUFFER_CAPACITY];
while (!disconnected) {
memset(buffer, 0, sizeof(buffer));
fgets(buffer, sizeof(buffer), stdin);
if (strcmp(buffer, "disconnect\n") == 0) {
break;
}
size_t len = strlen(buffer)-1;
sock_send(client, buffer, len);
}
sock_close(client);
printf("INFO: Closed socket\n");
return EXIT_SUCCESS;
}

179
examples/chat_server.c Normal file
View File

@@ -0,0 +1,179 @@
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#define SOCK_IMPLEMENTATION
#include "sock.h"
#define PORT 6969
#define POOL_CAPACITY 16
#define BUFFER_CAPACITY 4096
#define USERNAME_CAPACITY 16
Sock *socket_pool[POOL_CAPACITY];
pthread_mutex_t pool_lock;
bool add_client(Sock *sock)
{
bool added = false;
pthread_mutex_lock(&pool_lock);
for (size_t i = 0; i < POOL_CAPACITY; ++i) {
if (socket_pool[i] == NULL) {
socket_pool[i] = sock;
added = true;
break;
}
}
pthread_mutex_unlock(&pool_lock);
return added;
}
bool remove_client(Sock *sock) {
bool removed = false;
pthread_mutex_lock(&pool_lock);
for (size_t i = 0; i < POOL_CAPACITY; ++i) {
if (socket_pool[i] == sock) {
socket_pool[i] = NULL;
removed = true;
break;
}
}
pthread_mutex_unlock(&pool_lock);
return removed;
}
void broadcast(const Sock *from, const char *msg, size_t msg_len)
{
pthread_mutex_lock(&pool_lock);
for (size_t i = 0; i < POOL_CAPACITY; ++i) {
Sock *r = socket_pool[i];
if (r != NULL && r != from) {
sock_send(r, msg, msg_len);
}
}
pthread_mutex_unlock(&pool_lock);
}
void *handle_client(void *user_data)
{
Sock *client = (Sock*) user_data;
ssize_t received = 0;
char buffer[BUFFER_CAPACITY];
memset(buffer, 0, sizeof(buffer));
char username[USERNAME_CAPACITY];
size_t username_length = 0;
memset(username, 0, sizeof(username));
const char *username_prompt = "username:";
size_t prompt_length = strlen(username_prompt);
memcpy(buffer, "username: ", prompt_length);
sock_send(client, buffer, prompt_length);
received = sock_recv(client, username, sizeof(username));
if (received < 0) {
goto disconnect;
}
username_length = received;
printf("INFO: Client login with username `%.*s`\n", (int)username_length,
username);
received = snprintf(buffer, sizeof(buffer), "[Server] `%.*s` joined the chat",
(int)username_length, username);
broadcast(client, buffer, received);
memcpy(buffer, username, username_length);
buffer[username_length] = ':';
buffer[username_length + 1] = ' ';
size_t prefix_len = username_length + 2;
size_t read_len = sizeof(buffer) - prefix_len;
char *read_buf = buffer + prefix_len;
while ((received = sock_recv(client, read_buf, read_len)) > 0) {
printf("INFO: %.*s: %.*s\n", (int)username_length, username,
(int)received, read_buf);
broadcast(client, buffer, received + prefix_len);
}
disconnect:
sock_close(client);
remove_client(client);
printf("INFO: Client `%.*s` disconnected\n", (int)username_length,
username);
received = snprintf(buffer, sizeof(buffer), "[Server] `%.*s` left the chat",
(int)username_length, username);
broadcast(client, buffer, received);
return NULL;
}
int main(void)
{
Sock *server = sock_create(SOCK_IPV4, SOCK_TCP);
if (server == NULL) {
fprintf(stderr, "ERROR: Could not create socket\n");
return EXIT_FAILURE;
}
printf("INFO: Created socket\n");
if (!sock_bind(server, sock_addr("0.0.0.0", PORT))) {
fprintf(stderr, "ERROR: Could not bind socket\n");
sock_close(server);
return EXIT_FAILURE;
}
printf("INFO: Bind socket\n");
if (!sock_listen(server, 10)) {
fprintf(stderr, "ERROR: Could not listen on socket\n");
sock_close(server);
return EXIT_FAILURE;
}
printf("INFO: Listen socket\n");
while (true) {
Sock *client = sock_accept(server);
if (client == NULL) {
fprintf(stderr, "ERROR: Could not accept client\n");
sock_close(client);
continue;
}
if (!add_client(client)) {
fprintf(stderr, "ERROR: TCP_Socket pool buffer is full (%d)\n",
POOL_CAPACITY);
sock_close(client);
continue;
}
// printf("INFO: Pool:\n");
// pthread_mutex_lock(&pool_lock);
// for (size_t i = 0; i < POOL_CAPACITY; ++i) {
// printf(" %ld: %p\n", i, socket_pool[i]);
// }
// pthread_mutex_unlock(&pool_lock);
// printf("INFO: End pool:\n");
pthread_t thread;
if (pthread_create(&thread, NULL, &handle_client, client) != 0) {
fprintf(stderr, "ERROR: Could not create thread\n");
sock_close(client);
continue;
}
pthread_detach(thread);
printf("INFO: New client connected\n");
}
sock_close(server);
printf("INFO: Closed socket\n");
return EXIT_SUCCESS;
}

36
examples/hello_client.c Normal file
View File

@@ -0,0 +1,36 @@
#include <stdio.h>
#include <errno.h>
#define SOCK_IMPLEMENTATION
#include "sock.h"
int main(void)
{
char *err = "None";
Sock *sock = sock_create(SOCK_IPV4, SOCK_TCP);
if (sock == NULL) { err = "create"; goto defer; }
printf("create\n");
SockAddr addr = sock_addr("127.0.0.1", 6969);
if (!sock_connect(sock, addr)) { err = "connect"; goto defer; }
printf("connect\n");
const char *msg = "Hello from client!";
char buf[128];
memset(buf, 0, sizeof(buf));
sock_send(sock, msg, strlen(msg));
printf("send\n");
sock_recv(sock, buf, sizeof(buf));
printf("recv\n");
printf("%.*s\n", (int)sizeof(buf), buf);
defer:
sock_close(sock);
printf("close\n");
fprintf(stderr, "ERROR: %s: %s\n", err, strerror(errno));
return 0;
}

43
examples/hello_server.c Normal file
View File

@@ -0,0 +1,43 @@
#include <stdio.h>
#include <errno.h>
#define SOCK_IMPLEMENTATION
#include "sock.h"
int main(void) {
char *err = "None";
Sock *sock = sock_create(SOCK_IPV4, SOCK_TCP);
if (sock == NULL) { err = "create"; goto defer; }
printf("create\n");
SockAddr addr = sock_addr("0.0.0.0", 6969);
if (!sock_bind(sock, addr)) { err = "bind"; goto defer; }
printf("bind\n");
if (!sock_listen(sock, 16)) { err = "listen"; goto defer; }
printf("listen\n");
Sock *client = sock_accept(sock);
if (client == NULL) { err = "accept"; goto defer; }
printf("accept\n");
const char *msg = "Hello from server!";
char buf[128];
memset(buf, 0, sizeof(buf));
sock_send(client, msg, strlen(msg));
printf("send\n");
sock_recv(client, buf, sizeof(buf));
printf("recv\n");
printf("%.*s\n", (int)sizeof(buf), buf);
sock_close(client);
printf("close\n");
defer:
sock_close(sock);
printf("close\n");
fprintf(stderr, "ERROR: %s: %s\n", err, strerror(errno));
return 0;
}

27
examples/udp_client.c Normal file
View File

@@ -0,0 +1,27 @@
#include <stdio.h>
#define SOCK_IMPLEMENTATION
#include "sock.h"
int main(void)
{
Sock *sock = sock_create(SOCK_IPV4, SOCK_UDP);
if (sock == NULL) {
perror("sock_create");
return 1;
}
const char *msg = "Hello from client!";
sock_sendto(sock, msg, strlen(msg), sock_addr("127.0.0.1", 6969));
SockAddr server_addr;
char buf[128];
memset(buf, 0, sizeof(buf));
sock_recvfrom(sock, buf, sizeof(buf), &server_addr);
printf("Received \"%.*s\" from %s:%d\n", (int)sizeof(buf), buf,
server_addr.str, server_addr.port);
return 0;
}

35
examples/udp_server.c Normal file
View File

@@ -0,0 +1,35 @@
#include <stdio.h>
#define SOCK_IMPLEMENTATION
#include "sock.h"
int main(void)
{
Sock *server = sock_create(SOCK_IPV4, SOCK_UDP);
if (server == NULL) {
perror("sock_create");
return 1;
}
if (!sock_bind(server, sock_addr("0.0.0.0", 6969))) {
perror("sock_bind");
sock_close(server);
return 1;
}
SockAddr client_addr;
char buf[128];
memset(buf, 0, sizeof(buf));
sock_recvfrom(server, buf, sizeof(buf), &client_addr);
printf("Received \"%.*s\" from %s:%d\n", (int)sizeof(buf), buf,
client_addr.str, client_addr.port);
const char *msg = "Hello from server!";
sock_sendto(server, msg, strlen(msg), client_addr);
sock_close(server);
return 0;
}