gateway.c 19.1 KB
Newer Older
1
2
3
4
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/socket.h>
5
#include <sys/stat.h>
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <arpa/inet.h> //inet_addr
#include <unistd.h>
#include <stdint.h>
#include <pthread.h>
#include <sys/time.h>
#include <libpq-fe.h>
#include <math.h>
#include <signal.h>
#include <time.h>

#include <errno.h>

#include "gateway_protocol.h"
19
#include "gateway_telemetry_protocol.h"
20
21
#include "base64.h"
#include "task_queue.h"
22
#include "json.h"
23
#include "aes.h"
24

25
#define NTHREAD_MAX			10
Vladislav Rykov's avatar
Vladislav Rykov committed
26

Vladislav Rykov's avatar
Vladislav Rykov committed
27
28
29
#define TIMEDATE_LENGTH			32
#define PEND_SEND_RETRIES_MAX		5
#define GATEWAY_PROTOCOL_APP_KEY_SIZE	8
Vladislav Rykov's avatar
Vladislav Rykov committed
30
#define DEVICE_DATA_MAX_LENGTH		256
31
#define GATEWAY_SECURE_KEY_SIZE		16
32
#define GATEWAY_ID_SIZE			6
33

Vladislav Rykov's avatar
Vladislav Rykov committed
34

35
typedef struct {
36
	uint8_t 	gw_id[GATEWAY_ID_SIZE];
37
	uint8_t 	gw_secure_key[GATEWAY_SECURE_KEY_SIZE];
38
39
	uint16_t 	gw_port;
	char 		db_type[20];
40
	uint32_t	telemetry_send_period;
41
42
	char 		platform_gw_manager_ip[20];
	uint16_t 	platform_gw_manager_port;
43
44
} gw_conf_t;

45
46
47
48
49
50
51
52
typedef struct {
	char 		addr[15+1];
	uint16_t 	port;
	char 		db_name[32];
	char 		user_name[32];
	char 		user_pass[32];
} db_conf_t;

Vladislav Rykov's avatar
Vladislav Rykov committed
53
54
typedef struct {
	uint32_t utc;
Vladislav Rykov's avatar
Vladislav Rykov committed
55
	char timedate[TIMEDATE_LENGTH];
Vladislav Rykov's avatar
Vladislav Rykov committed
56

Vladislav Rykov's avatar
Vladislav Rykov committed
57
58
	uint8_t data[DEVICE_DATA_MAX_LENGTH];
	uint8_t data_length;
Vladislav Rykov's avatar
Vladislav Rykov committed
59
60
} sensor_data_t;

Vladislav Rykov's avatar
Vladislav Rykov committed
61
typedef struct {
Vladislav Rykov's avatar
Vladislav Rykov committed
62
	gateway_protocol_conf_t gwp_conf;
Vladislav Rykov's avatar
Vladislav Rykov committed
63
64
65
66
67
68
69
	int server_desc;
	int client_desc;
	struct sockaddr_in server;
	struct sockaddr_in client;
	int sock_len;
} gcom_ch_t; // gateway communication channel

70
71
72
73
74
75
76
typedef struct {
	gcom_ch_t gch;	
	gateway_protocol_packet_type_t packet_type;
	uint8_t packet[DEVICE_DATA_MAX_LENGTH];
	uint8_t packet_length;
} gcom_ch_request_t;

77
78
static const char * gw_conf_file = "gateway.conf";
static const char * db_conf_file = "db.conf";
79
static void process_gw_conf(json_value* value, gw_conf_t *gw_conf);
80
81
82
83
static void process_db_conf(json_value* value, db_conf_t *db_conf);
static json_value * read_json_conf(const char *file_path);
static int read_gw_conf(const char *gw_conf_file_path, gw_conf_t *gw_conf);
static int read_db_conf(const char *db_conf_file_path, db_conf_t *db_conf);
84

85
void process_packet(void *request);
Vladislav Rykov's avatar
Vladislav Rykov committed
86

87
88
89
uint8_t gateway_auth(const gw_conf_t *gw_conf, const char *db_conf_file_path);
void	*gateway_mngr(void *gw_conf);

