mapicommd.c 26.3 KB
Newer Older
1 2 3
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
's avatar
committed
4 5
#include <stdio.h>
#include <stdlib.h>
's avatar
committed
6 7 8
#include <string.h>
#include <unistd.h>
#include <ctype.h>
's avatar
committed
9 10
#include <pthread.h>
#include <signal.h>
's avatar
committed
11
#include <getopt.h>
's avatar
committed
12 13
#include <sys/types.h>
#include <sys/socket.h>
's avatar
committed
14
#include <arpa/inet.h>
's avatar
committed
15
#include <sys/time.h>
's avatar
committed
16
#include <errno.h>
17
#include <fcntl.h>
18
#include <time.h>
's avatar
committed
19 20
#include "mapi.h"
#include "mapiipc.h"
's avatar
committed
21
#include "parseconf.h"
22
#include "mapi_errors.h"
's avatar
committed
23
#include "mapilibhandler.h"
's avatar
committed
24
#include "printfstring.h"
25 26
#include "debug.h"
#include "log.h"
's avatar
committed
27

's avatar
committed
28
#define MAXPENDING 500    /* Maximum outstanding connection requests */
's avatar
committed
29

's avatar
committed
30
int service_count;
's avatar
committed
31
int dimapi_port;
32

's avatar
committed
33
int log_fd_info = -1;	// support for logging to file
's avatar
committed
34

's avatar
committed
35 36
static char daemonize = 0;

37
#ifdef DIMAPISSL
38 39
void signal_pipe_handle();

40 41 42 43
struct overload *inst = NULL;
SSL_CTX *ctx;
#endif

44
extern void set_agent();
's avatar
committed
45
void *handle_request(void *);
46
void *asyn_get_next_pkt(void *);	// function that is executed from asynchronous get_next_packet thread
's avatar
committed
47 48
int die(char *msg);
int getfid(struct dmapiipcbuf *dbuf);
49
void mapicommd_shutdown(int exit_value);
50

's avatar
committed
51 52
static void print_usage (const char *name) {
	printf ("Usage: %s [OPTIONS]\n", name);
53 54 55
	printf("  -d, --daemon		Run as daemon\n");
	printf("  -s, --syslog		Logging to syslog\n");
	printf("  -h, --help		Display this message\n");
's avatar
committed
56 57
}

's avatar
committed
58
static void parse_arguments (int argc, char **argv) {
59

's avatar
committed
60
	int c;
61
	static const char optstring[] = "dhs";
's avatar
committed
62 63
	static const struct option longopts[] = {
		{"daemon", no_argument, NULL, 'd'},
64
		{"syslog", no_argument, NULL, 's'},
's avatar
committed
65 66 67
		{"help", no_argument, NULL, 'h'},
		{NULL, 0, NULL, 0}
	};
's avatar
committed
68

's avatar
committed
69 70 71 72 73
	while ((c = getopt_long (argc, argv, optstring, longopts, NULL)) != -1) {
		switch (c) {
			case 'd':
				daemonize = 1;
				break;
74 75 76
			case 's':	// logging to syslog enabled
				log_to_syslog = 1;
				break;
's avatar
committed
77 78 79 80 81 82 83
			case 'h':
			case '?':
			default:
				print_usage(argv[0]);
			exit(EXIT_FAILURE);
		}
	}
's avatar
committed
84 85 86 87 88 89 90 91 92 93 94
}

static int continue_as_daemon() {
	int nullfd;

	printf("Closing stdin, stdout, stderr and going into background.\n");

	switch(fork()) {
		case 0: 
			break;
		case -1:
95
			DEBUG_CMD(Debug_Message("ERROR: fork() failed %d - %s", errno, strerror(errno)));
's avatar
committed
96 97 98 99 100 101
			return EXIT_FAILURE;
			break;
		default:
			_exit(0);
			break;
	}
's avatar
typo  
committed
102
	if(setsid() == -1) {
103
		DEBUG_CMD(Debug_Message("ERROR: setsid() failed %d - %s", errno, strerror(errno)));
's avatar
committed
104 105
		return EXIT_FAILURE;
	}
106

's avatar
committed
107
	setpgrp();
108

's avatar
committed
109 110 111 112
	switch(fork()) {
		case 0: 
			break;
		case -1:
113
			DEBUG_CMD(Debug_Message("ERROR: fork() failed %d - %s", errno, strerror(errno)));
's avatar
committed
114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
			return EXIT_FAILURE;
			break;
		default:
			_exit(0);
			break;
	}
	
	chdir("/");

	nullfd = open("/dev/null", O_RDONLY);
	dup2(nullfd, STDIN_FILENO);
	close(nullfd);
	nullfd = open("/dev/null", O_WRONLY);
	dup2(nullfd, STDOUT_FILENO);
	dup2(nullfd, STDERR_FILENO);
	close(nullfd);
	
	return EXIT_SUCCESS;
}

