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