【完结】基于upnp的DIAL协议的分析
1. 背景
⽬前基于Wi-Fi Display的应⽤越来越少,随着Android AOSP放弃UI上对Wi-Fi Display的⽀持,后续对ChromeCast的⽀持⼒度会不断增加。⽽ChromeCast 则是基于DIAL协议进⾏的扩展和封装。
对于多屏幕的⽀持,⽬前除了保持对Wi-Fi Display现有的⼒度,后续会逐渐切换到DIAL协议或Amazon的WhisperPlay SDK的学习上。 此篇则记录了基于最新的DIAL协议的⼀些简单分析。
2. 资料
测试设备:2台android设备(因后续交叉编译需要有编译环境,使⽤公司设别进⾏测试)
测试抓取的(rver IP:192.168.43.105 Client IP:192.168.43.208 AP:192.168.43.1),使⽤filter (!(ip.addr == 192.168.43.1)&&!(ip.addr == 8.8.8.8))后只查看rver和client通讯
fullof
3. 基本原理
DIAL是DI scovery A nd L aunch的缩写,主要应⽤是让cond-screen上的应⽤发现并启动first-screen设备上的应⽤。
这⾥需要解释⼀下⼀下⼏个名词:
First-screen : a TV, Blu-ray player, t-top-box, or similar device,可以简单认为是⼤屏幕的设备
Second-screen : a smartphone, tablet, or similar device,即⼩屏幕设备
DIAL Server: a device implementing the rver side of the DIAL protocol, usually a first-screen device.
DIAL Client : a device that can discover and launch applications on a DIAL rver, usually a cond-screen device.
当然First-Screen和Second-Screen并没有严格的界限。
从协议的⾓度看,DIAL可以分成两个阶段DIAL Service Discovery和DIAL REST Service. 此处和P2P的阶段有点类似。都需要先发现后交互,只是两者采⽤的协议不⼀样⽽已。其实在Wi-Fi Direct的应⽤层⾯已经有了相关的使⽤,具体可以参考Wi-Fi Direct Service中的Send Service(该协议就是基于uPnp实现设备的发现,⽂件的发送和校验)
DIAL Service Discovery
此过程基于Upnp协议,分成M-Search和Get Location URL两个阶段。
M-Search
Client端向239.255.255.250:1900地址⼴播M-Search消息,消息会设定ST(Seach Target)为urn:dail-multiscreen-org:rvice:dial 1。
Server会监听该端⼝,并回复该端⼝的⼴播信息。回复信息中会包含LOCATION URL(包含本地IP地址)或WAKEUP字段(如果⽀持WoL或WoWLAN)。Client收到回复后,需要存储⽀持WAKEUP字段的Server信息,⽤于远程唤醒。
需要注意的是, Client可能收到Server不同端⼝上相同的Service信息,例如Service含有多个⽹络接⼝。封包内容如下:
GET Location URL时髦的意思
在M-Search Respon后,client已经得到Server端SSDP服务的IP和端⼝。
日本父亲节>yearsoldClient端发送HTTP GET消息⽤于获取Server更多信息。
Server回复消息中会包含Application-URL
流程图如下:
DIAL REST Service
在Discovery阶段会得到Application-URL,该标⽰由DIAL REST Service URL 加单斜线“/”以及APP名字组成,后续的操作都是基于Application-URL来执⾏。主要操作包括:
应⽤状态查询: HTTP GET⽅法。参考流程图中(1)(2)中"find out if app X exists",具体信息参考6.1。
应⽤启动:HTTP Post⽅法,具体信息参考6.2. 参考流程图步骤3/4:
对应参考封包格式如下:友谊地久天长 英文
关于request 和respon的具体要求参考6.2.1 和6.2.2。关于启动了HDMI-CEC的命令格式,参考6.2.3.
应⽤停⽌:HTTP DELETE⽅法。
应⽤隐藏和恢复:HTTP POST⽅法。恢复实际上调⽤的是Launch的⽅法
发送附加数据:此部分属于Server和APP沟通格式的定义,6.3章有详细介绍,参考代码中没有对这部分实现,也没有仔细研究。此处还涉及到跨域请求部分,参考/articles/69313 的介绍。
4. 代码学习
本节分析的代码基于 ,包含source和client两部分。分析代码的第⼀步就是编译代码,实际运⾏后,思考为何要这么实现。
4.1 交叉编译
由于本机有了android的编译环境,最直接的⽅法是将Source Code放到android编译环境中直接编译。可以参考修改后的。
主要的修改有:
1. 在原android系统的external/wpa_supplicant 的android.mk中添加rver和client的makefile
2. 在rver和client中添加对应的makefile,参考原始的makefile
3. 修改部分编译错误,主要是C++数组初始化错误
编译完成,输出结果: dialServer dialClient 和Test。
测试步骤:
1. 准备两台android设备,复制对应的binary到/data/misc/media⽬录下(需要root)
2. 启动dialServercamel toe
3. 启动dialClient,⼀旦client发现rver,就会在client端log中打印出rver信息,选择对应的设别进⾏后续操作。 Q: 遇到好⼏次Client搜索到了Server设备,但是返回的IP, Friendly name等都是空。
4.2 Server端
启动Server后,等待Client链接。启动部分的流程图如下:
函数mg_start() 是开源库mangoo中已经提供的API,简单的分析如下:
struct mg_context *mg_start(mg_callback_t ur_callback, void *ur_data, int port) { struct mg_context *ctx;
// Allocate context and initialize reasonable general ca defaults.
let it be什么意思
// TODO(lsm): do proper error handling here.
ctx = (struct mg_context *) calloc(1, sizeof(*ctx));
//定义⽤户的回调函数,参考main函数中定义的回调函数
ctx->ur_callback = ur_callback;
ctx->ur_data = ur_data;
//更新socket连接需要使⽤的port信息
if (!t_ports_option(ctx, port)) {
free_context(ctx);
return NULL;
}
// Ignore SIGPIPE signal, so if browr cancels the request, it
// won't kill the whole process.
(void) signal(SIGPIPE, SIG_IGN);
(void) pthread_mutex_init(&ctx->mutex, NULL);
//cond : worker_thread处理完后通知master_thread 的信号
//sq_empty : worker_thread 消耗时发送的信号
//sq_full : master_thread 接受到新连接时发送的信号friendfinder
(void) pthread_cond_init(&ctx->cond, NULL);
(void) pthread_cond_init(&ctx->sq_empty, NULL);
(void) pthread_cond_init(&ctx->sq_full, NULL);
// Start master (listening) thread
start_thread(ctx, (mg_thread_func_t) master_thread, ctx);
// Start worker threads
for (int i = 0; i < NUM_THREADS; i++) {
if (start_thread(ctx, (mg_thread_func_t) worker_thread, ctx) != 0) {
cry(fc(ctx), "Cannot start worker thread: %d", ERRNO);
} el {
ctx->num_threads++;
}
}
return ctx;
}
其中SSDP对应的Port为:56790, DIAL rvice对应的port为56789。
pbc
对应流程图中的函数:
stake