int main (int argc, char *argv[]){
135

's avatar
committed
136 137 138 139
	int serv_sock = 0;
	int new_sock = 0;      /* client's socket descriptor (from connect()) */
	socklen_t clnt_len;    /* length of client address data structure */
	int yes=1;
140
	char* mapi_conf;
141
	long file_size;
142
	pthread_t chld_thr;
's avatar
committed
143 144
	struct sockaddr_in serv_addr;
	struct sockaddr_in clnt_addr;
145

146
	parse_arguments (argc, argv);
's avatar
committed
147

's avatar
committed
148
#ifdef DIMAPISSL
149 150 151 152 153
	SSL *con = NULL;
	OpenSSL_add_all_algorithms();	// adds all algorithms to the table (digests and ciphers)
					// OpenSSL keeps an internal table of digest algorithms and ciphers
	SSL_library_init();		// registers the available ciphers and digests
	SSL_load_error_strings();	// registers the error strings for all libcrypto functions and libssl
154
#endif
155 156 157 158

	signal (SIGTERM, mapicommd_shutdown);
	signal (SIGQUIT, mapicommd_shutdown);
	signal (SIGINT, mapicommd_shutdown);
159

160
	mapi_conf = printf_string( CONFDIR"/"CONF_FILE );
161

162
	printf("using %s\n", mapi_conf);
163 164
#ifdef DIMAPISSL
	printf("SSL enabled\n");
165
#endif
166
	log_level = get_log_level(mapi_conf);	// get log level from mapi.conf	
167

168
	if(log_to_syslog)	// logging to syslog is enabled
169
		open_syslog(log_level, "MAPICOMMD");
170
	
171 172 173 174
	log_to_file = set_logging_to_file(mapi_conf, &log_fd_info, &log_fd_debug);	// support for logging to file
	
	if(log_to_syslog == 0 && log_to_file == 0)
		log_level = LOGGING_DISABLED;
175

176
	if(pc_load (mapi_conf))
177 178
		dimapi_port = atoi(pc_get_param(pc_get_category(""), "dimapi_port"));
	else{
's avatar
committed
179
		printf("Error: cannot load mapi.conf file.\n");
180
		mapicommd_shutdown(1);
181
	}
's avatar
committed
182 183
	free(mapi_conf);
	pc_close();
's avatar
committed
184

185 186 187 188
	if(log_to_syslog == 0)	printf("logging to syslog: disabled\n");
	else			printf("logging to syslog: enabled - LogLevel: %d\n", log_level);

	if(log_to_file){
189 190
		daemon_started(log_fd_info, "MAPICOMMD", daemonize, 0);
		daemon_started(log_fd_debug, "MAPICOMMD", daemonize, 0);
191 192 193 194 195 196 197 198 199
	}
	
	if(log_to_syslog){
		log_message("MAPICOMMD was started %s", daemonize ? " ( is running as daemon )" : "");
#ifdef DIMAPISSL
		log_message("SSL enabled");
#endif
	}

's avatar
committed
200
	if ((serv_sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
's avatar
committed
201
		die("Unexpected error on socket()");
202
		mapicommd_shutdown(-1);
's avatar
committed
203
	}
's avatar
committed
204

205 206 207
	memset(&serv_addr, 0, sizeof serv_addr);

	serv_addr.sin_family = AF_INET;
's avatar
committed
208
	serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
's avatar
committed
209
	serv_addr.sin_port = htons(dimapi_port);
's avatar
committed
210

's avatar
committed
211 212 213
#ifdef DIMAPISSL
	if ((ctx=SSL_CTX_new(SSLv3_server_method())) == NULL) {
		ERR_print_errors_fp(stderr);
's avatar
committed
214
		return -1;
's avatar
committed
215
	}
216
	if (SSL_CTX_use_certificate_file(ctx, CONFDIR"/"MAPICOMMD_SSL_CERT_FILE, SSL_FILETYPE_PEM) <= 0) {
's avatar
committed
217
		ERR_print_errors_fp(stderr);
's avatar
committed
218
		return -1;
's avatar
committed
219
	}
220

221
	if (SSL_CTX_use_PrivateKey_file(ctx, CONFDIR"/"MAPICOMMD_SSL_KEY_FILE, SSL_FILETYPE_PEM) <= 0) {
's avatar
committed
222
		ERR_print_errors_fp(stderr);
's avatar
committed
223
		return -1;
's avatar
committed
224
	}
225 226

	signal(SIGPIPE, signal_pipe_handle);	// catch SIGPIPE signal (SSL_write)
's avatar
committed
227 228
#endif

's avatar
committed
229 230 231 232 233 234 235 236 237
	/* DANGEROUS, but useful for debugging, so leave it for now */
	if (setsockopt(serv_sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) {
		close(serv_sock);
		die("Unexpected error on setsockopt()");
	}

	if (bind(serv_sock, (struct sockaddr *)&serv_addr, sizeof serv_addr) == -1) {
		close(serv_sock);
		die("Unexpected error on bind()");
238
		mapicommd_shutdown(-1);
's avatar
committed
239 240 241 242 243 244 245
	}

	/* queue max 5 connections */
	if (listen(serv_sock, MAXPENDING) == -1) {
		shutdown(serv_sock, SHUT_RDWR);
		close(serv_sock);
		die("Unexpected error on listen()");
246
		mapicommd_shutdown(-1);
's avatar
committed
247 248
	}

249
	set_agent();
's avatar
committed
250

's avatar
committed
251 252
	if(daemonize) continue_as_daemon();

's avatar
committed
253 254 255
	while(1) {

		clnt_len = sizeof clnt_addr;
's avatar
committed
256
		if ((new_sock = accept(serv_sock, (struct sockaddr *)&clnt_addr, &clnt_len)) == -1) {
's avatar
committed
257
			die("Unexpected error on accept()");
's avatar
committed
258 259
			continue;
		}
's avatar
committed
260

's avatar
committed
261 262 263
#ifdef DIMAPISSL
		if ((con=SSL_new(ctx)) == NULL) {
			ERR_print_errors_fp(stderr);
's avatar
committed
264
			continue;
's avatar
committed
265 266 267
		}
		if (SSL_set_fd(con, new_sock) == 0) {
			ERR_print_errors_fp(stderr);
's avatar
committed
268
			continue;
's avatar
committed
269 270 271
		}
		if (SSL_accept(con) <= 0) {
			ERR_print_errors_fp(stderr);
's avatar
committed
272
			continue;
's avatar
committed
273 274
		}
#endif
's avatar
committed
275
		printf("<*> got connection from %s\n", inet_ntoa(clnt_addr.sin_addr));
276

277
		if(log_to_file){
278 279 280 281 282
			file_size = acquire_write_lock(log_fd_info);
			write_to_file(log_fd_info, "MAPICOMMD: mapicommd got connection from * %s * at ", inet_ntoa(clnt_addr.sin_addr));
			write_date(log_fd_info);
			write_newline(log_fd_info, "\n");
			release_write_lock(log_fd_info, file_size);
283
		}
284 285
		if(log_to_syslog)
			log_message("mapicommd got connection from * %s *", inet_ntoa(clnt_addr.sin_addr));
's avatar
committed
286
#ifdef DIMAPISSL
287
		inst = (struct overload *)malloc(sizeof(struct overload));
's avatar
committed
288 289
		inst->connection = con;
		inst->sock = new_sock;
290

291
		if (pthread_create(&chld_thr, NULL, handle_request, (void *) inst) != 0){
's avatar
committed
292 293 294
			die("pthread_create() failed");
			continue;
		}
295
#else
296 297 298 299
		int *sockfd = (int *)malloc(sizeof(int));
		*sockfd = new_sock;	// FIXME free ...

		if (pthread_create(&chld_thr, NULL, handle_request, (void *) sockfd) != 0) {
300
			die("pthread_create() failed");
's avatar
committed
301 302
			continue;
		}
's avatar
committed
303
#endif
304
	} /* while (1) */
's avatar
committed
305 306 307 308
	return 0; /* never reached */
}

void *handle_request(void *arg) {
309

's avatar
committed
310 311 312 313
#ifdef DIMAPISSL
	SSL *con ;
	con = ((struct overload*)arg)->connection;
	int sock = ((struct overload*)arg)->sock;
314
#else
315
	int sock = *(int *)arg;
316
#endif
317 318 319 320
	int recv_bytes, i, ac_fl_size=0, errno, *active_flows = NULL, mapid_result;
	char errorstr[MAPI_ERRORSTR_LENGTH], str[30], *dev;
	long file_size;
	struct asyn_mgnp *gnp_arg = NULL;
's avatar
committed
321
	struct dmapiipcbuf *dbuf=NULL;
322 323 324
	struct timeval tv; /*used for timestamping results when produced */
	struct mapipkt *pkt;
	struct mapi_stat stats;
's avatar
committed
325
	mapi_results_t *result;
's avatar
committed
326 327
	mapi_function_info_t funct_info;
	mapi_flow_info_t flow_info;
328
	mapi_device_info_t device_info;
329
   char *devtype = NULL;
's avatar
committed
330
#ifdef RECONNECT
331
	int ignore_flag = 0;
's avatar
committed
332
#endif
333 334
	
	pthread_detach(pthread_self());		// Guarantees that thread resources are deallocated upon return
's avatar
committed
335
	dbuf = (struct dmapiipcbuf *)malloc(sizeof(struct dmapiipcbuf));
336

's avatar
committed
337
#ifdef DIMAPISSL
338
	DEBUG_CMD(Debug_Message("<+> new thread %lu, socket number = %d", pthread_self(),(int) con));
339
	sprintf(str, "%d", (int) con);
340 341 342 343 344

	if(inst != NULL){
		free(inst);
		inst = NULL;
	}
345
#else
346
	DEBUG_CMD(Debug_Message("<+> new thread %lu, socket number = %d", pthread_self(), sock));
347
	sprintf(str, "%d", sock);
's avatar
committed
348
#endif
349
	if(log_to_file){
350
		file_size = acquire_write_lock(log_fd_info);
351
		write_to_file(log_fd_info, "MAPICOMMD: new thread %lu, socket number %s\n", pthread_self(), str);
352
		release_write_lock(log_fd_info, file_size);
353
	}
354 355
	
	while(1){
's avatar
committed
356

's avatar
committed
357 358
#ifdef DIMAPISSL
		recv_bytes = SSL_readn(con,dbuf,BASIC_SIZE);
359
#else
's avatar
committed
360 361
		recv_bytes=readn(sock, dbuf, BASIC_SIZE);
#endif
's avatar
committed
362
		if (recv_bytes == 0) { // the peer has gone
363 364 365
			DEBUG_CMD(Debug_Message("Peer has gone"));

			if(log_to_file){
366 367 368 369 370
				file_size = acquire_write_lock(log_fd_info);
				write_to_file(log_fd_info, "MAPICOMMD: Peer has gone at ");
				write_date(log_fd_info);
				write_newline(log_fd_info, "\n");
				release_write_lock(log_fd_info, file_size);
371
			}
's avatar
committed
372 373 374 375 376 377 378 379
			break;
		}
		else if (recv_bytes == -1) {
			die("recv()");
			break;
		}

		if (dbuf->length > DIMAPI_DATA_SIZE) {
380
			DEBUG_CMD(Debug_Message("WARNING: Ignoring invalid message"));
381
			
382
			if(log_to_file){
383 384 385
				file_size = acquire_write_lock(log_fd_info);
				write_to_file(log_fd_info, "MAPICOMMD: Warning - Ignoring invalid message\n");
				release_write_lock(log_fd_info, file_size);
386
			}
's avatar
committed
387 388
			continue;
		}
's avatar
committed
389

's avatar
committed
390
		if (dbuf->length-BASIC_SIZE>0) {
's avatar
committed
391 392
#ifdef DIMAPISSL
			recv_bytes = SSL_readn(con,(char *)dbuf+BASIC_SIZE,dbuf->length-BASIC_SIZE);
393
#else
's avatar
committed
394
			recv_bytes=readn(sock, (char*)dbuf+BASIC_SIZE, dbuf->length-BASIC_SIZE);
's avatar
committed
395
#endif
's avatar
committed
396
			if (recv_bytes == 0) { // the peer has gone
397 398 399
				DEBUG_CMD(Debug_Message("Peer has gone"));

				if(log_to_file){
400 401 402 403 404
					file_size = acquire_write_lock(log_fd_info);
					write_to_file(log_fd_info, "MAPICOMMD: Peer has gone at ");
					write_date(log_fd_info);
					write_newline(log_fd_info, "\n");
					release_write_lock(log_fd_info, file_size);
405
				}
's avatar
committed
406 407 408 409 410 411 412
				break;
			}
			else if (recv_bytes == -1) {
				die("recv()");
				break;
			}
		}
's avatar
committed
413 414 415
#ifdef RECONNECT

		if(dbuf->cmd == IGNORE_SLEEP){	// ignore some messages
416
			ignore_flag = 1;
's avatar
committed
417 418 419 420
			continue;
		}

		if(dbuf->cmd == IGNORE_NOTIFY){	// accept all kind of messages
421
			ignore_flag = 0;
's avatar
committed
422 423
			continue;
		}
424

425
		if(dbuf->cmd != CREATE_FLOW && dbuf->cmd != APPLY_FUNCTION && dbuf->cmd != CONNECT && dbuf->cmd != AUTHENTICATE && ignore_flag == 1)
's avatar
committed
426 427
			continue;
#endif
's avatar
committed
428 429
		switch(dbuf->cmd) {
			case CREATE_FLOW:
's avatar
committed
430
				mapid_result = mapi_create_flow(dbuf->data);
's avatar
committed
431
				fprintf(stdout,"CREATE_FLOW (%s, %d)\n",dbuf->data, mapid_result);
432
				mapicommd_logging(log_to_file, log_to_syslog, log_fd_info, dbuf, mapid_result);
's avatar
committed
433
				if(mapid_result <0) {
's avatar
committed
434
					dbuf->cmd = ERROR_ACK;
435
					mapi_read_error(&errno, errorstr);
's avatar
committed
436 437 438
					memcpy(dbuf->data, &errno, sizeof(int));
				}
				else {
439 440
					devtype = mapi_get_devtype_of_flow(mapid_result);
					if(devtype != NULL) {
's avatar
committed
441
					dbuf->cmd = CREATE_FLOW_ACK;
's avatar
committed
442
					memcpy(dbuf->data, &mapid_result, sizeof(int));
443
					memcpy(((char *)dbuf->data) + sizeof(int), devtype, strlen(devtype)+1);
's avatar
committed
444 445 446
					active_flows = realloc(active_flows,(ac_fl_size+1)*sizeof(int));
					active_flows[ac_fl_size++] = mapid_result;
				}
447 448 449 450 451 452 453
				else {
					dbuf->cmd = ERROR_ACK;
					mapi_read_error(&errno, errorstr);
					memcpy(dbuf->data, &errno, sizeof(int));
				}
				}
				dbuf->length = BASIC_SIZE+sizeof(int)+strlen(devtype)+1;
's avatar
committed
454 455 456 457
				break;
			case CLOSE_FLOW:
				fprintf(stdout,"CLOSE_FLOW (%d)\n",dbuf->fd);
				mapid_result = mapi_close_flow(dbuf->fd);
458
				mapicommd_logging(log_to_file, log_to_syslog, log_fd_info, dbuf, mapid_result);
's avatar
committed
459 460 461 462
				if(!mapid_result){
					for(i=0;i<ac_fl_size;++i){
						if(active_flows[i] == dbuf->fd){
							active_flows[i] = active_flows[--ac_fl_size];
's avatar
committed
463
							active_flows = realloc(active_flows,ac_fl_size*sizeof(int));
's avatar
committed
464 465 466
						}
					}
				}
's avatar
committed
467
				//no need to send responce
's avatar
committed
468 469 470 471
				break;
			case CONNECT:
				fprintf(stdout,"CONNECT (%d)",dbuf->fd);
				mapid_result = mapi_connect(dbuf->fd);
472
				mapicommd_logging(log_to_file, log_to_syslog, log_fd_info, dbuf, mapid_result);
's avatar
committed
473 474 475
				if(mapid_result >= 0){
					dbuf->cmd = CONNECT_ACK;
					fprintf(stdout," OK\n");
's avatar
committed
476
					dbuf->length = BASIC_SIZE;
's avatar
committed
477 478 479
				}
				else{
					dbuf->cmd = ERROR_ACK;
480
					mapi_read_error(&errno, errorstr);
's avatar
committed
481
					memcpy(dbuf->data, &errno, sizeof(int));
's avatar
committed
482
					fprintf(stdout," FAILED\n");
's avatar
committed
483
					dbuf->length = BASIC_SIZE+sizeof(int);
's avatar
committed
484 485 486
				}
				break;
			case APPLY_FUNCTION:
's avatar
committed
487
				fprintf(stdout,"APPLY_FUNCTION\n");
's avatar
committed
488
				if((( dbuf->fid = getfid(dbuf))!=-1)){
489
					mapicommd_logging(log_to_file, log_to_syslog, log_fd_info, dbuf, 0);
's avatar
committed
490
					dbuf->cmd = APPLY_FUNCTION_ACK;
's avatar
committed
491
					dbuf->length = BASIC_SIZE;
's avatar
committed
492 493
				}
				else{
494
					mapicommd_logging(log_to_file, log_to_syslog, log_fd_info, dbuf, -1);
's avatar
committed
495
					dbuf->cmd = ERROR_ACK;
496
					mapi_read_error(&errno, errorstr);
's avatar
committed
497 498
					memcpy(dbuf->data, &errno, sizeof(int));
					dbuf->length = BASIC_SIZE+sizeof(int);
's avatar
committed
499 500 501
				}
				break;
			case READ_RESULT:
's avatar
committed
502 503 504 505 506 507 508 509 510 511
#ifdef RECONNECT
				if (mapi_is_sensor_down(dbuf->fd)==1) {
					printf("SENSOR DOWN\n");
					int local_err=MAPI_READ_RESULT_RECONNECTION;
					dbuf->cmd = ERROR_ACK;
					memcpy(dbuf->data, &local_err, sizeof(int));
					dbuf->length = BASIC_SIZE + sizeof(int);
					break;
				}
#endif
512
				result = mapi_read_results(dbuf->fd,dbuf->fid);
513
				if(result!=NULL && result->size < DIMAPI_DATA_SIZE){
's avatar
committed
514
					dbuf->cmd = READ_RESULT_ACK;
's avatar
committed
515 516 517
					dbuf->timestamp = result->ts;
					memcpy(dbuf->data, result->res, result->size);
					dbuf->length = BASIC_SIZE + result->size;
's avatar
committed
518 519 520
				}
				else{
					fprintf(stdout,"mapi_read_results failed...\n");
521
					mapicommd_logging(log_to_file, log_to_syslog, log_fd_info, dbuf, -1);
's avatar
committed
522
					dbuf->cmd = ERROR_ACK;
523
					mapi_read_error(&errno, errorstr);
's avatar
committed
524 525
					memcpy(dbuf->data, &errno, sizeof(int));
					dbuf->length = BASIC_SIZE+sizeof(int);
526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548
#ifdef RECONNECT
					if(errno == MAPI_READ_RESULT_RECONNECTION){	// mapid is down ...
#ifdef DIMAPISSL
						SSL_write(con, dbuf, dbuf->length);
#else
						send(sock, dbuf, dbuf->length, 0);
#endif						// dummy read result operation to enable reconnection mechanism
						result = mapi_read_results(dbuf->fd, dbuf->fid);
						
						if(result != NULL && result->size < DIMAPI_DATA_SIZE){
							dbuf->cmd = READ_RESULT_ACK_RECONNECT;
							dbuf->timestamp = result->ts;
							memcpy(dbuf->data, result->res, result->size);
							dbuf->length = BASIC_SIZE + result->size;
						}
						else{
							dbuf->cmd = ERROR_ACK;
							mapi_read_error(&errno, errorstr);
							memcpy(dbuf->data, &errno, sizeof(int));
							dbuf->length = BASIC_SIZE+sizeof(int);
						}
					}
#endif
's avatar
committed
549 550 551 552
				}
				break;
			case GET_NEXT_PKT:
				pkt = (struct mapipkt *)mapi_get_next_pkt(dbuf->fd,dbuf->fid);
's avatar
committed
553
				gettimeofday(&tv, NULL);
's avatar
committed
554
				dbuf->timestamp = tv.tv_usec;
555
				if(pkt != NULL && pkt->caplen <= MAX_CAPLEN){
's avatar
committed
556 557 558 559 560
					dbuf->cmd = GET_NEXT_PKT_ACK;
					memcpy(dbuf->data, pkt, sizeof(struct mapipkt)-4+pkt->caplen);
					dbuf->length = BASIC_SIZE + sizeof(struct mapipkt) - 4 + pkt->caplen;
				}
				else{
561
					dbuf->cmd = GET_NEXT_PKT_ACK;
's avatar
committed
562 563 564
					dbuf->length = BASIC_SIZE;
				}
				break;
565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584
			case GET_NEXT_PKT_ASYN:

				fprintf(stdout, "Asynchronous mapi_get_next_pkt\n");
				mapicommd_logging(log_to_file, log_to_syslog, log_fd_info, dbuf, -1);
	
				gnp_arg = (struct asyn_mgnp *)malloc(sizeof(struct asyn_mgnp));
				gnp_arg->dbuf = (struct dmapiipcbuf *)malloc(sizeof(struct dmapiipcbuf));
				
				memcpy(gnp_arg->dbuf, dbuf, dbuf->length);
				// counts the number of sent packets, before the thread enters sleep mode. If sent_packets becomes equal
				// to the number of empty cells in the buffer array, then the thread enters sleep mode, waiting for a next request
				gnp_arg->sent_packets = 0;
#ifdef DIMAPISSL
				gnp_arg->con = (SSL *)malloc(sizeof(SSL));
				memcpy(gnp_arg->con, con, sizeof(SSL));
#else
				memcpy(&(gnp_arg->sock), &sock, sizeof(int));
#endif
				asyn_get_next_pkt(gnp_arg);
				break;
's avatar
committed
585 586 587
			case GET_FLOW_INFO:
				fprintf(stdout,"GET_FLOW_INFO\n");
				if(mapi_get_flow_info(dbuf->fd, &flow_info)){
588
					mapicommd_logging(log_to_file, log_to_syslog, log_fd_info, dbuf, -1);
589 590 591 592
					dbuf->cmd = MAPI_FLOW_INFO_ERR;
					dbuf->length = BASIC_SIZE;
				}
				else{
593
					mapicommd_logging(log_to_file, log_to_syslog, log_fd_info, dbuf, 0);
594 595 596 597 598 599 600 601
					dbuf->cmd = GET_FLOW_INFO_ACK;
					memcpy(dbuf->data,&flow_info,sizeof(mapi_flow_info_t));
					dbuf->length = BASIC_SIZE+sizeof(mapi_flow_info_t);
				}
				break;
			case GET_NEXT_FLOW_INFO:
				fprintf(stdout,"GET_NEXT_FLOW_INFO\n");
				if(mapi_get_next_flow_info(dbuf->fd, &flow_info)){
602
					mapicommd_logging(log_to_file, log_to_syslog, log_fd_info, dbuf, -1);
's avatar
committed
603 604 605 606
					dbuf->cmd = MAPI_FLOW_INFO_ERR;
					dbuf->length = BASIC_SIZE;
				}
				else{
607
					mapicommd_logging(log_to_file, log_to_syslog, log_fd_info, dbuf, 0);
's avatar
committed
608 609 610 611 612
					dbuf->cmd = GET_FLOW_INFO_ACK;
					memcpy(dbuf->data,&flow_info,sizeof(mapi_flow_info_t));
					dbuf->length = BASIC_SIZE+sizeof(mapi_flow_info_t);
				}
				break;
613 614 615
			case GET_DEVICE_INFO:
				fprintf(stdout,"GET_DEVICE_INFO\n");
				if(mapi_get_flow_info(dbuf->fd, &flow_info)){
616
					mapicommd_logging(log_to_file, log_to_syslog, log_fd_info, dbuf, -1);
617 618 619 620 621
					dbuf->cmd = GET_DEVICE_INFO_NACK;
					dbuf->length = BASIC_SIZE;
				}

				if(mapi_get_device_info(flow_info.devid, &device_info)<0){
622
					mapicommd_logging(log_to_file, log_to_syslog, log_fd_info, dbuf, -1);
623 624 625 626
					dbuf->cmd = GET_DEVICE_INFO_NACK;
					dbuf->length = BASIC_SIZE;
				}
				else{
627
					mapicommd_logging(log_to_file, log_to_syslog, log_fd_info, dbuf, 0);
628 629 630 631 632 633 634 635
					dbuf->cmd = GET_DEVICE_INFO_ACK;
					memcpy(dbuf->data,&device_info,sizeof(mapi_device_info_t));
					dbuf->length = BASIC_SIZE+sizeof(mapi_device_info_t);
				}
				break;
			case GET_NEXT_DEVICE_INFO:
				fprintf(stdout,"GET_NEXT_DEVICE_INFO\n");
				if(mapi_get_flow_info(dbuf->fd, &flow_info)){
636
					mapicommd_logging(log_to_file, log_to_syslog, log_fd_info, dbuf, -1);
637 638 639 640 641
					dbuf->cmd = GET_DEVICE_INFO_NACK;
					dbuf->length = BASIC_SIZE;
				}

				if(mapi_get_next_device_info(flow_info.devid, &device_info)<0){
642
					mapicommd_logging(log_to_file, log_to_syslog, log_fd_info, dbuf, -1);
643 644 645 646
					dbuf->cmd = GET_DEVICE_INFO_NACK;
					dbuf->length = BASIC_SIZE;
				}
				else{
647
					mapicommd_logging(log_to_file, log_to_syslog, log_fd_info, dbuf, 0);
648 649 650 651 652
					dbuf->cmd = GET_DEVICE_INFO_ACK;
					memcpy(dbuf->data,&device_info,sizeof(mapi_device_info_t));
					dbuf->length = BASIC_SIZE+sizeof(mapi_device_info_t);
				}
				break;
's avatar
committed
653 654 655
			case GET_FUNCTION_INFO:
				fprintf(stdout,"GET_FUNCTION_INFO\n");
				if(mapi_get_function_info(dbuf->fd, dbuf->fid, &funct_info)){
656
					mapicommd_logging(log_to_file, log_to_syslog, log_fd_info, dbuf, -1);
's avatar
committed
657 658 659 660
					dbuf->cmd = MAPI_FUNCTION_INFO_ERR;
					dbuf->length = BASIC_SIZE;
				}
				else{
661
					mapicommd_logging(log_to_file, log_to_syslog, log_fd_info, dbuf, 0);
's avatar
committed
662 663 664 665 666 667 668 669
					dbuf->cmd = GET_FUNCTION_INFO_ACK;
					memcpy(dbuf->data,&funct_info,sizeof(mapi_function_info_t));
					dbuf->length = BASIC_SIZE+sizeof(mapi_function_info_t);
				}
				break;
			case GET_NEXT_FUNCTION_INFO:
				fprintf(stdout,"GET_NEXT_FUNCTION_INFO\n");
				if(mapi_get_next_function_info(dbuf->fd, dbuf->fid, &funct_info)){
670
					mapicommd_logging(log_to_file, log_to_syslog, log_fd_info, dbuf, -1);
's avatar
committed
671 672 673 674
					dbuf->cmd = MAPI_FUNCTION_INFO_ERR;
					dbuf->length = BASIC_SIZE;
				}
				else{
675
					mapicommd_logging(log_to_file, log_to_syslog, log_fd_info, dbuf, 0);
's avatar
committed
676 677 678 679
					dbuf->cmd = GET_FUNCTION_INFO_ACK;
					memcpy(dbuf->data,&funct_info,sizeof(mapi_function_info_t));
					dbuf->length = BASIC_SIZE+sizeof(mapi_function_info_t);
				}
680
				break;
's avatar
committed
681 682 683 684 685 686 687 688 689 690 691 692 693
#ifdef WITH_ADMISSION_CONTROL
			case SET_AUTHDATA:
				fprintf(stdout,"SET_AUTHDATA\n");
				if(!agent_send_authdata(dbuf)){
					dbuf->cmd = SET_AUTHDATA_ACK;
				}
				else{
					dbuf->cmd = ERROR_ACK;
				}

				dbuf->length = BASIC_SIZE;
				break;
#endif
's avatar
committed
694 695
#ifdef WITH_AUTHENTICATION
			case AUTHENTICATE:
696
				fprintf(stdout, "AUTHENTICATE\n");
697
				if(!agent_authenticate(dbuf)){
698
					mapicommd_logging(log_to_file, log_to_syslog, log_fd_info, dbuf, 0);
699
					dbuf->cmd = AUTHENTICATE_ACK;
700 701
				}
				else{
702
					mapicommd_logging(log_to_file, log_to_syslog, log_fd_info, dbuf, -1);
703
					dbuf->cmd = ERROR_ACK;
704
				}
's avatar
 
committed
705
				dbuf->length = BASIC_SIZE;
's avatar
committed
706 707
				break;
#endif
708 709 710
			case MAPI_STATS:
				dev=strdup(dbuf->data);
				mapid_result = mapi_stats(dev, &stats);
711
				mapicommd_logging(log_to_file, log_to_syslog, log_fd_info, dbuf, mapid_result);
712 713 714 715 716 717 718 719 720
				if(mapid_result <0) {
					dbuf->cmd = MAPI_STATS_ERR;
					mapi_read_error(&errno, errorstr);
					memcpy(dbuf->data, &errno, sizeof(int));
					dbuf->length = BASIC_SIZE+sizeof(int);
				}
				else {
					dbuf->cmd = MAPI_STATS_ACK;
					memcpy(dbuf->data, &stats, sizeof(struct mapi_stat));
's avatar
committed
721
					dbuf->length = BASIC_SIZE+sizeof(struct mapi_stat);
722 723 724
				}
				free(dev);
				break;
725
			default:
's avatar
committed
726
				die("Default case found in handle_request loop!\n");
727
				break;
's avatar
committed
728 729
	        }

's avatar
committed
730
		//no need to send responce on mapi_close_flow
731
		if(dbuf->cmd!=CLOSE_FLOW && dbuf->cmd != GET_NEXT_PKT_ASYN){
's avatar
committed
732 733
#ifdef DIMAPISSL
			SSL_write(con,dbuf,dbuf->length);
734
#else
's avatar
committed
735 736
			send(sock,dbuf, dbuf->length,0);
#endif
's avatar
committed
737
		}
's avatar
committed
738
	}
739

's avatar
committed
740
	for(i=0;i<ac_fl_size;++i){//close all remaining flows before this thread exits
's avatar
committed
741
		if(active_flows[i]>0){//this should always be positive or realloc does not work
's avatar
committed
742 743 744
			mapi_close_flow(active_flows[i]);
		}
	}
745

's avatar
committed
746
	free(active_flows);
747
	free(dbuf);
's avatar
committed
748
	dbuf = NULL;
's avatar
committed
749

's avatar
committed
750 751 752
	shutdown(sock, SHUT_RDWR);
	close(sock);

's avatar
committed
753
#ifdef DIMAPISSL
754
	if (SSL_shutdown(con) == -1)	// shut down a TLS/SSL connection
's avatar
committed
755
		ERR_print_errors_fp(stderr);
756

757 758
	SSL_free(con);			// decrements the reference count of ssl, and removes the SSL structure pointed to by ssl
       					// frees up the allocated memory if the the reference count has reached 0
759 760
#endif	
	service_count++;	// update the global service counter
761 762 763 764
	DEBUG_CMD(Debug_Message("<+> thread %lu exiting", pthread_self()));
	DEBUG_CMD(Debug_Message("<+> total sockets served: %d", service_count));

	if(log_to_file){
765 766 767 768 769
		file_size = acquire_write_lock(log_fd_info);
		write_to_file(log_fd_info, "MAPICOMMD: thread %lu exiting at ", pthread_self());
		write_date(log_fd_info);
		write_to_file(log_fd_info, "\nMAPICOMMD: Total sockets served: %d\n", service_count);
		release_write_lock(log_fd_info, file_size);
770
	}
771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853

	pthread_exit((void *) 0);
}

void *asyn_get_next_pkt(void *buf){

	struct dmapiipcbuf *dbuf = NULL;
	struct asyn_mgnp *gnp_arg = NULL;
	struct mapipkt *pkt;
	struct timeval tv;	// used for timestamping results when produced
	char errorstr[MAPI_ERRORSTR_LENGTH];
	int recv_bytes;

	gnp_arg = (struct asyn_mgnp *)buf;
	dbuf = (struct dmapiipcbuf *)malloc(sizeof(struct dmapiipcbuf));

	while(1){

		pkt = (struct mapipkt *)mapi_asynchronous_get_next_pkt(gnp_arg->dbuf->fd, gnp_arg->dbuf->fid);
			
		gettimeofday(&tv, NULL);
		dbuf->timestamp = tv.tv_usec;
		
		if(pkt != NULL && pkt->caplen <= MAX_CAPLEN){
			
			dbuf->cmd = GET_NEXT_PKT_ASYN_ACK;
			dbuf->fd = gnp_arg->dbuf->fd;
			memcpy(dbuf->data, pkt, sizeof(struct mapipkt) - 4 + pkt->caplen);
			dbuf->length = BASIC_SIZE + sizeof(struct mapipkt) - 4 + pkt->caplen;
		}
		else{	// 'NULL' packet ... probably from a non-blocking way of reading packets

			dbuf->cmd = GET_NEXT_PKT_ASYN_ACK;
			mapi_read_error(&errno, errorstr);
			dbuf->fd = gnp_arg->dbuf->fd;
			dbuf->length = BASIC_SIZE;

			//if(errno != MAPI_INVALID_FLOW){
			//	DEBUG_CMD(Debug_Message("mapi_asynchronous_get_next_pkt failed"));
			//}

			if(errno == MAPI_INVALID_FLOW)	// flow with fd 'gnp_arg->dbuf->fd' is closed ...
				break;
		}
#ifdef DIMAPISSL
		SSL_write(gnp_arg->con, dbuf, dbuf->length);
#else
		if(send(gnp_arg->sock, dbuf, dbuf->length, MSG_NOSIGNAL) == -1)
			break;
#endif
		gnp_arg->sent_packets++;

		if(gnp_arg->sent_packets == (int) gnp_arg->dbuf->timestamp){		// buffer is full
#ifdef DIMAPISSL
			recv_bytes = SSL_readn(gnp_arg->con, dbuf, BASIC_SIZE);
#else
			recv_bytes = readn(gnp_arg->sock, dbuf, BASIC_SIZE);
#endif
			if(dbuf->length - BASIC_SIZE > 0){
#ifdef DIMAPISSL
				recv_bytes = SSL_readn(gnp_arg->con, (char *)dbuf + BASIC_SIZE, dbuf->length - BASIC_SIZE);
#else
				recv_bytes = readn(gnp_arg->sock, (char *)dbuf + BASIC_SIZE, dbuf->length - BASIC_SIZE);
#endif
			}
			gnp_arg->dbuf->timestamp = dbuf->timestamp;	// number of packets that must be sent
			gnp_arg->sent_packets = 0;				// initialize again
		}
	}

	DEBUG_CMD(Debug_Message("<++> thread %lu exiting", pthread_self()));

	free(dbuf);
	dbuf = NULL;
	free(gnp_arg->dbuf);
#ifdef DIMAPISSL
	free(gnp_arg->con);
#endif
	free(gnp_arg);
	gnp_arg = NULL;

	pthread_exit(NULL);
	return NULL;
's avatar
committed
854 855
}

856 857 858 859
int die(char *msg){

	long file_size;
	
860
	if(log_to_file){
861 862 863
		file_size = acquire_write_lock(log_fd_info);
		write_to_file(log_fd_info, "MAPICOMMD: %s\n", msg);
		release_write_lock(log_fd_info, file_size);
864 865
	}

's avatar
committed
866 867 868 869 870 871 872
	perror(msg);
	return EXIT_FAILURE;
}

//calls the appropriate mapi_apply_function and returns the fid from mapid
int getfid(struct dmapiipcbuf *dbuf){
	int result;
873

874
	char *function = (char *)dbuf->data;
's avatar
committed
875
	char *data = (char *)(dbuf->data+strlen(function)+1);
's avatar
committed
876

's avatar
committed
877 878
	result = mapi_apply_function(dbuf->fd, function, data);
	return (result);
's avatar
committed
879 880
}

881 882 883 884
void mapicommd_shutdown(int exit_value){

#ifdef DIMAPISSL
	
885 886 887 888 889 890 891
	if(ctx != NULL)
		SSL_CTX_free(ctx);	// decrements the reference count of ctx, and removes the SSL_CTX object pointed to by ctx
					// frees up the allocated memory if the the reference count has reached 0
	CRYPTO_cleanup_all_ex_data();	// clean up all allocated state
	ERR_free_strings();		// frees all previously loaded error strings
	ERR_remove_state(0);		// the current thread will have its error queue removed
	EVP_cleanup();			// removes all ciphers and digests from the table
892
#endif
893
	if(log_to_file){		
894 895
		daemon_terminated(log_fd_info, "MAPICOMMD", daemonize, 0);
		daemon_terminated(log_fd_debug, "MAPICOMMD", daemonize, 0);
896
	}
897 898
	if(log_to_syslog)
		log_message("MAPICOMMD was terminated %s", daemonize ? " ( was running as daemon )" : "");
's avatar
committed
899

900
	exit(exit_value);
901
}
902 903 904 905 906 907 908 909 910 911 912

#ifdef DIMAPISSL
void signal_pipe_handle(){	// catch the signal - SIGPIPE

	DEBUG_CMD(Debug_Message("Broken pipe (signal handler)"));
	DEBUG_CMD(Debug_Message("<++> thread %lu exiting", pthread_self()));
	
	pthread_exit(NULL);
	return;
}
#endif