-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathserver.cpp
More file actions
461 lines (396 loc) · 12.8 KB
/
server.cpp
File metadata and controls
461 lines (396 loc) · 12.8 KB
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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
//
// Created by mano on 19.11.16.
//
#include <iostream>
#include <fstream>
#include <map>
#include <set>
#include <algorithm>
#include <cassert>
#include <vector>
#include <string>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <netdb.h>
#include <libgen.h>
#include <chrono>
#include <sstream>
#include <ctime>
typedef std::pair<uint32_t, unsigned short> Ip_Port;
const int BUFFER_SIZE = 10000;
const int MAX_LENGTH = 10;
const int LITTLE_STRING_SIZE = 256;
const long long BASE = 4LL;
const int SELECT_TIMEOUT = 100000;
const long long TIME_WAIT_CLIENT = 10000000LL;
const long long DEFAULT_STEP = 1000LL;
const int ADDRESS_MAX_SIZE = 1000;
const int MD5_SIZE = 32;
const int CLIENT_ASKED_INTERVAL = 3;
const int CLIENT_NOT_FOUND_ANSWER = 2;
const int CLIENT_FOUND_ANSWER = 1;
const int CLIENT_IN_PROCESS = 0;
const int CLIENT_ERROR = -1;
const uint32_t CLIENT_WANT_INTERVAL = 1;
const uint32_t CLIENT_HAVE_ANSWER = 2;
const int RET_ERROR = -1;
const int RET_GOOD = 1;
int server_socket;
struct sockaddr_in my_addr;
long long get_cur_time() {
auto cur_time = std::chrono::high_resolution_clock::now().time_since_epoch();
return std::chrono::duration_cast<std::chrono::microseconds>(cur_time).count();
}
struct ClientData {
void * buf;
int pbuf;
long long last_time;
ClientData() {
buf = malloc(BUFFER_SIZE);
pbuf = 0;
last_time = get_cur_time();
}
~ClientData() {
free(buf);
}
};
std::map<int, ClientData *> clients;
void * buf;
int pbuf;
char str_answer_md5[LITTLE_STRING_SIZE];
char answer_md5[MD5_SIZE + 1];
char received_answer_str[LITTLE_STRING_SIZE]; // if receive from client
std::map<char, long long> M;
std::map<long long, char> RM;
std::map<std::pair<long long, long long>, long long> calculating_intervals;
std::string pack_address(struct sockaddr_in addr) {
char str_addr[ADDRESS_MAX_SIZE];
uint32_t ip = ntohl(addr.sin_addr.s_addr);
unsigned short port = ntohs(addr.sin_port);
sprintf(str_addr, "%d.%d.%d.%d:%d",
(ip & 0xff000000) >> 24,
(ip & 0x00ff0000) >> 16,
(ip & 0x0000ff00) >> 8,
(ip & 0x000000ff), port);
return std::string(str_addr);
}
Ip_Port get_ip_port(struct sockaddr_in addr) {
uint32_t ip = addr.sin_addr.s_addr;
unsigned short port = addr.sin_port;
return std::make_pair(ip, port);
}
long long str_to_ll(std::string str) {
long long p4 = 1LL;
long long base = BASE;
long long sum = 0;
for (int i = 0; i < str.size(); ++i) {
sum += M[str[i]] * p4;
p4 *= base;
}
return sum;
}
std::string ll_to_str(long long num) {
std::string str = "";
while (num) {
str += RM[num % BASE];
num /= BASE;
}
return str;
}
void init_socket(unsigned short port) {
socklen_t addr_size = sizeof(struct sockaddr_in);
bzero(&my_addr, addr_size);
my_addr.sin_family = PF_INET;
my_addr.sin_addr.s_addr = htonl(INADDR_ANY);
my_addr.sin_port = htons(port);
server_socket = socket(PF_INET, SOCK_STREAM, 0);
int option = 1;
setsockopt(server_socket, SOL_SOCKET, SO_REUSEADDR, (char *)&option, sizeof(option));
bind(server_socket, (struct sockaddr *) &my_addr, sizeof(struct sockaddr_in));
listen(server_socket, SOMAXCONN);
}
void init_global() {
std::vector<char> v = {'A', 'G', 'T', 'C'};
for (int i = 0; i < v.size(); ++i) {
M[v[i]] = i;
RM[i] = v[i];
}
buf = malloc(BUFFER_SIZE);
pbuf = 0;
}
// so crutch...
std::string get_md5_sum(const char* str) {
std::stringstream ss;
ss << "file_md5_sum_file_md5_sum_";
ss << (int)getpid();
std::string file_md5_name;
ss >> file_md5_name;
std::ofstream out(file_md5_name.c_str());
out << str;
out.close();
char command[LITTLE_STRING_SIZE];
char result[LITTLE_STRING_SIZE];
snprintf(command, LITTLE_STRING_SIZE, "md5sum %s", file_md5_name.c_str());
FILE * md5 = popen(command, "r");
fgets(result, LITTLE_STRING_SIZE, md5);
fclose(md5);
remove(file_md5_name.c_str());
std::string md5sum = std::string(result);
md5sum = md5sum.substr(0, md5sum.find(' '));
return md5sum;
}
long long get_max_right_bound() {
long long res = 1;
for (int i = 0; i < MAX_LENGTH; ++i) {
res *= BASE;
}
return res - 1LL;
}
std::vector<std::pair<long long, long long>> free_intervals;
std::pair<long long, long long> get_next_interval() {
static long long left_bound = 0LL;
static long long max_right_bound = get_max_right_bound();
std::pair<long long, long long> res;
if (!free_intervals.empty()) {
res = free_intervals.back();
free_intervals.pop_back();
return res;
}
else {
if (left_bound > max_right_bound) {
return std::make_pair(-1LL, -1LL);
}
res = {left_bound, std::min(left_bound + DEFAULT_STEP, max_right_bound)};
left_bound += DEFAULT_STEP;
return res;
}
};
int handle_new_connection() {
struct sockaddr_in addr;
socklen_t addr_size = sizeof(struct sockaddr_in);
int new_socket = accept(server_socket, (struct sockaddr *)&addr, &addr_size);
if (new_socket < 0) {
perror("accept");
return RET_ERROR;
}
fprintf(stderr, "Accepted new client connection: %s\n", pack_address(addr).c_str());
clients[new_socket] = new ClientData();
}
int delete_client_connection(int client_socket) {
if (!clients.count(client_socket)) {
fprintf(stderr, "No this client socket in delete\n");
return RET_ERROR;
}
close(client_socket);
delete clients[client_socket];
clients.erase(client_socket);
return RET_GOOD;
}
int send_interval_to_client(int client_socket) {
fprintf(stderr, "Send interval to new cliend\n");
if (!clients.count(client_socket)) {
fprintf(stderr, "No this client socket in send interval\n");
return RET_ERROR;
}
ClientData * cl = clients[client_socket];
std::pair<long long, long long> interval = get_next_interval();
long long l = interval.first;
long long r = interval.second;
const long long d = 1000000000LL;
uint32_t num_buf[4];
if (l == -1 && r == -1) {
// Send not correct interval
num_buf[0] = htonl((uint32_t)(1));
num_buf[1] = htonl((uint32_t)(1));
num_buf[2] = htonl((uint32_t)(0));
num_buf[3] = htonl((uint32_t)(0));
}
else {
num_buf[0] = htonl((uint32_t)(l / d));
num_buf[1] = htonl((uint32_t)(l % d));
num_buf[2] = htonl((uint32_t)(r / d));
num_buf[3] = htonl((uint32_t)(r % d));
}
memcpy(cl->buf, (void*)num_buf, 4 * sizeof(uint32_t));
memcpy((void*)((char*)cl->buf + 4 * sizeof(uint32_t)), answer_md5, MD5_SIZE);
send(client_socket, cl->buf, 4 * sizeof(uint32_t)+ MD5_SIZE , 0);
return RET_GOOD;
}
int receive_answer_from_client(ssize_t res, int client_socket) {
fprintf(stderr, "Receive answer form client\n");
if (!clients.count(client_socket)) {
fprintf(stderr, "No this client\n");
return RET_ERROR;
}
ClientData * cl = clients[client_socket];
if (res > 0) {
res = recv(client_socket, (void*)((char*)cl->buf + cl->pbuf), BUFFER_SIZE, 0);
pbuf += res;
}
if (res > 0) {
return CLIENT_IN_PROCESS;
}
if (res < 0) {
perror("recv");
return CLIENT_ERROR;
}
memcpy(received_answer_str, (void*)((char*)cl->buf + sizeof(uint32_t)), (size_t)cl->pbuf - sizeof(uint32_t));
received_answer_str[cl->pbuf - sizeof(uint32_t)] = '\0';
fprintf(stderr, "Received: %s\n", received_answer_str);
fprintf(stderr, "Strs: %s %s\n", get_md5_sum(received_answer_str).c_str(), answer_md5);
if (strcmp(get_md5_sum(received_answer_str).c_str(), answer_md5)) {
return CLIENT_NOT_FOUND_ANSWER;
}
else {
return CLIENT_FOUND_ANSWER;
}
}
int handle_client_message(int client_socket) {
if (!clients.count(client_socket)) {
fprintf(stderr, "No this client\n");
return RET_ERROR;
}
ClientData * cl = clients[client_socket];
ssize_t res = recv(client_socket, (void*)((char*)cl->buf + cl->pbuf), BUFFER_SIZE, 0);
cl->pbuf += res;
if (res < 0) {
perror("recv");
return CLIENT_ERROR;
}
if (res == 0 || cl->pbuf >= sizeof(uint32_t)) {
if (cl->pbuf < sizeof(uint32_t)) {
fprintf(stderr, "Client send bad message\n");
return CLIENT_ERROR;
}
uint32_t type = ntohl(((uint32_t*)cl->buf)[0]);
if (type == CLIENT_WANT_INTERVAL) {
send_interval_to_client(client_socket);
return CLIENT_ASKED_INTERVAL;
}
else if (type == CLIENT_HAVE_ANSWER){
int res_answer = receive_answer_from_client(res, client_socket);
return res_answer;
}
else {
fprintf(stderr, "Unknown type client message\n");
return CLIENT_ERROR;
}
}
else {
cl->pbuf += res;
return CLIENT_IN_PROCESS;
}
}
int main(int argc, char* argv[]) {
init_global();
int opt;
unsigned short my_port;
std::string res_md5sum;
bool flag_answer_set = false;
bool flag_port_set = false;
while ((opt = getopt(argc, argv, "p:a:")) != -1) {
switch (opt) {
case 'a':
strncpy(str_answer_md5, optarg, strlen(optarg));
str_answer_md5[strlen(optarg)] = '\0';
res_md5sum = get_md5_sum(str_answer_md5);
strncpy(answer_md5, res_md5sum.c_str(), res_md5sum.size());
answer_md5[MD5_SIZE] = '\0';
flag_answer_set = true;
break;
case 'p':
my_port = (unsigned short)atoi(optarg);
init_socket(my_port);
flag_port_set = true;
break;
default:
fprintf(stderr, "Unknown argument\n");
exit(EXIT_FAILURE);
}
}
if (!flag_answer_set || !flag_port_set) {
fprintf(stderr, "Not all arguments\n");
exit(EXIT_FAILURE);
}
long long start_time = get_cur_time();
bool flag_execute = true;
while (flag_execute) {
fd_set fds;
int max_fd = 0;
FD_ZERO(&fds);
FD_SET(server_socket, &fds);
max_fd = std::max(max_fd, server_socket);
for (auto client : clients) {
FD_SET(client.first, &fds);
max_fd = std::max(max_fd, client.first);
}
struct timeval tv = {0, SELECT_TIMEOUT};
int activity = select(max_fd + 1, &fds, NULL, NULL, &tv);
if (activity < 0) {
continue;
}
if (activity) {
fprintf(stderr, "Activity: %d\n", activity);
}
std::vector<int> to_delete;
for (auto client : clients) {
if (FD_ISSET(client.first, &fds)) {
fprintf(stderr, "Client: %d\n", client.first);
int res = handle_client_message(client.first);
if (res == CLIENT_FOUND_ANSWER) {
flag_execute = false;
break;
}
else if (res == CLIENT_IN_PROCESS) {
client.second->last_time = get_cur_time();
}
else if (res == CLIENT_NOT_FOUND_ANSWER){
to_delete.push_back(client.first);
}
else if (res == CLIENT_ASKED_INTERVAL) {
to_delete.push_back(client.first);
}
}
else {
long long cur_time = get_cur_time();
long long diff = cur_time - client.second->last_time;
if (diff > TIME_WAIT_CLIENT) {
to_delete.push_back(client.first);
}
}
}
if (!flag_execute) {
break;
}
std::vector<std::pair<long long, long long>> intervals_to_delete;
long long cur_time = get_cur_time();
for (auto interval : calculating_intervals) {
if (cur_time - interval.second > TIME_WAIT_CLIENT) {
intervals_to_delete.push_back(interval.first);
}
}
for (auto interval : intervals_to_delete) {
calculating_intervals.erase(interval);
free_intervals.push_back(interval);
}
for (auto id : to_delete) {
fprintf(stderr, "Have to delete\n");
delete_client_connection(id);
}
if (FD_ISSET(server_socket, &fds)) {
int res = handle_new_connection();
}
}
for (auto client : clients) {
delete client.second;
}
fprintf(stderr, "Answer: %s\n", received_answer_str);
long long end_time = get_cur_time();
std::cerr << double(end_time - start_time) / 1000000. << " sec.\n";
free(buf);
return 0;
}