diff --git a/net_io.c b/net_io.c index 14bceda..3740301 100644 --- a/net_io.c +++ b/net_io.c @@ -86,6 +86,11 @@ static void writeFATSVPositionUpdate(float lat, float lon, float alt); static void autoset_modeac(); +__attribute__ ((format (printf,3,0))) static char *safe_vsnprintf(char *p, char *end, const char *format, va_list ap); +__attribute__ ((format (printf,3,4))) static char *safe_snprintf(char *p, char *end, const char *format, ...); + +static const char *jsonEscapeString(const char *str); + // //========================================================================= // @@ -785,6 +790,8 @@ static void send_sbs_heartbeat(struct net_service *service) // // Write Stratux output to TCP clients // + +#define STRATUX_MAX_PACKET_SIZE 1000 static void modesSendStratuxOutput(struct modesMessage *mm, struct aircraft *a) { char *p; struct timespec now; @@ -806,14 +813,12 @@ static void modesSendStratuxOutput(struct modesMessage *mm, struct aircraft *a) if (!mm->reliable && !a->reliable) return; - //// For now, suppress non-ICAO addresses - //if (mm->addr & MODES_NON_ICAO_ADDRESS) - // return; - - p = prepareWrite(&Modes.stratux_out, 1000); // larger buffer size needed vs SBS + p = prepareWrite(&Modes.stratux_out, STRATUX_MAX_PACKET_SIZE); // larger buffer size needed vs SBS if (!p) return; + char *end = p + STRATUX_MAX_PACKET_SIZE; + // Begin populating the traffic.go fields. // ICAO address, Mode S message types, and signal level @@ -824,7 +829,7 @@ static void modesSendStratuxOutput(struct modesMessage *mm, struct aircraft *a) cacf = mm->CF; } - p += sprintf(p, + p = safe_snprintf(p, end, "{\"Icao_addr\":%d," "\"DF\":%d,\"CA\":%d," "\"TypeCode\":%d," @@ -846,68 +851,68 @@ static void modesSendStratuxOutput(struct modesMessage *mm, struct aircraft *a) //// callsign if (mm->callsign_valid) - p += sprintf(p, "\"Tail\":\"%s\",", mm->callsign); + p = safe_snprintf(p, end, "\"Tail\":\"%s\",", jsonEscapeString(mm->callsign)); else - p += sprintf(p, "\"Tail\":null,"); + p = safe_snprintf(p, end, "\"Tail\":null,"); //// altitude & gnss bool alt_is_geom; if (mm->altitude_baro_valid) { - p += sprintf(p, "\"Alt\":%d,",mm->altitude_baro); + p = safe_snprintf(p, end, "\"Alt\":%d,",mm->altitude_baro); alt_is_geom = false; } else if (mm->altitude_geom_valid) { - p += sprintf(p, "\"Alt\":%d,",mm->altitude_geom); + p = safe_snprintf(p, end, "\"Alt\":%d,",mm->altitude_geom); alt_is_geom = true; } else { - p += sprintf(p, "\"Alt\":null,"); + p = safe_snprintf(p, end, "\"Alt\":null,"); alt_is_geom = false; } // altitude source if (alt_is_geom) - p += sprintf(p, "\"AltIsGNSS\":true,"); + p = safe_snprintf(p, end, "\"AltIsGNSS\":true,"); else - p += sprintf(p, "\"AltIsGNSS\":false,"); + p = safe_snprintf(p, end, "\"AltIsGNSS\":false,"); // GNSS alt. delta From baro alt. if (trackDataValid(&a->geom_delta_valid)) - p += sprintf(p, "\"GnssDiffFromBaroAlt\":%d,",a->geom_delta); + p = safe_snprintf(p, end, "\"GnssDiffFromBaroAlt\":%d,",a->geom_delta); else - p += sprintf(p, "\"GnssDiffFromBaroAlt\":null,"); + p = safe_snprintf(p, end, "\"GnssDiffFromBaroAlt\":null,"); //// //// ground speed and track if (mm->gs_valid) - p += sprintf(p, "\"Speed_valid\":true,\"Speed\":%.0f,", mm->gs.selected); + p = safe_snprintf(p, end, "\"Speed_valid\":true,\"Speed\":%.0f,", mm->gs.selected); else - p += sprintf(p, "\"Speed_valid\":false,\"Speed\":null,"); + p = safe_snprintf(p, end, "\"Speed_valid\":false,\"Speed\":null,"); //// ground heading if (mm->heading_valid && mm->heading_type == HEADING_GROUND_TRACK) - p += sprintf(p, "\"Track\":%.0f,", mm->heading); + p = safe_snprintf(p, end, "\"Track\":%.0f,", mm->heading); else - p += sprintf(p, "\"Track\":null,"); + p = safe_snprintf(p, end, "\"Track\":null,"); //// position if (mm->cpr_decoded) - p += sprintf(p, "\"Lat\":%.6f,\"Lng\":%.6f,\"Position_valid\":true,", + p = safe_snprintf(p, end, "\"Lat\":%.6f,\"Lng\":%.6f,\"Position_valid\":true,", mm->decoded_lat, mm->decoded_lon); else - p += sprintf(p, "\"Lat\":null,\"Lng\":null,\"Position_valid\":false,"); + p = safe_snprintf(p, end, "\"Lat\":null,\"Lng\":null,\"Position_valid\":false,"); //// vrate (use barometric if possible) if (mm->baro_rate_valid) - p += sprintf(p, "\"Vvel\":%d,", mm->baro_rate); + p = safe_snprintf(p, end, "\"Vvel\":%d,", mm->baro_rate); else if (mm->geom_rate_valid) - p += sprintf(p, "\"Vvel\":%d,", mm->geom_rate); + p = safe_snprintf(p, end, "\"Vvel\":%d,", mm->geom_rate); else - p += sprintf(p, "\"Vvel\":null,"); + p = safe_snprintf(p, end, "\"Vvel\":null,"); //// squawk if (mm->squawk_valid) - p += sprintf(p, "\"Squawk\":%x,", mm->squawk); + p = safe_snprintf(p, end, "\"Squawk\":%x,", mm->squawk); else - p += sprintf(p, "\"Squawk\":null,"); + p = safe_snprintf(p, end, "\"Squawk\":null,"); // TODO: squawk changing alert support in stratux? // TODO: squawk emergency flag? @@ -916,61 +921,59 @@ static void modesSendStratuxOutput(struct modesMessage *mm, struct aircraft *a) // airground switch (mm->airground) { case AG_GROUND: - p += sprintf(p, "\"OnGround\":true,"); + p = safe_snprintf(p, end, "\"OnGround\":true,"); break; case AG_AIRBORNE: - p += sprintf(p, "\"OnGround\":false,"); + p = safe_snprintf(p, end, "\"OnGround\":false,"); break; default: - p += sprintf(p, "\"OnGround\":null,"); + p = safe_snprintf(p, end, "\"OnGround\":null,"); } // navigation accuracy category - position if (mm->accuracy.nac_p_valid) { - p += sprintf(p, "\"NACp\":%d,", mm->accuracy.nac_p); + p = safe_snprintf(p, end, "\"NACp\":%d,", mm->accuracy.nac_p); } else { - p += sprintf(p, "\"NACp\":null,"); + p = safe_snprintf(p, end, "\"NACp\":null,"); } // emitter type - int emitter = 0; - int setEmitter = 0; + int emitter = -1; if ((mm->msgtype == 17) || (mm->msgtype == 18)) { switch (mm->metype) { case 1: emitter = ((mm->mesub) | 0x18); - setEmitter = 1; break; case 2: emitter = ((mm->mesub) | 0x10); - setEmitter = 1; break; case 3: emitter = ((mm->mesub) | 0x08); - setEmitter = 1; break; case 4: emitter = (mm->mesub); - setEmitter = 1; break; } } - if (setEmitter) - p += sprintf(p, "\"Emitter_category\":%d,", emitter); + if (emitter >= 0) + p = safe_snprintf(p, end, "\"Emitter_category\":%d,", emitter); else - p += sprintf(p, "\"Emitter_category\":null,"); + p = safe_snprintf(p, end, "\"Emitter_category\":null,"); // Time message received (based on system clock). Format is 2016-02-20T06:35:43.155Z - p += sprintf(p, "\"Timestamp\":\"%04d-%02d-%02dT%02d:%02d:%02d.%03dZ\"", + p = safe_snprintf(p, end, "\"Timestamp\":\"%04d-%02d-%02dT%02d:%02d:%02d.%03dZ\"", (stTime_receive.tm_year+1900),(stTime_receive.tm_mon+1), stTime_receive.tm_mday, stTime_receive.tm_hour, stTime_receive.tm_min, stTime_receive.tm_sec, (unsigned)(mm->sysTimestampMsg % 1000)); - p += sprintf(p, "}\r\n"); + p = safe_snprintf(p, end, "}\r\n"); - completeWrite(&Modes.stratux_out, p); + if (p < end) + completeWrite(&Modes.stratux_out, p); + else + fprintf(stderr, "stratux: output too large (max %d, overran by %d)\n", STRATUX_MAX_PACKET_SIZE, (int) (p - end)); } static void send_stratux_heartbeat(struct net_service *service)