gateway.c 19 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
	pthread_t gw_mngr;
	sigset_t sigset;

	sigemptyset(&sigset);
124
	/* block SIGALRM for gateway manager thread */
125
126
	sigaddset(&sigset, SIGALRM);
	sigprocmask(SIG_BLOCK, &sigset, NULL);
127

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

134
135
136
137
138
139
140
141
	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)) {
142
143
144
		return EXIT_FAILURE;
	}
	
145
146
	snprintf(db_conninfo, 512, 
			"hostaddr=%s port=%d dbname=%s user=%s password=%s", 
147
148
149
150
151
152
153
154
			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);

155
	conn = PQconnectdb(db_conninfo);
156
157
158
159
160
161
162
163
164
165
	
	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);
	
166
	free(db_conninfo);
Vladislav Rykov's avatar
Vladislav Rykov committed
167
	if (PQstatus(conn) == CONNECTION_BAD) {
Vladislav Rykov's avatar
Vladislav Rykov committed
168
		fprintf(stderr,"connection to db error: %s\n", PQerrorMessage(conn));
169
		free(gw_conf);
Vladislav Rykov's avatar
Vladislav Rykov committed
170
171
172
		return EXIT_FAILURE;
	}

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

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

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

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

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

	pthread_mutex_init(&mutex, NULL);
Vladislav Rykov's avatar
Vladislav Rykov committed
201
202

	gateway_protocol_set_checkup_callback(gateway_protocol_checkup_callback);
Vladislav Rykov's avatar
Vladislav Rykov committed
203
204
	
	while (working) {
205
206
207
		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));
208
	
Vladislav Rykov's avatar
Vladislav Rykov committed
209
		printf("listenninig...\n");
210
		req->gch.sock_len = sizeof(req->gch.client);
Vladislav Rykov's avatar
Vladislav Rykov committed
211
		
212
213
		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
214
		} else {
215
			fprintf(stderr, "packet receive error\n");
Vladislav Rykov's avatar
Vladislav Rykov committed
216
		}
Vladislav Rykov's avatar
Vladislav Rykov committed
217
218
	}

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

Vladislav Rykov's avatar
Vladislav Rykov committed
225
226
227
	return EXIT_SUCCESS;
}

Vladislav Rykov's avatar
Vladislav Rykov committed
228
229
230
231
void ctrc_handler (int sig) {
	working = 0;
}

232
233
234
235
236
237
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
238
239
	if (gateway_protocol_packet_decode(
		&(req->gch.gwp_conf),
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
		&(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), 
266
				"INSERT INTO dev_%s_%d VALUES (%lu, '%s', $1)", 
Vladislav Rykov's avatar
Vladislav Rykov committed
267
				(char *)req->gch.gwp_conf.app_key, req->gch.gwp_conf.dev_id, t, sensor_data.timedate
268
269
270
271
272
			);
			
			const char *params[1];
			int paramslen[1];
			int paramsfor[1];
273
			params[0] = (char *) sensor_data.data;
274
275
276
			paramslen[0] = sensor_data.data_length;
			paramsfor[0] = 1; // format - binary

277
			pthread_mutex_lock(&mutex);
278
			res = PQexecParams(conn, db_query, 1, NULL, params, paramslen, paramsfor, 0);
279
280
			pthread_mutex_unlock(&mutex);

281
282
283
284
285
			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
286
					(char *)req->gch.gwp_conf.app_key, req->gch.gwp_conf.dev_id
287
				);
288
289
				
				pthread_mutex_lock(&mutex);
290
				res = PQexec(conn, db_query);
291
292
				pthread_mutex_unlock(&mutex);
				
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
				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
316
				(char *)req->gch.gwp_conf.app_key, req->gch.gwp_conf.dev_id
317
			);
318
			pthread_mutex_lock(&mutex);
319
			res = PQexec(conn, db_query);
320
			pthread_mutex_unlock(&mutex);
321
322
323
324
325
326
327
328
329
330
331
332
333
334
			
			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
335
336
				gateway_protocol_packet_encode(
					&(req->gch.gwp_conf),
337
338
339
					GATEWAY_PROTOCOL_PACKET_TYPE_PEND_SEND,
					payload_length, payload,
					&(req->packet_length), req->packet);
