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;
}
|