Files
yolov5-inferrence/snapshot_notify.cpp
2026-06-05 18:14:00 +08:00

200 lines
5.3 KiB
C++

#include "snapshot_notify.h"
#include <arpa/inet.h>
#include <errno.h>
#include <netinet/in.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <unistd.h>
static int g_snapshot_fd = -1;
static struct sockaddr_in g_snapshot_addr;
static unsigned long g_notify_seq = 0;
static void set_reason(char *reason, int reason_size, const char *text)
{
if (reason && reason_size > 0) {
snprintf(reason, reason_size, "%s", text ? text : "unknown");
}
}
static int json_escape(char *out, int out_size, const char *in)
{
if (!out || out_size <= 0) {
return -1;
}
int used = 0;
const char *src = in ? in : "";
for (const char *p = src; *p; ++p) {
const char *rep = NULL;
char tmp[7];
switch (*p) {
case '\\':
rep = "\\\\";
break;
case '"':
rep = "\\\"";
break;
case '\b':
rep = "\\b";
break;
case '\f':
rep = "\\f";
break;
case '\n':
rep = "\\n";
break;
case '\r':
rep = "\\r";
break;
case '\t':
rep = "\\t";
break;
default:
if ((unsigned char)*p < 0x20) {
snprintf(tmp, sizeof(tmp), "\\u%04x", (unsigned char)*p);
rep = tmp;
}
break;
}
if (rep) {
int len = strlen(rep);
if (used + len >= out_size) {
return -1;
}
memcpy(out + used, rep, len);
used += len;
} else {
if (used + 1 >= out_size) {
return -1;
}
out[used++] = *p;
}
}
out[used] = '\0';
return 0;
}
int snapshot_notify_init(void)
{
if (g_snapshot_fd >= 0) {
return 0;
}
g_snapshot_fd = socket(AF_INET, SOCK_DGRAM, 0);
if (g_snapshot_fd < 0) {
return -1;
}
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 20000;
setsockopt(g_snapshot_fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
memset(&g_snapshot_addr, 0, sizeof(g_snapshot_addr));
g_snapshot_addr.sin_family = AF_INET;
g_snapshot_addr.sin_port = htons(SNAPSHOT_NOTIFY_DEFAULT_PORT);
if (inet_pton(AF_INET, SNAPSHOT_NOTIFY_DEFAULT_HOST, &g_snapshot_addr.sin_addr) != 1) {
close(g_snapshot_fd);
g_snapshot_fd = -1;
return -1;
}
return 0;
}
void snapshot_notify_close(void)
{
if (g_snapshot_fd >= 0) {
close(g_snapshot_fd);
g_snapshot_fd = -1;
}
}
int snapshot_notify_send(const snapshot_notify_event_t *event, char *reason, int reason_size)
{
if (!event) {
set_reason(reason, reason_size, "invalid_event");
return -1;
}
if (snapshot_notify_init() != 0) {
set_reason(reason, reason_size, "socket_init_failed");
return -1;
}
char camera_id[256];
char rtsp[1024];
char label[256];
if (json_escape(camera_id, sizeof(camera_id), event->camera_id) != 0 ||
json_escape(rtsp, sizeof(rtsp), event->rtsp) != 0 ||
json_escape(label, sizeof(label), event->label) != 0) {
set_reason(reason, reason_size, "json_escape_failed");
return -1;
}
unsigned long notify_id = ++g_notify_seq;
char notify_id_text[32];
snprintf(notify_id_text, sizeof(notify_id_text), "%lu", notify_id);
char payload[2048];
int n = snprintf(payload, sizeof(payload),
"{\"notify_id\":\"%s\",\"camera_id\":\"%s\",\"rtsp\":\"%s\",\"ts\":%ld,\"frame\":%lld,"
"\"ccid\":%d,\"label\":\"%s\",\"confidence\":%.3f,"
"\"box\":[%d,%d,%d,%d]}",
notify_id_text,
camera_id,
rtsp,
event->ts,
event->frame,
event->ccid,
label,
event->confidence,
event->box_left,
event->box_top,
event->box_right,
event->box_bottom);
if (n <= 0 || n >= (int)sizeof(payload)) {
set_reason(reason, reason_size, "payload_too_large");
return -1;
}
ssize_t sent = sendto(g_snapshot_fd, payload, n, 0,
(struct sockaddr *)&g_snapshot_addr,
sizeof(g_snapshot_addr));
if (sent != n) {
char buf[64];
snprintf(buf, sizeof(buf), "send_failed_%d", errno);
set_reason(reason, reason_size, buf);
return -1;
}
char ack[128];
ssize_t got = recv(g_snapshot_fd, ack, sizeof(ack) - 1, 0);
if (got <= 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK) {
set_reason(reason, reason_size, "ack_timeout");
} else {
char buf[64];
snprintf(buf, sizeof(buf), "ack_failed_%d", errno);
set_reason(reason, reason_size, buf);
}
return -1;
}
ack[got] = '\0';
char expected_ack[64];
snprintf(expected_ack, sizeof(expected_ack), "OK %s", notify_id_text);
if (strncmp(ack, expected_ack, strlen(expected_ack)) == 0) {
set_reason(reason, reason_size, "ok");
return 0;
}
set_reason(reason, reason_size, ack);
return -1;
}