l 反应堆(fdevent)
主线程在完成一系列初始化操作后,就调用fdevent_loop进入循环。fdevent是对反应堆(reactor)IO模式的封装,使用epoll或者select实现。
在windows平台,通过自己管理句柄表,将windows HANDLE转换为一个整数。而对于socket pair,则直接模拟数据传输,没有依赖windows API。windows平台的fdevent使用WaitForMultipleObjects实现,如果句柄数超过MAXIMUM_WAIT_OBJECTS,就会使用线程并发调用WaitForMultipleObjects来模拟,中间使用Event做了一个巧妙的设计,设置Evnent通知主线程的同时,也通知其他线程结束等待。
l 链路与内部管道
因为有usb,所以链路的io模式是阻塞模式。为了能够将链路句柄加入到fdevent句柄池(epoll实现)中,使用了内部管道(UNIX域套接字实现)对接机制,内部管道的一段代表链接句柄被加入到fdevent句柄池中。同时为每个链接创建两个线程分别处理链路数据的与内部管道之间的转发。这些操作都在链接注册时完成,链路注册也需要通过一个独立的内部管道(注册管道)转发。
内部管道的源代码位于transport.c。
每当创建了一个链路,调用register_ transport注册,注册事件通过注册管道发送到event线程处理。transport_registration_func处理链路注册,销毁。注册时创建对应内部管道,并创建两个线程分别处理数据转发。内部管道加入到fdevent句柄池中,在transport_socket_events处理读事件。
注册管道上传输的数据格式为tmsg,其他内部管道上传输的数据格式为apacket指针。
Tcp链路实现在transport_local.c中,一开始启动线程,创建侦听套接字,并一直侦听外部接入。针对模拟器的情形,有另一套实现。
Tcp链接上,收到接入tcp连接后,调用register_socket_transport创建链路,后者继续调用register_transport发送注册链路事件。
l 套接字绑定
套接字有一个ID和一个peer指针,peer指向与其绑定的另一个套接字。
三种类型的套接字:本地套接字(local_socket),远程套接字(remote_socket)和轻型套接字(smart_socket)绑定方式有:
1. 本地套接字——本地套接字
2. 本地套接字——远程套接字
3. 本地套接字——轻型套接字
还有一些特殊的套接字,如JdwpSocket、JdwpTracker,对应一个本地服务,直接处理请求数据,他和远程套接字绑定。
本地套接字代表实际的服务或者客户,有一个实际文件句柄,其ID是本地分配的;而远程套接字代表链路上的一个逻辑通道,只有一个链路的指针,其ID是远端对应的本地套接字ID。本地套接字与远程套接字绑定使用。本地套接字读取实际句柄上的传输数据,转发到逻辑通道上;而逻辑通道上传递过来的数据,通过本地套接字转发给实际句柄。
套接字实现源文件为sockets.c。
本地套接字的实际文件句柄被加入到fdevent句柄池,通过local_socket_event_func响应读写触发事件。本地套接字会负责报文的组装和拆分。
远程套接字寄生于链路上。通过在链路上发送A_OPEN、A_CLOSE、A_WRITE消息实现远程通道的建立、关闭以及数据发送。远程套接字直接将报文(标记上本地id、远端id)写入链路(链路的内部管道)中,等待链路在另一个线程循环中发送。
当链路上收到A_OPEN请求时,创建本地套接字,与服务对应的文件句柄关联,同时创建远程套接字,与逻辑通道ID关联。
当链路上收到A_WRITE请求时,转发给本地套接字排队发送给实际句柄。
轻型套接字也是一个逻辑上的套接字,他简化了与服务连接的过程,只需要一开始发送“<hex4> <service-name>”,收到返回的“OKAY”,后续就直接向服务发送请求接收应答。
程序在Tcp的5037(或者5038)端口监听,收到连接后创建一个本地套接字,并创建一个轻型套接字进行绑定,连接上的请求转发给轻型套接字处理。
轻型套接字在smart_socket_enqueue中处理请求,先调用handle_host_request处理简单的能够立即完成的请求,并断开连接(但是transport系列的请求例外,需要保持连接),剩余的请求调用create_host_service_socket创建服务对应的套接字,此后将之前的本地套接字与服务套接字绑定,轻型套接字退出。
对于transport系列的请求,轻型套接字还负责转发下一条请求到远程链路上(调用connect_to_remote),同时解除与本地套接字的绑定,后续收到远程A_OKAY应答后在创建远程套接字并与本地套接字绑定。
l 转发
转发端口在install_listener中建立,建立时需要记录与远端间的链路,和目标服务的名称。接收到的连接在listener_event_func中处理,连接接收时创建本地套接字,并通过connect_to_remote连接到远程对应的服务,connect_to_remote在链路上发送A_OPEN请求,后续收到远程A_OKAY应答后再创建远程套接字并与本地套接字绑定。这与上面的transport请求处理方式相同,可以认为转发是一种预先注册的transport请求。