Initial commit
This commit is contained in:
74
examples/chat_client.c
Normal file
74
examples/chat_client.c
Normal 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(<id, 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
179
examples/chat_server.c
Normal 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
36
examples/hello_client.c
Normal 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
43
examples/hello_server.c
Normal 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
27
examples/udp_client.c
Normal 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
35
examples/udp_server.c
Normal 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;
|
||||
}
|
||||
Reference in New Issue
Block a user