VK1ET : Numerous changes to Port handling

Changes based on ideas from John VK1ET. His commit notes are as follows
:

1. Change input socket handling to avoid unnecessary memmove (use
pointers instead)

2. Add ability to read and decode binary beast format TCP.

3. Change output socket handling same as sbs_output - only call output
handler if there is a current client connected use separate ports for
beast in and out - no need for --net-beast flag. Will input/output
format defined by socket connected to. avr raw, beast binary and sbs can
be handled simultaneously.

4. Some comments changes, filtering of ModeAC to json,.
This commit is contained in:
Malcolm Robb 2013-05-24 22:29:00 +01:00
parent f64a65b5a2
commit e86eb3921e

View file

@ -56,7 +56,7 @@
// MinorVer changes when additional features are added, but not for bug fixes (range 00-99) // MinorVer changes when additional features are added, but not for bug fixes (range 00-99)
// DayDate & Year changes for all changes, including for bug fixes. It represent the release date of the update // DayDate & Year changes for all changes, including for bug fixes. It represent the release date of the update
// //
#define MODES_DUMP1090_VERSION "1.06.2305.13" #define MODES_DUMP1090_VERSION "1.07.2305.13"
#define MODES_USER_LATITUDE_DFLT (0.0) #define MODES_USER_LATITUDE_DFLT (0.0)
#define MODES_USER_LONGITUDE_DFLT (0.0) #define MODES_USER_LONGITUDE_DFLT (0.0)
@ -146,9 +146,11 @@
#define MODES_INTERACTIVE_TTL 60 /* TTL before being removed */ #define MODES_INTERACTIVE_TTL 60 /* TTL before being removed */
#define MODES_NET_MAX_FD 1024 #define MODES_NET_MAX_FD 1024
#define MODES_NET_OUTPUT_SBS_PORT 30003
#define MODES_NET_OUTPUT_RAW_PORT 30002
#define MODES_NET_INPUT_RAW_PORT 30001 #define MODES_NET_INPUT_RAW_PORT 30001
#define MODES_NET_OUTPUT_RAW_PORT 30002
#define MODES_NET_OUTPUT_SBS_PORT 30003
#define MODES_NET_INPUT_BEAST_PORT 30004
#define MODES_NET_OUTPUT_BEAST_PORT 30005
#define MODES_NET_HTTP_PORT 8080 #define MODES_NET_HTTP_PORT 8080
#define MODES_CLIENT_BUF_SIZE 1024 #define MODES_CLIENT_BUF_SIZE 1024
#define MODES_NET_SNDBUF_SIZE (1024*64) #define MODES_NET_SNDBUF_SIZE (1024*64)
@ -229,9 +231,13 @@ struct {
int sbsos; /* SBS output listening socket. */ int sbsos; /* SBS output listening socket. */
int ros; /* Raw output listening socket. */ int ros; /* Raw output listening socket. */
int ris; /* Raw input listening socket. */ int ris; /* Raw input listening socket. */
int bos; /* Beast output listening socket */
int bis; /* Beast input listening socket */
int https; /* HTTP listening socket. */ int https; /* HTTP listening socket. */
char * rawOut; /* Buffer for building raw output data */ char * rawOut; /* Buffer for building raw output data */
int rawOutUsed; /* How much if the buffer is currently used */ int rawOutUsed; /* How much if the buffer is currently used */
char *beastOut; /* Buffer for building beast output data */
int beastOutUsed; /* How much if the buffer is currently used */
/* Configuration */ /* Configuration */
char *filename; /* Input form file, --ifile option. */ char *filename; /* Input form file, --ifile option. */
@ -250,6 +256,8 @@ struct {
int net_output_raw_rate_count; /* Rate (in 64mS increments) of output raw data */ int net_output_raw_rate_count; /* Rate (in 64mS increments) of output raw data */
int net_output_raw_port; /* Raw output TCP port. */ int net_output_raw_port; /* Raw output TCP port. */
int net_input_raw_port; /* Raw input TCP port. */ int net_input_raw_port; /* Raw input TCP port. */
int net_output_beast_port; /* Beast output TCP port */
int net_input_beast_port; /* Beast input TCP port */
int net_http_port; /* HTTP port. */ int net_http_port; /* HTTP port. */
int quiet; /* Suppress stdout */ int quiet; /* Suppress stdout */
int interactive; /* Interactive mode */ int interactive; /* Interactive mode */
@ -286,6 +294,8 @@ struct {
unsigned int stat_http_requests; unsigned int stat_http_requests;
unsigned int stat_sbs_connections; unsigned int stat_sbs_connections;
unsigned int stat_raw_connections;
unsigned int stat_beast_connections;
unsigned int stat_out_of_phase; unsigned int stat_out_of_phase;
unsigned int stat_ph_demodulated0; unsigned int stat_ph_demodulated0;
unsigned int stat_ph_demodulated1; unsigned int stat_ph_demodulated1;
@ -316,6 +326,7 @@ struct modesMessage {
uint32_t addr; // ICAO Address from bytes 1 2 and 3 uint32_t addr; // ICAO Address from bytes 1 2 and 3
int phase_corrected; // True if phase correction was applied int phase_corrected; // True if phase correction was applied
uint64_t timestampMsg; // Timestamp of the message uint64_t timestampMsg; // Timestamp of the message
int remote; // If set this message is from a remote station
unsigned char signalLevel; // Signal Amplitude unsigned char signalLevel; // Signal Amplitude
// DF 11 // DF 11
@ -353,7 +364,7 @@ void modesSendRawOutput(struct modesMessage *mm);
void modesSendBeastOutput(struct modesMessage *mm); void modesSendBeastOutput(struct modesMessage *mm);
void modesSendSBSOutput(struct modesMessage *mm); void modesSendSBSOutput(struct modesMessage *mm);
void useModesMessage(struct modesMessage *mm); void useModesMessage(struct modesMessage *mm);
int fixBitErrors(unsigned char *msg, int bits, int maxfixable, int *bitpos); int fixBitErrors(unsigned char *msg, int bits, int maxfix, char *fixedbits);
int fixSingleBitErrors(unsigned char *msg, int bits); int fixSingleBitErrors(unsigned char *msg, int bits);
int fixTwoBitsErrors(unsigned char *msg, int bits); int fixTwoBitsErrors(unsigned char *msg, int bits);
void modesInitErrorInfo(); void modesInitErrorInfo();
@ -390,6 +401,8 @@ void modesInitConfig(void) {
Modes.net_output_sbs_port = MODES_NET_OUTPUT_SBS_PORT; Modes.net_output_sbs_port = MODES_NET_OUTPUT_SBS_PORT;
Modes.net_output_raw_port = MODES_NET_OUTPUT_RAW_PORT; Modes.net_output_raw_port = MODES_NET_OUTPUT_RAW_PORT;
Modes.net_input_raw_port = MODES_NET_INPUT_RAW_PORT; Modes.net_input_raw_port = MODES_NET_INPUT_RAW_PORT;
Modes.net_output_beast_port = MODES_NET_OUTPUT_BEAST_PORT;
Modes.net_input_beast_port = MODES_NET_INPUT_BEAST_PORT;
Modes.net_http_port = MODES_NET_HTTP_PORT; Modes.net_http_port = MODES_NET_HTTP_PORT;
Modes.interactive_rows = MODES_INTERACTIVE_ROWS; Modes.interactive_rows = MODES_INTERACTIVE_ROWS;
Modes.interactive_ttl = MODES_INTERACTIVE_TTL; Modes.interactive_ttl = MODES_INTERACTIVE_TTL;
@ -408,6 +421,7 @@ void modesInit(void) {
((Modes.data = (uint16_t *) malloc(MODES_ASYNC_BUF_SIZE) ) == NULL) || ((Modes.data = (uint16_t *) malloc(MODES_ASYNC_BUF_SIZE) ) == NULL) ||
((Modes.magnitude = (uint16_t *) malloc(MODES_ASYNC_BUF_SIZE+MODES_PREAMBLE_SIZE+MODES_LONG_MSG_SIZE) ) == NULL) || ((Modes.magnitude = (uint16_t *) malloc(MODES_ASYNC_BUF_SIZE+MODES_PREAMBLE_SIZE+MODES_LONG_MSG_SIZE) ) == NULL) ||
((Modes.maglut = (uint16_t *) malloc(sizeof(uint16_t) * 256 * 256) ) == NULL) || ((Modes.maglut = (uint16_t *) malloc(sizeof(uint16_t) * 256 * 256) ) == NULL) ||
((Modes.beastOut = (char *) malloc(MODES_RAWOUT_BUF_SIZE) ) == NULL) ||
((Modes.rawOut = (char *) malloc(MODES_RAWOUT_BUF_SIZE) ) == NULL) ) ((Modes.rawOut = (char *) malloc(MODES_RAWOUT_BUF_SIZE) ) == NULL) )
{ {
fprintf(stderr, "Out of memory allocating data buffer.\n"); fprintf(stderr, "Out of memory allocating data buffer.\n");
@ -2649,13 +2663,19 @@ void detectModeS(uint16_t *m, uint32_t mlen) {
} }
//Send any remaining partial raw buffers now //Send any remaining partial raw buffers now
if (Modes.rawOutUsed) if (Modes.rawOutUsed || Modes.beastOutUsed)
{ {
Modes.net_output_raw_rate_count++; Modes.net_output_raw_rate_count++;
if (Modes.net_output_raw_rate_count > Modes.net_output_raw_rate) if (Modes.net_output_raw_rate_count > Modes.net_output_raw_rate)
{ {
if (Modes.rawOutUsed) {
modesSendAllClients(Modes.ros, Modes.rawOut, Modes.rawOutUsed); modesSendAllClients(Modes.ros, Modes.rawOut, Modes.rawOutUsed);
Modes.rawOutUsed = 0; Modes.rawOutUsed = 0;
}
if (Modes.beastOutUsed) {
modesSendAllClients(Modes.bos, Modes.beastOut, Modes.beastOutUsed);
Modes.beastOutUsed = 0;
}
Modes.net_output_raw_rate_count = 0; Modes.net_output_raw_rate_count = 0;
} }
} }
@ -2684,19 +2704,10 @@ void useModesMessage(struct modesMessage *mm) {
displayModesMessage(mm); displayModesMessage(mm);
} }
// Feed SBS output clients // Feed output clients
if (Modes.stat_sbs_connections) { if (Modes.stat_sbs_connections) {modesSendSBSOutput(mm);}
modesSendSBSOutput(mm); if (Modes.stat_beast_connections) {modesSendBeastOutput(mm);}
} if (Modes.stat_raw_connections) {modesSendRawOutput(mm);}
// Send data to connected network clients
if (Modes.net) {
if (Modes.beast) {
modesSendBeastOutput(mm);
} else {
modesSendRawOutput(mm);
}
}
} }
} }
@ -3346,9 +3357,11 @@ void modesInitNet(void) {
char *descr; char *descr;
int *socket; int *socket;
int port; int port;
} services[4] = { } services[6] = {
{"Raw TCP output", &Modes.ros, Modes.net_output_raw_port}, {"Raw TCP output", &Modes.ros, Modes.net_output_raw_port},
{"Raw TCP input", &Modes.ris, Modes.net_input_raw_port}, {"Raw TCP input", &Modes.ris, Modes.net_input_raw_port},
{"Beast TCP output", &Modes.bos, Modes.net_output_beast_port},
{"Beast TCP input", &Modes.bis, Modes.net_input_beast_port},
{"HTTP server", &Modes.https, Modes.net_http_port}, {"HTTP server", &Modes.https, Modes.net_http_port},
{"Basestation TCP output", &Modes.sbsos, Modes.net_output_sbs_port} {"Basestation TCP output", &Modes.sbsos, Modes.net_output_sbs_port}
}; };
@ -3357,7 +3370,7 @@ void modesInitNet(void) {
memset(Modes.clients,0,sizeof(Modes.clients)); memset(Modes.clients,0,sizeof(Modes.clients));
Modes.maxfd = -1; Modes.maxfd = -1;
for (j = 0; j < 4; j++) { for (j = 0; j < 6; j++) {
int s = anetTcpServer(Modes.aneterr, services[j].port, NULL); int s = anetTcpServer(Modes.aneterr, services[j].port, NULL);
if (s == -1) { if (s == -1) {
fprintf(stderr, "Error opening the listening port %d (%s): %s\n", fprintf(stderr, "Error opening the listening port %d (%s): %s\n",
@ -3378,12 +3391,14 @@ void modesAcceptClients(void) {
int fd, port; int fd, port;
unsigned int j; unsigned int j;
struct client *c; struct client *c;
int services[4]; int services[6];
services[0] = Modes.ros; services[0] = Modes.ros;
services[1] = Modes.ris; services[1] = Modes.ris;
services[2] = Modes.https; services[2] = Modes.bos;
services[3] = Modes.sbsos; services[3] = Modes.bis;
services[4] = Modes.https;
services[5] = Modes.sbsos;
for (j = 0; j < sizeof(services)/sizeof(int); j++) { for (j = 0; j < sizeof(services)/sizeof(int); j++) {
fd = anetTcpAccept(Modes.aneterr, services[j], NULL, &port); fd = anetTcpAccept(Modes.aneterr, services[j], NULL, &port);
@ -3404,6 +3419,8 @@ void modesAcceptClients(void) {
if (Modes.maxfd < fd) Modes.maxfd = fd; if (Modes.maxfd < fd) Modes.maxfd = fd;
if (services[j] == Modes.sbsos) Modes.stat_sbs_connections++; if (services[j] == Modes.sbsos) Modes.stat_sbs_connections++;
if (services[j] == Modes.ros) Modes.stat_raw_connections++;
if (services[j] == Modes.bos) Modes.stat_beast_connections++;
j--; /* Try again with the same listening port. */ j--; /* Try again with the same listening port. */
@ -3415,6 +3432,15 @@ void modesAcceptClients(void) {
/* On error free the client, collect the structure, adjust maxfd if needed. */ /* On error free the client, collect the structure, adjust maxfd if needed. */
void modesFreeClient(int fd) { void modesFreeClient(int fd) {
close(fd); close(fd);
if (Modes.clients[fd]->service == Modes.sbsos) {
if (Modes.stat_sbs_connections) Modes.stat_sbs_connections--;
}
else if (Modes.clients[fd]->service == Modes.ros) {
if (Modes.stat_raw_connections) Modes.stat_raw_connections--;
}
else if (Modes.clients[fd]->service == Modes.bos) {
if (Modes.stat_beast_connections) Modes.stat_beast_connections--;
}
free(Modes.clients[fd]); free(Modes.clients[fd]);
Modes.clients[fd] = NULL; Modes.clients[fd] = NULL;
@ -3451,7 +3477,7 @@ void modesSendAllClients(int service, void *msg, int len) {
/* Write raw output in Beast Binary format with Timestamp to TCP clients */ /* Write raw output in Beast Binary format with Timestamp to TCP clients */
void modesSendBeastOutput(struct modesMessage *mm) { void modesSendBeastOutput(struct modesMessage *mm) {
char *p = &Modes.rawOut[Modes.rawOutUsed]; char *p = &Modes.beastOut[Modes.beastOutUsed];
int msgLen = mm->msgbits / 8; int msgLen = mm->msgbits / 8;
char * pTimeStamp; char * pTimeStamp;
int j; int j;
@ -3475,11 +3501,11 @@ void modesSendBeastOutput(struct modesMessage *mm) {
memcpy(p, mm->msg, msgLen); memcpy(p, mm->msg, msgLen);
Modes.rawOutUsed += (msgLen + 9); Modes.beastOutUsed += (msgLen + 9);
if (Modes.rawOutUsed >= Modes.net_output_raw_size) if (Modes.beastOutUsed >= Modes.net_output_raw_size)
{ {
modesSendAllClients(Modes.ros, Modes.rawOut, Modes.rawOutUsed); modesSendAllClients(Modes.bos, Modes.beastOut, Modes.beastOutUsed);
Modes.rawOutUsed = 0; Modes.beastOutUsed = 0;
Modes.net_output_raw_rate_count = 0; Modes.net_output_raw_rate_count = 0;
} }
} }
@ -3665,42 +3691,80 @@ void modesSendSBSOutput(struct modesMessage *mm) {
p += sprintf(p, "\r\n"); p += sprintf(p, "\r\n");
modesSendAllClients(Modes.sbsos, msg, p-msg); modesSendAllClients(Modes.sbsos, msg, p-msg);
} }
//
// 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;
unsigned char msg[MODES_LONG_MSG_BYTES];
struct modesMessage mm;
MODES_NOTUSED(c);
memset(&mm, 0, sizeof(mm));
/* Turn an hex digit into its 4 bit decimal value. if ((*p == '1') && (Modes.mode_ac)) { // skip ModeA/C unless user enables --modes-ac
* Returns -1 if the digit is not in the 0-F range. */ msgLen = MODEAC_MSG_BYTES;
} else if (*p == '2') {
msgLen = MODES_SHORT_MSG_BYTES;
} else if (*p == '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;
p += 7; // Skip the timestamp
mm.signalLevel = *p++; // Grab the signal level
memcpy(msg, p, msgLen); // and the data
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) { int hexDigitVal(int c) {
c = tolower(c); c = tolower(c);
if (c >= '0' && c <= '9') return c-'0'; if (c >= '0' && c <= '9') return c-'0';
else if (c >= 'a' && c <= 'f') return c-'a'+10; else if (c >= 'a' && c <= 'f') return c-'a'+10;
else return -1; else return -1;
} }
//
/* This function decodes a string representing a Mode S message in // This function decodes a string representing message in raw hex format
* raw hex format like: *8D4B969699155600E87406F5B69F; // like: *8D4B969699155600E87406F5B69F; The string is null-terminated.
* The string is supposed to be at the start of the client buffer //
* and null-terminated. // The message is passed to the higher level layers, so it feeds
* // the selected screen output, the network output and so forth.
* 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.
* //
* If the message looks invalid 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.
* The function always returns 0 (success) to the caller as there is int decodeHexMessage(struct client *c, char *hex) {
* no case where we want broken messages here to close the client
* connection. */
int decodeHexMessage(struct client *c) {
char *hex = c->buf;
int l = strlen(hex), j; int l = strlen(hex), j;
unsigned char msg[MODES_LONG_MSG_BYTES]; unsigned char msg[MODES_LONG_MSG_BYTES];
struct modesMessage mm; struct modesMessage mm;
MODES_NOTUSED(c);
memset(&mm, 0, sizeof(mm)); memset(&mm, 0, sizeof(mm));
// Always mark the timestamp as invalid for packets received over the internet // Mark messages received over the internet as remote so that we don't try to
// Mixing of data from two or more different receivers and publishing // pass them off as being received by this instance when forwarding them
// as coming from one would lead to corrupt mlat data mm.remote = 1;
// Non timemarked internet data has indeterminate delay mm.signalLevel = 0xFF;
mm.timestampMsg = 0;
mm.signalLevel = -1;
// Remove spaces on the left and on the right // Remove spaces on the left and on the right
while(l && isspace(hex[l-1])) { while(l && isspace(hex[l-1])) {
@ -3736,7 +3800,15 @@ int decodeHexMessage(struct client *c) {
break;} break;}
} }
if ( (l < 4) || (l > MODES_LONG_MSG_BYTES*2) ) return (0); // Too short or long message... broken 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
if ( (0 == Modes.mode_ac)
&& (l == (MODEAC_MSG_BYTES * 2)) )
{return (0);} // Right length for ModeA/C, but not enabled
for (j = 0; j < l; j += 2) { for (j = 0; j < l; j += 2) {
int high = hexDigitVal(hex[j]); int high = hexDigitVal(hex[j]);
int low = hexDigitVal(hex[j+1]); int low = hexDigitVal(hex[j+1]);
@ -3745,8 +3817,11 @@ int decodeHexMessage(struct client *c) {
msg[j/2] = (high << 4) | low; msg[j/2] = (high << 4) | low;
} }
if (l < 5) {decodeModeAMessage(&mm, ((msg[0] << 8) | msg[1]));} // ModeA or ModeC if (l == (MODEAC_MSG_BYTES * 2)) { // ModeA or ModeC
else {decodeModesMessage(&mm, msg);} decodeModeAMessage(&mm, ((msg[0] << 8) | msg[1]));
} else { // Assume ModeS
decodeModesMessage(&mm, msg);
}
useModesMessage(&mm); useModesMessage(&mm);
return (0); return (0);
@ -3767,6 +3842,11 @@ char *aircraftsToJson(int *len) {
int position = 0; int position = 0;
int track = 0; int track = 0;
if (a->modeACflags & MODEAC_MSG_FLAG) { // skip any fudged ICAO records Mode A/C
a = a->next;
continue;
}
/* Convert units to metric if --metric was specified. */ /* Convert units to metric if --metric was specified. */
if (Modes.metric) { if (Modes.metric) {
altitude = (int) (altitude / 3.2828); altitude = (int) (altitude / 3.2828);
@ -3823,11 +3903,11 @@ char *aircraftsToJson(int *len) {
* *
* Returns 1 on error to signal the caller the client connection should * Returns 1 on error to signal the caller the client connection should
* be closed. */ * be closed. */
int handleHTTPRequest(struct client *c) { int handleHTTPRequest(struct client *c, char *p) {
char hdr[512]; char hdr[512];
int clen, hdrlen; int clen, hdrlen;
int httpver, keepalive; int httpver, keepalive;
char *p, *url, *content; char *url, *content;
char ctype[48]; char ctype[48];
char getFile[1024]; char getFile[1024];
char *ext; char *ext;
@ -3836,17 +3916,17 @@ int handleHTTPRequest(struct client *c) {
printf("\nHTTP request: %s\n", c->buf); printf("\nHTTP request: %s\n", c->buf);
// Minimally parse the request. // Minimally parse the request.
httpver = (strstr(c->buf, "HTTP/1.1") != NULL) ? 11 : 10; httpver = (strstr(p, "HTTP/1.1") != NULL) ? 11 : 10;
if (httpver == 10) { if (httpver == 10) {
// HTTP 1.0 defaults to close, unless otherwise specified. // HTTP 1.0 defaults to close, unless otherwise specified.
keepalive = strstr(c->buf, "Connection: keep-alive") != NULL; keepalive = strstr(p, "Connection: keep-alive") != NULL;
} else if (httpver == 11) { } else if (httpver == 11) {
// HTTP 1.1 defaults to keep-alive, unless close is specified. // HTTP 1.1 defaults to keep-alive, unless close is specified.
keepalive = strstr(c->buf, "Connection: close") == NULL; keepalive = strstr(p, "Connection: close") == NULL;
} }
// Identify he URL. // Identify he URL.
p = strchr(c->buf,' '); p = strchr(p,' ');
if (!p) return 1; /* There should be the method and a space... */ if (!p) return 1; /* There should be the method and a space... */
url = ++p; /* Now this should point to the requested URL. */ url = ++p; /* Now this should point to the requested URL. */
p = strchr(p, ' '); p = strchr(p, ' ');
@ -3930,77 +4010,110 @@ int handleHTTPRequest(struct client *c) {
Modes.stat_http_requests++; Modes.stat_http_requests++;
return !keepalive; return !keepalive;
} }
//
/* This function polls the clients using read() in order to receive new // This function polls the clients using read() in order to receive new
* messages from the net. // messages from the net.
* //
* The message is supposed to be separated by the next message by the // The message is supposed to be separated from the next message by the
* separator 'sep', that is a null-terminated C string. // separator 'sep', which is a null-terminated C string.
* //
* Every full message received is decoded and passed to the higher layers // Every full message received is decoded and passed to the higher layers
* calling the function 'handler'. // calling the function's 'handler'.
* //
* The handelr returns 0 on success, or 1 to signal this function we // The handler returns 0 on success, or 1 to signal this function we should
* should close the connection with the client in case of non-recoverable // close the connection with the client in case of non-recoverable errors.
* errors. */
void modesReadFromClient(struct client *c, char *sep, void modesReadFromClient(struct client *c, char *sep,
int(*handler)(struct client *)) int(*handler)(struct client *, char *)) {
{ int left;
int nread;
int fullmsg;
char *s, *e;
while(1) { while(1) {
int left = MODES_CLIENT_BUF_SIZE - c->buflen;
int nread = read(c->fd, c->buf+c->buflen, left); fullmsg = 0;
int fullmsg = 0; left = MODES_CLIENT_BUF_SIZE - c->buflen;
int i; // If our buffer is full discard it, this is some badly formatted shit
char *p; if (left == 0) {
c->buflen = 0;
left = MODES_CLIENT_BUF_SIZE;
// If there is garbage, read more to discard it ASAP
}
nread = read(c->fd, c->buf+c->buflen, left);
if (nread <= 0) { if (nread <= 0) {
if (nread == 0 || errno != EAGAIN) { if (nread == 0 || errno != EAGAIN) { // Error, or end of file
/* Error, or end of file. */
modesFreeClient(c->fd); modesFreeClient(c->fd);
} }
break; /* Serve next client. */ break; // Serve next client
} }
c->buflen += nread; c->buflen += nread;
/* Always null-term so we are free to use strstr() */ // Always null-term so we are free to use strstr() (it won't affect binary case)
c->buf[c->buflen] = '\0'; c->buf[c->buflen] = '\0';
/* If there is a complete message there must be the separator 'sep' e = s = c->buf; // Start with the start of buffer, first message
* in the buffer, note that we full-scan the buffer at every read
* for simplicity. */ if (c->service == Modes.bis) {
while ((p = strstr(c->buf, sep)) != NULL) { // This is the Bease Binary scanning case.
i = p - c->buf; /* Turn it as an index inside the buffer. */ // If there is a complete message still in the buffer, there must be the separator 'sep'
c->buf[i] = '\0'; /* Te handler expects null terminated strings. */ // in the buffer, note that we full-scan the buffer at every read for simplicity.
/* Call the function to process the message. It returns 1
* on error to signal we should close the client connection. */ left = c->buflen; // Length of valid search for memchr()
if (handler(c)) { while (left && ((s = memchr(e, (char) 0x1a, left)) != NULL)) { // In reality the first byte of buffer 'should' be 0x1a
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;
}
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)) {
modesFreeClient(c->fd); modesFreeClient(c->fd);
return; return;
} }
/* Move what's left at the start of the buffer. */
i += strlen(sep); /* The separator is part of the previous msg. */
memmove(c->buf,c->buf+i,c->buflen-i);
c->buflen -= i;
c->buf[c->buflen] = '\0';
/* Maybe there are more messages inside the buffer.
* Start looping from the start again. */
fullmsg = 1; fullmsg = 1;
} }
/* If our buffer is full discard it, this is some badly s = e; // For the buffer remainder below
* formatted shit. */
if (c->buflen == MODES_CLIENT_BUF_SIZE) { } else {
c->buflen = 0; // This is the ASCII scanning case, AVR RAW or HTTP at present
/* If there is garbage, read more to discard it ASAP. */ // If there is a complete message still in the buffer, there must be the separator 'sep'
continue; // 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.
modesFreeClient(c->fd); // Handler returns 1 on error to signal we .
return; // should close the client connection
} }
/* If no message was decoded process the next client, otherwise s = e + strlen(sep); // Move to start of next message
* read more data from the same client. */ fullmsg = 1;
if (!fullmsg) break;
} }
} }
/* Read data from clients. This function actually delegates a lower-level if (fullmsg) { // We processed something - so
* function that depends on the kind of service (raw, http, ...). */ c->buflen = &(c->buf[c->buflen]) - s; // 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) { void modesReadFromClients(void) {
int j; int j;
struct client *c; struct client *c;
@ -4009,6 +4122,8 @@ void modesReadFromClients(void) {
if ((c = Modes.clients[j]) == NULL) continue; if ((c = Modes.clients[j]) == NULL) continue;
if (c->service == Modes.ris) if (c->service == Modes.ris)
modesReadFromClient(c,"\n",decodeHexMessage); modesReadFromClient(c,"\n",decodeHexMessage);
else if (c->service == Modes.bis)
modesReadFromClient(c,"",decodeBinMessage);
else if (c->service == Modes.https) else if (c->service == Modes.https)
modesReadFromClient(c,"\r\n\r\n",handleHTTPRequest); modesReadFromClient(c,"\r\n\r\n",handleHTTPRequest);
} }
@ -4035,12 +4150,14 @@ void showHelp(void) {
"--modeac Enable decoding of SSR Modes 3/A & 3/C\n" "--modeac Enable decoding of SSR Modes 3/A & 3/C\n"
"--net-beast TCP raw output in Beast binary format\n" "--net-beast TCP raw output in Beast binary format\n"
"--net-only Enable just networking, no RTL device or file used\n" "--net-only Enable just networking, no RTL device or file used\n"
"--net-http-port <port> HTTP server port (default: 8080)\n"
"--net-ri-port <port> TCP raw input listen port (default: 30001)\n"
"--net-ro-port <port> TCP raw output listen port (default: 30002)\n"
"--net-sbs-port <port> TCP BaseStation output listen port (default: 30003)\n"
"--net-bi-port <port> TCP Beast input listen port (default: 30004)\n"
"--net-bo-port <port> TCP Beast output listen port (default: 30005)\n"
"--net-ro-size <size> TCP raw output minimum size (default: 0)\n" "--net-ro-size <size> TCP raw output minimum size (default: 0)\n"
"--net-ro-rate <rate> TCP raw output memory flush rate (default: 0)\n" "--net-ro-rate <rate> TCP raw output memory flush rate (default: 0)\n"
"--net-ro-port <port> TCP raw output listen port (default: 30002)\n"
"--net-ri-port <port> TCP raw input listen port (default: 30001)\n"
"--net-http-port <port> HTTP server port (default: 8080)\n"
"--net-sbs-port <port> TCP BaseStation output listen port (default: 30003)\n"
"--lat <latitude> Reference/receiver latitide for surface posn (opt)\n" "--lat <latitude> Reference/receiver latitide for surface posn (opt)\n"
"--lon <longitude> Reference/receiver longitude for surface posn (opt)\n" "--lon <longitude> Reference/receiver longitude for surface posn (opt)\n"
"--fix Enable single-bits error correction using CRC\n" "--fix Enable single-bits error correction using CRC\n"
@ -4143,8 +4260,14 @@ int main(int argc, char **argv) {
Modes.net_output_raw_rate = atoi(argv[++j]); Modes.net_output_raw_rate = atoi(argv[++j]);
} else if (!strcmp(argv[j],"--net-ro-port") && more) { } else if (!strcmp(argv[j],"--net-ro-port") && more) {
Modes.net_output_raw_port = atoi(argv[++j]); Modes.net_output_raw_port = atoi(argv[++j]);
if (Modes.beast) // Required for legacy backward compatibility
{Modes.net_output_beast_port = Modes.net_output_raw_port;}
} else if (!strcmp(argv[j],"--net-ri-port") && more) { } else if (!strcmp(argv[j],"--net-ri-port") && more) {
Modes.net_input_raw_port = atoi(argv[++j]); Modes.net_input_raw_port = atoi(argv[++j]);
} else if (!strcmp(argv[j],"--net-bo-port") && more) {
Modes.net_output_beast_port = atoi(argv[++j]);
} else if (!strcmp(argv[j],"--net-bi-port") && more) {
Modes.net_input_beast_port = atoi(argv[++j]);
} else if (!strcmp(argv[j],"--net-http-port") && more) { } else if (!strcmp(argv[j],"--net-http-port") && more) {
Modes.net_http_port = atoi(argv[++j]); Modes.net_http_port = atoi(argv[++j]);
} else if (!strcmp(argv[j],"--net-sbs-port") && more) { } else if (!strcmp(argv[j],"--net-sbs-port") && more) {
@ -4292,7 +4415,7 @@ int main(int argc, char **argv) {
printf("%d phase enhanced with bad crc\n", Modes.stat_ph_badcrc); printf("%d phase enhanced with bad crc\n", Modes.stat_ph_badcrc);
printf("%d phase enhanced errors corrected\n", Modes.stat_ph_fixed); printf("%d phase enhanced errors corrected\n", Modes.stat_ph_fixed);
for (j = 0; j < MODES_MAX_BITERRORS; j++) { for (j = 0; j < MODES_MAX_BITERRORS; j++) {
printf(" %d with %d bit %s\n", Modes.stat_bit_fix[j], j+1, (j==0)?"error":"errors"); printf(" %d with %d bit %s\n", Modes.stat_ph_bit_fix[j], j+1, (j==0)?"error":"errors");
} }
} }
printf("%d total usable messages\n", Modes.stat_goodcrc + Modes.stat_ph_goodcrc + Modes.stat_fixed + Modes.stat_ph_fixed); printf("%d total usable messages\n", Modes.stat_goodcrc + Modes.stat_ph_goodcrc + Modes.stat_fixed + Modes.stat_ph_fixed);