Browse Source

Some more progress on the tracker

Now with argument parsing and database link !
thehip 3 years ago
parent
commit
7840eb1f09
1 changed files with 255 additions and 64 deletions
  1. 255 64
      tracker/main.c

+ 255 - 64
tracker/main.c

@ -1,7 +1,7 @@
1 1
/***********************
2 2
 * CPX TORRENT TRACKER *
3 3
 ***********************/
4
 
4

													
5 5
// Part of the CPX Project
6 6
// Distributed under the MIT License
7 7

													
@ -9,19 +9,24 @@
9 9
#include <netinet/in.h> // sockaddr_in
10 10
#include <stdio.h>      // printf() and so on
11 11
#include <unistd.h>     // close()
12
#include <string.h>     // strlen()
12
#include <string.h>     // strlen(), strcmp()
13 13
#include <signal.h>     // Signal handling
14 14
#include <sys/socket.h> // socket()
15 15
#include <sys/types.h>  // Sometimes needed when using sockets
16 16
#include "colors.h"     // colored output
17
#include <stdlib.h>     // malloc()
17
#include <stdlib.h>     // malloc(), atoi()
18

													
19
// MongoDB
20
#include <bson.h>
21
#include <bcon.h>
22
#include <mongoc.h>
18 23

													
19 24
// Some stuff to use sockets
20 25
typedef struct sockaddr_in SOCKADDR_IN;
21 26
typedef struct sockaddr SOCKADDR;
22 27
typedef struct in_addr IN_ADDR;
23 28

													
24
//The indexes of the array we'll use to store the request settings
29
// The indexes of the array we'll use to store the request settings
25 30
enum{
26 31
	REQUEST_UP,      // Uploaded amount since last announce
27 32
	REQUEST_DOWN,    // Downloaded amount since last announce
@ -39,7 +44,7 @@ enum{
39 44
	REQUEST_SIZE     // The length of the array
40 45
};
41 46

													
42
int string_until(char *string, char delimiter){ // Reads the string until it reaches <delimiter>, then returns the number of bytes read
47
int string_until (char *string, char delimiter) { // Reads the string until it reaches <delimiter>, then returns the number of bytes read
43 48
	int bytes_read = 0;
44 49
	while(string[bytes_read] != delimiter && string[bytes_read] != 0) // Get the next byte until it's the correct one, but don't go too far!
45 50
		bytes_read++;
@ -50,12 +55,12 @@ int string_until(char *string, char delimiter){ // Reads the string until it rea
50 55
}
51 56

													
52 57
int stop = 0; //When the program catches a Ctrl+C event, the status of this variable will change and it will begin a graceful stop
53
void sig_stop(int sig){ // Function called when Ctrl+C event fired
58
void sig_stop (int sig) { // Function called when Ctrl+C event fired
54 59
	stop = 1; // Change the value of stop, so that the program stops on next request
55 60
}
56 61

													
57 62
// Here begins the program
58
int main(int argc, char* argv[]){
63
int main (int argc, char* argv[]) {
59 64
	// First of all, say hello. It's important
60 65
	printf(COLOR_BLUE "\n"
61 66
	"***************\n"
@ -65,38 +70,189 @@ int main(int argc, char* argv[]){
65 70
	/**************************
66 71
	 * 0 - Handle Ctrl+C case *
67 72
	 **************************/
68
	if(signal(SIGINT, sig_stop) == SIG_ERR)
73
	if (signal(SIGINT, sig_stop) == SIG_ERR)
69 74
		perror(COLOR_YELLOW "Could not bind Ctrl+C event. Won't web able to make a clean stop" COLOR_RESET);
70 75
	// But if we can't that's fine, just emit a warning with perror()
71

													
76
	
77
	/*****************************
78
	 * 1 - Set the configuration *
79
	 *****************************/
80
	// We need to know which database to connect to and which port to listen on
81
	
82
	// a - First, initialise everything
83
	char *db_uri = NULL;
84
	char *db_name = NULL;
85
	int port = 0;
86
	
87
	// b - Parse the command line arguments
88
	if (argc > 1) { // The first argument is always the name of the program, which means our parameters begin with the second argument
89
		for (int arg_number = 1; arg_number < argc; arg_number++) {
90
			if (strcmp(argv[arg_number], "--port") == 0 || strcmp(argv[arg_number], "-p") == 0) { // The next argument is the port number
91
				arg_number++;
92
				
93
				if (arg_number >= argc) { // Wow, someone called us ending the call with --port
94
					printf(COLOR_RED "Error : Missing port value (--port)\n" COLOR_RESET);
95
					return -1; // Maybe we should relax, and just ignore the setting. But I'm not feeling like it today. :P
96
				}
97
				
98
				// Set the port number with what we got
99
				port = atoi(argv[arg_number]);
100
				
101
				// Make sure we have a valid port number
102
				if (port <= 0 || port > 65535) {
103
					printf(COLOR_RED "Error : Incorrect port given (got %i)\n" COLOR_RESET, port);
104
					return -1;
105
				}
106
				
107
			} else if (strcmp(argv[arg_number], "--dburi") == 0 || strcmp(argv[arg_number], "-u") == 0) { // We're talking about database this time
108
				arg_number++;
109
				
110
				if (arg_number >= argc) { // Wow, someone called us ending the call with --db
111
					printf(COLOR_RED "Error : Missing database URI value (--dburi)\n" COLOR_RESET);
112
					return -1; // Maybe we should relax, and just ignore the setting. But I'm not feeling like it today. :P
113
				}
114
				
115
				// No special checks about this here, the driver will take care of this
116
				db_uri = argv[arg_number];
117
				
118
			} else if (strcmp(argv[arg_number], "--dbname") == 0 || strcmp(argv[arg_number], "-n") == 0) { // We're talking about database this time
119
				arg_number++;
120
				
121
				if (arg_number >= argc) { // Wow, someone called us ending the call with --db
122
					printf(COLOR_RED "Error : Missing database name value (--dbname)\n" COLOR_RESET);
123
					return -1; // Maybe we should relax, and just ignore the setting. But I'm not feeling like it today. :P
124
				}
125
				
126
				// No special checks about this here, the driver will take care of this
127
				db_name = argv[arg_number];
128
				
129
			} else if (strcmp(argv[arg_number], "--help") == 0|| strcmp(argv[arg_number], "-?") == 0){ // Need some help ?
130
				printf("Usage : %s [OPTIONS]\n"
131
				"  -p, --port=PORT            sets the port the tracker listens to connections on\n"
132
				"  -u, --dburi=DATABASE_URI   sets the MongoDB URI the tracker connects to\n"
133
				"      Format : mongodb://[username:password@]host[:port][/[database][?options]]\n"
134
				"      More details : https://api.mongodb.com/c/current/mongoc_uri_t.html#format\n"
135
				"  -n, --dbname=DATABASE_NAME sets the MongoDB database used for data storage\n", argv[0]);
136
				return 0;
137
				
138
			} else {
139
				printf(COLOR_RED "Unrecognized argument : '%s'\n" COLOR_RESET
140
				"Type '%s --help' for usage\n", argv[arg_number], argv[0]);
141
				return -1;
142
			}
143
		}
144
	}
145
	
146
	// c - Use defaults if we still have nothing set - and give a warning while we're on it
147
	if (port == 0) {
148
		printf(COLOR_YELLOW "No port set (--port). Using default (8080).\n" COLOR_RESET);
149
		port = 8080;
150
	}
151
	if (db_uri == NULL) {
152
		printf(COLOR_YELLOW "No database URI set (--dburi). Using default (mongodb://localhost:27017).\n" COLOR_RESET);
153
		db_uri = "mongodb://localhost:27017";
154
	}
155
	if (db_name == NULL) {
156
		printf(COLOR_YELLOW "No database name set (--dbname). Using default (cpx).\n" COLOR_RESET);
157
		db_name = "cpx";
158
	}
159
	
72 160
	/******************************
73
	 * 1 - Open and bind a socket * 
161
	 * 2 - Open and bind a socket *
74 162
	 ******************************/
75
	// Create a socket
163
	// a - Create a socket
76 164
	int sock = socket(AF_INET, SOCK_STREAM, 0);
77
	if(sock < 0){ // Something went wrong when trying to create the socket
165
	if (sock < 0) { // Something went wrong when trying to create the socket
78 166
		perror(COLOR_RED "Unable to create the socket" COLOR_RESET);
79 167
		return -1;
80 168
	}
81 169
	
82
	// Bind it to the correct port - TODO : Get the port from the command prompt (as an argument)
170
	// b - Avoid "Adress Already in use" error message
171
	int yes = 1;
172
	if(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) {
173
		perror(COLOR_RED "Unable to set socket options" COLOR_RESET);
174
		return -1;
175
	}
176
	
177
	// c - Bind the socket to the correct port
83 178
	SOCKADDR_IN inaddr = { 0 };
84
	inaddr.sin_addr.s_addr = htonl(INADDR_ANY); // You can contact me on any adress
85
	inaddr.sin_port = htons(8080);
179
	inaddr.sin_addr.s_addr = htonl(INADDR_ANY); // You can contact me on any adress, because I'm a server
180
	inaddr.sin_port = htons(port);
86 181
	inaddr.sin_family = AF_INET;
87
	if(bind(sock, (SOCKADDR *) &inaddr, sizeof inaddr) < 0){
182
	if (bind(sock, (SOCKADDR *) &inaddr, sizeof inaddr) < 0) {
88 183
		perror(COLOR_RED "Unable to bind the socket" COLOR_RESET);
89 184
		return -1;
90 185
	}
91 186
	
92
	// Listen to requests
93
	if(listen(sock, 5) < 0){ // We set a maximum of 5 maximum queued requests - perhaps more ?
187
	// d - Listen to requests
188
	if (listen(sock, 5) < 0) { // We set a maximum of 5 maximum queued requests - perhaps more ?
94 189
		perror(COLOR_RED "Could not listen to requests" COLOR_RESET);
95 190
		return -1;
96 191
	}
97 192
	
193
	/******************************
194
	 * 3 - Get the database ready *
195
	 ******************************/
196
	mongoc_init(); // Initialize the driver
197
	
198
	// Connect to the database
199
	mongoc_client_t *client = mongoc_client_new(db_uri);
200
	if (client == NULL){
201
		printf(COLOR_RED "Bad Mongo URI (got '%s')\n" COLOR_RESET, db_uri);
202
		// Some cleanup...
203
		close(sock);
204
		mongoc_cleanup();
205
		return -1;
206
	}
207
	
208
	// Query documents
209
	bson_oid_t oid;
210
	
211
	bson_error_t db_error;
212
	bson_error_t *_db_error = &db_error;
213
	
214
	// Make sure it works (and test our permissions) by adding and removing a document
215
	mongoc_collection_t *db_clients = mongoc_client_get_collection(client, db_name, "clients");
216
	bson_oid_init(&oid, NULL);
217
	bson_t *doc = BCON_NEW("_id", BCON_OID(&oid), "hello", BCON_UTF8("world"));
218
	
219
	if(!mongoc_collection_insert(db_clients, MONGOC_INSERT_NO_VALIDATE, doc, NULL, _db_error)){
220
		printf(COLOR_RED "Database test failed : %d.%d: %s\n" COLOR_RESET, db_error.domain, db_error.code, db_error.message);
221
		// Some cleanup...
222
		close(sock);
223
		bson_destroy(doc);
224
		mongoc_collection_destroy(db_clients);
225
		mongoc_client_destroy(client);
226
		mongoc_cleanup();
227
		return -1;
228
	}
229
	
230
	bson_t *selector = BCON_NEW("_id", BCON_OID(&oid));
231
	bool result;
232
	
233
	result = mongoc_collection_remove(db_clients, MONGOC_REMOVE_NONE, selector, NULL, _db_error);
234
	
235
	// A bit of cleanup before we continue
236
	bson_destroy(doc);
237
	bson_destroy(selector);
238
	
239
	if (!result){
240
		printf(COLOR_RED "Database test failed : %d.%d: %s\n" COLOR_RESET, db_error.domain, db_error.code, db_error.message);
241
		// Some cleanup...
242
		close(sock);
243
		mongoc_collection_destroy(db_clients);
244
		mongoc_client_destroy(client);
245
		mongoc_cleanup();
246
		return -1;
247
	}
248
	
249
	// Initialize the other collections
250
	mongoc_collection_t *db_torrents = mongoc_client_get_collection(client, db_name, "torrents");
251
	mongoc_collection_t *db_users = mongoc_client_get_collection(client, db_name, "users");
252
	mongoc_collection_t *db_whitelist = mongoc_client_get_collection(client, db_name, "whitelist");
253
	
98 254
	/*************************
99
	 * 2 - Initialise memory * 
255
	 * 4 - Initialise memory *
100 256
	 *************************/
101 257
	
102 258
	// a - The request string
@ -106,8 +262,8 @@ int main(int argc, char* argv[]){
106 262
	char *request_params[REQUEST_SIZE];
107 263
	
108 264
	// c - Data related to the processing of the request
109
	char *request_char = request; // Pointer to the processed adress
110
	int length; //The length of the item we're processing
265
	char *request_char; // Pointer to the processed adress - goes through the request characters
266
	int length; // The length of the item we're processing
111 267
	int param_location; // Used when processing parameters, to know the array index corresponding to the parameter name
112 268
	char *param_end; // Used when processing parameters, to know the end of the string related to them
113 269
	char *request_end; // To indicate where we should not go after
@ -115,21 +271,23 @@ int main(int argc, char* argv[]){
115 271
	// d - Socket stuff
116 272
	int response_socket; // The socket we will write our response on
117 273
	SOCKADDR_IN client_data = { 0 }; // We can get some data about the way the client contacted us with this, such as its IP
274
	SOCKADDR *_client_data = (SOCKADDR *)&client_data; // Pointer to the client data so that accept fills it
118 275
	socklen_t client_data_size = (socklen_t) sizeof client_data; // The size of the client data. Not really needed, but the accept() method wants it
119 276
	socklen_t *_client_data_size = &client_data_size; // Just creating the pointer, so that we don't have to do it for every request
120 277
	
121 278
	/************************
122
	 * 3 - Process Requests *
279
	 * 5 - Process Requests *
123 280
	 ************************/
124 281
	
125
	while(stop == 0){ // While we're not asked to stop
282
	while(stop == 0) { // While we're not asked to stop
126 283
		/*****************************
127 284
		 * Get ready for the request *
128 285
		 *****************************/
129 286
		
130 287
		// Reset request buffers
131
		memset(request, 0, 512);
132
		memset(request_params, 0, REQUEST_SIZE);
288
		memset(request, 0, 512 * sizeof(char));
289
		memset(request_params, 0, REQUEST_SIZE * sizeof(char*));
290
		// Short performance note : sizeof is evaluated at compile time, so this doesn't affect performance
133 291
		
134 292
		// Come back to the beginning of the request
135 293
		request_char = request;
@ -138,28 +296,31 @@ int main(int argc, char* argv[]){
138 296
		 * Wait for a request *
139 297
		 **********************/
140 298
		
141
		response_socket = accept(sock, (SOCKADDR *)&client_data, _client_data_size);
299
		response_socket = accept(sock, _client_data, _client_data_size);
142 300
		request_end = request_char + recv(response_socket, request, 512, 0) + 1;
143 301
		
144
		if(request_end == request_char + 1) // If we got 0 bytes, this is not a correct request
145
			goto badreq; // Goto is definitively the best way to do this, as we just want to skip other processing, and if() structure would be horrible
302
		if (request_end == request_char + 1) // If we got 0 bytes, then this is not a correct request
303
			goto badreq; // Goto is definitively the best way to do this, as we just want to skip other processing, and if () structure would be horrible
146 304
		
147 305
		request[511]=0; //Make sure the last byte is 0 (which is the 511st, as numbering begins at 0), just in case
148 306
		
149 307
		/***************************
150 308
		 * Begin of the processing *
151 309
		 ***************************/
152
		// Requests are made in the HTTP style
310
		// Requests are made in the HTTP style.
311
		#ifdef DEBUG
312
			printf("============= DEGIN RAW DATA =============\n%s\n============== END RAW DATA ==============\n", request);
313
		#endif
153 314
		
154 315
		/******************
155 316
		 * Request Method *
156 317
		 ******************/
157 318
		// Make sure the method is a GET
158 319
		length = string_until(request_char, ' ');
159
		if(length == 0) // The request begins with a space - Really ?!
320
		if (length == 0) // The request begins with a space - Really ?!
160 321
			goto badreq;
161 322
		
162
		if(strcmp("GET", request_char) != 0) // I only reply to GET requests
323
		if (strcmp("GET", request_char) != 0) // I only reply to GET requests
163 324
			goto badreq;
164 325

													
165 326
		request_char += length + 2; //Skip the delimiter (+1) and the first slash (+1) --> +2
@ -172,7 +333,7 @@ int main(int argc, char* argv[]){
172 333
		// Put a delimiter at the next slash
173 334
		length = string_until(request_char,'/');
174 335
		
175
		if(length == 0) // If there is no passkey
336
		if (length == 0) // If there is no passkey
176 337
			goto badreq;
177 338
		
178 339
		request_char += length + 1; // Go ahead!
@ -183,11 +344,11 @@ int main(int argc, char* argv[]){
183 344
		// Make sure the client wants an announce
184 345
		length = string_until(request_char, '?'); // "?" is the delimiter between the name of the page and the parameters
185 346
		
186
		if(length == 0) // No page name
347
		if (length == 0) // No page name
187 348
			goto badreq;
188 349
		
189 350
		// Actually, we can only handle announce, so let's check it's what we're asked
190
		if(strcmp(request_char, "announce") != 0){
351
		if (strcmp(request_char, "announce") != 0) {
191 352
			send(response_socket, "d14:failure reason14:Unknown methode", 36, 0);
192 353
			goto nextreq;
193 354
		}
@ -200,32 +361,32 @@ int main(int argc, char* argv[]){
200 361
		// Parameters end with a space. Let's see where we have to stop
201 362
		length = string_until(request_char, ' ');
202 363
		
203
		if(length == 0) // No parameters
364
		if (length == 0) // No parameters
204 365
			goto badreq;
205 366
		
206 367
		param_end = request_char + length; // This is a pointer to the space, which we must not go after!
207 368
		while(param_end > request_char) // If we've passed the space, get out!
208 369
		{
209 370
			length = string_until(request_char, '='); // The equal separates the name of the parameter and its value
210
			if(length == 0) // No more parameters - Normally not triggered, but just in case
371
			if (length == 0) // No more parameters - Normally not triggered, but just in case
211 372
				break;
212 373
			
213 374
			//request_char now contains the name of the parameter
214 375
			param_location=-1;
215 376
			// Determine where we should put the data of the parameter
216
			if(strcmp(request_char, "uploaded") == 0)
377
			if (strcmp(request_char, "uploaded") == 0)
217 378
				param_location=REQUEST_UP;
218
			else if(strcmp(request_char, "downloaded") == 0)
379
			else if (strcmp(request_char, "downloaded") == 0)
219 380
				param_location=REQUEST_DOWN;
220
			else if(strcmp(request_char, "port") == 0)
381
			else if (strcmp(request_char, "port") == 0)
221 382
				param_location=REQUEST_PORT;
222
			else if(strcmp(request_char, "left") == 0)
383
			else if (strcmp(request_char, "left") == 0)
223 384
				param_location=REQUEST_LEFT;
224
			else if(strcmp(request_char, "compact") == 0)
385
			else if (strcmp(request_char, "compact") == 0)
225 386
				param_location=REQUEST_COMPACT;
226
			else if(strcmp(request_char, "event") == 0)
387
			else if (strcmp(request_char, "event") == 0)
227 388
				param_location=REQUEST_EVENT;
228
			else if(strcmp(request_char, "info_hash") == 0)
389
			else if (strcmp(request_char, "info_hash") == 0)
229 390
				param_location=REQUEST_HASH;
230 391
			
231 392
			// Let's see the value of the parameter
@ -233,18 +394,18 @@ int main(int argc, char* argv[]){
233 394

													
234 395
			length = string_until(request_char, '&'); // & indicates a new parameter - or the function will stop at 0, which indicates the end of the parameters
235 396
			
236
			if(length == 0) // Unspecified value
397
			if (length == 0) // Unspecified value
237 398
				goto badreq;
238 399
			
239
			if(param_location != -1) // If we want to use this parameter
400
			if (param_location != -1) // If we want to use this parameter
240 401
				request_params[param_location]=request_char;
241 402
			
242
			request_char += length + 1; // Now, proceed the next parameter!
403
			request_char += length + 1; // Now, process the next parameter!
243 404
		}
244 405
		
245 406
		// Let's check we have all the parameters set
246 407
		for(param_location=REQUEST_UP; param_location < REQUEST_PASSKEY; param_location++)
247
			if(request_params[param_location] == 0) // If one parameter is missing, then we're not fine
408
			if (request_params[param_location] == 0) // If one parameter is missing, then we're not ready to continue
248 409
				goto badreq;
249 410
		
250 411
		/************************
@ -254,18 +415,18 @@ int main(int argc, char* argv[]){
254 415
		
255 416
		// First, let's go to the next line
256 417
		length = string_until(request_char, '\n');
257
		if(length == 0) // Normally, we should have "HTTP/1.1", which is not empty
418
		if (length == 0) // Normally, we should have "HTTP/1.1", which is not empty
258 419
			goto badreq;
259 420
		
260 421
		request_char += length + 1;
261 422
		
262 423
		// Now iterate over the headers
263
		while(request_char < request_end){ // Don't go after the end of the request
424
		while(request_char < request_end) { // Don't go after the end of the request
264 425
			length = string_until(request_char, ':'); // The colon indicates we are switching to the header value
265
			if(length == 0) // No header name
426
			if (length == 0) // No header name
266 427
				goto badreq;
267 428
			
268
			if(strcmp(request_char, "User-Agent") == 0){ // This is the data we want!
429
			if (strcmp(request_char, "User-Agent") == 0) { // This is the data we want!
269 430
				request_char += length + 2; // Go to the corresponding value - There is also a space after the colon
270 431
				
271 432
				request_params[REQUEST_CLIENT] = request_char;
@ -276,21 +437,14 @@ int main(int argc, char* argv[]){
276 437
			} else { // This is not the data we want
277 438
				request_char += length + 1; // Go after ":", and try the next line
278 439
				length = string_until(request_char, '\n');
279
				if(length == 0) //We've reached the end of the data
440
				if (length == 0) //We've reached the end of the data
280 441
					goto badreq; // As we haven't got any data about the client used, we consider this to be a bad request
281 442
			}
282 443
		}
283 444
		// If we reach this point, it means we got the client.
284 445
		
285
		// TODO : Process the data with the DB : Integrate Mongo First!
286
		
287
		/*********************
288
		 * Check the passkey *
289
		 *********************/
290
		// While we're on it, we'll also update the uploaded and downloaded data, as MongoDB will return the number of affected lines
291
		
292
		
293 446
		/**** This is just debug, to show it works correctly ****/
447
		#ifdef DEBUG
294 448
		printf(
295 449
			COLOR_YELLOW "====== THE DATA OF THE REQUEST =======\n"
296 450
			COLOR_BLUE "PASSKEY  : " COLOR_WHITE "%s\n"
@ -310,10 +464,36 @@ int main(int argc, char* argv[]){
310 464
			request_params[REQUEST_COMPACT],
311 465
			request_params[REQUEST_LEFT]
312 466
		);
313
		if(request_params[REQUEST_EVENT] != 0)
467
		if (request_params[REQUEST_EVENT] != 0)
314 468
			printf(COLOR_BLUE "EVENT    : " COLOR_RESET "%s\n", request_params[REQUEST_EVENT]);
315 469
		printf("\n");
470
		#endif
471
		
472
		// And now : process the data with the DB !
473
		
474
		/*********************
475
		 * Check the passkey *
476
		 *********************/
477
		
478
		/*
479
		// So, is your passkey correct ?
480
		selector = BCON_NEW("passkey", request_params[REQUEST_PASSKEY]);
316 481
		
482
		// Let's reuse the length variable to count the number of matching users (normally 1)
483
		
484
		
485
		doc = BCON_NEW("$inc", "{", "upload", BCON_INT32(4), "download", BCON_INT32(4), "}");
486
		if(!mongoc_collection_update(db_users, MONGOC_UPDATE_NO_VALIDATE, selector, doc, NULL, _db_error)){
487
			// BUG : Won't return  the number of docs updated, maybe use mongoc_collection_find_and_modify()
488
			printf(COLOR_RED "Error while updating user's stats : %d.%d: %s\n" COLOR_RESET, db_error.domain, db_error.code, db_error.message);
489
			send(response_socket, "d14:failure reason15:Passkey not recognizede", 44, 0);
490
			goto nextreq;
491
		}
492
		// Of course, cleanup the data
493
		bson_destroy(&doc);
494
		bson_destroy(&selector);
495
		
496
		*/
317 497
		send(response_socket, "d14:failure reason15:Not Implementede", 37, 0);
318 498
		
319 499
		goto nextreq; // Avoid sending him failed request data, he's not going to like it
@ -334,12 +514,23 @@ int main(int argc, char* argv[]){
334 514

													
335 515
	}
336 516
	/*********************
337
	 * 4 - Graceful stop *
517
	 * 6 - Graceful stop *
338 518
	 *********************/
339 519

													
340
	// Just close the socket, the system will take care of the memory
520
	// Close the socket
341 521
	close(sock);
342 522
	
523
	// Free the memory allocated with malloc()
524
	free(request);
525
	
526
	// Also clean up the MongoDB client
527
	mongoc_collection_destroy(db_clients);
528
	mongoc_collection_destroy(db_torrents);
529
	mongoc_collection_destroy(db_users);
530
	mongoc_collection_destroy(db_whitelist);
531
	mongoc_client_destroy(client);
532
	mongoc_cleanup();
533
	
343 534
	// Say everyhing went fine
344 535
	return 0;
345
}
536
}