aboutsummaryrefslogtreecommitdiffstats
path: root/server/channel.c
blob: 2d81abbdbf8885ee81f0b759bb3738f724d1d808 (plain)
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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
#include "channel.h"

#include <container.h>
#include <stdlib.h>
#include <errno.h>

void thread_loop(void) {
	struct channel_handle *channel = channel_init();
	struct kv_packet **recvd_data = array_new(struct kv_packet*, 100);
	struct kv_packet work_buffer;
	size_t recvd_index = 0;
	int recv_flag = MSG_DONTWAIT;
	while (true) {
		struct sockaddr_in client_addr;
		socklen_t client_addr_len; // unused
		int recvlength = recvfrom(channel->sockfd, &work_buffer, 
					  KV_PACKET_SIZE, recv_flag, 
					  (struct sockaddr*)&client_addr, &client_addr_len);
		if (recvlength > 0) {
			DEBUGF("rec_id = %i\n", work_buffer.id);
			if (work_buffer.id <= 0) {
				handle_system_packet(&work_buffer, &client_addr, channel);
				continue;
			} else {
				recv_flag |= MSG_DONTWAIT;
			}
			struct kv_packet *kv_copy = malloc(KV_PACKET_SIZE);
			memcpy(kv_copy, &work_buffer, KV_PACKET_SIZE);
			++recvd_index;
			if (recvd_index >= array_size(recvd_data)) {
				array_push(recvd_data, kv_copy);
			} else {
				recvd_data[recvd_index] = kv_copy;
			}
		} else if (errno == EWOULDBLOCK) {
			if (array_size(recvd_data) == 0) recv_flag &= ~MSG_DONTWAIT;
			send_packets_back(recvd_data, channel);
			clear_packet_array(recvd_data);
		} else {
			perror("thread_loop failed");
		}
	}
	array_free(recvd_data);
	channel_uninit(channel);
}

struct channel_handle *channel_init(void) {
	struct sockaddr_in thread_local_address = {
		.sin_family = AF_INET, 
		.sin_port = 0, 
		.sin_addr = {INADDR_ANY}
	};
	struct channel_handle *handle = NULL;
	char chain_result = /* This is evil, but */
		(handle = (struct channel_handle*)calloc(1, sizeof(struct channel_handle))) != NULL
		&& (handle->users = array_new(struct user, 0)) != NULL 
		&& (handle->sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) >= 0 
		&& bind(handle->sockfd, (struct sockaddr*)&thread_local_address, sizeof(thread_local_address)) == 0;
	if (!chain_result) {
		perror("channel init failed");
		if (handle) {
			if (handle->users) array_free(handle->users);
			if (handle->sockfd >= 0) close(handle->sockfd);
			free(handle);
		}
		return NULL;
	}
	DEBUGF("Channel [%i] created\n", handle->sockfd);
	return handle;
}

void channel_uninit(struct channel_handle *handle) {
	array_free(handle->users);
	if (close(handle->sockfd) == -1) 
		perror("could not gracefully uninitialize channel");
	free(handle);
}

void handle_system_packet(struct kv_packet* packet, struct sockaddr_in *source, struct channel_handle* handle) {
	struct kv_system_packet* spacket = (struct kv_system_packet*) packet;
	if (system_packet_checksum(spacket) != spacket->checksum) return;
	switch (spacket->operation_id) {
	case keepalive: TODO;
	case join_channel: TODO;
	case leave_channel: TODO;
	case acknowledgement: TODO;
	default: TODO;
	}
}

void send_packets_back(struct kv_packet** packets, struct channel_handle* handle) {
	for (size_t i = 0; i < array_size(handle->users); ++i) {
		struct user* current_user = &handle->users[i];
		struct sockaddr_in destination = {
			.sin_family = AF_INET, 
			.sin_port = htons(current_user->port), 
			.sin_addr = { htonl(current_user->ip) }
		};
		for (size_t j = 0; packets[j] != NULL && j < array_size(packets); ++j) {
			DEBUGF("sending packet with id %i", packets[j]->id);
			DEBUGF("to destination: %u.%u.%u.%u:%hu\n", 
					(destination.sin_addr.s_addr >> 24) & 0xFF, 
					(destination.sin_addr.s_addr >> 16) & 0xFF, 
					(destination.sin_addr.s_addr >> 8) & 0xFF, 
					destination.sin_addr.s_addr & 0xFF,
					destination.sin_port);
			if (packets[j]->id == current_user->id) continue;
			int error_code = sendto(handle->sockfd, packets[j], KV_PACKET_SIZE, 0, (struct sockaddr*)&destination, sizeof(destination));
			if (error_code) perror("could not send packets back"); 
		}
	}
}

void clear_packet_array(struct kv_packet **array) {
	for (size_t i = 0 ; i < array_size(array); ++i) {
		if (array[i] == NULL) return;
		free(array[i]);
		array[i] = NULL;
	}
}

int __user_cmp(const void* a, const void* b) {
	struct user *_a = (struct user*)a,
		    *_b = (struct user*)b;
	return _a->id - _b->id;
}