Vladislav Rykov's avatar
Vladislav Rykov committed
90
91
92
int send_gcom_ch(gcom_ch_t *gch, uint8_t *pck, uint8_t pck_size);
int recv_gcom_ch(gcom_ch_t *gch, uint8_t *pck, uint8_t *pck_length, uint16_t pck_size);

Vladislav Rykov's avatar
Vladislav Rykov committed
93
94
95
96
void gateway_protocol_data_send_payload_decode(
	sensor_data_t *sensor_data, 
	const uint8_t *payload, 
	const uint8_t payload_length);
Vladislav Rykov's avatar
Vladislav Rykov committed
97

Vladislav Rykov's avatar
Vladislav Rykov committed
98
99
100
101
102
103
104
105
void gateway_protocol_mk_stat(
	gcom_ch_t *gch,
	gateway_protocol_stat_t stat,
	uint8_t *pck,
	uint8_t *pck_len);

void send_utc(gcom_ch_t *pch);

Vladislav Rykov's avatar
Vladislav Rykov committed
106
107
void gateway_protocol_checkup_callback(gateway_protocol_conf_t *gwp_conf);

Vladislav Rykov's avatar
Vladislav Rykov committed
108
109
void ctrc_handler (int sig);
static volatile uint8_t working = 1;
Vladislav Rykov's avatar
Vladislav Rykov committed
110

111
112
113
pthread_mutex_t mutex;
PGconn *conn;

