2017-09-04 11:02:47 +02:00
|
|
|
// dump1090, a Mode S messages decoder for RTLSDR devices.
|
|
|
|
//
|
|
|
|
// Copyright (C) 2012 by Salvatore Sanfilippo <antirez@gmail.com>
|
|
|
|
//
|
|
|
|
// All rights reserved.
|
|
|
|
//
|
|
|
|
// Redistribution and use in source and binary forms, with or without
|
|
|
|
// modification, are permitted provided that the following conditions are
|
|
|
|
// met:
|
|
|
|
//
|
|
|
|
// * Redistributions of source code must retain the above copyright
|
|
|
|
// notice, this list of conditions and the following disclaimer.
|
|
|
|
//
|
|
|
|
// * Redistributions in binary form must reproduce the above copyright
|
|
|
|
// notice, this list of conditions and the following disclaimer in the
|
|
|
|
// documentation and/or other materials provided with the distribution.
|
|
|
|
//
|
|
|
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
|
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
|
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
|
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
|
|
// HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
|
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
|
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
|
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
|
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
|
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
|
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
//
|
|
|
|
|
|
|
|
#include "dump1090.h"
|
|
|
|
//
|
|
|
|
// ============================= Networking =============================
|
|
|
|
//
|
|
|
|
// Note: here we disregard any kind of good coding practice in favor of
|
|
|
|
// extreme simplicity, that is:
|
|
|
|
//
|
|
|
|
// 1) We only rely on the kernel buffers for our I/O without any kind of
|
|
|
|
// user space buffering.
|
|
|
|
// 2) We don't register any kind of event handler, from time to time a
|
|
|
|
// function gets called and we accept new connections. All the rest is
|
|
|
|
// handled via non-blocking I/O and manually polling clients to see if
|
|
|
|
// they have something new to share with us when reading is needed.
|
|
|
|
//
|
|
|
|
//=========================================================================
|
|
|
|
//
|
|
|
|
// Networking "stack" initialization
|
|
|
|
//
|
|
|
|
struct service {
|
|
|
|
char *descr;
|
|
|
|
int *socket;
|
|
|
|
int port;
|
|
|
|
int enabled;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct service services[MODES_NET_SERVICES_NUM];
|
|
|
|
|
|
|
|
void modesInitNet(void) {
|
|
|
|
int j;
|
|
|
|
|
|
|
|
struct service svc[MODES_NET_SERVICES_NUM] = {
|
2020-03-07 22:19:49 +01:00
|
|
|
{"Raw TCP output", &modes.ros, modes.net_output_raw_port, 1},
|
|
|
|
{"Raw TCP input", &modes.ris, modes.net_input_raw_port, 1},
|
|
|
|
{"Beast TCP output", &modes.bos, modes.net_output_beast_port, 1},
|
|
|
|
{"Beast TCP input", &modes.bis, modes.net_input_beast_port, 1},
|
|
|
|
{"HTTP server", &modes.https, modes.net_http_port, 1},
|
|
|
|
{"Basestation TCP output", &modes.sbsos, modes.net_output_sbs_port, 1}
|
2017-09-04 11:02:47 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
memcpy(&services, &svc, sizeof(svc));//services = svc;
|
|
|
|
|
2020-03-07 22:19:49 +01:00
|
|
|
modes.clients = NULL;
|
2017-09-04 11:02:47 +02:00
|
|
|
|
|
|
|
#ifdef _WIN32
|
2020-03-07 22:19:49 +01:00
|
|
|
if ( (!modes.wsaData.wVersion)
|
|
|
|
&& (!modes.wsaData.wHighVersion) ) {
|
2017-09-04 11:02:47 +02:00
|
|
|
// Try to start the windows socket support
|
2020-03-07 22:19:49 +01:00
|
|
|
if (WSAStartup(MAKEWORD(2,1),&modes.wsaData) != 0)
|
2017-09-04 11:02:47 +02:00
|
|
|
{
|
|
|
|
fprintf(stderr, "WSAStartup returned Error\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
for (j = 0; j < MODES_NET_SERVICES_NUM; j++) {
|
|
|
|
services[j].enabled = (services[j].port != 0);
|
|
|
|
if (services[j].enabled) {
|
2020-03-07 22:19:49 +01:00
|
|
|
int s = anetTcpServer(modes.aneterr, services[j].port, modes.net_bind_address);
|
2017-09-04 11:02:47 +02:00
|
|
|
if (s == -1) {
|
|
|
|
fprintf(stderr, "Error opening the listening port %d (%s): %s\n",
|
2020-03-07 22:19:49 +01:00
|
|
|
services[j].port, services[j].descr, modes.aneterr);
|
2017-09-04 11:02:47 +02:00
|
|
|
exit(1);
|
|
|
|
}
|
2020-03-07 22:19:49 +01:00
|
|
|
anetNonBlock(modes.aneterr, s);
|
2017-09-04 11:02:47 +02:00
|
|
|
*services[j].socket = s;
|
|
|
|
} else {
|
2020-03-07 22:19:49 +01:00
|
|
|
if (modes.debug & MODES_DEBUG_NET) printf("%s port is disabled\n", services[j].descr);
|
2017-09-04 11:02:47 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifndef _WIN32
|
|
|
|
signal(SIGPIPE, SIG_IGN);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
//
|
|
|
|
//=========================================================================
|
|
|
|
//
|
|
|
|
// This function gets called from time to time when the decoding thread is
|
|
|
|
// awakened by new data arriving. This usually happens a few times every second
|
|
|
|
//
|
|
|
|
struct client * modesAcceptClients(void) {
|
|
|
|
int fd, port;
|
|
|
|
unsigned int j;
|
|
|
|
struct client *c;
|
|
|
|
|
|
|
|
for (j = 0; j < MODES_NET_SERVICES_NUM; j++) {
|
|
|
|
if (services[j].enabled) {
|
2020-03-07 22:19:49 +01:00
|
|
|
fd = anetTcpAccept(modes.aneterr, *services[j].socket, NULL, &port);
|
2017-09-04 11:02:47 +02:00
|
|
|
if (fd == -1) continue;
|
|
|
|
|
2020-03-07 22:19:49 +01:00
|
|
|
anetNonBlock(modes.aneterr, fd);
|
2017-09-04 11:02:47 +02:00
|
|
|
c = (struct client *) malloc(sizeof(*c));
|
|
|
|
c->service = *services[j].socket;
|
2020-03-07 22:19:49 +01:00
|
|
|
c->next = modes.clients;
|
2017-09-04 11:02:47 +02:00
|
|
|
c->fd = fd;
|
|
|
|
c->buflen = 0;
|
2020-03-07 22:19:49 +01:00
|
|
|
modes.clients = c;
|
|
|
|
anetSetSendBuffer(modes.aneterr,fd, (MODES_NET_SNDBUF_SIZE << modes.net_sndbuf_size));
|
2017-09-04 11:02:47 +02:00
|
|
|
|
2020-03-07 22:19:49 +01:00
|
|
|
if (*services[j].socket == modes.sbsos) modes.stat_sbs_connections++;
|
|
|
|
if (*services[j].socket == modes.ros) modes.stat_raw_connections++;
|
|
|
|
if (*services[j].socket == modes.bos) modes.stat_beast_connections++;
|
2017-09-04 11:02:47 +02:00
|
|
|
|
|
|
|
j--; // Try again with the same listening port
|
|
|
|
|
2020-03-07 22:19:49 +01:00
|
|
|
if (modes.debug & MODES_DEBUG_NET)
|
2017-09-04 11:02:47 +02:00
|
|
|
printf("Created new client %d\n", fd);
|
|
|
|
}
|
|
|
|
}
|
2020-03-07 22:19:49 +01:00
|
|
|
return modes.clients;
|
2017-09-04 11:02:47 +02:00
|
|
|
}
|
|
|
|
//
|
|
|
|
//=========================================================================
|
|
|
|
//
|
|
|
|
// On error free the client, collect the structure, adjust maxfd if needed.
|
|
|
|
//
|
|
|
|
void modesFreeClient(struct client *c) {
|
|
|
|
|
|
|
|
// Unhook this client from the linked list of clients
|
2020-03-07 22:19:49 +01:00
|
|
|
struct client *p = modes.clients;
|
2017-09-04 11:02:47 +02:00
|
|
|
if (p) {
|
|
|
|
if (p == c) {
|
2020-03-07 22:19:49 +01:00
|
|
|
modes.clients = c->next;
|
2017-09-04 11:02:47 +02:00
|
|
|
} else {
|
|
|
|
while ((p) && (p->next != c)) {
|
|
|
|
p = p->next;
|
|
|
|
}
|
|
|
|
if (p) {
|
|
|
|
p->next = c->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
free(c);
|
|
|
|
}
|
|
|
|
//
|
|
|
|
//=========================================================================
|
|
|
|
//
|
|
|
|
// Close the client connection and mark it as closed
|
|
|
|
//
|
|
|
|
void modesCloseClient(struct client *c) {
|
|
|
|
close(c->fd);
|
2020-03-07 22:19:49 +01:00
|
|
|
if (c->service == modes.sbsos) {
|
|
|
|
if (modes.stat_sbs_connections) modes.stat_sbs_connections--;
|
|
|
|
} else if (c->service == modes.ros) {
|
|
|
|
if (modes.stat_raw_connections) modes.stat_raw_connections--;
|
|
|
|
} else if (c->service == modes.bos) {
|
|
|
|
if (modes.stat_beast_connections) modes.stat_beast_connections--;
|
2017-09-04 11:02:47 +02:00
|
|
|
}
|
|
|
|
|
2020-03-07 22:19:49 +01:00
|
|
|
if (modes.debug & MODES_DEBUG_NET)
|
2017-09-04 11:02:47 +02:00
|
|
|
printf("Closing client %d\n", c->fd);
|
|
|
|
|
|
|
|
c->fd = -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
//=========================================================================
|
|
|
|
//
|
|
|
|
// This function decodes a Beast binary format message
|
|
|
|
//
|
|
|
|
// 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 it is silently discarded.
|
|
|
|
//
|
|
|
|
// The function always returns 0 (success) to the caller as there is no
|
|
|
|
// case where we want broken messages here to close the client connection.
|
|
|
|
//
|
|
|
|
int decodeBinMessage(struct client *c, char *p) {
|
|
|
|
int msgLen = 0;
|
|
|
|
int j;
|
|
|
|
char ch;
|
|
|
|
char * ptr;
|
|
|
|
unsigned char msg[MODES_LONG_MSG_BYTES];
|
|
|
|
struct modesMessage mm;
|
|
|
|
MODES_NOTUSED(c);
|
|
|
|
memset(&mm, 0, sizeof(mm));
|
|
|
|
|
|
|
|
ch = *p++; /// Get the message type
|
|
|
|
if (0x1A == ch) {p++;}
|
|
|
|
|
2020-03-07 22:19:49 +01:00
|
|
|
if ((ch == '1') && (modes.mode_ac)) { // skip ModeA/C unless user enables --modes-ac
|
2017-09-04 11:02:47 +02:00
|
|
|
msgLen = MODEAC_MSG_BYTES;
|
|
|
|
} else if (ch == '2') {
|
|
|
|
msgLen = MODES_SHORT_MSG_BYTES;
|
|
|
|
} else if (ch == '3') {
|
|
|
|
msgLen = MODES_LONG_MSG_BYTES;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (msgLen) {
|
|
|
|
// Mark messages received over the internet as remote so that we don't try to
|
|
|
|
// pass them off as being received by this instance when forwarding them
|
|
|
|
mm.remote = 1;
|
|
|
|
|
|
|
|
ptr = (char*) &mm.timestampMsg;
|
|
|
|
for (j = 0; j < 6; j++) { // Grab the timestamp (big endian format)
|
|
|
|
ptr[5-j] = ch = *p++;
|
|
|
|
if (0x1A == ch) {p++;}
|
|
|
|
}
|
|
|
|
|
|
|
|
mm.signalLevel = ch = *p++; // Grab the signal level
|
|
|
|
if (0x1A == ch) {p++;}
|
|
|
|
|
|
|
|
for (j = 0; j < msgLen; j++) { // and the data
|
|
|
|
msg[j] = ch = *p++;
|
|
|
|
if (0x1A == ch) {p++;}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (msgLen == MODEAC_MSG_BYTES) { // ModeA or ModeC
|
|
|
|
decodeModeAMessage(&mm, ((msg[0] << 8) | msg[1]));
|
|
|
|
} else {
|
|
|
|
decodeModesMessage(&mm, msg);
|
|
|
|
}
|
|
|
|
|
|
|
|
useModesMessage(&mm);
|
|
|
|
}
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
//
|
|
|
|
//=========================================================================
|
|
|
|
//
|
|
|
|
// 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 message in raw hex format
|
|
|
|
// like: *8D4B969699155600E87406F5B69F; The string is null-terminated.
|
|
|
|
//
|
|
|
|
// 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 it is silently discarded.
|
|
|
|
//
|
|
|
|
// The function always returns 0 (success) to the caller as there is no
|
|
|
|
// case where we want broken messages here to close the client connection.
|
|
|
|
//
|
|
|
|
int decodeHexMessage(struct client *c, char *hex) {
|
|
|
|
int l = strlen(hex), j;
|
|
|
|
unsigned char msg[MODES_LONG_MSG_BYTES];
|
|
|
|
struct modesMessage mm;
|
|
|
|
MODES_NOTUSED(c);
|
|
|
|
memset(&mm, 0, sizeof(mm));
|
|
|
|
|
|
|
|
// Mark messages received over the internet as remote so that we don't try to
|
|
|
|
// pass them off as being received by this instance when forwarding them
|
|
|
|
mm.remote = 1;
|
|
|
|
mm.signalLevel = 0xFF;
|
|
|
|
|
|
|
|
// Remove spaces on the left and on the right
|
|
|
|
while(l && isspace(hex[l-1])) {
|
|
|
|
hex[l-1] = '\0'; l--;
|
|
|
|
}
|
|
|
|
while(isspace(*hex)) {
|
|
|
|
hex++; l--;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Turn the message into binary.
|
|
|
|
// Accept *-AVR raw @-AVR/BEAST timeS+raw %-AVR timeS+raw (CRC good) <-BEAST timeS+sigL+raw
|
|
|
|
// and some AVR records that we can understand
|
|
|
|
if (hex[l-1] != ';') {return (0);} // not complete - abort
|
|
|
|
|
|
|
|
switch(hex[0]) {
|
|
|
|
case '<': {
|
|
|
|
mm.signalLevel = (hexDigitVal(hex[13])<<4) | hexDigitVal(hex[14]);
|
|
|
|
hex += 15; l -= 16; // Skip <, timestamp and siglevel, and ;
|
|
|
|
break;}
|
|
|
|
|
|
|
|
case '@': // No CRC check
|
|
|
|
case '%': { // CRC is OK
|
|
|
|
hex += 13; l -= 14; // Skip @,%, and timestamp, and ;
|
|
|
|
break;}
|
|
|
|
|
|
|
|
case '*':
|
|
|
|
case ':': {
|
|
|
|
hex++; l-=2; // Skip * and ;
|
|
|
|
break;}
|
|
|
|
|
|
|
|
default: {
|
|
|
|
return (0); // We don't know what this is, so abort
|
|
|
|
break;}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( (l != (MODEAC_MSG_BYTES * 2))
|
|
|
|
&& (l != (MODES_SHORT_MSG_BYTES * 2))
|
|
|
|
&& (l != (MODES_LONG_MSG_BYTES * 2)) )
|
|
|
|
{return (0);} // Too short or long message... broken
|
|
|
|
|
2020-03-07 22:19:49 +01:00
|
|
|
if ( (0 == modes.mode_ac)
|
2017-09-04 11:02:47 +02:00
|
|
|
&& (l == (MODEAC_MSG_BYTES * 2)) )
|
|
|
|
{return (0);} // Right length for ModeA/C, but not enabled
|
|
|
|
|
|
|
|
for (j = 0; j < l; j += 2) {
|
|
|
|
int high = hexDigitVal(hex[j]);
|
|
|
|
int low = hexDigitVal(hex[j+1]);
|
|
|
|
|
|
|
|
if (high == -1 || low == -1) return 0;
|
|
|
|
msg[j/2] = (high << 4) | low;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (l == (MODEAC_MSG_BYTES * 2)) { // ModeA or ModeC
|
|
|
|
decodeModeAMessage(&mm, ((msg[0] << 8) | msg[1]));
|
|
|
|
} else { // Assume ModeS
|
|
|
|
decodeModesMessage(&mm, msg);
|
|
|
|
}
|
|
|
|
|
|
|
|
useModesMessage(&mm);
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
//
|
|
|
|
//=========================================================================
|
|
|
|
//
|
|
|
|
// This function polls the clients using read() in order to receive new
|
|
|
|
// messages from the net.
|
|
|
|
//
|
|
|
|
// The message is supposed to be separated from the next message by the
|
|
|
|
// separator 'sep', which is a null-terminated C string.
|
|
|
|
//
|
|
|
|
// Every full message received is decoded and passed to the higher layers
|
|
|
|
// calling the function's 'handler'.
|
|
|
|
//
|
|
|
|
// The handler returns 0 on success, or 1 to signal this function we should
|
|
|
|
// close the connection with the client in case of non-recoverable errors.
|
|
|
|
//
|
|
|
|
void modesReadFromClient(struct client *c, char *sep,
|
|
|
|
int(*handler)(struct client *, char *)) {
|
|
|
|
int left;
|
|
|
|
int nread;
|
|
|
|
int fullmsg;
|
|
|
|
int bContinue = 1;
|
|
|
|
char *s, *e, *p;
|
|
|
|
|
|
|
|
while(bContinue) {
|
|
|
|
|
|
|
|
fullmsg = 0;
|
|
|
|
left = MODES_CLIENT_BUF_SIZE - c->buflen;
|
|
|
|
// If our buffer is full discard it, this is some badly formatted shit
|
|
|
|
if (left <= 0) {
|
|
|
|
c->buflen = 0;
|
|
|
|
left = MODES_CLIENT_BUF_SIZE;
|
|
|
|
// If there is garbage, read more to discard it ASAP
|
|
|
|
}
|
|
|
|
#ifndef _WIN32
|
|
|
|
nread = read(c->fd, c->buf+c->buflen, left);
|
|
|
|
#else
|
|
|
|
nread = recv(c->fd, c->buf+c->buflen, left, 0);
|
|
|
|
if (nread < 0) {errno = WSAGetLastError();}
|
|
|
|
#endif
|
|
|
|
if (nread == 0) {
|
|
|
|
modesCloseClient(c);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we didn't get all the data we asked for, then return once we've processed what we did get.
|
|
|
|
if (nread != left) {
|
|
|
|
bContinue = 0;
|
|
|
|
}
|
|
|
|
#ifndef _WIN32
|
|
|
|
if ( (nread < 0 && errno != EAGAIN && errno != EWOULDBLOCK) || nread == 0 ) { // Error, or end of file
|
|
|
|
#else
|
|
|
|
if ( (nread < 0) && (errno != EWOULDBLOCK)) { // Error, or end of file
|
|
|
|
#endif
|
|
|
|
modesCloseClient(c);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (nread <= 0) {
|
|
|
|
break; // Serve next client
|
|
|
|
}
|
|
|
|
c->buflen += nread;
|
|
|
|
|
|
|
|
// Always null-term so we are free to use strstr() (it won't affect binary case)
|
|
|
|
c->buf[c->buflen] = '\0';
|
|
|
|
|
|
|
|
e = s = c->buf; // Start with the start of buffer, first message
|
|
|
|
|
2020-03-07 22:19:49 +01:00
|
|
|
|
|
|
|
|
|
|
|
if (c->service == modes.bis) {
|
2017-09-04 11:02:47 +02:00
|
|
|
// This is the Beast Binary scanning case.
|
|
|
|
// If there is a complete message still in the buffer, there must be the separator 'sep'
|
|
|
|
// in the buffer, note that we full-scan the buffer at every read for simplicity.
|
|
|
|
|
|
|
|
left = c->buflen; // Length of valid search for memchr()
|
2020-03-07 22:19:49 +01:00
|
|
|
while (left && ((s = (char*)memchr(e, (char) 0x1a, left)) != NULL)) { // The first byte of buffer 'should' be 0x1a
|
2017-09-04 11:02:47 +02:00
|
|
|
s++; // skip the 0x1a
|
|
|
|
if (*s == '1') {
|
|
|
|
e = s + MODEAC_MSG_BYTES + 8; // point past remainder of message
|
|
|
|
} else if (*s == '2') {
|
|
|
|
e = s + MODES_SHORT_MSG_BYTES + 8;
|
|
|
|
} else if (*s == '3') {
|
|
|
|
e = s + MODES_LONG_MSG_BYTES + 8;
|
|
|
|
} else {
|
|
|
|
e = s; // Not a valid beast message, skip
|
|
|
|
left = &(c->buf[c->buflen]) - e;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
// we need to be careful of double escape characters in the message body
|
|
|
|
for (p = s; p < e; p++) {
|
|
|
|
if (0x1A == *p) {
|
|
|
|
p++; e++;
|
|
|
|
if (e > &(c->buf[c->buflen])) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
left = &(c->buf[c->buflen]) - e;
|
|
|
|
if (left < 0) { // Incomplete message in buffer
|
|
|
|
e = s - 1; // point back at last found 0x1a.
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
// Have a 0x1a followed by 1, 2 or 3 - pass message less 0x1a to handler.
|
|
|
|
if (handler(c, s)) {
|
|
|
|
modesCloseClient(c);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
fullmsg = 1;
|
|
|
|
}
|
|
|
|
s = e; // For the buffer remainder below
|
|
|
|
|
|
|
|
} else {
|
|
|
|
//
|
|
|
|
// This is the ASCII scanning case, AVR RAW or HTTP at present
|
|
|
|
// If there is a complete message still in the buffer, there must be the separator 'sep'
|
|
|
|
// in the buffer, note that we full-scan the buffer at every read for simplicity.
|
|
|
|
//
|
|
|
|
while ((e = strstr(s, sep)) != NULL) { // end of first message if found
|
|
|
|
*e = '\0'; // The handler expects null terminated strings
|
|
|
|
if (handler(c, s)) { // Pass message to handler.
|
|
|
|
modesCloseClient(c); // Handler returns 1 on error to signal we .
|
|
|
|
return; // should close the client connection
|
|
|
|
}
|
|
|
|
s = e + strlen(sep); // Move to start of next message
|
|
|
|
fullmsg = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fullmsg) { // We processed something - so
|
|
|
|
c->buflen = &(c->buf[c->buflen]) - s; // Update the unprocessed buffer length
|
|
|
|
memmove(c->buf, s, c->buflen); // Move what's remaining to the start of the buffer
|
|
|
|
} else { // If no message was decoded process the next client
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
|
|
//=========================================================================
|
|
|
|
//
|
|
|
|
// Read data from clients. This function actually delegates a lower-level
|
|
|
|
// function that depends on the kind of service (raw, http, ...).
|
|
|
|
//
|
|
|
|
void modesReadFromClients(void) {
|
|
|
|
|
|
|
|
struct client *c = modesAcceptClients();
|
|
|
|
|
|
|
|
while (c) {
|
|
|
|
// Read next before servicing client incase the service routine deletes the client!
|
|
|
|
struct client *next = c->next;
|
|
|
|
|
|
|
|
if (c->fd >= 0) {
|
|
|
|
modesReadFromClient(c,"",decodeBinMessage);
|
|
|
|
} else {
|
|
|
|
modesFreeClient(c);
|
|
|
|
}
|
|
|
|
c = next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
|
|
// =============================== Network IO ===========================
|
|
|
|
//
|