1 /*
2     clsync - file tree sync utility based on inotify
3 
4     Copyright (C) 2013  Dmitry Yu Okunev <dyokunev@ut.mephi.ru> 0x8E30679C
5 
6     This program is free software: you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation, either version 3 of the License, or
9     (at your option) any later version.
10 
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15 
16     You should have received a copy of the GNU General Public License
17     along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #include <stdarg.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <sys/errno.h>
25 #include <sys/param.h>
26 #include <sys/socket.h>
27 #include <sys/un.h>	// for "struct sockaddr_un"
28 #include <unistd.h>
29 
30 
31 #include "configuration.h"
32 #include "error.h"
33 #include "malloc.h"
34 #include "program.h"
35 #include "socket.h"
36 
37 pthread_mutex_t socket_thread_mutex = PTHREAD_MUTEX_INITIALIZER;
38 
39 int clsyncsockthreads_last	= -1;
40 int clsyncsockthreads_count	=  0;
41 int clsyncsockthreads_num	=  0;
42 
43 char clsyncsockthread_busy[SOCKET_MAX+1] = {0};
44 
45 socket_sockthreaddata_t sockthreaddata[SOCKET_MAX+1] = {{0}};
46 
socket_gc()47 int socket_gc() {
48 	int i=clsyncsockthreads_last+1;
49 	while(i) {
50 		i--;
51 		switch(sockthreaddata[i].state) {
52 			case CLSTATE_DIED:
53 				debug(3, "Forgeting clsyncsock #%u", i);
54 				pthread_join(sockthreaddata[i].thread, NULL);
55 				sockthreaddata[i].state = CLSTATE_NONE;
56 				break;
57 			default:
58 				break;
59 		}
60 	}
61 
62 	return 0;
63 }
64 
65 static char *recv_stps[SOCKET_MAX];
66 static char *recv_ptrs[SOCKET_MAX];
67 
68 const char *const textmessage_args[SOCKCMD_MAXID] = {
69 	[SOCKCMD_REQUEST_NEGOTIATION] 	= "%u",
70 	[SOCKCMD_REQUEST_DUMP]	 	= "%s",
71 	[SOCKCMD_REPLY_NEGOTIATION] 	= "%u",
72 	[SOCKCMD_REPLY_ACK]		= "%03u %lu",
73 	[SOCKCMD_REPLY_EINVAL]		= "%03u %lu",
74 	[SOCKCMD_REPLY_VERSION]		= "%u %u %s",
75 	[SOCKCMD_REPLY_INFO]		= "%s\003/ %s\003/ %x %x",
76 	[SOCKCMD_REPLY_UNKNOWNCMD]	= "%03u %lu",
77 	[SOCKCMD_REPLY_INVALIDCMDID]	= "%lu",
78 	[SOCKCMD_REPLY_EEXIST]		= "%s\003/",
79 	[SOCKCMD_REPLY_EPERM]		= "%s\003/",
80 	[SOCKCMD_REPLY_ECUSTOM]		= "%s\003/ %s\003/ %u %s\003/",
81 };
82 
83 const char *const textmessage_descr[SOCKCMD_MAXID] = {
84 	[SOCKCMD_REQUEST_NEGOTIATION]	= "Protocol version is %u.",
85 	[SOCKCMD_REPLY_NEGOTIATION]	= "Protocol version is %u.",
86 	[SOCKCMD_REPLY_ACK]		= "Acknowledged command: id == %03u; num == %lu.",
87 	[SOCKCMD_REPLY_EINVAL]		= "Rejected command: id == %03u; num == %lu. Invalid arguments: %s.",
88 	[SOCKCMD_REPLY_LOGIN]		= "Enter your login and password, please.",
89 	[SOCKCMD_REPLY_UNEXPECTEDEND]	= "Need to go, sorry. :)",
90 	[SOCKCMD_REPLY_DIE]		= "Okay :(",
91 	[SOCKCMD_REPLY_BYE]		= "Bye.",
92 	[SOCKCMD_REPLY_VERSION]		= "clsync v%u.%u%s",
93 	[SOCKCMD_REPLY_INFO]		= "config_block == \"%s\"; label == \"%s\"; flags == %x; flags_set == %x.",
94 	[SOCKCMD_REPLY_DUMP]		= "Ready",
95 	[SOCKCMD_REPLY_UNKNOWNCMD]	= "Unknown command.",
96 	[SOCKCMD_REPLY_INVALIDCMDID]	= "Invalid command id. Required: 0 <= cmd_id < 1000.",
97 	[SOCKCMD_REPLY_EEXIST]		= "File exists: \"%s\".",
98 	[SOCKCMD_REPLY_EPERM]		= "Permission denied: \"%s\".",
99 	[SOCKCMD_REPLY_ECUSTOM]		= "%s(%s): Error #%u: \"%s\".",
100 };
101 
socket_check_bysock(int sock)102 int socket_check_bysock(int sock) {
103 
104 	int error_code, ret;
105 	socklen_t error_code_len = sizeof(error_code);
106 
107 	if((ret=getsockopt(sock, SOL_SOCKET, SO_ERROR, &error_code, &error_code_len))) {
108 		return errno;
109 	}
110 	if(error_code) {
111 		errno = error_code;
112 		return error_code;
113 	}
114 
115 	return 0;
116 }
117 
socket_check(clsyncsock_t * clsyncsock_p)118 static inline int socket_check(clsyncsock_t *clsyncsock_p) {
119 	return socket_check_bysock(clsyncsock_p->sock);
120 }
121 
socket_new(int clsyncsock_sock)122 clsyncsock_t *socket_new(int clsyncsock_sock) {
123 	clsyncsock_t *clsyncsock_p = xmalloc(sizeof(*clsyncsock_p));
124 
125 	debug(2, "sock == %i.", clsyncsock_sock);
126 
127 	clsyncsock_p->sock    = clsyncsock_sock;
128 
129 	clsyncsock_p->prot    = SOCKET_DEFAULT_PROT;
130 	clsyncsock_p->subprot = SOCKET_DEFAULT_SUBPROT;
131 
132 	return clsyncsock_p;
133 }
134 
socket_cleanup(clsyncsock_t * clsyncsock_p)135 int socket_cleanup(clsyncsock_t *clsyncsock_p) {
136 	int clsyncsock_sock = clsyncsock_p->sock;
137 
138 	debug(2, "sock == %i.", clsyncsock_sock);
139 
140 	recv_ptrs[clsyncsock_sock] = NULL;
141 	recv_stps[clsyncsock_sock] = NULL;
142 
143 
144 	free(clsyncsock_p);
145 	return 0;
146 }
147 
socket_close(clsyncsock_t * clsyncsock_p)148 int socket_close(clsyncsock_t *clsyncsock_p) {
149 	close(clsyncsock_p->sock);
150 
151 	return socket_cleanup(clsyncsock_p);
152 }
153 
socket_thread_delete(socket_sockthreaddata_t * threaddata_p)154 int socket_thread_delete(socket_sockthreaddata_t *threaddata_p) {
155 	int thread_id;
156 
157 	pthread_mutex_lock(&socket_thread_mutex);
158 
159 	thread_id = threaddata_p->id;
160 
161 	socket_close(threaddata_p->clsyncsock_p);
162 
163 	clsyncsockthreads_count--;
164 
165 	if(clsyncsockthreads_last == thread_id)
166 		clsyncsockthreads_last = thread_id-1;
167 
168 	clsyncsockthread_busy[thread_id]=0;
169 
170 	threaddata_p->state = CLSTATE_DIED;
171 
172 	if (threaddata_p->freefunct_arg != NULL)
173 		threaddata_p->freefunct_arg(threaddata_p->arg);
174 
175 	pthread_mutex_unlock(&socket_thread_mutex);
176 	return 0;
177 }
178 
socket_accept(int sock)179 clsyncsock_t *socket_accept(int sock) {
180 	// Cleaning up after died connections (getting free space for new connection)
181 	socket_gc();
182 
183 	// Getting new connection
184 	int clsyncsock_sock = accept(sock, NULL, NULL);
185 	if(clsyncsock_sock == -1) {
186 		error("socket_accept(%i): Cannot accept()", sock);
187 		return NULL;
188 	}
189 
190 	return socket_new(clsyncsock_sock);
191 }
192 
socket_listen_unix(const char * const socket_path)193 clsyncsock_t *socket_listen_unix(const char *const socket_path) {
194 	// creating a simple unix socket
195 	int s;
196 	s = socket(AF_UNIX, SOCK_STREAM, 0);
197 
198 	// checking the path
199 	// already exists? - unlink
200 	if(!access(socket_path, F_OK))
201 		if(unlink(socket_path)) {
202 			error("Cannot unlink() \"%s\".",
203 				socket_path);
204 			close(s);
205 			return NULL;
206 		}
207 
208 	// binding
209 	{
210 		struct sockaddr_un addr;
211 		memset(&addr, 0, sizeof(addr));
212 		addr.sun_family = AF_UNIX;
213 		strncpy(addr.sun_path, socket_path, sizeof(addr.sun_path)-1);
214 		if(bind(s, (struct sockaddr *)&addr, sizeof(addr))) {
215 			error("Cannot bind() on address \"%s\".",
216 				socket_path);
217 			close(s);
218 			return NULL;
219 		}
220 	}
221 
222 	// starting to listening
223 	if(listen(s, SOCKET_BACKLOG)) {
224 		error("Cannot listen() on address \"%s\".",
225 			socket_path);
226 		close(s);
227 		return NULL;
228 	}
229 
230 	return socket_new(s);
231 }
232 
233 #ifdef SOCKET_PROVIDER_LIBCLSYNC
socket_connect_unix(const char * const socket_path)234 clsyncsock_t *socket_connect_unix(const char *const socket_path) {
235 	// creating a simple unix socket
236 	int s;
237 
238 	s = socket(AF_UNIX, SOCK_STREAM, 0);
239 	if (s == -1)
240 		return NULL;
241 
242 	// checking the path
243 	if(access(socket_path, F_OK)) {
244 		error("Cannot access() to \"%s\".",
245 			socket_path);
246 		close(s);
247 		return NULL;
248 	}
249 
250 	// connecting
251 	{
252 		struct sockaddr_un addr;
253 		memset(&addr, 0, sizeof(addr));
254 		addr.sun_family = AF_UNIX;
255 		strncpy(addr.sun_path, socket_path, sizeof(addr.sun_path)-1);
256 		if(connect(s, (struct sockaddr *)&addr, sizeof(addr))) {
257 			error("Cannot connect() to address \"%s\".",
258 				socket_path);
259 			close(s);
260 			return NULL;
261 		}
262 	}
263 
264 	return socket_new(s);
265 }
266 #endif
267 
socket_send(clsyncsock_t * clsyncsock,sockcmd_id_t cmd_id,...)268 int socket_send(clsyncsock_t *clsyncsock, sockcmd_id_t cmd_id, ...) {
269 	va_list ap;
270 	int ret;
271 
272 	va_start(ap, cmd_id);
273 	char prebuf0[SOCKET_BUFSIZ], prebuf1[SOCKET_BUFSIZ], sendbuf[SOCKET_BUFSIZ];
274 
275 	ret = 0;
276 
277 	switch(clsyncsock->prot) {
278 		case 0:
279 			switch(clsyncsock->subprot) {
280 				case SUBPROT0_TEXT: {
281 					va_list ap_copy;
282 
283 					debug(3, "%p %p %p", prebuf0, textmessage_args[cmd_id], ap_copy);
284 
285 					if(textmessage_args[cmd_id]) {
286 						va_copy(ap_copy, ap);
287 						vsprintf(prebuf0, textmessage_args[cmd_id], ap_copy);
288 					} else
289 						*prebuf0 = 0;
290 
291 					va_copy(ap_copy, ap);
292 					vsprintf(prebuf1, textmessage_descr[cmd_id], ap);
293 
294 					size_t sendlen = sprintf(sendbuf, "%03u %s :%s\n", cmd_id, prebuf0, prebuf1);
295 
296 					send(clsyncsock->sock, sendbuf, sendlen, 0);
297 					break;
298 				}
299 /*				case SUBPROT0_BINARY:
300 					break;*/
301 				default:
302 					error("Unknown subprotocol with id %u.", clsyncsock->subprot);
303 					ret = EINVAL;
304 					goto l_socket_send_end;
305 			}
306 			break;
307 		default:
308 			error("Unknown protocol with id %u.", clsyncsock->prot);
309 			ret = EINVAL;
310 			goto l_socket_send_end;
311 	}
312 
313 l_socket_send_end:
314 	va_end(ap);
315 	return ret;
316 }
317 
socket_overflow_fix(char * buf,char ** data_start_p,char ** data_end_p)318 static inline int socket_overflow_fix(char *buf, char **data_start_p, char **data_end_p) {
319 	debug(3, "buf==%p; data_start==%p; data_end==%p", buf, *data_start_p, *data_end_p);
320 	if(buf == *data_start_p)
321 		return 0;
322 
323 	size_t ptr_diff = *data_start_p - buf;
324 
325 	if(*data_start_p != *data_end_p) {
326 		*data_start_p = buf;
327 		*data_end_p   = buf;
328 		return ptr_diff;
329 	}
330 
331 	size_t data_length = *data_end_p - *data_start_p;
332 
333 	memmove(buf, *data_start_p, data_length);
334 	*data_start_p =  buf;
335 	*data_end_p   = &buf[data_length];
336 
337 	return ptr_diff;
338 }
339 
340 #define PARSE_TEXT_DATA_SSCANF(dat_t, ...) {\
341 	sockcmd_p->data = xmalloc(sizeof(dat_t));\
342 	dat_t *d = (dat_t *)sockcmd_p->data;\
343 	if(sscanf(args, textmessage_args[sockcmd_p->cmd_id], __VA_ARGS__) < min_args)\
344 		return EINVAL;\
345 }
346 
parse_text_data(sockcmd_t * sockcmd_p,char * args,size_t args_len)347 static inline int parse_text_data(sockcmd_t *sockcmd_p, char *args, size_t args_len) {
348 	if(!args_len)
349 		return 0;
350 
351 	int min_args = 0;
352 	const char *ptr = (const char *)textmessage_args[sockcmd_p->cmd_id];
353 
354 	if(ptr != NULL) {
355 		while(*ptr) {
356 			if(*ptr == '%') {
357 				if(ptr[1] == '%')
358 					ptr++;
359 				else
360 					min_args++;
361 			}
362 			ptr++;
363 		}
364 	}
365 
366 	switch(sockcmd_p->cmd_id) {
367 		case SOCKCMD_REQUEST_NEGOTIATION:
368 		case SOCKCMD_REPLY_NEGOTIATION:
369 			PARSE_TEXT_DATA_SSCANF(sockcmd_dat_negotiation_t, &d->prot, &d->subprot);
370 			break;
371 		case SOCKCMD_REQUEST_DUMP:
372 			PARSE_TEXT_DATA_SSCANF(sockcmd_dat_dump_t, &d->dir_path);
373 			break;
374 		case SOCKCMD_REPLY_ACK:
375 			PARSE_TEXT_DATA_SSCANF(sockcmd_dat_ack_t, &d->cmd_id, &d->cmd_num);
376 			break;
377 		case SOCKCMD_REPLY_EINVAL:
378 			PARSE_TEXT_DATA_SSCANF(sockcmd_dat_einval_t, &d->cmd_id, &d->cmd_num);
379 			break;
380 		case SOCKCMD_REPLY_VERSION:
381 			if(args_len > sizeof(1<<8))
382 				args[args_len=1<<8] = 0;
383 			PARSE_TEXT_DATA_SSCANF(sockcmd_dat_version_t, &d->major, &d->minor, &d->revision);
384 			break;
385 		case SOCKCMD_REPLY_INFO:
386 			if(args_len > sizeof(1<<8))
387 				args[args_len=1<<8] = 0;
388 			PARSE_TEXT_DATA_SSCANF(sockcmd_dat_info_t, &d->config_block, &d->label, &d->flags, &d->flags_set);
389 			break;
390 		case SOCKCMD_REPLY_UNKNOWNCMD:
391 			PARSE_TEXT_DATA_SSCANF(sockcmd_dat_unknowncmd_t, &d->cmd_id, &d->cmd_num);
392 			break;
393 		case SOCKCMD_REPLY_INVALIDCMDID:
394 			PARSE_TEXT_DATA_SSCANF(sockcmd_dat_invalidcmd_t, &d->cmd_num);
395 			break;
396 		case SOCKCMD_REPLY_EEXIST:
397 			PARSE_TEXT_DATA_SSCANF(sockcmd_dat_eexist_t, &d->file_path);
398 			break;
399 		case SOCKCMD_REPLY_EPERM:
400 			PARSE_TEXT_DATA_SSCANF(sockcmd_dat_eperm_t,  &d->descr);
401 			break;
402 		default:
403 			sockcmd_p->data = xmalloc(args_len+1);
404 			memcpy(sockcmd_p->data, args, args_len);
405 			((char *)sockcmd_p->data)[args_len] = 0;
406 			break;
407 	}
408 
409 	return 0;
410 }
411 
socket_recv(clsyncsock_t * clsyncsock,sockcmd_t * sockcmd_p)412 int socket_recv(clsyncsock_t *clsyncsock, sockcmd_t *sockcmd_p) {
413 	static char bufs[SOCKET_MAX][SOCKET_BUFSIZ];
414 	char *buf, *ptr, *start, *end;
415 	int clsyncsock_sock;
416 	size_t filled_length, rest_length, recv_length, filled_length_new;
417 
418 	clsyncsock_sock = clsyncsock->sock;
419 
420 	buf = bufs[clsyncsock_sock];
421 
422 	start =  recv_stps[clsyncsock_sock];
423 	start = (start==NULL ? buf : start);
424 
425 	ptr   =  recv_ptrs[clsyncsock_sock];
426 	ptr   = (ptr==NULL   ? buf : ptr);
427 
428 	debug(3, "buf==%p; start==%p; ptr==%p", buf, start, ptr);
429 
430 	while(1) {
431 		filled_length = ptr-buf;
432 		rest_length = SOCKET_BUFSIZ-filled_length-16;
433 
434 		if(rest_length <= 0) {
435 			if(!socket_overflow_fix(buf, &start, &ptr)) {
436 				debug(1, "Got too big message. Ignoring.");
437 				ptr = buf;
438 			}
439 			continue;
440 		}
441 
442 		recv_length = recv(clsyncsock_sock, ptr, rest_length, 0);
443 		filled_length_new = filled_length + recv_length;
444 
445 		if(recv_length <= 0)
446 			return errno;
447 
448 		switch(clsyncsock->prot) {
449 			case 0: {
450 				// Checking if binary
451 				uint16_t cmd_id_binary = *(uint16_t *)buf;
452 				clsyncsock->subprot = (
453 								cmd_id_binary == SOCKCMD_REQUEST_NEGOTIATION ||
454 								cmd_id_binary == SOCKCMD_REPLY_NEGOTIATION
455 							)
456 							? SUBPROT0_BINARY : SUBPROT0_TEXT;
457 
458 				// Processing
459 				switch(clsyncsock->subprot) {
460 					case SUBPROT0_TEXT:
461 						if((end=strchr(ptr, '\n'))!=NULL) {
462 							if(sscanf(start, "%03u", (unsigned int *)&sockcmd_p->cmd_id) != 1)
463 								return ENOMSG;
464 
465 							char *str_args = &start[3+1];
466 							parse_text_data(sockcmd_p, str_args, end-str_args);
467 
468 
469 							// TODO Process message here
470 
471 							goto l_socket_recv_end;
472 						}
473 						break;
474 					default:
475 						return ENOPROTOOPT;
476 				}
477 				break;
478 			}
479 			default:
480 				return ENOPROTOOPT;
481 		}
482 
483 
484 	}
485 
486 l_socket_recv_end:
487 
488 	//       ----------------------------------
489 	//       buf    ptr    end    filled
490 	// cut:  ---------------
491 	//                    start    ptr
492 	//                     new     new
493 
494 	start = &end[1];
495 	ptr   = &buf[filled_length_new];
496 
497 	// No data buffered. Reset "start" and "ptr".
498 
499 	if(start == ptr) {
500 		start = buf;
501 		ptr   = buf;
502 	}
503 
504 	// Remembering the values
505 
506 	recv_stps[clsyncsock_sock] = start;
507 	recv_ptrs[clsyncsock_sock] = ptr;
508 
509 	debug(3, "sockcmd_p->cmd_id == %i; buf==%p; ptr==%p; end==%p, filled=%p, buf_end==%p",
510 		sockcmd_p->cmd_id, buf, ptr, end, &buf[filled_length_new], &buf[SOCKET_BUFSIZ]);
511 
512 	sockcmd_p->cmd_num++;
513 	return 0;
514 }
515 
socket_sendinvalid(clsyncsock_t * clsyncsock_p,sockcmd_t * sockcmd_p)516 int socket_sendinvalid(clsyncsock_t *clsyncsock_p, sockcmd_t *sockcmd_p) {
517 	if(sockcmd_p->cmd_id >= 1000)
518 		return socket_send(clsyncsock_p, SOCKCMD_REPLY_INVALIDCMDID, sockcmd_p->cmd_num);
519 	else
520 		return socket_send(clsyncsock_p, SOCKCMD_REPLY_UNKNOWNCMD,   sockcmd_p->cmd_id, sockcmd_p->cmd_num);
521 }
522 
socket_procclsyncsock(socket_sockthreaddata_t * arg)523 int socket_procclsyncsock(socket_sockthreaddata_t *arg) {
524 	char		_sockcmd_buf[SOCKET_BUFSIZ]={0};
525 
526 	sockcmd_t		*sockcmd_p    = (sockcmd_t *)_sockcmd_buf;
527 
528 	clsyncsock_t		*clsyncsock_p = arg->clsyncsock_p;
529 	clsyncsock_procfunct_t   procfunct    = arg->procfunct;
530 	//sockprocflags_t		 flags        = arg->flags;
531 
532 	sockcmd_p->cmd_num = -1;
533 
534 	enum auth_flags {
535 		AUTHFLAG_ENTERED_LOGIN = 0x01,
536 	};
537 	typedef enum auth_flags auth_flags_t;
538 	auth_flags_t	 auth_flags = 0;
539 
540 	debug(3, "Started new thread for new connection.");
541 
542 	arg->state = (arg->authtype == SOCKAUTH_NULL) ? CLSTATE_MAIN : CLSTATE_AUTH;
543 	socket_send(clsyncsock_p, SOCKCMD_REQUEST_NEGOTIATION, clsyncsock_p->prot, clsyncsock_p->subprot);
544 
545 	while((arg->running && *arg->running) && (arg->state==CLSTATE_AUTH || arg->state==CLSTATE_MAIN)) {
546 		debug(3, "Iteration.");
547 
548 		// Receiving message
549 		int ret;
550 		if((ret = socket_recv(clsyncsock_p, sockcmd_p))) {
551 			error("Got error while receiving a message from clsyncsock with sock %u: %s (errno: %u)",
552 				arg->clsyncsock_p->sock);
553 			break;
554 		}
555 
556 		// Processing the message
557 		if(procfunct(arg, sockcmd_p))
558 			switch(sockcmd_p->cmd_id) {
559 				case SOCKCMD_REPLY_NEGOTIATION:
560 				case SOCKCMD_REQUEST_NEGOTIATION: {
561 					sockcmd_dat_negotiation_t *data = (sockcmd_dat_negotiation_t *)sockcmd_p->data;
562 					switch(data->prot) {
563 						case 0:
564 							switch(data->subprot) {
565 								case SUBPROT0_TEXT:
566 								case SUBPROT0_BINARY:
567 									clsyncsock_p->subprot = data->subprot;
568 									if(sockcmd_p->cmd_id == SOCKCMD_REQUEST_NEGOTIATION)
569 										socket_send(clsyncsock_p, SOCKCMD_REPLY_NEGOTIATION, data->prot, data->subprot);
570 									else {
571 										socket_send(clsyncsock_p, SOCKCMD_REPLY_ACK,    sockcmd_p->cmd_id, sockcmd_p->cmd_num);
572 										debug(1, "Negotiated proto: %u %u", data->prot, data->subprot);
573 									}
574 									break;
575 								default:
576 									socket_send(clsyncsock_p, SOCKCMD_REPLY_EINVAL, sockcmd_p->cmd_id, sockcmd_p->cmd_num, "Incorrect subprotocol id");
577 							}
578 							break;
579 						default:
580 							socket_send(clsyncsock_p, SOCKCMD_REPLY_EINVAL, sockcmd_p->cmd_id, sockcmd_p->cmd_num, "Incorrect protocol id");
581 					}
582 					break;
583 				}
584 				case SOCKCMD_REQUEST_VERSION: {
585 					socket_send(clsyncsock_p, SOCKCMD_REPLY_VERSION, VERSION_MAJ, VERSION_MIN, REVISION);
586 					break;
587 				}
588 				case SOCKCMD_REQUEST_QUIT: {
589 					socket_send(clsyncsock_p, SOCKCMD_REPLY_BYE);
590 					arg->state = CLSTATE_DYING;
591 					break;
592 				}
593 				default:
594 					socket_sendinvalid(clsyncsock_p, sockcmd_p);
595 					break;
596 			}
597 
598 		if(sockcmd_p->data != NULL) {
599 			free(sockcmd_p->data);
600 			sockcmd_p->data = NULL;
601 		}
602 
603 		// Check if the socket is still alive
604 		if(socket_check(clsyncsock_p)) {
605 			debug(1, "clsyncsock socket error: %s", strerror(errno));
606 			break;
607 		}
608 
609 		// Sending prompt
610 		switch(arg->state) {
611 			case CLSTATE_AUTH:
612 				if(!(auth_flags&AUTHFLAG_ENTERED_LOGIN))
613 					socket_send(clsyncsock_p, SOCKCMD_REQUEST_LOGIN);
614 				break;
615 			default:
616 				break;
617 		}
618 	}
619 
620 	debug(3, "Ending a connection thread.");
621 
622 	socket_thread_delete(arg);
623 
624 	return 0;
625 }
626 
socket_thread_new()627 socket_sockthreaddata_t *socket_thread_new() {
628 	pthread_mutex_lock(&socket_thread_mutex);
629 	socket_sockthreaddata_t *threaddata_p = &sockthreaddata[clsyncsockthreads_num];
630 
631 	if(clsyncsockthreads_num >= SOCKET_MAX) {
632 		error("Warning: socket_thread_new(): Too many connection threads.");
633 		errno = EUSERS;
634 		pthread_mutex_unlock(&socket_thread_mutex);
635 		return NULL;
636 	}
637 
638 	threaddata_p->id = clsyncsockthreads_num;
639 
640 	clsyncsockthread_busy[clsyncsockthreads_num]=1;
641 	// TODO: SECURITY: Possible DoS-attack on huge "SOCKET_MAX" value. Fix it.
642 	while(clsyncsockthread_busy[++clsyncsockthreads_num]);
643 
644 #ifdef PARANOID
645 	// Processing the events: checking if previous check were been made right
646 
647 	if(threaddata_p->state != CLSTATE_NONE) {
648 		// This's not supposed to be
649 		error("Internal-Error: socket_newconnarg(): connproc_arg->state != CLSTATE_NONE");
650 		pthread_mutex_unlock(&socket_thread_mutex);
651 		errno = EILSEQ;
652 		return NULL;
653 	}
654 #endif
655 
656 	// Processing the events: creating a thread for new connection
657 
658 	debug(3, "clsyncsockthreads_count == %u;\tclsyncsockthreads_last == %u;\tclsyncsockthreads_num == %u",
659 		clsyncsockthreads_count, clsyncsockthreads_last, clsyncsockthreads_num);
660 
661 	clsyncsockthreads_last = MAX(clsyncsockthreads_last, clsyncsockthreads_num);
662 
663 	clsyncsockthreads_count++;
664 	pthread_mutex_unlock(&socket_thread_mutex);
665 	return threaddata_p;
666 }
667 
socket_thread_attach(clsyncsock_t * clsyncsock_p)668 socket_sockthreaddata_t *socket_thread_attach(clsyncsock_t *clsyncsock_p) {
669 
670 	socket_sockthreaddata_t *threaddata_p = socket_thread_new();
671 
672 	if (threaddata_p == NULL)
673 		return NULL;
674 
675 	threaddata_p->clsyncsock_p	= clsyncsock_p;
676 
677 	return threaddata_p;
678 }
679 
socket_thread_start(socket_sockthreaddata_t * threaddata_p)680 int socket_thread_start(socket_sockthreaddata_t *threaddata_p) {
681 	if(pthread_create(&threaddata_p->thread, NULL, (void *(*)(void *))socket_procclsyncsock, threaddata_p)) {
682 		error("Cannot create a thread for connection");
683 		return errno;
684 	}
685 
686 	return 0;
687 }
688 
socket_init()689 int socket_init() {
690 	return 0;
691 }
692 
socket_deinit()693 int socket_deinit() {
694 	return 0;
695 }
696 
697 
698