[hamradio-commits] [dump1090] 27/389: Ability to receive traffic from network.
Matthew Ernisse
mernisse-guest at moszumanska.debian.org
Wed Nov 5 00:19:37 UTC 2014
This is an automated email from the git hooks/post-receive script.
mernisse-guest pushed a commit to branch master
in repository dump1090.
commit 0ce746dc5f4af6fcd607fb485e4410ffb5cb75bc
Author: antirez <antirez at gmail.com>
Date: Sat Jan 12 11:46:32 2013 +0100
Ability to receive traffic from network.
---
README | 33 +++++++++++-
dump1090.c | 180 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-------
2 files changed, 192 insertions(+), 21 deletions(-)
diff --git a/README b/README
index 70a807c..a5909b5 100644
--- a/README
+++ b/README
@@ -101,8 +101,11 @@ Network server features
---
By enabling the networking support with --net Dump1090 starts listening
-for clients connections on port 30002 (you can change the port using
-the --net-ro-port option).
+for clients connections on port 30002 and 30001 (you can change both the
+ports if you want, see --help output).
+
+Port 30002
+---
Connected clients are served with data ASAP as they arrive from the device
(or from file if --ifile is used) in the raw format similar to the following:
@@ -111,6 +114,32 @@ Connected clients are served with data ASAP as they arrive from the device
Every entry is separated by a simple newline (LF character, hex 0x0A).
+Port 30001
+---
+
+Port 30001 is the raw input port, and can be used to feed Dump1090 with
+data in the same format as specified above, with hex messages starting with
+a '*' and ending with a ';' character.
+
+So for instance if there is another remote Dump1090 instance collecting data
+it is possible to sum the output to a local Dump1090 instance doing something
+like this:
+
+ nc remote-dump1090.example.net 30002 | nc localhost 30001
+
+It is important to note that what is received via port 30001 is also
+broadcasted to clients listening to port 30002.
+
+In general everything received from port 30001 is handled exactly like the
+normal traffic from RTL devices or from file when --ifile is used.
+
+It is possible to use Dump1090 just as an hub using --ifile with /dev/zero
+as argument as in the following example:
+
+ ./dump1090 --ifile /dev/zero --net --interactive
+
+Then you can feed it from different data sources from the internet.
+
Antenna
---
diff --git a/dump1090.c b/dump1090.c
index 03a0f58..b5f4a4a 100644
--- a/dump1090.c
+++ b/dump1090.c
@@ -80,6 +80,8 @@
#define MODES_NET_MAX_FD 1024
#define MODES_NET_OUTPUT_RAW_PORT 30002
+#define MODES_NET_INPUT_RAW_PORT 30001
+#define MODES_CLIENT_BUF_SIZE 256
#define MODES_NOTUSED(V) ((void) V)
@@ -87,6 +89,8 @@
struct client {
int fd; /* File descriptor. */
int service; /* TCP port the client is connected to. */
+ char buf[MODES_CLIENT_BUF_SIZE]; /* Read buffer. */
+ int buflen; /* Amount of data on buffer. */
};
/* Structure used to describe an aircraft in iteractive mode. */
@@ -137,6 +141,7 @@ struct {
struct client *clients[MODES_NET_MAX_FD]; /* Our clients. */
int maxfd; /* Greatest fd currently active. */
int ros; /* Raw output listening socket. */
+ int ris; /* Raw input listening socket. */
/* Configuration */
char *filename; /* Input form file, --ifile option. */
@@ -146,6 +151,7 @@ struct {
int debug; /* Debugging mode. */
int net; /* Enable networking. */
int net_output_raw_port; /* Raw output TCP port. */
+ int net_input_raw_port; /* Raw input TCP port. */
int interactive; /* Interactive mode */
int interactive_rows; /* Interactive mode: max number of rows. */
int interactive_ttl; /* Interactive mode: TTL before deletion. */
@@ -212,6 +218,7 @@ struct modesMessage {
void interactiveShowData(void);
void interactiveReceiveData(struct modesMessage *mm);
void modesSendRawOutput(struct modesMessage *mm);
+void useModesMessage(struct modesMessage *mm);
/* ============================= Utility functions ========================== */
@@ -238,6 +245,7 @@ void modesInitConfig(void) {
Modes.raw = 0;
Modes.net = 0;
Modes.net_output_raw_port = MODES_NET_OUTPUT_RAW_PORT;
+ Modes.net_input_raw_port = MODES_NET_INPUT_RAW_PORT;
Modes.onlyaddr = 0;
Modes.debug = 0;
Modes.interactive = 0;
@@ -1227,18 +1235,7 @@ void detectModeS(uint16_t *m, uint32_t mlen) {
dumpRawMessage("Decoded with good CRC", msg, m, j);
/* Pass data to the next layer */
- if (!Modes.stats && (Modes.check_crc == 0 || mm.crcok)) {
- if (Modes.interactive) {
- interactiveReceiveData(&mm);
- } else {
- displayModesMessage(&mm);
- if (!Modes.raw && !Modes.onlyaddr) printf("\n");
- }
- /* Send data to connected clients. */
- if (Modes.net) {
- modesSendRawOutput(&mm); /* Feed raw output clients. */
- }
- }
+ useModesMessage(&mm);
/* Skip this message if we are sure it's fine. */
if (mm.crcok) j += (MODES_PREAMBLE_US+(msglen*8))*2;
@@ -1251,6 +1248,28 @@ void detectModeS(uint16_t *m, uint32_t mlen) {
}
}
+/* When a new message is available, because it was decoded from the
+ * RTL device, file, or received in the TCP input port, or any other
+ * way we can receive a decoded message, we call this function in order
+ * to use the message.
+ *
+ * Basically this function passes a raw message to the upper layers for
+ * further processing and visualization. */
+void useModesMessage(struct modesMessage *mm) {
+ if (!Modes.stats && (Modes.check_crc == 0 || mm->crcok)) {
+ if (Modes.interactive) {
+ interactiveReceiveData(mm);
+ } else {
+ displayModesMessage(mm);
+ if (!Modes.raw && !Modes.onlyaddr) printf("\n");
+ }
+ /* Send data to connected clients. */
+ if (Modes.net) {
+ modesSendRawOutput(mm); /* Feed raw output clients. */
+ }
+ }
+}
+
/* ========================= Interactive mode =============================== */
/* Return a new aircraft structure for the interactive mode linked list
@@ -1575,13 +1594,25 @@ void snipMode(int level) {
void modesInitNet(void) {
memset(Modes.clients,0,sizeof(Modes.clients));
Modes.maxfd = -1;
+
+ /* Raw output port */
Modes.ros = anetTcpServer(Modes.aneterr, Modes.net_output_raw_port, NULL);
- anetNonBlock(Modes.aneterr, Modes.ros);
if (Modes.ros == -1) {
- fprintf(stderr, "Error opening TCP port %d: %s\n",
+ fprintf(stderr, "Error opening raw TCP output port %d: %s\n",
Modes.net_output_raw_port, Modes.aneterr);
exit(1);
}
+
+ /* Raw input port */
+ Modes.ris = anetTcpServer(Modes.aneterr, Modes.net_input_raw_port, NULL);
+ if (Modes.ris == -1) {
+ fprintf(stderr, "Error opening raw TCP input port %d: %s\n",
+ Modes.net_input_raw_port, Modes.aneterr);
+ exit(1);
+ }
+
+ anetNonBlock(Modes.aneterr, Modes.ros);
+ anetNonBlock(Modes.aneterr, Modes.ris);
signal(SIGPIPE, SIG_IGN);
}
@@ -1590,22 +1621,30 @@ void modesInitNet(void) {
* second. */
void modesAcceptClients(void) {
int fd, port;
+ unsigned int j;
struct client *c;
+ int services[2];
+
+ services[0] = Modes.ros;
+ services[1] = Modes.ris;
+
+ for (j = 0; j < sizeof(services)/sizeof(int); j++) {
+ fd = anetTcpAccept(Modes.aneterr, services[j], NULL, &port);
+ if (fd == -1) continue;
- while(1) {
- fd = anetTcpAccept(Modes.aneterr, Modes.ros, NULL, &port);
- if (fd == -1) return;
if (fd >= MODES_NET_MAX_FD) {
close(fd);
return; /* Max number of clients reached. */
}
c = malloc(sizeof(*c));
- c->service = Modes.ros;
+ c->service = services[j];
c->fd = fd;
+ c->buflen = 0;
Modes.clients[fd] = c;
if (Modes.maxfd < fd) Modes.maxfd = fd;
+ j--; /* Try again with the same listening port. */
}
}
@@ -1658,6 +1697,103 @@ void modesSendRawOutput(struct modesMessage *mm) {
modesSendAllClients(Modes.ros, msg, p-msg);
}
+/* Turn an hex digit into its 4 bit decimal value.
+ * Returns -1 if the digit is not in the 0-F range. */
+int hexDigitVal(int c) {
+ c = tolower(c);
+ if (c >= '0' && c <= '9') return c-'0';
+ else if (c >= 'a' && c <= 'f') return c-'a'+10;
+ else return -1;
+}
+
+/* This function decodes a string representing a Mode S message in
+ * raw hex format like: *8D4B969699155600E87406F5B69F;
+ *
+ * The message is passed to the higher level layers, so it feeds
+ * the selected screen output, the network output and so forth.
+ *
+ * If the message looks invalid is silently discarded. */
+void decodeHexMessage(char *hex) {
+ int l = strlen(hex), j;
+ unsigned char msg[MODES_LONG_MSG_BYTES];
+ struct modesMessage mm;
+
+ if (l < 2 || hex[0] != '*' || hex[l-1] != ';') return;
+ hex++; l-=2; /* Skip * and ; */
+ if (l > MODES_LONG_MSG_BYTES*2) return; /* Too long message... broken. */
+ for (j = 0; j < l; j += 2) {
+ int high = hexDigitVal(hex[j]);
+ int low = hexDigitVal(hex[j+1]);
+
+ if (high == -1 || low == -1) return;
+ msg[j/2] = (high<<4) | low;
+ }
+ decodeModesMessage(&mm,msg);
+ useModesMessage(&mm);
+}
+
+/* This function polls all the clients using read() in order to receive new
+ * messages from the net.
+ *
+ * Every full message received is decoded and passed to the higher layers. */
+void modesReceiveRawInput(void) {
+ int j;
+ struct client *c;
+
+ for (j = 0; j <= Modes.maxfd; j++) {
+ c = Modes.clients[j];
+ if (c && c->service == Modes.ris) {
+ while(1) {
+ int left = sizeof(c->buf) - c->buflen;
+ int nread = read(j, c->buf+c->buflen, left);
+ int decoded = 0;
+ int oldpos = c->buflen;
+ int i;
+
+ if (nread < 0) {
+ if (nread == 0 || errno != EAGAIN) {
+ /* Error, or end of file. */
+ modesFreeClient(j);
+ }
+ break; /* Serve next client. */
+ }
+ c->buflen += nread;
+
+ /* If there is a complete message there must be a newline
+ * in the buffer. The iteration starts from 'oldpos' as
+ * we need to check only the chars we read in this interaction
+ * as we are sure there is no newline in the pre-existing
+ * buffer. */
+ for (i = oldpos; i < c->buflen; i++) {
+ if (c->buf[i] == '\n') {
+ c->buf[i] = '\0';
+ if (i && c->buf[i-1] == '\r') c->buf[i-1] = '\0';
+ decodeHexMessage(c->buf);
+ /* Move what's left at the start of the buffer. */
+ i++;
+ memmove(c->buf,c->buf+i,c->buflen-i);
+ c->buflen -= i;
+ /* Maybe there are more messages inside the buffer.
+ * Start looping from the start again. */
+ i = -1;
+ decoded = 1;
+ }
+ }
+ /* If our buffer is full discard it, this is some badly
+ * formatted shit. */
+ if (c->buflen == sizeof(c->buf)) {
+ c->buflen = 0;
+ /* If there is garbage, read more to discard it ASAP. */
+ continue;
+ }
+ /* If no message was decoded process the next client, otherwise
+ * read more data from the same client. */
+ if (!decoded) break;
+ }
+ }
+ }
+}
+
/* ================================ Main ==================================== */
void showHelp(void) {
@@ -1673,6 +1809,7 @@ void showHelp(void) {
"--raw Show only messages hex values.\n"
"--net Enable networking.\n"
"--net-ro-port <port> TCP listening port for raw output (default: 30002).\n"
+"--net-ri-port <port> TCP listening port for raw input (default: 30001).\n"
"--no-fix Disable single-bits error correction using CRC.\n"
"--no-crc-check Disable messages with broken CRC (discouraged).\n"
"--stats With --ifile print stats at exit. No other output.\n"
@@ -1714,6 +1851,8 @@ int main(int argc, char **argv) {
Modes.net = 1;
} else if (!strcmp(argv[j],"--net-ro-port") && more) {
Modes.net_output_raw_port = atoi(argv[++j]);
+ } else if (!strcmp(argv[j],"--net-ri-port") && more) {
+ Modes.net_input_raw_port = atoi(argv[++j]);
} else if (!strcmp(argv[j],"--onlyaddr")) {
Modes.onlyaddr = 1;
} else if (!strcmp(argv[j],"--metric")) {
@@ -1779,7 +1918,10 @@ int main(int argc, char **argv) {
* slow processors). */
pthread_mutex_unlock(&Modes.data_mutex);
detectModeS(Modes.magnitude, Modes.data_len/2);
- if (Modes.net) modesAcceptClients();
+ if (Modes.net) {
+ modesAcceptClients();
+ modesReceiveRawInput();
+ }
/* Refresh screen when in interactive mode. */
if (Modes.interactive &&
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-hamradio/dump1090.git
More information about the pkg-hamradio-commits
mailing list