Vladislav Rykov's avatar
Vladislav Rykov committed
114
int main (int argc, char **argv) {
115
	gw_conf_t *gw_conf = (gw_conf_t *)malloc(sizeof(gw_conf_t));
116
	db_conf_t *db_conf = (db_conf_t *)malloc(sizeof(db_conf_t));
117
	char *db_conninfo = (char *)malloc(512);
118
	gcom_ch_t gch;
119
	task_queue_t *tq;
120
121
122
123
124
125
126
127
128
129
	pthread_t gw_mngr;
	sigset_t sigset;

	sigemptyset(&sigset);
	/* SIGINT for finishing gateway task */	
	sigaddset(&sigset, SIGINT);
	/* SIGALRM for gateway manager thread */	
	sigaddset(&sigset, SIGALRM);
	/* block all other signals */
	sigprocmask(SIG_BLOCK, &sigset, NULL);
130

Vladislav Rykov's avatar
Vladislav Rykov committed
131
	signal(SIGINT, ctrc_handler);
132
	
133
	if (read_gw_conf(gw_conf_file, gw_conf)) {
134
135
136
		return EXIT_FAILURE;
	}

137
138
139
140
141
142
143
144
	gateway_telemetry_protocol_init(gw_conf->gw_id, gw_conf->gw_secure_key);

	if (!gateway_auth(gw_conf, db_conf_file)) {
		fprintf(stderr, "Gateway authentication failure.");
		return EXIT_FAILURE;
	}

	if (read_db_conf(db_conf_file, db_conf)) {
145
146
147
		return EXIT_FAILURE;
	}
	
148
149
	snprintf(db_conninfo, 512, 
			"hostaddr=%s port=%d dbname=%s user=%s password=%s", 
150
151
152
153
154
155
156
157
			db_conf->addr,
			db_conf->port,
			db_conf->db_name,
			db_conf->user_name,
			db_conf->user_pass);
	
	printf("db_conf : '%s'\n", db_conninfo);

158
	conn = PQconnectdb(db_conninfo);
159
160
161
162
163
164
165
166
167
168
	
	snprintf(db_conninfo, 512, 
			"id=%s secure_key=%s port=%d type=%s telemetry_send_period=%d\n", 
			gw_conf->gw_id,
			gw_conf->gw_secure_key,
			gw_conf->gw_port,
			gw_conf->db_type,
			gw_conf->telemetry_send_period);
	printf("gw_conf : '%s'\n", db_conninfo);
	
169
	free(db_conninfo);
Vladislav Rykov's avatar
Vladislav Rykov committed
170
	if (PQstatus(conn) == CONNECTION_BAD) {
Vladislav Rykov's avatar
Vladislav Rykov committed
171
		fprintf(stderr,"connection to db error: %s\n", PQerrorMessage(conn));
172
		free(gw_conf);
Vladislav Rykov's avatar
Vladislav Rykov committed
173
174
175
		return EXIT_FAILURE;
	}

Vladislav Rykov's avatar
Vladislav Rykov committed
176
	if ((gch.server_desc = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
Vladislav Rykov's avatar
Vladislav Rykov committed
177
		perror("socket creation error");
178
		free(gw_conf);
Vladislav Rykov's avatar
Vladislav Rykov committed
179
180
181
		return EXIT_FAILURE;
	}

Vladislav Rykov's avatar
Vladislav Rykov committed
182
	gch.server.sin_family 		= AF_INET;
183
	gch.server.sin_port		= htons(gw_conf->gw_port);
Vladislav Rykov's avatar
Vladislav Rykov committed
184
	gch.server.sin_addr.s_addr 	= INADDR_ANY;
Vladislav Rykov's avatar
Vladislav Rykov committed
185

Vladislav Rykov's avatar
Vladislav Rykov committed
186
	if (bind(gch.server_desc, (struct sockaddr *) &gch.server, sizeof(gch.server)) < 0) {
Vladislav Rykov's avatar
Vladislav Rykov committed
187
		perror("binding error");
188
		free(gw_conf);
Vladislav Rykov's avatar
Vladislav Rykov committed
189
190
191
		return EXIT_FAILURE;
	}

192
193
194
195
196
	if (pthread_create(&gw_mngr, NULL, gateway_mngr, gw_conf)) {
		fprintf(stderr, "Failed to create gateway manager thread.");
		return EXIT_FAILURE;
	}

197
198
	if(!(tq = task_queue_create(NTHREAD_MAX))) {
		perror("task_queue creation error");
199
		free(gw_conf);
200
201
		return EXIT_FAILURE;
	}
202
203

	pthread_mutex_init(&mutex, NULL);
Vladislav Rykov's avatar
Vladislav Rykov committed
204
205

	gateway_protocol_set_checkup_callback(gateway_protocol_checkup_callback);
Vladislav Rykov's avatar
Vladislav Rykov committed
206
207
	
	while (working) {
208
209
210
		gcom_ch_request_t *req = (gcom_ch_request_t *)malloc(sizeof(gcom_ch_request_t));
		memset(req, 0x0, sizeof(gcom_ch_request_t));
		memcpy(&req->gch, &gch, sizeof(gcom_ch_t));
211
	
Vladislav Rykov's avatar
Vladislav Rykov committed
212
		printf("listenninig...\n");
213
		req->gch.sock_len = sizeof(req->gch.client);
Vladislav Rykov's avatar
Vladislav Rykov committed
214
		
215
216
		if (recv_gcom_ch(&req->gch, req->packet, &req->packet_length, DEVICE_DATA_MAX_LENGTH)) {
			task_queue_enqueue(tq, process_packet, req);
Vladislav Rykov's avatar
Vladislav Rykov committed
217
		} else {
218
			fprintf(stderr, "packet receive error\n");
Vladislav Rykov's avatar
Vladislav Rykov committed
219
		}
Vladislav Rykov's avatar
Vladislav Rykov committed
220
221
	}

222
	free(gw_conf);
223
	free(db_conf);
224
	pthread_mutex_destroy(&mutex);
Vladislav Rykov's avatar
Vladislav Rykov committed
225
	close(gch.server_desc);
Vladislav Rykov's avatar
Vladislav Rykov committed
226
	PQfinish(conn);
Vladislav Rykov's avatar
Vladislav Rykov committed
227

Vladislav Rykov's avatar
Vladislav Rykov committed
228
229
230
	return EXIT_SUCCESS;
}

Vladislav Rykov's avatar
Vladislav Rykov committed
231
232
233
234
void ctrc_handler (int sig) {
	working = 0;
}

235
236
237
238
239
240
void process_packet(void *request) {
	gcom_ch_request_t *req = (gcom_ch_request_t *)request;
	uint8_t payload[DEVICE_DATA_MAX_LENGTH];
	uint8_t payload_length;	
	PGresult *res;

Vladislav Rykov's avatar
Vladislav Rykov committed
241
242
	if (gateway_protocol_packet_decode(
		&(req->gch.gwp_conf),
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
		&(req->packet_type),
		&payload_length, payload,
		req->packet_length, req->packet))
	{
		if (req->packet_type == GATEWAY_PROTOCOL_PACKET_TYPE_TIME_REQ) {
			printf("TIME REQ received\n");
			send_utc(&(req->gch));
		} else if (req->packet_type == GATEWAY_PROTOCOL_PACKET_TYPE_DATA_SEND) {
			sensor_data_t sensor_data;
			time_t t;
			// DEVICE_DATA_MAX_LENGTH*2 {hex} + 150
			char db_query[662];

			printf("DATA SEND received\n");
			gateway_protocol_data_send_payload_decode(&sensor_data, payload, payload_length);
			
			if (sensor_data.utc == 0) {
				struct timeval tv;
				gettimeofday(&tv, NULL);
				t = tv.tv_sec;
			} else {
				t = sensor_data.utc;
			}
			
			strftime(sensor_data.timedate, TIMEDATE_LENGTH, "%d/%m/%Y %H:%M:%S", localtime(&t));
			snprintf(db_query, sizeof(db_query), 
269
				"INSERT INTO dev_%s_%d VALUES (%lu, '%s', $1)", 
Vladislav Rykov's avatar
Vladislav Rykov committed
270
				(char *)req->gch.gwp_conf.app_key, req->gch.gwp_conf.dev_id, t, sensor_data.timedate
271
272
273
274
275
			);
			
			const char *params[1];
			int paramslen[1];
			int paramsfor[1];
276
			params[0] = (char *) sensor_data.data;
277
278
279
			paramslen[0] = sensor_data.data_length;
			paramsfor[0] = 1; // format - binary

280
			pthread_mutex_lock(&mutex);
281
			res = PQexecParams(conn, db_query, 1, NULL, params, paramslen, paramsfor, 0);
282
283
			pthread_mutex_unlock(&mutex);

284
285
286
287
288
			if (PQresultStatus(res) == PGRES_COMMAND_OK) {
				PQclear(res);

				snprintf(db_query, sizeof(db_query),
					 "SELECT * FROM pend_msgs WHERE app_key='%s' and dev_id = %d and ack = False", 
Vladislav Rykov's avatar
Vladislav Rykov committed
289
					(char *)req->gch.gwp_conf.app_key, req->gch.gwp_conf.dev_id
290
				);
291
292
				
				pthread_mutex_lock(&mutex);
293
				res = PQexec(conn, db_query);
294
295
				pthread_mutex_unlock(&mutex);
				
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
				if (PQresultStatus(res) == PGRES_TUPLES_OK && PQntuples(res)) {
					gateway_protocol_mk_stat(
						&(req->gch), 
						GATEWAY_PROTOCOL_STAT_ACK_PEND,
						req->packet, &(req->packet_length));
					printf("ACK_PEND prepared\n");
				} else {
					gateway_protocol_mk_stat(
						&(req->gch), 
						GATEWAY_PROTOCOL_STAT_ACK,
						req->packet, &(req->packet_length));
					printf("ACK prepared\n");
				}
				
				send_gcom_ch(&(req->gch), req->packet, req->packet_length);
			} else {
				fprintf(stderr, "database error : %s\n", PQerrorMessage(conn));
			}
			PQclear(res);
		} else if (req->packet_type == GATEWAY_PROTOCOL_PACKET_TYPE_PEND_REQ) {
			char db_query[200];
			snprintf(db_query, sizeof(db_query),
				 "SELECT * FROM pend_msgs WHERE app_key = '%s' AND dev_id = %d AND ack = False", 
Vladislav Rykov's avatar
Vladislav Rykov committed
319
				(char *)req->gch.gwp_conf.app_key, req->gch.gwp_conf.dev_id
320
			);
321
			pthread_mutex_lock(&mutex);
322
			res = PQexec(conn, db_query);
323
			pthread_mutex_unlock(&mutex);
324
325
326
327
328
329
330
331
332
333
334
335
336
337
			
			if (PQresultStatus(res) == PGRES_TUPLES_OK && PQntuples(res)) {
				char msg_cont[150];
				strncpy(msg_cont, PQgetvalue(res, 0, 2), sizeof(msg_cont));
				printf("PEND_SEND prepared : %s\n", msg_cont);
				PQclear(res);
			
				base64_decode(msg_cont, strlen(msg_cont)-1, payload);
				payload_length = BASE64_DECODE_OUT_SIZE(strlen(msg_cont));
				printf("prepared to send %d bytes : %s\n", payload_length, payload);
				
				// send the msg until ack is received
				uint8_t received_ack = 0;
				uint8_t pend_send_retries = PEND_SEND_RETRIES_MAX;
Vladislav Rykov's avatar
Vladislav Rykov committed
338
339
				gateway_protocol_packet_encode(
					&(req->gch.gwp_conf),
340
341
342
					GATEWAY_PROTOCOL_PACKET_TYPE_PEND_SEND,
					payload_length, payload,
					&(req->packet_length), req->packet);
343
344
				do {
					send_gcom_ch(&(req->gch), req->packet, req->packet_length);
345
346
347
348
349
350
351
352
353
354
355
					
					// 300 ms
					usleep(300000);

					pthread_mutex_lock(&mutex);
					res = PQexec(conn, db_query);
					pthread_mutex_unlock(&mutex);
					
					if (PQresultStatus(res) == PGRES_TUPLES_OK) {
						if (!PQntuples(res) || strcmp(PQgetvalue(res, 0, 2), msg_cont)) {
							received_ack = 1;
356
357
						}
					}
358
359
					PQclear(res);
					printf("received_ack = %d, retries = %d\n", received_ack, pend_send_retries);
360
361
362
363
364
365
366
367
368
				} while (!received_ack && pend_send_retries--);
			} else {
				gateway_protocol_mk_stat(
					&(req->gch),
					GATEWAY_PROTOCOL_STAT_NACK,
					req->packet, &(req->packet_length));
				
				send_gcom_ch(&(req->gch), req->packet, req->packet_length);
				
Vladislav Rykov's avatar
Vladislav Rykov committed
369
				printf("nothing for app %s dev %d\n", (char *)req->gch.gwp_conf.app_key, req->gch.gwp_conf.dev_id);
370
			}
371
372
373
374
375
376
		} else if (req->packet_type == GATEWAY_PROTOCOL_PACKET_TYPE_STAT) {
			// TODO change to ACK_PEND = 0x01
			if (payload[0] == 0x00) {
				char db_query[200];
				snprintf(db_query, sizeof(db_query),
					 "SELECT * FROM pend_msgs WHERE app_key = '%s' AND dev_id = %d AND ack = False", 
Vladislav Rykov's avatar
Vladislav Rykov committed
377
					(char *)req->gch.gwp_conf.app_key, req->gch.gwp_conf.dev_id
378
379
380
381
382
383
384
				);
				pthread_mutex_lock(&mutex);
				res = PQexec(conn, db_query);
				pthread_mutex_unlock(&mutex);
				if (PQresultStatus(res) == PGRES_TUPLES_OK && PQntuples(res)) {
					snprintf(db_query, sizeof(db_query),
						"UPDATE pend_msgs SET ack = True WHERE app_key = '%s' AND dev_id = %d AND msg = '%s'",
Vladislav Rykov's avatar
Vladislav Rykov committed
385
						(char *)req->gch.gwp_conf.app_key, req->gch.gwp_conf.dev_id, PQgetvalue(res, 0, 2)
386
387
388
389
390
391
392
393
394
395
396
397
398
					);
					PQclear(res);
					pthread_mutex_lock(&mutex);
					res = PQexec(conn, db_query);
					pthread_mutex_unlock(&mutex);
					if (PQresultStatus(res) == PGRES_COMMAND_OK) {
						printf("pend_msgs updated\n");
					} else {
						fprintf(stderr, "database error : %s\n", PQerrorMessage(conn));
					}
				}
				PQclear(res);
			}
399
400
401
402
403
404
405
406
		} else {
			gateway_protocol_mk_stat(
				&(req->gch),
				GATEWAY_PROTOCOL_STAT_NACK,
				req->packet, &(req->packet_length));
			
			send_gcom_ch(&(req->gch), req->packet, req->packet_length);
				
407
			fprintf(stderr, "packet type error : %02X\n", req->packet_type);
408
409
410
411
		}
	} else {
		fprintf(stderr, "payload decode error\n");
	}
412
413
	
	free(req);
414
415
}

416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
uint8_t gateway_auth(const gw_conf_t *gw_conf, const char *db_conf_file_path) {
	int sockfd;
	struct sockaddr_in platformaddr;
	uint8_t buffer[1024];
	uint16_t buffer_length = 0;
	uint8_t payload_buffer[1024];
	uint16_t payload_buffer_length = 0;
	FILE *fp;

	if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
		return 0;
	}

	memset(&platformaddr, 0x0, sizeof(platformaddr));

	platformaddr.sin_family = AF_INET;
	platformaddr.sin_addr.s_addr = inet_addr(gw_conf->platform_gw_manager_ip);
	platformaddr.sin_port = htons(gw_conf->platform_gw_manager_port);
	
	if (connect(sockfd, (struct sockaddr *)&platformaddr, sizeof(platformaddr))) {
		return 0;
	}

	gateway_telemetry_protocol_encode_packet(buffer, 0, GATEWAY_TELEMETRY_PROTOCOL_AUTH, buffer, &buffer_length);
	write(sockfd, buffer, buffer_length);
	
	buffer_length = read(sockfd, buffer, sizeof(buffer));
	gateway_telemetry_protocol_packet_type_t pt;
	if (!gateway_telemetry_protocol_decode_packet(payload_buffer, &payload_buffer_length, &pt, buffer, buffer_length)) {
		return 0;
	}

	// write db_conf into file
	fp = fopen(db_conf_file_path, "w");
	fwrite(payload_buffer, payload_buffer_length, 1, fp);
	fclose(fp);

	return 1;
}

