Summary Files Commits Branches @commit @diff @stats
path: root / src / sockets / socket_server.c
blob: 5280341db008bce4a35d2b0e82722d11676d506b (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
#include "socket_server.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

static socket_server* __new_socket_server(uint16_t port, uint32_t incoming_ip) {
	socket_server* srv = malloc(sizeof(socket_server));

	srv->socket = socket(AF_INET, SOCK_STREAM, 0);

	struct sockaddr_in addr = {
		.sin_family      = AF_INET, // Address Family Internet
		.sin_port        = htons(port), // Host to network short
		.sin_addr.s_addr = htonl(incoming_ip), // Host to network long
	};

	while (bind(srv->socket, (struct sockaddr*)&addr, sizeof(addr)) != 0) {
		perror("Socket bind");
		sleep(5);
	}

	return srv;
}

/*** Single Request Server ***/

static int start_single_req(socket_server* this);
static void destroy_single_req(socket_server* this);

socket_server* new_socket_server_single_req(uint16_t port, uint32_t incoming_ip) {
	socket_server* res = __new_socket_server(port, incoming_ip);
	res->start = start_single_req;
	res->destroy = destroy_single_req;
	return res;
}

static int ends_on_two_newlines(char str[2]) {
	return (str[0] == '\n' || str[0] == '\r') && (str[1] == '\n' || str[1] == '\r');
}

static int start_single_req(socket_server* this) {
	if (this == NULL) return -1;

	listen(this->socket, 1);

	struct sockaddr_in client = {
		.sin_family = AF_INET,
		.sin_port = 0,
		.sin_addr.s_addr = 0,
	};
	socklen_t client_size = sizeof(client);

	int client_socket = accept(this->socket, (struct sockaddr*)&client, &client_size);

	char input[1024] = { 0 };
	size_t input_size = 0;

	char line[256] = { 0 };
	size_t line_size = 0;
	do {
		input_size += line_size = recv(client_socket, line, 255, 0);
		line[line_size] = '\0';
		strcat(input, line);
	} while (input_size > 0 && !ends_on_two_newlines(input + input_size - 2));

	callback_args ca_args = {
		.input = input,
		.input_size = input_size,

		.output = NULL,
		.output_size = 0,
		.free_output = 0,

		.extra = this->callback_args,
		.extra_size = this->callback_argc,
	};

	if (this->callback != NULL)
		this->callback(&ca_args);

	if (ca_args.output != NULL && ca_args.output_size > 0)
		send(client_socket, ca_args.output, ca_args.output_size, 0);

	if (ca_args.free_output)
		free(ca_args.output);

	close(client_socket);

	return 0;
}

static void destroy_single_req(socket_server* this) {
	if (this == NULL) return;

	close(this->socket);
	free(this);
	this = NULL;
}