340
341
				do {
					send_gcom_ch(&(req->gch), req->packet, req->packet_length);
342
343
344
345
346
347
348
349
350
351
352
					
					// 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;
353
354
						}
					}
355
356
					PQclear(res);
					printf("received_ack = %d, retries = %d\n", received_ack, pend_send_retries);
357
358
359
360
361
362
363
364
365
				} 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
366
				printf("nothing for app %s dev %d\n", (char *)req->gch.gwp_conf.app_key, req->gch.gwp_conf.dev_id);
367
			}
368
369
370
371
372
373
		} 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
374
					(char *)req->gch.gwp_conf.app_key, req->gch.gwp_conf.dev_id
375
376
377
378
379
380
381
				);
				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
382
						(char *)req->gch.gwp_conf.app_key, req->gch.gwp_conf.dev_id, PQgetvalue(res, 0, 2)
383
384
385
386
387
388
389
390
391
392
393
394
395
					);
					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);
			}
396
397
398
399
400
401
402
403
		} 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);
				
404
			fprintf(stderr, "packet type error : %02X\n", req->packet_type);
405
406
407
408
		}
	} else {
		fprintf(stderr, "payload decode error\n");
	}
409
410
	
	free(req);
411
412
}

413
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
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);

	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
481
void gateway_protocol_data_send_payload_decode(
Vladislav Rykov's avatar
Vladislav Rykov committed
482
483
484
485
	sensor_data_t *sensor_data, 
	const uint8_t *payload, 
	const uint8_t payload_length) 
{
Vladislav Rykov's avatar
Vladislav Rykov committed
486
487
488
489
490
	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
491
492
	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
493
494
}

Vladislav Rykov's avatar
Vladislav Rykov committed
495
496
497
498
499
500
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
501
502
	gateway_protocol_packet_encode(
		&(gch->gwp_conf),
Vladislav Rykov's avatar
Vladislav Rykov committed
503
		GATEWAY_PROTOCOL_PACKET_TYPE_STAT,
Vladislav Rykov's avatar
Vladislav Rykov committed
504
		1, (uint8_t *)&stat,
Vladislav Rykov's avatar
Vladislav Rykov committed
505
		pck_len, pck);
Vladislav Rykov's avatar
Vladislav Rykov committed
506
507
}

Vladislav Rykov's avatar
Vladislav Rykov committed
508
509


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

Vladislav Rykov's avatar
Vladislav Rykov committed
527
528
529
void gateway_protocol_checkup_callback(gateway_protocol_conf_t *gwp_conf) {
	PGresult *res;
	char db_query[200];
530
	
Vladislav Rykov's avatar
Vladislav Rykov committed
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
	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
547
int send_gcom_ch(gcom_ch_t *gch, uint8_t *pck, uint8_t pck_size) {
548
	int ret;
Vladislav Rykov's avatar
Vladislav Rykov committed
549
	
550
	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
551
552
		perror("sendto error");
	}
553

Vladislav Rykov's avatar
Vladislav Rykov committed
554
555
556
557
	return ret;
}

int recv_gcom_ch(gcom_ch_t *gch, uint8_t *pck, uint8_t *pck_length, uint16_t pck_size) {
558
	int ret;
559
	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
560
		perror("socket receive error");
561
562
	} else {
		*pck_length = ret;
563
		
Vladislav Rykov's avatar
Vladislav Rykov committed
564
	}
565

566
	return ret;
Vladislav Rykov's avatar
Vladislav Rykov committed
567
}
568
569
570


static void process_gw_conf(json_value* value, gw_conf_t *gw_conf) {
571
572
573
574
575
576
577
578
579
580
581
582
583
	/* 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]
	);
584
585
586
	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;
587
588
	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;
589
}
590

591
592
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));
593
	db_conf->port = atoi(value->u.object.values[1].value->u.string.ptr);
594
595
596
	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));
597
598
}

599
static json_value * read_json_conf(const char *file_path) {
600
601
602
603
604
605
	struct stat filestatus;
	FILE *fp;
	char *file_contents;
	json_char *json;
	json_value *jvalue;

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

	json_value_free(jvalue);
	
	return 0;
}
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673

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;
}