void * gateway_mngr(void *gw_conf) {
	struct itimerval tval;
	uint32_t period = ((gw_conf_t *)gw_conf)->telemetry_send_period;
	sigset_t alarm_msk;
	int sig;

	sigemptyset(&alarm_msk);
	sigaddset(&alarm_msk, SIGALRM);
	pthread_sigmask(SIG_BLOCK, &alarm_msk, NULL);

	tval.it_value.tv_sec = period;
	tval.it_value.tv_usec = 0;
	tval.it_interval.tv_sec = period;
	tval.it_interval.tv_usec = 0;

	if (setitimer(ITIMER_REAL, &tval, NULL)) {
		perror("Failed to set itimer");
		return NULL;
	}

	while (1) {
		// get utc
		// create applications and devices serving log
		// flush utc and log into a query
		printf("periodic action done!\n");
		sigwait(&alarm_msk, &sig);
	}
}

Vladislav Rykov's avatar
Vladislav Rykov committed
485
void gateway_protocol_data_send_payload_decode(
Vladislav Rykov's avatar
Vladislav Rykov committed
486
487
488
489
	sensor_data_t *sensor_data, 
	const uint8_t *payload, 
	const uint8_t payload_length) 
{
Vladislav Rykov's avatar
Vladislav Rykov committed
490
491
492
493
494
	uint8_t p_len = 0;

	memcpy(&sensor_data->utc, &payload[p_len], sizeof(sensor_data->utc));
	p_len += sizeof(sensor_data->utc);

Vladislav Rykov's avatar
Vladislav Rykov committed
495
496
	memcpy(sensor_data->data, &payload[p_len], payload_length - p_len);
	sensor_data->data_length = payload_length - p_len;
Vladislav Rykov's avatar
Vladislav Rykov committed
497
498
}

