Files
MeowOS-For-R3P2/patch_v2/meow_launcherd/test_ipc_harness.c
T

155 lines
6.5 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* test_ipc_harness.c — 宿主 IPC 服务端模拟(等价 launcher ipc_dispatch 的媒体子集).
*
* 用 meow_media.c + meow_ipc.h 复刻 launcher 的 IPC 服务器对媒体消息的处理,
* 供「qemu-mipsel meow_ipc listen/meta/playctl」端到端验证:
* listen → HELLO(MF_PLAYBACK)+META 注册源并等待下发;
* meta → 上报 META(作为新源/更新);
* playctl → 上传控制,服务端转发给「最近活跃会话」fd。
* 运行:gcc test_ipc_harness.c meow_media.c -o /tmp/meow_srv ; /tmp/meow_srv /tmp/e2e.sock
*/
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/stat.h>
#include <poll.h>
#include "meow_ipc.h"
#include "meow_media.h"
#define MAXCLI 8
typedef struct {
int fd;
uint8_t hdr[MEOW_IPC_HDR_LEN]; int hdr_n;
uint8_t pay[MEOW_IPC_MAX]; uint32_t pay_tot, pay_n;
char app_id[MEOW_APP_ID_MAX];
} conn;
static conn g_c[MAXCLI];
static size_t srv_send(int fd, uint16_t type, uint32_t req, const void *payload, uint32_t len)
{
if (fd < 0) return 0;
uint8_t h[MEOW_IPC_HDR_LEN];
uint32_t magic = MEOW_IPC_MAGIC; uint16_t ver = MEOW_IPC_VERSION;
memcpy(h+0,&magic,4); memcpy(h+4,&ver,2); memcpy(h+6,&type,2); memcpy(h+8,&req,4); memcpy(h+12,&len,4);
size_t off=0;
while (off<sizeof h){ ssize_t w=write(fd,h+off,sizeof h-off); if(w<=0)return off; off+=(size_t)w; }
if(len&&payload){ size_t p=0; while(p<len){ ssize_t w=write(fd,(const uint8_t*)payload+p,len-p); if(w<=0)break; p+=(size_t)w; } off+=p; }
return off;
}
static conn *find_slot(int fd) { for (int i=0;i<MAXCLI;i++) if (g_c[i].fd==fd) return &g_c[i]; return NULL; }
static conn *alloc_slot(int fd){ for (int i=0;i<MAXCLI;i++) if (g_c[i].fd==-1){ g_c[i].fd=fd; g_c[i].hdr_n=0; g_c[i].pay_tot=g_c[i].pay_n=0; g_c[i].app_id[0]=0; return &g_c[i]; } return NULL; }
static void handle(conn *c)
{
uint16_t type; uint32_t req;
memcpy(&type, c->hdr+6, 2); memcpy(&req, c->hdr+8, 4);
switch (type) {
case MSG_HELLO: {
m_hello_t h; memset(&h,0,sizeof h); memcpy(&h,c->pay,c->pay_n<sizeof h?c->pay_n:sizeof h);
snprintf(c->app_id, sizeof c->app_id, "%s", h.app_id);
m_ack_t a; a.code=MEOW_OK; a.status=1; srv_send(c->fd,MSG_ACK,req,&a,sizeof a);
printf("SRV: HELLO app=%s flags=%u -> ACK\n", c->app_id, h.flags); break;
}
case MSG_META: {
m_meta_t m; memset(&m,0,sizeof m); memcpy(&m,c->pay,c->pay_n<sizeof m?c->pay_n:sizeof m);
m.app_id[MEOW_APP_ID_MAX-1]=0; m.title[127]=0; m.artist[127]=0; m.album[127]=0; m.artwork[191]=0; m.lyric[191]=0;
int rc = meow_media_meta(&m, c->fd);
m_ack_t a; a.code=MEOW_OK; a.status=(uint32_t)rc; srv_send(c->fd,MSG_ACK,req,&a,sizeof a);
const meow_media_session_t *cur = meow_media_current();
printf("SRV: META app=%s state=%u rc=%d | current=%s\n", m.app_id, m.state, rc,
cur?cur->app_id:"(none)");
break;
}
case MSG_PLAYCTL: {
m_playctl_t p; memset(&p,0,sizeof p); memcpy(&p,c->pay,c->pay_n<sizeof p?c->pay_n:sizeof p);
int rc = meow_media_playctl(p.cmd, p.seek_ms);
m_ack_t a; a.code=MEOW_OK; a.status=(uint32_t)rc; srv_send(c->fd,MSG_ACK,req,&a,sizeof a);
printf("SRV: PLAYCTL cmd=%u seek=%lld rc=%d (target current)\n", p.cmd, (long long)p.seek_ms, rc);
break;
}
default: {
m_err_t e; memset(&e,0,sizeof e); e.code=MEOW_ERR_INVAL; e.msg_len=5; memcpy(e.msg,"nope",5);
srv_send(c->fd,MSG_ERR,req,&e,sizeof e);
printf("SRV: unsupported type 0x%04x\n", type); break;
}
}
}
/* 读一个连接可用字节并组装帧(>=1 完整帧即 dispatch)。返回 0=ok,-1=连接关闭。 */
static int conn_read(conn *c)
{
for (;;) {
if ((unsigned)c->hdr_n < MEOW_IPC_HDR_LEN) {
ssize_t r = read(c->fd, c->hdr + c->hdr_n, MEOW_IPC_HDR_LEN - c->hdr_n);
if (r < 0) { if (errno==EAGAIN) return 0; return -1; }
if (r == 0) return -1;
c->hdr_n += (int)r;
if ((unsigned)c->hdr_n < MEOW_IPC_HDR_LEN) return 0;
uint32_t magic, len; uint16_t ver;
memcpy(&magic,c->hdr,4); memcpy(&ver,c->hdr+4,2); memcpy(&len,c->hdr+12,4);
if (magic!=MEOW_IPC_MAGIC||ver!=MEOW_IPC_VERSION||len>MEOW_IPC_MAX) return -1;
c->pay_tot=len; c->pay_n=0;
if (len==0){ handle(c); c->hdr_n=0; continue; }
}
if (c->pay_n < c->pay_tot) {
ssize_t r = read(c->fd, c->pay + c->pay_n, c->pay_tot - c->pay_n);
if (r < 0){ if (errno==EAGAIN) return 0; return -1; }
if (r==0) return -1;
c->pay_n += (uint32_t)r;
if (c->pay_n < c->pay_tot) return 0;
}
handle(c);
c->hdr_n=0; c->pay_n=0;
}
}
int main(int argc, char **argv)
{
const char *path = (argc>1)?argv[1]:"/tmp/meow_ipc_e2e.sock";
for (int i=0;i<MAXCLI;i++) g_c[i].fd=-1;
meow_media_ops ops;
ops.send=srv_send; ops.log=NULL; meow_media_init(&ops);
int lfd=socket(AF_UNIX,SOCK_STREAM,0);
unlink(path);
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 (bind(lfd,(struct sockaddr*)&a,sizeof a)<0){ perror("bind"); return 1; }
chmod(path,0666);
if (listen(lfd,8)<0){ perror("listen"); return 1; }
fcntl(lfd,F_SETFL,O_NONBLOCK);
printf("SRV: listening %s\n", path); fflush(stdout);
struct pollfd fds[MAXCLI+1]; int nfds=1;
fds[0].fd=lfd; fds[0].events=POLLIN; fds[0].revents=0;
while (1) {
fds[0].fd=lfd; fds[0].events=POLLIN;
int n=1;
for (int i=0;i<MAXCLI;i++) if (g_c[i].fd>=0){ fds[n].fd=g_c[i].fd; fds[n].events=POLLIN; fds[n].revents=0; n++; }
nfds=n;
int r=poll(fds,nfds,400);
if (r<0){ if(errno==EINTR)continue; break; }
if (fds[0].revents&POLLIN){
for(;;){ int c=accept(lfd,NULL,NULL); if(c<0)break; fcntl(c,F_SETFL,O_NONBLOCK);
if(!alloc_slot(c)){ close(c); printf("SRV: reject conn (full)\n"); } else printf("SRV: accept fd=%d\n", c); }
}
for (int i=1;i<nfds;i++){
int ev=fds[i].revents;
if (ev&(POLLIN|POLLHUP|POLLERR|POLLNVAL)){
conn *c=find_slot(fds[i].fd);
if (!c) continue;
if (conn_read(c)<0){ printf("SRV: conn %d closed\n", c->fd); close(c->fd); c->fd=-1; }
}
}
fflush(stdout);
}
close(lfd); unlink(path);
return 0;
}