From aa31532d8c6d47ee1a0f773f878bb26ec8ce8414 Mon Sep 17 00:00:00 2001 From: ms Date: Sat, 14 Feb 2026 19:32:04 +0100 Subject: [PATCH] Fix multiple bugs and harden modb_orno3.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Fix NULL pointer dereference: move modbus_set_slave after ctx validation (ORNO) - Fix InfluxDB line protocol: remove stray comma in voltage measurement - Move InfluxDB token to env variable INFLUX_TOKEN with fallback to default - Fix spike detection for negative power values using fabs() - Read and validate HTTP response from InfluxDB after writes - Replace all sprintf with snprintf to prevent buffer overflows - Batch ORNO InfluxDB writes into single TCP connection (5→1) - Fix non-portable absolute include path for modbus-rtu.h Co-Authored-By: Claude Opus 4.6 --- modb_orno3.c | 109 +++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 89 insertions(+), 20 deletions(-) diff --git a/modb_orno3.c b/modb_orno3.c index 501bc88..a38e53a 100644 --- a/modb_orno3.c +++ b/modb_orno3.c @@ -1,7 +1,7 @@ #include #include #include -#include +#include #include #include #include @@ -62,7 +62,7 @@ typedef struct { float Freq; } s_frequency; #define INFLUX_PORT 5086 #define INFLUX_ORG "sic" /* Zmień na swoją organizację */ #define INFLUX_BUCKET "energydb" /* Zmień na swój bucket */ -#define INFLUX_TOKEN "BCIZ6kcCAVgpcwSfU0PBS7m0Zb6an93kuOtizbEtlXub-uaoYp4dmIQBQYaJCv8_KE4QYYZ08jxtpaZ3TUWP-Q==" /* Zmień na swój token */ +#define INFLUX_TOKEN_DEFAULT "BCIZ6kcCAVgpcwSfU0PBS7m0Zb6an93kuOtizbEtlXub-uaoYp4dmIQBQYaJCv8_KE4QYYZ08jxtpaZ3TUWP-Q==" /* Fallback - preferuj zmienną INFLUX_TOKEN */ /* ============================================ */ /* @@ -156,6 +156,7 @@ void mosq_log_callback(struct mosquitto *mosq, void *userdata, int level, const } } +const char *influx_token = NULL; struct mosquitto *mosq = NULL; void mqtt_setup() { @@ -224,7 +225,7 @@ int mqtt_send_U(float U1, float U2, float U3) { if (DISABLE_MQTT) return 0; char buf[128]; - sprintf(buf, "{\"U1\":%f,\"U2\":%f,\"U3\":%f}", U1, U2, U3); + snprintf(buf, sizeof(buf), "{\"U1\":%f,\"U2\":%f,\"U3\":%f}", U1, U2, U3); return mosquitto_publish(mosq, NULL, "/energy/orno/U", strlen(buf), buf, 0, 0); } @@ -232,7 +233,7 @@ int mqtt_send_P(float P_Tot, float P1, float P2, float P3) { if (DISABLE_MQTT) return 0; char buf[128]; - sprintf(buf, "{\"P_Tot\":%f,\"P1\":%f,\"P2\":%f,\"P3\":%f}", P_Tot, P1, P2, P3); + snprintf(buf, sizeof(buf), "{\"P_Tot\":%f,\"P1\":%f,\"P2\":%f,\"P3\":%f}", P_Tot, P1, P2, P3); return mosquitto_publish(mosq, NULL, "/energy/orno/P", strlen(buf), buf, 0, 0); } @@ -240,7 +241,7 @@ int mqtt_send_W(float W_Tot, float W1, float W2, float W3) { if (DISABLE_MQTT) return 0; char buf[128]; - sprintf(buf, "{\"W_Tot\":%f,\"W1\":%f,\"W2\":%f,\"W3\":%f}", W_Tot, W1, W2, W3); + snprintf(buf, sizeof(buf), "{\"W_Tot\":%f,\"W1\":%f,\"W2\":%f,\"W3\":%f}", W_Tot, W1, W2, W3); return mosquitto_publish(mosq, NULL, "/energy/orno/W", strlen(buf), buf, 0, 0); } @@ -248,7 +249,7 @@ int mqtt_send_I(float I1, float I2, float I3) { if (DISABLE_MQTT) return 0; char buf[128]; - sprintf(buf, "{\"I1\":%f,\"I2\":%f,\"I3\":%f}", I1, I2, I3); + snprintf(buf, sizeof(buf), "{\"I1\":%f,\"I2\":%f,\"I3\":%f}", I1, I2, I3); return mosquitto_publish(mosq, NULL, "/energy/orno/I", strlen(buf), buf, 0, 0); } @@ -256,7 +257,7 @@ int mqtt_send_Hz(float Hz) { if (DISABLE_MQTT) return 0; char buf[64]; - sprintf(buf, "%f", Hz); + snprintf(buf, sizeof(buf), "%f", Hz); return mosquitto_publish(mosq, NULL, "/energy/orno/Hz", strlen(buf), buf, 0, 0); } @@ -300,7 +301,7 @@ int influx_send_post(char *data) "Content-Length: %ld\r\n" "Content-Type: text/plain; charset=utf-8\r\n" "Connection: close\r\n\r\n", - INFLUX_ORG, INFLUX_BUCKET, INFLUX_HOST, INFLUX_PORT, INFLUX_TOKEN, strlen(data)); + INFLUX_ORG, INFLUX_BUCKET, INFLUX_HOST, INFLUX_PORT, influx_token, strlen(data)); if (send(sock, header, strlen(header), 0) < 0) { perror("INFLUX: Send header to InfluxDB failed"); @@ -314,13 +315,31 @@ int influx_send_post(char *data) return -1; } + /* Read HTTP response to check for errors */ + char resp[512]; + int resp_len = recv(sock, resp, sizeof(resp) - 1, 0); + if (resp_len > 0) { + resp[resp_len] = '\0'; + /* Check HTTP status code (e.g. "HTTP/1.1 204") */ + int http_status = 0; + if (sscanf(resp, "HTTP/%*d.%*d %d", &http_status) == 1) { + if (http_status < 200 || http_status >= 300) { + printf("INFLUX: ERROR: HTTP %d response from InfluxDB\n", http_status); + close(sock); + return -1; + } + } + } else if (resp_len < 0) { + printf("INFLUX: WARNING: No response from InfluxDB (timeout)\n"); + } + close(sock); return 0; } int influx_send_U(float U1, float U2, float U3) { char line[256]; - snprintf(line, sizeof(line), "orno,device=orno,pomiar=voltage, L1=%.2f,L2=%.2f,L3=%.2f", U1, U2, U3); + snprintf(line, sizeof(line), "orno,device=orno,pomiar=voltage L1=%.2f,L2=%.2f,L3=%.2f", U1, U2, U3); return influx_send_post(line); } @@ -348,6 +367,41 @@ int influx_send_Hz(float Hz) { return influx_send_post(line); } +int influx_send_orno_batch(s_voltage *v, int v_ok, s_current *i, int i_ok, + s_power *p, int p_ok, s_energy *w, int w_ok, + s_frequency *f, int f_ok) { + if (DISABLE_INFLUX) return 0; + char batch[1024]; + int offset = 0; + + if (v_ok) { + offset += snprintf(batch + offset, sizeof(batch) - offset, + "orno,device=orno,pomiar=voltage L1=%.2f,L2=%.2f,L3=%.2f\n", v->U1, v->U2, v->U3); + } + if (i_ok) { + offset += snprintf(batch + offset, sizeof(batch) - offset, + "orno,device=orno,pomiar=current L1=%.2f,L2=%.2f,L3=%.2f\n", i->I1, i->I2, i->I3); + } + if (p_ok) { + offset += snprintf(batch + offset, sizeof(batch) - offset, + "orno,device=orno,pomiar=power total=%.3f,L1=%.3f,L2=%.3f,L3=%.3f\n", p->P_Tot, p->P1, p->P2, p->P3); + } + if (w_ok) { + offset += snprintf(batch + offset, sizeof(batch) - offset, + "orno,device=orno,pomiar=energy total=%.3f,L1=%.3f,L2=%.3f,L3=%.3f\n", w->W_Tot, w->W1, w->W2, w->W3); + } + if (f_ok) { + offset += snprintf(batch + offset, sizeof(batch) - offset, + "orno,device=orno,pomiar=frequency value=%.4f\n", f->Freq); + } + + if (offset == 0) return 0; + /* Remove trailing newline */ + if (offset > 0 && batch[offset - 1] == '\n') batch[offset - 1] = '\0'; + + return influx_send_post(batch); +} + int influx_send_SUN2K(t_mb_reg *reg_to_send, char *_str_buf) { if (!_str_buf || strlen(_str_buf) == 0) return 0; char line[256]; @@ -398,7 +452,7 @@ int mosq_test() char *buf = malloc(64); while (k-- > 0) { - sprintf(buf, "i=%i", i++); + snprintf(buf, 64, "i=%i", i++); int snd = mqtt_send("/testtopic", buf); if (snd != 0) printf("TEST: mqtt_send error=%i\n", snd); @@ -408,7 +462,14 @@ int mosq_test() int main(int argc, char *argv[]) { - /* Użyj wartości z #define */ + /* Użyj wartości z #define, token z env lub fallback */ + influx_token = getenv("INFLUX_TOKEN"); + if (!influx_token || strlen(influx_token) == 0) { + influx_token = INFLUX_TOKEN_DEFAULT; + printf("CFG: INFLUX_TOKEN env not set, using default from code\n"); + } else { + printf("CFG: INFLUX_TOKEN loaded from environment\n"); + } const char *USB_DEV = USB_DEV_DEFAULT; int ORNO_SLAVE = ORNO_SLAVE_ADR; int SUN2000_SLAVE = SUN2000_SLAVE_ADR; @@ -455,13 +516,13 @@ int main(int argc, char *argv[]) { //Create a new RTU context modbus_t *ctx = modbus_new_rtu(USB_DEV, 9600, 'E', 8, 1); - //Set the Modbus address of the remote slave - modbus_set_slave(ctx, ORNO_SLAVE); if (!ctx) { fprintf(stderr, "ORNO: Failed to create the context: %s\n", modbus_strerror(errno)); exit(1); } + //Set the Modbus address of the remote slave + modbus_set_slave(ctx, ORNO_SLAVE); if (modbus_connect(ctx) == -1) { @@ -616,7 +677,7 @@ int main(int argc, char *argv[]) } int spike_P = 0; - if (prev_power.P_Tot != 0 && (current_power.P_Tot > prev_power.P_Tot * 1.8 || current_power.P_Tot < prev_power.P_Tot * 0.2)) spike_P = 1; + if (prev_power.P_Tot != 0 && (fabs(current_power.P_Tot - prev_power.P_Tot) > fabs(prev_power.P_Tot) * 0.8)) spike_P = 1; if(spike_P) { send_power = prev_power; @@ -648,19 +709,21 @@ int main(int argc, char *argv[]) prev_freq = current_freq; } + int valid_U = 0, valid_I = 0, valid_P = 0, valid_W = 0, valid_F = 0; + printf("ORNO: Voltages: L1=%.1f V, L2=%.1f V, L3=%.1f V\n", send_voltage.U1, send_voltage.U2, send_voltage.U3); if (is_valid_float(send_voltage.U1, 150.0, 280.0) && is_valid_float(send_voltage.U2, 150.0, 280.0) && is_valid_float(send_voltage.U3, 150.0, 280.0)) { mqtt_send_U(send_voltage.U1, send_voltage.U2, send_voltage.U3); - influx_send_U(send_voltage.U1, send_voltage.U2, send_voltage.U3); + valid_U = 1; printf("ORNO: MQTT: Published voltages\n"); } else { printf("ORNO: MQTT: Skipping voltages - invalid values\n"); } - + printf("ORNO: Currents: L1=%.2f A, L2=%.2f A, L3=%.2f A\n", send_current.I1, send_current.I2, send_current.I3); if (is_valid_float(send_current.I1, 0.0, 100.0) && is_valid_float(send_current.I2, 0.0, 100.0) && is_valid_float(send_current.I3, 0.0, 100.0)) { mqtt_send_I(send_current.I1, send_current.I2, send_current.I3); - influx_send_I(send_current.I1, send_current.I2, send_current.I3); + valid_I = 1; printf("ORNO: MQTT: Published currents\n"); } else { printf("ORNO: MQTT: Skipping currents - invalid values\n"); @@ -669,7 +732,7 @@ int main(int argc, char *argv[]) printf("ORNO: Power: Total=%.3f W, L1=%.3f W, L2=%.3f W, L3=%.3f W\n", send_power.P_Tot, send_power.P1, send_power.P2, send_power.P3); if (is_valid_float(send_power.P_Tot, -25000.0, 25000.0) && is_valid_float(send_power.P1, -10000.0, 10000.0) && is_valid_float(send_power.P2, -10000.0, 10000.0) && is_valid_float(send_power.P3, -10000.0, 10000.0)) { mqtt_send_P(send_power.P_Tot, send_power.P1, send_power.P2, send_power.P3); - influx_send_P(send_power.P_Tot, send_power.P1, send_power.P2, send_power.P3); + valid_P = 1; printf("ORNO: MQTT: Published power\n"); } else { printf("ORNO: MQTT: Skipping power - invalid values\n"); @@ -678,7 +741,7 @@ int main(int argc, char *argv[]) printf("ORNO: Energy: Total=%.3f kWh, L1=%.3f kWh, L2=%.3f kWh, L3=%.3f kWh\n", send_energy.W_Tot, send_energy.W1, send_energy.W2, send_energy.W3); if (is_valid_float(send_energy.W_Tot, 0.0, 1000000.0) && is_valid_float(send_energy.W1, 0.0, 1000000.0) && is_valid_float(send_energy.W2, 0.0, 1000000.0) && is_valid_float(send_energy.W3, 0.0, 1000000.0)) { mqtt_send_W(send_energy.W_Tot, send_energy.W1, send_energy.W2, send_energy.W3); - influx_send_W(send_energy.W_Tot, send_energy.W1, send_energy.W2, send_energy.W3); + valid_W = 1; printf("ORNO: MQTT: Published energy\n"); } else { printf("ORNO: MQTT: Skipping energy - invalid values\n"); @@ -687,11 +750,17 @@ int main(int argc, char *argv[]) printf("ORNO: Frequency: %.4f Hz\n", send_freq.Freq); if (is_valid_float(send_freq.Freq, 47.0, 53.0)) { mqtt_send_Hz(send_freq.Freq); - influx_send_Hz(send_freq.Freq); + valid_F = 1; printf("ORNO: MQTT: Published frequency\n"); } else { printf("ORNO: MQTT: Skipping frequency - invalid value\n"); } + + /* Send all ORNO data to InfluxDB in one batch (1 TCP connection instead of 5) */ + influx_send_orno_batch( + &send_voltage, valid_U, &send_current, valid_I, + &send_power, valid_P, &send_energy, valid_W, + &send_freq, valid_F); } } if (do_sun2k)