Vladislav Rykov's avatar
Vladislav Rykov committed
499
500
501
502
503
504
void gateway_protocol_mk_stat(
	gcom_ch_t *gch,
	gateway_protocol_stat_t stat,
	uint8_t *pck,
	uint8_t *pck_len)
{
Vladislav Rykov's avatar
Vladislav Rykov committed
505
506
	gateway_protocol_packet_encode(
		&(gch->gwp_conf),
Vladislav Rykov's avatar
Vladislav Rykov committed
507
		GATEWAY_PROTOCOL_PACKET_TYPE_STAT,
Vladislav Rykov's avatar
Vladislav Rykov committed
508
		1, (uint8_t *)&stat,
Vladislav Rykov's avatar
Vladislav Rykov committed
509
		pck_len, pck);
Vladislav Rykov's avatar
Vladislav Rykov committed
510
511
}

Vladislav Rykov's avatar
Vladislav Rykov committed
512
513


Vladislav Rykov's avatar
Vladislav Rykov committed
514
void send_utc(gcom_ch_t *gch) {
Vladislav Rykov's avatar
Vladislav Rykov committed
515
	uint8_t buf[50];
Vladislav Rykov's avatar
Vladislav Rykov committed
516
517
518
519
520
	uint8_t buf_len = 0;
	struct timeval tv;
				
	gettimeofday(&tv, NULL);
				
Vladislav Rykov's avatar
Vladislav Rykov committed
521
522
	gateway_protocol_packet_encode (
		&(gch->gwp_conf),
Vladislav Rykov's avatar
Vladislav Rykov committed
523
		GATEWAY_PROTOCOL_PACKET_TYPE_TIME_SEND,
Vladislav Rykov's avatar
Vladislav Rykov committed
524
		sizeof(uint32_t), (uint8_t *)&tv.tv_sec,
Vladislav Rykov's avatar
Vladislav Rykov committed
525
526
527
528
529
530
		&buf_len, buf
	);
					
	send_gcom_ch(gch, buf, buf_len);
}

