Clean up serialize interface.
Switch to jansson for JSON handling. Add server ID. Expose IDs in JSON.
This commit is contained in:
2
Makefile
2
Makefile
@@ -1,7 +1,7 @@
|
|||||||
CC ?= clang
|
CC ?= clang
|
||||||
CFLAGS ?= -Wall -Werror -O4 -g --std=gnu11 --pedantic-errors
|
CFLAGS ?= -Wall -Werror -O4 -g --std=gnu11 --pedantic-errors
|
||||||
LDFLAGS ?= -Wall -O4
|
LDFLAGS ?= -Wall -O4
|
||||||
LIBS ?= -luuid
|
LIBS ?= -luuid -ljansson
|
||||||
|
|
||||||
all: adsbus
|
all: adsbus
|
||||||
|
|
||||||
|
|||||||
1
adsbus.c
1
adsbus.c
@@ -67,6 +67,7 @@ static int loop(int epoll_fd) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
|
server_init();
|
||||||
hex_init();
|
hex_init();
|
||||||
airspy_adsb_init();
|
airspy_adsb_init();
|
||||||
beast_init();
|
beast_init();
|
||||||
|
|||||||
14
backend.c
14
backend.c
@@ -45,7 +45,7 @@ bool backend_connect(char *node, char *service, struct backend *backend, int epo
|
|||||||
|
|
||||||
int gai_err = getaddrinfo(node, service, &hints, &addrs);
|
int gai_err = getaddrinfo(node, service, &hints, &addrs);
|
||||||
if (gai_err) {
|
if (gai_err) {
|
||||||
fprintf(stderr, "%s: getaddrinfo(%s %s): %s\n", backend->id, node, service, gai_strerror(gai_err));
|
fprintf(stderr, "B %s: getaddrinfo(%s %s): %s\n", backend->id, node, service, gai_strerror(gai_err));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -68,13 +68,13 @@ bool backend_connect(char *node, char *service, struct backend *backend, int epo
|
|||||||
|
|
||||||
if (addr == NULL) {
|
if (addr == NULL) {
|
||||||
freeaddrinfo(addrs);
|
freeaddrinfo(addrs);
|
||||||
fprintf(stderr, "%s: Can't connect to %s %s\n", backend->id, node, service);
|
fprintf(stderr, "B %s: Can't connect to %s %s\n", backend->id, node, service);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];
|
char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];
|
||||||
if (getnameinfo(addr->ai_addr, addr->ai_addrlen, hbuf, sizeof(hbuf), sbuf, sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV) == 0) {
|
if (getnameinfo(addr->ai_addr, addr->ai_addrlen, hbuf, sizeof(hbuf), sbuf, sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV) == 0) {
|
||||||
fprintf(stderr, "%s: Connected to %s %s\n", backend->id, hbuf, sbuf);
|
fprintf(stderr, "B %s: Connected to %s %s\n", backend->id, hbuf, sbuf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,17 +98,19 @@ bool backend_connect(char *node, char *service, struct backend *backend, int epo
|
|||||||
|
|
||||||
bool backend_read(struct backend *backend) {
|
bool backend_read(struct backend *backend) {
|
||||||
if (buf_fill(&backend->buf, backend->fd) < 0) {
|
if (buf_fill(&backend->buf, backend->fd) < 0) {
|
||||||
fprintf(stderr, "%s: Connection closed by backend\n", backend->id);
|
fprintf(stderr, "B %s: Connection closed by backend\n", backend->id);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct packet packet;
|
struct packet packet = {
|
||||||
|
.backend = backend,
|
||||||
|
};
|
||||||
while (backend->parser(backend, &packet)) {
|
while (backend->parser(backend, &packet)) {
|
||||||
client_write(&packet);
|
client_write(&packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (backend->buf.length == BUF_LEN_MAX) {
|
if (backend->buf.length == BUF_LEN_MAX) {
|
||||||
fprintf(stderr, "%s: Input buffer overrun. This probably means that adsbus doesn't understand the protocol that this source is speaking.\n", backend->id);
|
fprintf(stderr, "B %s: Input buffer overrun. This probably means that adsbus doesn't understand the protocol that this source is speaking.\n", backend->id);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
24
client.c
24
client.c
@@ -15,7 +15,7 @@ struct client {
|
|||||||
struct client *next;
|
struct client *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef size_t (*serializer)(struct packet *, char *);
|
typedef void (*serializer)(struct packet *, struct buf *);
|
||||||
struct serializer {
|
struct serializer {
|
||||||
char *name;
|
char *name;
|
||||||
serializer serialize;
|
serializer serialize;
|
||||||
@@ -40,13 +40,12 @@ struct serializer *client_get_serializer(char *name) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool client_hello(int fd, struct serializer *serializer) {
|
static bool client_hello(int fd, struct serializer *serializer) {
|
||||||
char buf[SERIALIZE_LEN];
|
struct buf buf = BUF_INIT;
|
||||||
size_t len = serializer->serialize(NULL, buf);
|
serializer->serialize(NULL, &buf);
|
||||||
if (len == 0) {
|
if (buf.length == 0) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (write(fd, buf, len) != len) {
|
if (write(fd, buf_at(&buf, 0), buf.length) != buf.length) {
|
||||||
fprintf(stderr, "Failed to write hello to client\n");
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@@ -59,6 +58,7 @@ void client_add(int fd, struct serializer *serializer) {
|
|||||||
assert(fcntl(fd, F_SETFL, flags) == 0);
|
assert(fcntl(fd, F_SETFL, flags) == 0);
|
||||||
|
|
||||||
if (!client_hello(fd, serializer)) {
|
if (!client_hello(fd, serializer)) {
|
||||||
|
fprintf(stderr, "C xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx: Failed to write hello to client\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -70,7 +70,7 @@ void client_add(int fd, struct serializer *serializer) {
|
|||||||
client->next = serializer->client_head;
|
client->next = serializer->client_head;
|
||||||
serializer->client_head = client;
|
serializer->client_head = client;
|
||||||
|
|
||||||
fprintf(stderr, "%s (%s): New client\n", client->id, serializer->name);
|
fprintf(stderr, "C %s (%s): New client\n", client->id, serializer->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
void client_write(struct packet *packet) {
|
void client_write(struct packet *packet) {
|
||||||
@@ -79,18 +79,18 @@ void client_write(struct packet *packet) {
|
|||||||
if (serializer->client_head == NULL) {
|
if (serializer->client_head == NULL) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
char buf[SERIALIZE_LEN];
|
struct buf buf = BUF_INIT;
|
||||||
size_t len = serializer->serialize(packet, buf);
|
serializer->serialize(packet, &buf);
|
||||||
if (len == 0) {
|
if (buf.length == 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
struct client *client = serializer->client_head, *prev_client = NULL;
|
struct client *client = serializer->client_head, *prev_client = NULL;
|
||||||
while (client) {
|
while (client) {
|
||||||
if (write(client->fd, buf, len) == len) {
|
if (write(client->fd, buf_at(&buf, 0), buf.length) == buf.length) {
|
||||||
prev_client = client;
|
prev_client = client;
|
||||||
client = client->next;
|
client = client->next;
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "%s (%s): Client disconnected\n", client->id, serializer->name);
|
fprintf(stderr, "C %s (%s): Client disconnected\n", client->id, serializer->name);
|
||||||
if (prev_client) {
|
if (prev_client) {
|
||||||
prev_client->next = client->next;
|
prev_client->next = client->next;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
2
client.h
2
client.h
@@ -2,8 +2,6 @@
|
|||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
|
||||||
#define SERIALIZE_LEN 256
|
|
||||||
|
|
||||||
|
|
||||||
struct serializer *client_get_serializer(char *);
|
struct serializer *client_get_serializer(char *);
|
||||||
void client_add(int, struct serializer *);
|
void client_add(int, struct serializer *);
|
||||||
|
|||||||
8
common.c
8
common.c
@@ -111,3 +111,11 @@ void uuid_gen(char *out) {
|
|||||||
uuid_generate(uuid);
|
uuid_generate(uuid);
|
||||||
uuid_unparse(uuid, out);
|
uuid_unparse(uuid, out);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
char server_id[UUID_LEN];
|
||||||
|
|
||||||
|
void server_init() {
|
||||||
|
uuid_gen(server_id);
|
||||||
|
fprintf(stderr, "S %s: Server start\n", server_id);
|
||||||
|
}
|
||||||
|
|||||||
11
common.h
11
common.h
@@ -39,6 +39,7 @@ void buf_consume(struct buf *, size_t);
|
|||||||
//////// packet
|
//////// packet
|
||||||
|
|
||||||
#define DATA_LEN_MAX 14
|
#define DATA_LEN_MAX 14
|
||||||
|
struct backend;
|
||||||
struct packet {
|
struct packet {
|
||||||
enum {
|
enum {
|
||||||
MODE_AC,
|
MODE_AC,
|
||||||
@@ -48,13 +49,15 @@ struct packet {
|
|||||||
uint8_t payload[DATA_LEN_MAX];
|
uint8_t payload[DATA_LEN_MAX];
|
||||||
uint64_t mlat_timestamp;
|
uint64_t mlat_timestamp;
|
||||||
uint32_t rssi;
|
uint32_t rssi;
|
||||||
|
struct backend *backend;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
//////// mlat
|
//////// mlat
|
||||||
|
|
||||||
#define MLAT_MHZ 120
|
#define MLAT_MHZ 120
|
||||||
#define MLAT_MAX UINT64_MAX
|
// Use the signed max to avoid problems with some consumers; it's large enough to not matter.
|
||||||
|
#define MLAT_MAX INT64_MAX
|
||||||
#define RSSI_MAX UINT32_MAX
|
#define RSSI_MAX UINT32_MAX
|
||||||
|
|
||||||
struct mlat_state {
|
struct mlat_state {
|
||||||
@@ -82,3 +85,9 @@ void hex_from_bin(char *, uint8_t *, size_t);
|
|||||||
|
|
||||||
#define UUID_LEN 37
|
#define UUID_LEN 37
|
||||||
void uuid_gen(char *);
|
void uuid_gen(char *);
|
||||||
|
|
||||||
|
|
||||||
|
///////// server
|
||||||
|
|
||||||
|
extern char server_id[];
|
||||||
|
void server_init();
|
||||||
|
|||||||
84
json.c
84
json.c
@@ -1,6 +1,9 @@
|
|||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <jansson.h>
|
||||||
|
|
||||||
|
#include "backend.h"
|
||||||
#include "client.h"
|
#include "client.h"
|
||||||
#include "json.h"
|
#include "json.h"
|
||||||
|
|
||||||
@@ -8,57 +11,74 @@
|
|||||||
// Hobo JSON to avoid overhead. Assumes that we can't get quotes in the data.
|
// Hobo JSON to avoid overhead. Assumes that we can't get quotes in the data.
|
||||||
|
|
||||||
void json_init() {
|
void json_init() {
|
||||||
|
assert(JSON_INTEGER_IS_LONG_LONG);
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t json_hello(char *buf) {
|
static int json_buf_append_callback(const char *buffer, size_t size, void *data) {
|
||||||
int len = snprintf(buf, SERIALIZE_LEN,
|
struct buf *buf = data;
|
||||||
"{\"mlat_timestamp_mhz\":%ju, \"mlat_timestamp_max\":%ju, \"rssi_max\":%ju}\n",
|
if (size > BUF_LEN_MAX - buf->length - 1) {
|
||||||
(uintmax_t) MLAT_MHZ,
|
return -1;
|
||||||
(uintmax_t) MLAT_MAX,
|
}
|
||||||
(uintmax_t) RSSI_MAX);
|
memcpy(buf_at(buf, buf->length), buffer, size);
|
||||||
assert(len < SERIALIZE_LEN);
|
buf->length += size;
|
||||||
return len;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t json_serialize_mode_s_short(struct packet *packet, char *buf) {
|
static void json_hello(struct buf *buf) {
|
||||||
|
json_t *hello = json_pack("{sssIsIsI}",
|
||||||
|
"server_id", server_id,
|
||||||
|
"mlat_timestamp_mhz", (json_int_t) MLAT_MHZ,
|
||||||
|
"mlat_timestamp_max", (json_int_t) MLAT_MAX,
|
||||||
|
"rssi_max", (json_int_t) RSSI_MAX);
|
||||||
|
assert(json_dump_callback(hello, json_buf_append_callback, buf, 0) == 0);
|
||||||
|
json_decref(hello);
|
||||||
|
buf_chr(buf, buf->length++) = '\n';
|
||||||
|
}
|
||||||
|
|
||||||
|
static void json_serialize_mode_s_short(struct packet *packet, struct buf *buf) {
|
||||||
|
assert(packet->mlat_timestamp < MLAT_MAX);
|
||||||
char hexbuf[14];
|
char hexbuf[14];
|
||||||
hex_from_bin(hexbuf, packet->payload, 7);
|
hex_from_bin(hexbuf, packet->payload, 7);
|
||||||
int len = snprintf(buf, SERIALIZE_LEN,
|
json_t *out = json_pack("{ssss#sIsI}",
|
||||||
"{\"payload\":\"%.14s\", \"mlat_timestamp\":%ju, \"rssi\":%ju}\n",
|
"backend_id", packet->backend->id,
|
||||||
hexbuf,
|
"payload", hexbuf, 14,
|
||||||
(uintmax_t) packet->mlat_timestamp,
|
"mlat_timestamp", (json_int_t) packet->mlat_timestamp,
|
||||||
(uintmax_t) packet->rssi);
|
"rssi", (json_int_t) packet->rssi);
|
||||||
assert(len < SERIALIZE_LEN);
|
assert(json_dump_callback(out, json_buf_append_callback, buf, 0) == 0);
|
||||||
return len;
|
json_decref(out);
|
||||||
|
buf_chr(buf, buf->length++) = '\n';
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t json_serialize_mode_s_long(struct packet *packet, char *buf) {
|
static void json_serialize_mode_s_long(struct packet *packet, struct buf *buf) {
|
||||||
char hexbuf[28];
|
assert(packet->mlat_timestamp < MLAT_MAX);
|
||||||
|
char hexbuf[14];
|
||||||
hex_from_bin(hexbuf, packet->payload, 14);
|
hex_from_bin(hexbuf, packet->payload, 14);
|
||||||
int len = snprintf(buf, SERIALIZE_LEN,
|
json_t *out = json_pack("{ssss#sIsI}",
|
||||||
"{\"payload\":\"%.28s\", \"mlat_timestamp\":%ju, \"rssi\":%ju}\n",
|
"backend_id", packet->backend->id,
|
||||||
hexbuf,
|
"payload", hexbuf, 28,
|
||||||
(uintmax_t) packet->mlat_timestamp,
|
"mlat_timestamp", (json_int_t) packet->mlat_timestamp,
|
||||||
(uintmax_t) packet->rssi);
|
"rssi", (json_int_t) packet->rssi);
|
||||||
assert(len < SERIALIZE_LEN);
|
assert(json_dump_callback(out, json_buf_append_callback, buf, 0) == 0);
|
||||||
return len;
|
json_decref(out);
|
||||||
|
buf_chr(buf, buf->length++) = '\n';
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t json_serialize(struct packet *packet, char *buf) {
|
void json_serialize(struct packet *packet, struct buf *buf) {
|
||||||
if (!packet) {
|
if (!packet) {
|
||||||
return json_hello(buf);
|
json_hello(buf);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (packet->type) {
|
switch (packet->type) {
|
||||||
case MODE_AC:
|
case MODE_AC:
|
||||||
return 0;
|
break;
|
||||||
|
|
||||||
case MODE_S_SHORT:
|
case MODE_S_SHORT:
|
||||||
return json_serialize_mode_s_short(packet, buf);
|
json_serialize_mode_s_short(packet, buf);
|
||||||
|
break;
|
||||||
|
|
||||||
case MODE_S_LONG:
|
case MODE_S_LONG:
|
||||||
return json_serialize_mode_s_long(packet, buf);
|
json_serialize_mode_s_long(packet, buf);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user