clsync
socket.c
Go to the documentation of this file.
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 <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 
42 
44 
46 
47 int socket_gc()
48 {
49  int i = clsyncsockthreads_last + 1;
50 
51  while ( i ) {
52  i--;
53 
54  switch ( sockthreaddata[i].state ) {
55  case CLSTATE_DIED:
56  debug ( 3, "Forgeting clsyncsock #%u", i );
57  pthread_join ( sockthreaddata[i].thread, NULL );
59  break;
60 
61  default:
62  break;
63  }
64  }
65 
66  return 0;
67 }
68 
69 static char *recv_stps[SOCKET_MAX];
70 static char *recv_ptrs[SOCKET_MAX];
71 
72 const char *const textmessage_args[SOCKCMD_MAXID] = {
74  [SOCKCMD_REQUEST_DUMP] = "%s",
75  [SOCKCMD_REQUEST_SET] = "%s\003/ %s\003/",
77  [SOCKCMD_REPLY_ACK] = "%u %lu",
78  [SOCKCMD_REPLY_EINVAL] = "%u %lu",
79  [SOCKCMD_REPLY_VERSION] = "%u %u %s",
80  [SOCKCMD_REPLY_INFO] = "%s\003/ %s\003/ %x %x",
81  [SOCKCMD_REPLY_UNKNOWNCMD] = "%u %lu",
83  [SOCKCMD_REPLY_EEXIST] = "%s\003/",
84  [SOCKCMD_REPLY_EPERM] = "%s\003/",
85  [SOCKCMD_REPLY_ECUSTOM] = "%s\003/ %s\003/ %u %s\003/",
86 };
87 
88 const char *const textmessage_descr[SOCKCMD_MAXID] = {
89  [SOCKCMD_REQUEST_NEGOTIATION] = "Protocol version is %u.",
90  [SOCKCMD_REPLY_NEGOTIATION] = "Protocol version is %u.",
91  [SOCKCMD_REPLY_ACK] = "Acknowledged command: id == %u; num == %lu.",
92  [SOCKCMD_REPLY_EINVAL] = "Rejected command: id == %u; num == %lu. Invalid arguments: %s.",
93  [SOCKCMD_REPLY_LOGIN] = "Enter your login and password, please.",
94  [SOCKCMD_REPLY_UNEXPECTEDEND] = "Need to go, sorry. :)",
95  [SOCKCMD_REPLY_DIE] = "Okay :(",
96  [SOCKCMD_REPLY_BYE] = "Bye.",
97  [SOCKCMD_REPLY_VERSION] = "clsync v%u.%u%s",
98  [SOCKCMD_REPLY_INFO] = "config_block == \"%s\"; label == \"%s\"; flags == %x; flags_set == %x.",
99  [SOCKCMD_REPLY_SET] = "Set",
100  [SOCKCMD_REPLY_DUMP] = "Ready",
101  [SOCKCMD_REPLY_UNKNOWNCMD] = "Unknown command.",
102  [SOCKCMD_REPLY_INVALIDCMDID] = "Invalid command id. Required: 0 <= cmd_id < 1000.",
103  [SOCKCMD_REPLY_EEXIST] = "File exists: \"%s\".",
104  [SOCKCMD_REPLY_EPERM] = "Permission denied: \"%s\".",
105  [SOCKCMD_REPLY_ECUSTOM] = "%s(%s): Error #%u: \"%s\".",
106 };
107 
108 int socket_check_bysock ( int sock )
109 {
110  int error_code, ret;
111  socklen_t error_code_len = sizeof ( error_code );
112 
113  if ( ( ret = getsockopt ( sock, SOL_SOCKET, SO_ERROR, &error_code, &error_code_len ) ) ) {
114  return errno;
115  }
116 
117  if ( error_code ) {
118  errno = error_code;
119  return error_code;
120  }
121 
122  return 0;
123 }
124 
125 static inline int socket_check ( clsyncsock_t *clsyncsock_p )
126 {
127  return socket_check_bysock ( clsyncsock_p->sock );
128 }
129 
130 clsyncsock_t *socket_new ( int clsyncsock_sock )
131 {
132  clsyncsock_t *clsyncsock_p = xmalloc ( sizeof ( *clsyncsock_p ) );
133  debug ( 2, "sock == %i.", clsyncsock_sock );
134  clsyncsock_p->sock = clsyncsock_sock;
135  clsyncsock_p->prot = SOCKET_DEFAULT_PROT;
136  clsyncsock_p->subprot = SOCKET_DEFAULT_SUBPROT;
137  return clsyncsock_p;
138 }
139 
140 int socket_cleanup ( clsyncsock_t *clsyncsock_p )
141 {
142  int clsyncsock_sock = clsyncsock_p->sock;
143  debug ( 2, "sock == %i.", clsyncsock_sock );
144  recv_ptrs[clsyncsock_sock] = NULL;
145  recv_stps[clsyncsock_sock] = NULL;
146  free ( clsyncsock_p );
147  return 0;
148 }
149 
150 int socket_close ( clsyncsock_t *clsyncsock_p )
151 {
152  close ( clsyncsock_p->sock );
153  return socket_cleanup ( clsyncsock_p );
154 }
155 
157 {
158  int thread_id;
159  pthread_mutex_lock ( &socket_thread_mutex );
160  thread_id = threaddata_p->id;
161  socket_close ( threaddata_p->clsyncsock_p );
163 
164  if ( clsyncsockthreads_last == thread_id )
165  clsyncsockthreads_last = thread_id - 1;
166 
167  clsyncsockthread_busy[thread_id] = 0;
168  threaddata_p->state = CLSTATE_DIED;
169 
170  if ( threaddata_p->freefunct_arg != NULL )
171  threaddata_p->freefunct_arg ( threaddata_p->arg );
172 
173  pthread_mutex_unlock ( &socket_thread_mutex );
174  return 0;
175 }
176 
178 {
179  // Cleaning up after died connections (getting free space for new connection)
180  socket_gc();
181  // Getting new connection
182  int clsyncsock_sock = accept ( sock, NULL, NULL );
183 
184  if ( clsyncsock_sock == -1 ) {
185  error ( "socket_accept(%i): Cannot accept()", sock );
186  return NULL;
187  }
188 
189  return socket_new ( clsyncsock_sock );
190 }
191 
192 clsyncsock_t *socket_listen_unix ( const char *const socket_path )
193 {
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 
215  if ( bind ( s, ( struct sockaddr * ) &addr, sizeof ( addr ) ) ) {
216  error ( "Cannot bind() on address \"%s\".",
217  socket_path );
218  close ( s );
219  return NULL;
220  }
221  }
222 
223  // starting to listening
224  if ( listen ( s, SOCKET_BACKLOG ) ) {
225  error ( "Cannot listen() on address \"%s\".",
226  socket_path );
227  close ( s );
228  return NULL;
229  }
230 
231  return socket_new ( s );
232 }
233 
234 #ifdef SOCKET_PROVIDER_LIBCLSYNC
235 clsyncsock_t *socket_connect_unix ( const char *const socket_path )
236 {
237  // creating a simple unix socket
238  int s;
239  s = socket ( AF_UNIX, SOCK_STREAM, 0 );
240 
241  if ( s == -1 )
242  return NULL;
243 
244  // checking the path
245  if ( access ( socket_path, F_OK ) ) {
246  error ( "Cannot access() to \"%s\".",
247  socket_path );
248  close ( s );
249  return NULL;
250  }
251 
252  // connecting
253  {
254  struct sockaddr_un addr;
255  memset ( &addr, 0, sizeof ( addr ) );
256  addr.sun_family = AF_UNIX;
257  strncpy ( addr.sun_path, socket_path, sizeof ( addr.sun_path ) - 1 );
258 
259  if ( connect ( s, ( struct sockaddr * ) &addr, sizeof ( addr ) ) ) {
260  error ( "Cannot connect() to address \"%s\".",
261  socket_path );
262  close ( s );
263  return NULL;
264  }
265  }
266  return socket_new ( s );
267 }
268 #endif
269 
270 int _socket_send ( clsyncsock_t *clsyncsock, uint64_t *cmd_num_p, sockcmd_id_t cmd_id, va_list ap )
271 {
272  int ret;
273  # define PREBUF0_SIZE ((SOCKET_BUFSIZ >> 1) - 128)
274  # define PREBUF1_SIZE (SOCKET_BUFSIZ >> 1)
275  char prebuf0[PREBUF0_SIZE], prebuf1[PREBUF1_SIZE], sendbuf[SOCKET_BUFSIZ];
276  ret = 0;
277 
278  switch ( clsyncsock->prot ) {
279  case 0:
280  switch ( clsyncsock->subprot ) {
281  case SUBPROT0_TEXT: {
282  va_list ap_copy;
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  vsnprintf ( prebuf0, PREBUF0_SIZE, textmessage_args[cmd_id], ap_copy );
288  } else
289  *prebuf0 = 0;
290 
291  va_copy ( ap_copy, ap );
292  vsnprintf ( prebuf1, PREBUF1_SIZE, textmessage_descr[cmd_id], ap );
293 #ifdef PARANOID
294  prebuf0[PREBUF0_SIZE-1] = 0;
295  prebuf1[PREBUF1_SIZE-1] = 0;
296 #endif
297  size_t sendlen = snprintf (
298  sendbuf, SOCKET_BUFSIZ,
299  "%lu %u %s :%s\n",
300  ( *cmd_num_p )++,
301  cmd_id, prebuf0, prebuf1
302  );
303 #ifdef PARANOID
304  sendbuf[SOCKET_BUFSIZ-1] = 0;
305 #endif
306  debug ( 5, "send(): \"%s\"", sendbuf );
307  send ( clsyncsock->sock, sendbuf, sendlen, 0 );
308  break;
309  }
310 
311  /* case SUBPROT0_BINARY:
312  break;*/
313  default:
314  error ( "Unknown subprotocol with id %u.", clsyncsock->subprot );
315  ret = EINVAL;
316  goto l_socket_send_end;
317  }
318 
319  break;
320 
321  default:
322  error ( "Unknown protocol with id %u.", clsyncsock->prot );
323  ret = EINVAL;
324  goto l_socket_send_end;
325  }
326 
327 l_socket_send_end:
328  return ret;
329 }
330 
331 int socket_reply ( clsyncsock_t *clsyncsock_p, sockcmd_t *sockcmd_p, sockcmd_id_t cmd_id, ... )
332 {
333  va_list ap;
334  int ret;
335  uint64_t cmd_num = sockcmd_p->cmd_num;
336  va_start ( ap, cmd_id );
337  ret = _socket_send ( clsyncsock_p, &cmd_num, cmd_id, ap );
338  va_end ( ap );
339  return ret;
340 }
341 
342 int socket_send ( clsyncsock_t *clsyncsock_p, sockcmd_id_t cmd_id, ... )
343 {
344  va_list ap;
345  int ret;
346  va_start ( ap, cmd_id );
347  ret = _socket_send ( clsyncsock_p, &clsyncsock_p->cmd_num, cmd_id, ap );
348  va_end ( ap );
349  return ret;
350 }
351 
352 int socket_send_cb ( clsyncsock_t *clsyncsock_p, sockcmd_id_t cmd_id, clsyncsock_cb_funct_t cb, void *cb_arg, ... )
353 {
354  if ( clsyncsock_p->cbqueue_len >= CLSYNCSOCK_WINDOW ) {
355  errno = EOVERFLOW;
356  error ( "Callback queue overflowed. Closing the socket." );
357  socket_close ( clsyncsock_p );
358  return errno;
359  }
360 
361  {
362  va_list ap;
363  int ret;
364  uint64_t cmd_num = clsyncsock_p->cmd_num;
365  va_start ( ap, cb_arg );
366  ret = _socket_send ( clsyncsock_p, &clsyncsock_p->cmd_num, cmd_id, ap );
367  va_end ( ap );
368 
369  if ( !ret ) {
370  clsynccbqueue_t *cbq = &clsyncsock_p->cbqueue[clsyncsock_p->cbqueue_len];
371  int id;
372  cbq->cmd_num = cmd_num;
373  cbq->callback_funct = cb;
374  cbq->callback_arg = cb_arg;
375  id = cmd_num % ( 2 * CLSYNCSOCK_WINDOW );
376 
377  while ( clsyncsock_p->cbqueue_cache[id] != NULL ) id++;
378 
379  clsyncsock_p->cbqueue_cache[id] = cbq;
380  clsyncsock_p->cbqueue_len++;
381  }
382 
383  return ret;
384  }
385 }
386 
387 static inline int socket_overflow_fix ( char *buf, char **data_start_p, char **data_end_p )
388 {
389  debug ( 3, "buf==%p; data_start==%p; data_end==%p", buf, *data_start_p, *data_end_p );
390 
391  if ( buf == *data_start_p )
392  return 0;
393 
394  size_t ptr_diff = *data_start_p - buf;
395 
396  if ( *data_start_p != *data_end_p ) {
397  *data_start_p = buf;
398  *data_end_p = buf;
399  return ptr_diff;
400  }
401 
402  size_t data_length = *data_end_p - *data_start_p;
403  memmove ( buf, *data_start_p, data_length );
404  *data_start_p = buf;
405  *data_end_p = &buf[data_length];
406  return ptr_diff;
407 }
408 
409 #define PARSE_TEXT_DATA_SSCANF(dat_t, ...) {\
410  sockcmd_p->data = xmalloc(sizeof(dat_t));\
411  dat_t *d = (dat_t *)sockcmd_p->data;\
412  if (sscanf(args, textmessage_args[sockcmd_p->cmd_id], __VA_ARGS__) < min_args)\
413  return EINVAL;\
414  }
415 
416 static inline int parse_text_data ( sockcmd_t *sockcmd_p, char *args, size_t args_len )
417 {
418  debug ( 6, "(%p, %p, %u)", sockcmd_p, args, args_len );
419 
420  if ( !args_len )
421  return 0;
422 
423  int min_args = 0;
424  const char *ptr = ( const char * ) textmessage_args[sockcmd_p->cmd_id];
425 
426  if ( ptr != NULL ) {
427  while ( *ptr ) {
428  if ( *ptr == '%' ) {
429  if ( ptr[1] == '%' )
430  ptr++;
431  else
432  min_args++;
433  }
434 
435  ptr++;
436  }
437  }
438 
439  switch ( sockcmd_p->cmd_id ) {
443  break;
444 
447  break;
448 
449  case SOCKCMD_REQUEST_SET:
450  PARSE_TEXT_DATA_SSCANF ( sockcmd_dat_set_t, &d->key, &d->value );
451  break;
452 
453  case SOCKCMD_REPLY_ACK:
454  PARSE_TEXT_DATA_SSCANF ( sockcmd_dat_ack_t, &d->cmd_id, &d->cmd_num );
455  break;
456 
458  PARSE_TEXT_DATA_SSCANF ( sockcmd_dat_einval_t, &d->cmd_id, &d->cmd_num );
459  break;
460 
462  if ( args_len > sizeof ( 1 << 8 ) )
463  args[args_len = 1 << 8] = 0;
464 
465  PARSE_TEXT_DATA_SSCANF ( sockcmd_dat_version_t, &d->major, &d->minor, &d->revision );
466  break;
467 
468  case SOCKCMD_REPLY_INFO:
469  if ( args_len > sizeof ( 1 << 8 ) )
470  args[args_len = 1 << 8] = 0;
471 
472  PARSE_TEXT_DATA_SSCANF ( sockcmd_dat_info_t, &d->config_block, &d->label, &d->flags, &d->flags_set );
473  break;
474 
476  PARSE_TEXT_DATA_SSCANF ( sockcmd_dat_unknowncmd_t, &d->cmd_id, &d->cmd_num );
477  break;
478 
481  break;
482 
485  break;
486 
487  case SOCKCMD_REPLY_EPERM:
489  break;
490 
491  default:
492  sockcmd_p->data = xmalloc ( args_len + 1 );
493  memcpy ( sockcmd_p->data, args, args_len );
494  ( ( char * ) sockcmd_p->data ) [args_len] = 0;
495  break;
496  }
497 
498  return 0;
499 }
500 
502 {
503  static char bufs[SOCKET_MAX][SOCKET_BUFSIZ];
504  char *buf, *ptr, *start, *end;
505  int clsyncsock_sock;
506  size_t filled_length, rest_length, filled_length_new;
507  ssize_t recv_length;
508  errno = 0;
509  clsyncsock_sock = clsyncsock->sock;
510  buf = bufs[clsyncsock_sock];
511  start = recv_stps[clsyncsock_sock];
512  start = ( start == NULL ? buf : start );
513  ptr = recv_ptrs[clsyncsock_sock];
514  ptr = ( ptr == NULL ? buf : ptr );
515  debug ( 3, "buf==%p; start==%p; ptr==%p", buf, start, ptr );
516 
517  while ( 1 ) {
518  filled_length = ptr - buf;
519  rest_length = SOCKET_BUFSIZ - filled_length - 16;
520 
521  if ( rest_length <= 0 ) {
522  if ( !socket_overflow_fix ( buf, &start, &ptr ) ) {
523  debug ( 1, "Got too big message. Ignoring." );
524  ptr = buf;
525  }
526 
527  continue;
528  }
529 
530  recv_length = recv ( clsyncsock_sock, ptr, rest_length, 0 );
531  filled_length_new = filled_length + recv_length;
532  debug ( 5, "recv_length == %u; filled_length_new == %u", recv_length, filled_length_new );
533 
534  if ( recv_length == 0 )
535  return ECONNRESET;
536 
537  if ( recv_length < 0 )
538  return errno;
539 
540  switch ( clsyncsock->prot ) {
541  case 0: {
542  // Checking if binary
543  uint16_t cmd_id_binary = * ( uint16_t * ) buf;
544  clsyncsock->subprot = (
545  cmd_id_binary == SOCKCMD_REQUEST_NEGOTIATION ||
546  cmd_id_binary == SOCKCMD_REPLY_NEGOTIATION
547  )
549 
550  // Processing
551  switch ( clsyncsock->subprot ) {
552  case SUBPROT0_TEXT:
553  if ( ( end = strchr ( ptr, '\n' ) ) != NULL ) {
554  if ( sscanf ( start, "%lu %u", &sockcmd_p->cmd_num, ( unsigned int * ) &sockcmd_p->cmd_id ) != 2 ) {
555  *end = 0;
556  error ( "It's expected to parse \"%%lu %%u\" from \"%s\"", start );
557  *end = '\n';
558  return errno = ENOMSG;
559  }
560 
561  char *str_args = start;
562 
563  // Skipping the first number
564  while ( *str_args >= '0' && *str_args <= '9' ) str_args++;
565 
566  // Skipping the space
567  str_args++;
568 
569  // Skipping the second number
570  while ( *str_args >= '0' && *str_args <= '9' ) str_args++;
571 
572  // Skipping the space
573  str_args++;
574 
575  // Parsing the arguments
576  if ( end > str_args )
577  parse_text_data ( sockcmd_p, str_args, end - str_args );
578 
579  // TODO Process message here
580  goto l_socket_recv_end;
581  }
582 
583  break;
584 
585  default:
586  return errno = ENOPROTOOPT;
587  }
588 
589  break;
590  }
591 
592  default:
593  return errno = ENOPROTOOPT;
594  }
595  }
596 
597 l_socket_recv_end:
598  // ----------------------------------
599  // buf ptr end filled
600  // cut: ---------------
601  // start ptr
602  // new new
603  start = &end[1];
604  ptr = &buf[filled_length_new];
605 
606  // No data buffered. Reset "start" and "ptr".
607 
608  if ( start == ptr ) {
609  start = buf;
610  ptr = buf;
611  }
612 
613  // Remembering the values
614  recv_stps[clsyncsock_sock] = start;
615  recv_ptrs[clsyncsock_sock] = ptr;
616  debug ( 3, "sockcmd_p->cmd_num == %lu; sockcmd_p->cmd_id == %i; buf==%p; ptr==%p; end==%p, filled=%p, buf_end==%p",
617  sockcmd_p->cmd_num, sockcmd_p->cmd_id, buf, ptr, end, &buf[filled_length_new], &buf[SOCKET_BUFSIZ] );
618  return 0;
619 }
620 
621 int socket_sendinvalid ( clsyncsock_t *clsyncsock_p, sockcmd_t *sockcmd_p )
622 {
623  if ( sockcmd_p->cmd_id >= 1000 )
624  return socket_reply ( clsyncsock_p, sockcmd_p, SOCKCMD_REPLY_INVALIDCMDID, sockcmd_p->cmd_num );
625  else
626  return socket_reply ( clsyncsock_p, sockcmd_p, SOCKCMD_REPLY_UNKNOWNCMD, sockcmd_p->cmd_id, sockcmd_p->cmd_num );
627 }
628 
630 {
631  char _sockcmd_buf[SOCKET_BUFSIZ] = {0};
632  sockcmd_t *sockcmd_p = ( sockcmd_t * ) _sockcmd_buf;
633  clsyncsock_t *clsyncsock_p = arg->clsyncsock_p;
634  clsyncsock_procfunct_t procfunct = arg->procfunct;
635  //sockprocflags_t flags = arg->flags;
636  enum auth_flags {
637  AUTHFLAG_ENTERED_LOGIN = 0x01,
638  };
639  typedef enum auth_flags auth_flags_t;
640  auth_flags_t auth_flags = 0;
641  debug ( 3, "Started new thread for new connection." );
642  arg->state = ( arg->authtype == SOCKAUTH_NULL ) ? CLSTATE_MAIN : CLSTATE_AUTH;
643  socket_send ( clsyncsock_p, SOCKCMD_REQUEST_NEGOTIATION, clsyncsock_p->prot, clsyncsock_p->subprot );
644 
645  while ( ( arg->running && *arg->running ) && ( arg->state == CLSTATE_AUTH || arg->state == CLSTATE_MAIN ) ) {
646  debug ( 3, "Iteration." );
647  // Receiving message
648  int ret;
649 
650  if ( ( ret = socket_recv ( clsyncsock_p, sockcmd_p ) ) ) {
651  debug ( 2, "Got error while receiving a message from clsyncsock with sock %u. Ending the thread.",
652  arg->clsyncsock_p->sock );
653  break;
654  }
655 
656  // Checking for a callback for this answer
657  {
658  uint64_t cmd_num = sockcmd_p->cmd_num;
659  int i;
660  i = cmd_num % ( 2 * CLSYNCSOCK_WINDOW );
661 
662  while ( clsyncsock_p->cbqueue_cache[i] != NULL ) {
663  if ( clsyncsock_p->cbqueue_cache[i]->cmd_num == cmd_num ) { // Found!
664  clsynccbqueue_t *cbq;
665  cbq = clsyncsock_p->cbqueue_cache[i];
666  // Calling the callback function
667  cbq->callback_funct ( arg, sockcmd_p, cbq->callback_arg );
668  // Removing from queue
669  memcpy ( cbq, &clsyncsock_p->cbqueue[--clsyncsock_p->cbqueue_len], sizeof ( *cbq ) );
670  clsyncsock_p->cbqueue_cache[i] = NULL;
671  }
672 
673  i++;
674  }
675  }
676 
677  // Processing the message
678  if ( procfunct ( arg, sockcmd_p ) )
679  switch ( sockcmd_p->cmd_id ) {
683 
684  switch ( data->prot ) {
685  case 0:
686  switch ( data->subprot ) {
687  case SUBPROT0_TEXT:
688  case SUBPROT0_BINARY:
689  clsyncsock_p->subprot = data->subprot;
690 
691  if ( sockcmd_p->cmd_id == SOCKCMD_REQUEST_NEGOTIATION )
692  socket_reply ( clsyncsock_p, sockcmd_p, SOCKCMD_REPLY_NEGOTIATION, data->prot, data->subprot );
693  else {
694  socket_reply ( clsyncsock_p, sockcmd_p, SOCKCMD_REPLY_ACK, sockcmd_p->cmd_id, sockcmd_p->cmd_num );
695  debug ( 1, "Negotiated proto: %u %u", data->prot, data->subprot );
696  }
697 
698  break;
699 
700  default:
701  socket_reply ( clsyncsock_p, sockcmd_p, SOCKCMD_REPLY_EINVAL, sockcmd_p->cmd_id, sockcmd_p->cmd_num, "Incorrect subprotocol id" );
702  }
703 
704  break;
705 
706  default:
707  socket_reply ( clsyncsock_p, sockcmd_p, SOCKCMD_REPLY_EINVAL, sockcmd_p->cmd_id, sockcmd_p->cmd_num, "Incorrect protocol id" );
708  }
709 
710  break;
711  }
712 
714  socket_reply ( clsyncsock_p, sockcmd_p, SOCKCMD_REPLY_VERSION, VERSION_MAJ, VERSION_MIN, REVISION );
715  break;
716  }
717 
718  case SOCKCMD_REQUEST_QUIT: {
719  socket_reply ( clsyncsock_p, sockcmd_p, SOCKCMD_REPLY_BYE );
720  arg->state = CLSTATE_DYING;
721  break;
722  }
723 
724  default:
725  socket_sendinvalid ( clsyncsock_p, sockcmd_p );
726  break;
727  }
728 
729  if ( sockcmd_p->data != NULL ) {
730  free ( sockcmd_p->data );
731  sockcmd_p->data = NULL;
732  }
733 
734  // Check if the socket is still alive
735  if ( socket_check ( clsyncsock_p ) ) {
736  debug ( 1, "clsyncsock socket error: %s", strerror ( errno ) );
737  break;
738  }
739 
740  // Sending prompt
741  switch ( arg->state ) {
742  case CLSTATE_AUTH:
743  if ( ! ( auth_flags & AUTHFLAG_ENTERED_LOGIN ) )
744  socket_send ( clsyncsock_p, SOCKCMD_REQUEST_LOGIN );
745 
746  break;
747 
748  default:
749  break;
750  }
751  }
752 
753  debug ( 3, "Ending a connection thread." );
754  socket_thread_delete ( arg );
755  return 0;
756 }
757 
759 {
760  pthread_mutex_lock ( &socket_thread_mutex );
762 
764  error ( "Warning: socket_thread_new(): Too many connection threads." );
765  errno = EUSERS;
766  pthread_mutex_unlock ( &socket_thread_mutex );
767  return NULL;
768  }
769 
770  threaddata_p->id = clsyncsockthreads_num;
772 
773  // TODO: SECURITY: Possible DoS-attack on huge "SOCKET_MAX" value. Fix it.
775 
776 #ifdef PARANOID
777  // Processing the events: checking if previous check were been made right
778 
779  if ( threaddata_p->state != CLSTATE_NONE ) {
780  // This's not supposed to be
781  error ( "Internal-Error: socket_newconnarg(): connproc_arg->state != CLSTATE_NONE" );
782  pthread_mutex_unlock ( &socket_thread_mutex );
783  errno = EILSEQ;
784  return NULL;
785  }
786 
787 #endif
788  // Processing the events: creating a thread for new connection
789  debug ( 3, "clsyncsockthreads_count == %u;\tclsyncsockthreads_last == %u;\tclsyncsockthreads_num == %u",
793  pthread_mutex_unlock ( &socket_thread_mutex );
794  return threaddata_p;
795 }
796 
798 {
799  socket_sockthreaddata_t *threaddata_p = socket_thread_new();
800 
801  if ( threaddata_p == NULL )
802  return NULL;
803 
804  threaddata_p->clsyncsock_p = clsyncsock_p;
805  return threaddata_p;
806 }
807 
809 {
810  if ( pthread_create ( &threaddata_p->thread, NULL, ( void * ( * ) ( void * ) ) socket_procclsyncsock, threaddata_p ) ) {
811  error ( "Cannot create a thread for connection" );
812  return errno;
813  }
814 
815  return 0;
816 }
817 
819 {
820  return 0;
821 }
822 
824 {
825  return 0;
826 }
827 
828 
recv_ptrs
static char * recv_ptrs[8]
Definition: socket.c:70
socket_sockthreaddata
Definition: socket.h:209
socket_sockthreaddata::id
int id
Definition: socket.h:210
sockcmd_dat_version::major
int major
Definition: socket.h:151
clsyncsock_procfunct_t
int(* clsyncsock_procfunct_t)(struct socket_sockthreaddata *, sockcmd_t *)
Definition: socket.h:207
clsyncsock::cbqueue_cache
clsynccbqueue_t * cbqueue_cache[4 *CLSYNCSOCK_WINDOW+1]
Definition: socket.h:74
socket_sockthreaddata::clsyncsock_p
clsyncsock_t * clsyncsock_p
Definition: socket.h:213
socket_sockthreaddata::arg
void * arg
Definition: socket.h:214
recv_stps
static char * recv_stps[8]
Definition: socket.c:69
clsyncsock_cb_funct_t
int(* clsyncsock_cb_funct_t)(struct socket_sockthreaddata *thread, struct sockcmd *sockcmd_p, void *arg)
Definition: socket.h:56
sockcmd_dat_dump::dir_path
char dir_path[PATH_MAX]
Definition: socket.h:166
SOCKET_DEFAULT_SUBPROT
#define SOCKET_DEFAULT_SUBPROT
Definition: socket.h:35
SOCKCMD_REQUEST_SET
@ SOCKCMD_REQUEST_SET
Definition: socket.h:114
close
close(fd_w)
sockcmd_id_t
enum sockcmd_id sockcmd_id_t
Definition: socket.h:127
socket_thread_new
socket_sockthreaddata_t * socket_thread_new()
Definition: socket.c:758
socket_thread_start
int socket_thread_start(socket_sockthreaddata_t *threaddata_p)
Definition: socket.c:808
program.h
sockcmd_dat_info::config_block
char config_block[1<< 8]
Definition: socket.h:158
SOCKET_MAX
#define SOCKET_MAX
Definition: socket.h:50
CLSTATE_DYING
@ CLSTATE_DYING
Definition: socket.h:95
clsyncsock::subprot
uint16_t subprot
Definition: socket.h:68
clsynccbqueue::callback_funct
clsyncsock_cb_funct_t callback_funct
Definition: socket.h:60
PREBUF0_SIZE
#define PREBUF0_SIZE
SOCKCMD_MAXID
@ SOCKCMD_MAXID
Definition: socket.h:125
SOCKCMD_REPLY_VERSION
@ SOCKCMD_REPLY_VERSION
Definition: socket.h:117
SOCKCMD_REPLY_BYE
@ SOCKCMD_REPLY_BYE
Definition: socket.h:123
PREBUF1_SIZE
#define PREBUF1_SIZE
socket_listen_unix
clsyncsock_t * socket_listen_unix(const char *const socket_path)
Definition: socket.c:192
sockcmd_dat_ack
Definition: socket.h:135
clsynccbqueue
Definition: socket.h:57
clsyncsockthreads_last
int clsyncsockthreads_last
Definition: socket.c:39
sockcmd_dat_negotiation::prot
uint16_t prot
Definition: socket.h:130
socket_send
int socket_send(clsyncsock_t *clsyncsock_p, sockcmd_id_t cmd_id,...)
Definition: socket.c:342
sockcmd_dat_unknowncmd_t
#define sockcmd_dat_unknowncmd_t
Definition: socket.h:143
socket_recv
int socket_recv(clsyncsock_t *clsyncsock, sockcmd_t *sockcmd_p)
Definition: socket.c:501
_socket_send
int _socket_send(clsyncsock_t *clsyncsock, uint64_t *cmd_num_p, sockcmd_id_t cmd_id, va_list ap)
Definition: socket.c:270
SOCKCMD_REPLY_DIE
@ SOCKCMD_REPLY_DIE
Definition: socket.h:122
sockcmd_dat_dump
Definition: socket.h:165
CLSTATE_AUTH
@ CLSTATE_AUTH
Definition: socket.h:93
clsyncsockthread_busy
char clsyncsockthread_busy[8+1]
Definition: socket.c:43
socket_sockthreaddata::running
int * running
Definition: socket.h:217
SOCKCMD_REPLY_LOGIN
@ SOCKCMD_REPLY_LOGIN
Definition: socket.h:120
SOCKCMD_REPLY_UNEXPECTEDEND
@ SOCKCMD_REPLY_UNEXPECTEDEND
Definition: socket.h:124
socket_reply
int socket_reply(clsyncsock_t *clsyncsock_p, sockcmd_t *sockcmd_p, sockcmd_id_t cmd_id,...)
Definition: socket.c:331
clsyncsockthreads_num
int clsyncsockthreads_num
Definition: socket.c:41
clsyncsock::prot
uint16_t prot
Definition: socket.h:67
sockcmd_dat_invalidcmd::cmd_num
uint64_t cmd_num
Definition: socket.h:146
sockcmd_dat_set::key
char key[BUFSIZ]
Definition: socket.h:181
if
if(auditd_restart())
Definition: mon_bsm.c:262
socket_deinit
int socket_deinit()
Definition: socket.c:823
socket_cleanup
int socket_cleanup(clsyncsock_t *clsyncsock_p)
Definition: socket.c:140
sockcmd_dat_einval_t
#define sockcmd_dat_einval_t
Definition: socket.h:141
SUBPROT0_BINARY
@ SUBPROT0_BINARY
Definition: socket.h:87
SOCKCMD_REQUEST_LOGIN
@ SOCKCMD_REQUEST_LOGIN
Definition: socket.h:113
SOCKCMD_REQUEST_NEGOTIATION
@ SOCKCMD_REQUEST_NEGOTIATION
Definition: socket.h:101
SOCKAUTH_NULL
@ SOCKAUTH_NULL
Definition: socket.h:201
CLSYNCSOCK_WINDOW
#define CLSYNCSOCK_WINDOW
Definition: configuration.h:159
sockcmd::cmd_id
uint16_t cmd_id
Definition: socket.h:188
sockcmd_dat_invalidcmd
Definition: socket.h:145
error
#define error(...)
Definition: error.h:36
SOCKCMD_REPLY_INFO
@ SOCKCMD_REPLY_INFO
Definition: socket.h:118
SOCKCMD_REPLY_ECUSTOM
@ SOCKCMD_REPLY_ECUSTOM
Definition: socket.h:109
error.h
CLSTATE_MAIN
@ CLSTATE_MAIN
Definition: socket.h:94
socket_thread_delete
int socket_thread_delete(socket_sockthreaddata_t *threaddata_p)
Definition: socket.c:156
sockcmd_dat_negotiation::subprot
uint16_t subprot
Definition: socket.h:131
textmessage_args
const char *const textmessage_args[SOCKCMD_MAXID]
Definition: socket.c:72
socket_sendinvalid
int socket_sendinvalid(clsyncsock_t *clsyncsock_p, sockcmd_t *sockcmd_p)
Definition: socket.c:621
malloc.h
socket_close
int socket_close(clsyncsock_t *clsyncsock_p)
Definition: socket.c:150
socket_overflow_fix
static int socket_overflow_fix(char *buf, char **data_start_p, char **data_end_p)
Definition: socket.c:387
debug
#define debug(debug_level,...)
Definition: error.h:50
SOCKCMD_REPLY_EINVAL
@ SOCKCMD_REPLY_EINVAL
Definition: socket.h:106
CLSTATE_DIED
@ CLSTATE_DIED
Definition: socket.h:96
socket_sockthreaddata::authtype
sockauth_id_t authtype
Definition: socket.h:216
sockcmd_dat_eexist::file_path
char file_path[PATH_MAX]
Definition: socket.h:171
CLSTATE_NONE
@ CLSTATE_NONE
Definition: socket.h:92
socket_procclsyncsock
int socket_procclsyncsock(socket_sockthreaddata_t *arg)
Definition: socket.c:629
clsyncsock::sock
int sock
Definition: socket.h:66
sockcmd::cmd_num
uint64_t cmd_num
Definition: socket.h:187
SOCKCMD_REPLY_SET
@ SOCKCMD_REPLY_SET
Definition: socket.h:121
socket_send_cb
int socket_send_cb(clsyncsock_t *clsyncsock_p, sockcmd_id_t cmd_id, clsyncsock_cb_funct_t cb, void *cb_arg,...)
Definition: socket.c:352
sockcmd_dat_info
Definition: socket.h:157
SOCKCMD_REPLY_UNKNOWNCMD
@ SOCKCMD_REPLY_UNKNOWNCMD
Definition: socket.h:104
sockcmd_dat_eperm
Definition: socket.h:175
sockthreaddata
socket_sockthreaddata_t sockthreaddata[8+1]
Definition: socket.c:45
SUBPROT0_TEXT
@ SUBPROT0_TEXT
Definition: socket.h:86
socket_gc
int socket_gc()
Definition: socket.c:47
SOCKET_BUFSIZ
#define SOCKET_BUFSIZ
Definition: socket.h:38
socket_sockthreaddata::procfunct
clsyncsock_procfunct_t procfunct
Definition: socket.h:211
sockcmd_dat_negotiation
Definition: socket.h:129
SOCKCMD_REPLY_INVALIDCMDID
@ SOCKCMD_REPLY_INVALIDCMDID
Definition: socket.h:105
SOCKCMD_REQUEST_VERSION
@ SOCKCMD_REQUEST_VERSION
Definition: socket.h:110
configuration.h
sockcmd
Definition: socket.h:186
socket.h
SOCKCMD_REQUEST_QUIT
@ SOCKCMD_REQUEST_QUIT
Definition: socket.h:116
clsynccbqueue::callback_arg
void * callback_arg
Definition: socket.h:61
sockcmd_dat_eperm::descr
char descr[BUFSIZ]
Definition: socket.h:176
SOCKCMD_REPLY_EPERM
@ SOCKCMD_REPLY_EPERM
Definition: socket.h:108
socket_sockthreaddata::thread
pthread_t thread
Definition: socket.h:219
socket_init
int socket_init()
Definition: socket.c:818
clsyncsock::cmd_num
uint64_t cmd_num
Definition: socket.h:70
socket_thread_mutex
pthread_mutex_t socket_thread_mutex
Definition: socket.c:37
PARSE_TEXT_DATA_SSCANF
#define PARSE_TEXT_DATA_SSCANF(dat_t,...)
Definition: socket.c:409
SOCKET_DEFAULT_PROT
#define SOCKET_DEFAULT_PROT
Definition: socket.h:34
sockcmd_dat_version
Definition: socket.h:150
clsyncsock::cbqueue_len
size_t cbqueue_len
Definition: socket.h:72
socket_sockthreaddata::freefunct_arg
freefunct_t freefunct_arg
Definition: socket.h:212
socket_check_bysock
int socket_check_bysock(int sock)
Definition: socket.c:108
textmessage_descr
const char *const textmessage_descr[SOCKCMD_MAXID]
Definition: socket.c:88
sockcmd_dat_eexist
Definition: socket.h:170
SOCKCMD_REPLY_ACK
@ SOCKCMD_REPLY_ACK
Definition: socket.h:103
clsyncsock::cbqueue
clsynccbqueue_t cbqueue[CLSYNCSOCK_WINDOW+1]
Definition: socket.h:73
clsyncsockthreads_count
int clsyncsockthreads_count
Definition: socket.c:40
SOCKET_BACKLOG
#define SOCKET_BACKLOG
Definition: configuration.h:25
clsyncsock
Definition: socket.h:65
SOCKCMD_REPLY_DUMP
@ SOCKCMD_REPLY_DUMP
Definition: socket.h:119
SOCKCMD_REPLY_NEGOTIATION
@ SOCKCMD_REPLY_NEGOTIATION
Definition: socket.h:102
socket_check
static int socket_check(clsyncsock_t *clsyncsock_p)
Definition: socket.c:125
socket_thread_attach
socket_sockthreaddata_t * socket_thread_attach(clsyncsock_t *clsyncsock_p)
Definition: socket.c:797
SOCKCMD_REPLY_EEXIST
@ SOCKCMD_REPLY_EEXIST
Definition: socket.h:107
clsynccbqueue::cmd_num
uint64_t cmd_num
Definition: socket.h:58
sockcmd::data
void * data
Definition: socket.h:190
socket_accept
clsyncsock_t * socket_accept(int sock)
Definition: socket.c:177
SOCKCMD_REQUEST_DUMP
@ SOCKCMD_REQUEST_DUMP
Definition: socket.h:112
sockcmd_dat_set
Definition: socket.h:180
socket_sockthreaddata::state
clsyncsock_state_t state
Definition: socket.h:215
sockcmd_dat_ack::cmd_id
uint16_t cmd_id
Definition: socket.h:137
socket_new
clsyncsock_t * socket_new(int clsyncsock_sock)
Definition: socket.c:130
VERSION_MAJ
#define VERSION_MAJ
Definition: program.h:21
VERSION_MIN
#define VERSION_MIN
Definition: program.h:23
parse_text_data
static int parse_text_data(sockcmd_t *sockcmd_p, char *args, size_t args_len)
Definition: socket.c:416
socket_connect_unix
clsyncsock_t * socket_connect_unix(const char *const socket_path)