Vladislav Rykov's avatar
Vladislav Rykov committed
531
532
533
void gateway_protocol_checkup_callback(gateway_protocol_conf_t *gwp_conf) {
	PGresult *res;
	char db_query[200];
534
	
Vladislav Rykov's avatar
Vladislav Rykov committed
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
	snprintf(db_query, sizeof(db_query), 
		"SELECT secure_key, secure FROM applications WHERE app_key = '%s'", (char *)gwp_conf->app_key
	);
	pthread_mutex_lock(&mutex);
	res = PQexec(conn, db_query);
	pthread_mutex_unlock(&mutex);

	if ((PQresultStatus(res) == PGRES_TUPLES_OK) && PQntuples(res)) {
		base64_decode(PQgetvalue(res, 0, 0), strlen(PQgetvalue(res, 0, 0))-1, gwp_conf->secure_key);
		gwp_conf->secure = PQgetvalue(res, 0, 1)[0] == 't';
	} else {
		perror("gateway_protocol_checkup_callback error");
	}
	PQclear(res);
}

Vladislav Rykov's avatar
Vladislav Rykov committed
551
int send_gcom_ch(gcom_ch_t *gch, uint8_t *pck, uint8_t pck_size) {
552
	int ret;
Vladislav Rykov's avatar
Vladislav Rykov committed
553
	
554
	if ((ret = sendto(gch->server_desc, (char *)pck, pck_size, 0, (struct sockaddr *)&gch->client, gch->sock_len)) < 0) {
Vladislav Rykov's avatar
Vladislav Rykov committed
555
556
		perror("sendto error");
	}
557

Vladislav Rykov's avatar
Vladislav Rykov committed
558
559
560
561
	return ret;
}

