exosip在osip基础上,实现了rfc3261中的传输层(下文简称传输层,请不要和TCP传输层混淆)。本文初步分析下exosip传输层中的TCP传输机制
exosip的TCP主要是在eXtl_tcp.c中实现。
首先是核心变量
struct eXtl_protocol eXtl_tcp = {
1,
5060,
"TCP",
"0.0.0.0",
IPPROTO_TCP,
AF_INET,
0,
0,
&tcp_tl_init,
&tcp_tl_free,
&tcp_tl_open,
&tcp_tl_set_fdset,
&tcp_tl_read_message,
&tcp_tl_send_message,
&tcp_tl_keepalive,
&tcp_tl_set_socket,
&tcp_tl_masquerade_contact,
&tcp_tl_get_masquerade_contact,
&tcp_tl_reset
};
这个结构体变量实际起了中间件的作用,对上层屏蔽了tcp/udp。所以对应其他传输方式(tls udp),有eXtl_tls eXtl_udp。
这些函数名相当清楚。
tcp_tl_init
初始化变量eXtltcp_reserved(C语言,没工厂,只能这样了)。这个变量保存TCP的监听、连接句柄和连接信息(ip\端口).
tcp_tl_free
清空、释放内存(这代码写的很谨慎,在释放前再对待释放区做清零,不太明白这样意义)
tcp_tl_open
创建监听socket(excontext->eXtltcp_reserved->tcp_socket),绑定,监听
tcp_tl_set_fdset
为了select多路复用、把所有的socket绑在fdset(可能exosip主要用于sip电话开发,并发要求低,其实可以仿造lighttp或nginx中的反应器封装,要速度用epoll,要兼容用select)
tcp_tl_read_message如果有accept连接,则将连接放到socket_tab。如果socket_tab中有可发送的,调用_tcp_tl_send_sockinfo。如果socket_tab中有可接收的,调用_tcp_tl_recv一个典型的select模型
tcp_tl_send_message
发送,有点复杂。这个函数可以让外部提供socket。假定不使用外部socket,如果没定义MINISIZE(默认),先DNS找目标。然后检查已存连接(socket_tab中没connect的先
connect)。接下去,寻找是否存在与目标的连接,如果找不到新建连接。找到(创建)连接后生成sip消息后调用_tcp_tl_send发送。如果有外部socket,那先判断外部
socket是否在socket_tab中,如果有,再判断下还有没有地址:端口和传入参数一样的socket(当然不是刚才匹配成功的外部socket),如果有,优先选择这样的socket。这样
主要是为了应对对端双socket(一个用于发事务,一个用于收事务)
tcp_tl_keepalive
发送心跳包
tcp_tl_set_socket
设置接收socket(如果外部创建的话)
tcp_tl_masquerade_contact,tcp_tl_get_masquerade_contact,设置、修改tcp_firewall_ip、tcp_firewall_port(NAT相关)
tcp_tl_reset
将所有连接置为无效