/* * meow_net_ipc.c — MeowOS SDK 网络自愿通道 → netmgrd IPC 桥(期4;追加式协议 0x00EE/0x00EF)。 * * 与 meow_notify_ipc.c 同型:只做「一次性 connect + send + read」,不维护连接/订阅循环。 * - meow_net_policy_check(host):MSG_NET_SDK op=NET_SDK_CHECK(app_id=MEOW_LOG_APP + host); * 读到 allow=1 → 返回 0(allow),allow=0 → 返回 1(block);任何失败(无 socket/超时/非法应答) * → 返回 0(乐观放行,绝不因监控不可用误封业务——NETMGR_DESIGN §6.3 自愿性质)。 * - meow_net_report(rx,tx):MSG_NET_SDK op=NET_SDK_REPORT;send 后读一次应答头即关(不读文本), * best-effort,失败静默(返回值 void)。 * 映射层(SDK 入参 ↔ IPC m_net_sdk_t 字段)集中在本文件;app_id 取 env MEOW_LOG_APP(与 meow_ui_log.c * 口径一致),socket 路径取 env MEOW_NET_SOCK(宿主/qemu 覆盖)缺省 /usr/data/meow_net.sock。 * * 线程安全:app_id pthread_once 缓存;本文件纯传输层不调 meow_log(与 meow_notify_ipc.c 同约定)。 */ #include "meow_net_ipc.h" #include "meow_ipc.h" /* 共享协议:帧头/m_net_sdk_t/m_net_sdk_result_t/MSG_NET_SDK* —— 防漂移 */ #include /* snprintf */ #include /* getenv */ #include #include /* EINTR */ #include #include #include #include #include #define MEOW_NET_IPC_TIMEOUT_MS 500 /* 应答读超时:netmgrd 单线程 poll,>500ms 视为降级 */ static pthread_once_t g_once = PTHREAD_ONCE_INIT; static char g_app_id[MEOW_APP_ID_MAX] = "app"; static void ipc_init(void) { const char *s = getenv("MEOW_LOG_APP"); if (s && s[0]) snprintf(g_app_id, sizeof g_app_id, "%s", s); } const char *meow_net_ipc_app_id(void) { pthread_once(&g_once, ipc_init); return g_app_id; } /* socket 路径:优先 env MEOW_NET_SOCK,缺省 /usr/data/meow_net.sock。 */ static const char *ipc_sock_path(void) { const char *s = getenv("MEOW_NET_SOCK"); return (s && s[0]) ? s : "/usr/data/meow_net.sock"; } /* 连接 socket;失败 -1(调用方降级)。 */ static int conn_path(const char *path) { int fd = socket(AF_UNIX, SOCK_STREAM, 0); if (fd < 0) return -1; struct sockaddr_un a; memset(&a, 0, sizeof a); a.sun_family = AF_UNIX; strncpy(a.sun_path, path, sizeof a.sun_path - 1); if (connect(fd, (struct sockaddr *)&a, sizeof a) < 0) { close(fd); return -1; } return fd; } static int write_all(int fd, const uint8_t *p, size_t n) { size_t off = 0; while (off < n) { ssize_t w = write(fd, p + off, n - off); if (w < 0) { if (errno == EINTR) continue; return 0; } if (w == 0) return 0; off += (size_t)w; } return 1; } static int read_all(int fd, uint8_t *p, size_t n) { size_t off = 0; while (off < n) { ssize_t r = read(fd, p + off, n - off); if (r < 0) { if (errno == EINTR) continue; return 0; } if (r == 0) return 0; off += (size_t)r; } return 1; } static int send_frame(int fd, uint16_t type, uint32_t req_id, const void *payload, uint32_t len) { uint8_t hdr[MEOW_IPC_HDR_LEN]; uint32_t magic = MEOW_IPC_MAGIC, rl = len; uint16_t ver = MEOW_IPC_VERSION, t = type; memcpy(hdr + 0, &magic, 4); memcpy(hdr + 4, &ver, 2); memcpy(hdr + 6, &t, 2); memcpy(hdr + 8, &req_id, 4); memcpy(hdr + 12, &rl, 4); if (!write_all(fd, hdr, sizeof hdr)) return 0; if (len && payload && !write_all(fd, payload, len)) return 0; return 1; } static void set_timeout(int fd) { struct timeval tv; tv.tv_sec = MEOW_NET_IPC_TIMEOUT_MS / 1000; tv.tv_usec = (MEOW_NET_IPC_TIMEOUT_MS % 1000) * 1000; setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof tv); } int meow_net_policy_check(const char *host) { if (!host || !host[0]) return 0; m_net_sdk_t q; memset(&q, 0, sizeof q); q.op = NET_SDK_CHECK; snprintf(q.app_id, sizeof q.app_id, "%s", meow_net_ipc_app_id()); snprintf(q.host, sizeof q.host, "%s", host); int fd = conn_path(ipc_sock_path()); if (fd < 0) return 0; /* java socket:乐观放行 */ set_timeout(fd); int allow = 0; /* 默认放行 */ if (send_frame(fd, MSG_NET_SDK, 0x4E455443u /* "NETC" */, &q, (uint32_t)sizeof q)) { uint8_t rhdr[MEOW_IPC_HDR_LEN]; if (read_all(fd, rhdr, sizeof rhdr)) { uint16_t rtype; uint32_t rlen; memcpy(&rtype, rhdr + 6, 2); memcpy(&rlen, rhdr + 12, 4); if (rtype == MSG_NET_SDK_RESULT && rlen >= 10) { uint8_t pay[12]; if (read_all(fd, pay, 12)) { /* code(4)+allow(4)+text_len(2)+pad(2) */ m_net_sdk_result_t res; memset(&res, 0, sizeof res); memcpy(&res.code, pay, 4); memcpy(&res.allow, pay + 4, 4); memcpy(&res.text_len, pay + 8, 2); if (res.text_len < sizeof res.text) read_all(fd, (uint8_t *)res.text, res.text_len); if (res.code == MEOW_OK) allow = (res.allow != 0) ? 1 : 0; } } } } close(fd); return allow ? 0 : 1; /* allow=1 → 返回 0(放行);allow=0 → 返回 1(block) */ } void meow_net_report(uint32_t rx, uint32_t tx) { m_net_sdk_t q; memset(&q, 0, sizeof q); q.op = NET_SDK_REPORT; snprintf(q.app_id, sizeof q.app_id, "%s", meow_net_ipc_app_id()); q.rx = rx; q.tx = tx; int fd = conn_path(ipc_sock_path()); if (fd < 0) return; /* 无 socket:静默 */ set_timeout(fd); if (send_frame(fd, MSG_NET_SDK, 0x4E455452u /* "NETR" */, &q, (uint32_t)sizeof q)) { uint8_t rhdr[MEOW_IPC_HDR_LEN]; read_all(fd, rhdr, sizeof rhdr); /* best-effort:读一次应答头即关,不解析 */ } close(fd); }