int recv_gcom_ch(gcom_ch_t *gch, uint8_t *pck, uint8_t *pck_length, uint16_t pck_size) {
562
	int ret;
563
	if ((ret = recvfrom(gch->server_desc, (char *)pck, pck_size, MSG_WAITALL, (struct sockaddr *)&gch->client, &gch->sock_len)) < 0) {
Vladislav Rykov's avatar
Vladislav Rykov committed
564
		perror("socket receive error");
565
566
	} else {
		*pck_length = ret;
567
		
Vladislav Rykov's avatar
Vladislav Rykov committed
568
	}
569

570
	return ret;
Vladislav Rykov's avatar
Vladislav Rykov committed
571
}
572
573
574


static void process_gw_conf(json_value* value, gw_conf_t *gw_conf) {
575
576
577
578
579
580
581
582
583
584
585
586
587
	/* bad practice. must add checks for the EUI string */
	char buffer[128];
	strncpy(buffer, value->u.object.values[0].value->u.string.ptr, sizeof(buffer));
	sscanf(buffer, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &gw_conf->gw_id[0], &gw_conf->gw_id[1], &gw_conf->gw_id[2],
							&gw_conf->gw_id[3], &gw_conf->gw_id[4], &gw_conf->gw_id[5]
	);
	strncpy(buffer, value->u.object.values[1].value->u.string.ptr, sizeof(buffer));
	sscanf(buffer, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", 
			&gw_conf->gw_secure_key[0], &gw_conf->gw_secure_key[1], &gw_conf->gw_secure_key[2], &gw_conf->gw_secure_key[3],
			&gw_conf->gw_secure_key[4], &gw_conf->gw_secure_key[5], &gw_conf->gw_secure_key[6], &gw_conf->gw_secure_key[7],
			&gw_conf->gw_secure_key[8], &gw_conf->gw_secure_key[9], &gw_conf->gw_secure_key[10], &gw_conf->gw_secure_key[11],
			&gw_conf->gw_secure_key[12], &gw_conf->gw_secure_key[13], &gw_conf->gw_secure_key[14], &gw_conf->gw_secure_key[15]
	);
588
589
590
	gw_conf->gw_port = value->u.object.values[2].value->u.integer;
	strncpy(gw_conf->db_type, value->u.object.values[3].value->u.string.ptr, sizeof(gw_conf->db_type));
	gw_conf->telemetry_send_period = value->u.object.values[4].value->u.integer;
591
592
	strncpy(gw_conf->platform_gw_manager_ip, value->u.object.values[5].value->u.string.ptr, sizeof(gw_conf->platform_gw_manager_ip));
	gw_conf->platform_gw_manager_port = value->u.object.values[6].value->u.integer;
593
}
594

595
596
static void process_db_conf(json_value* value, db_conf_t *db_conf) {
	strncpy(db_conf->addr, value->u.object.values[0].value->u.string.ptr, sizeof(db_conf->addr));
597
	db_conf->port = atoi(value->u.object.values[1].value->u.string.ptr);
598
599
600
	strncpy(db_conf->db_name, value->u.object.values[2].value->u.string.ptr, sizeof(db_conf->db_name));
	strncpy(db_conf->user_name, value->u.object.values[3].value->u.string.ptr, sizeof(db_conf->user_name));
	strncpy(db_conf->user_pass, value->u.object.values[4].value->u.string.ptr, sizeof(db_conf->user_pass));
601
602
}

603
static json_value * read_json_conf(const char *file_path) {
604
605
606
607
608
609
	struct stat filestatus;
	FILE *fp;
	char *file_contents;
	json_char *json;
	json_value *jvalue;

610
611
612
	if (stat(file_path, &filestatus)) {
		fprintf(stderr, "File %s not found.", file_path);
		return NULL;
613
614
615
	}
	file_contents = (char *)malloc(filestatus.st_size);
	if (!file_contents) {
616
617
		fprintf(stderr, "Memory error allocating %d bytes.", (int) filestatus.st_size);
		return NULL;
618
	}
619
	fp = fopen(file_path, "rt");
620
	if (!fp) {
621
		fprintf(stderr, "Unable to open %s.", file_path);
622
623
		fclose(fp);
		free(file_contents);
624
		return NULL;
625
626
	}
	if (fread(file_contents, filestatus.st_size, 1, fp) != 1) {
627
		fprintf(stderr, "Unable to read %s.", file_path);
628
629
		fclose(fp);
		free(file_contents);
630
		return NULL;
631
632
633
	}
	fclose(fp);
	
634
635
	file_contents[filestatus.st_size] = '\0';
	printf("file content : \n'%s'\n", file_contents);
636
637
638
639
640
641
	
	json = (json_char *)file_contents;
	jvalue = json_parse(json, filestatus.st_size);
	if (!jvalue) {
		perror("Unable to parse json.");
		free(file_contents);
642
		return NULL;
643
644
	}
	
645
646
647
648
649
650
651
652
653
654
655
656
	free(file_contents);
	
	return jvalue;
}

static int read_gw_conf(const char *gw_conf_file_path, gw_conf_t *gw_conf) {
	json_value *jvalue;
	
	jvalue = read_json_conf(gw_conf_file_path);
	if (!jvalue) {
		return 1;
	}
657
658
659
660
661
662
	process_gw_conf(jvalue, gw_conf);

	json_value_free(jvalue);
	
	return 0;
}
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677

static int read_db_conf(const char *db_conf_file_path, db_conf_t *db_conf) {
	json_value *jvalue;
	
	jvalue = read_json_conf(db_conf_file_path);
	if (!jvalue) {
		return 1;
	}
	process_db_conf(jvalue, db_conf);

	json_value_free(jvalue);
	
	return 0;
}