说说 GTalk

[GTalk] 出来也有段时间了,因为是 [Google] 出品的,所以也吸引了一定的眼球,首先提供的功能是即时通讯和语音,和 [Skype] 有的一拼,语音质量还可以。其[开发者]页面中说明了它用的是 [Jabber] 协议,所以其他的 Jabber 客户端都可以连得上去,比如 [Gaim]。接下来说说语音,一般多媒体的支持都需要两个部分,第一部分可以叫做信令(Signaling),这一部分让两个客户端能够互相联系起来、各自支持的编解码器、采取什么方式进行数据传输等等。另一方面就是真正的语音数据传输,现在 IP 网络上的多媒体一般都是使用 [RTP/RTCP],是由 [IETF][AVT] 工作组制定,已经广泛使用。

GTalk 的语音协议使用的库是 [libjingle],其信令协议的实现和 [XEP-0166 Jingle](原来叫[JEP-166 Jingle],以下不再赘述) 以及其他相关的标准 [XEP-0167 Jingle Audio Content Description Format][XEP-0176 Jingle ICE Transport] 等略有不同,可能是因为先有的 libjingle,然后 Google 和 Jabber 合作将其规范化,从 Jingle 作者的 email 就可以看出来,有好几个是 Google 的,其中还有 Gaim 的头 Sean Egan。Jingle 的协议现在还在更新中,等最后稳定下来以后,GTalk 肯定也会跟上的。这些是从公开的文档中看到的。

通过抓包发现以下过程:

  1. 打电话的人发起 Jabber 请求,要求进行语音通讯:
    1. <iq to="yyy@gmail.com/Talk.v95CFB74394" type="set" id="143">
    2.   <session xmlns="http://www.google.com/session" type="initiate" id="2482103147"
    3.            initiator="xxx@gmail.com/Talk.v927553D771">
    4.     <description xmlns="http://www.google.com/session/phone">
    5.       <payload-type xmlns="http://www.google.com/session/phone" id="103" name="ISAC"/>
    6.       <payload-type xmlns="http://www.google.com/session/phone" id="97" name="IPCMWB"/>
    7.       <payload-type xmlns="http://www.google.com/session/phone" id="4" name="G723"/>
    8.       <payload-type xmlns="http://www.google.com/session/phone" id="100" name="EG711U"/>
    9.       <payload-type xmlns="http://www.google.com/session/phone" id="101" name="EG711A"/>
    10.       <payload-type xmlns="http://www.google.com/session/phone" id="0" name="PCMU"/>
    11.       <payload-type xmlns="http://www.google.com/session/phone" id="8" name="PCMA"/>
    12.       <payload-type xmlns="http://www.google.com/session/phone" id="13" name="CN"/>
    13.       <payload-type xmlns="http://www.google.com/session/phone" id="102" name="iLBC"/>
    14.       <payload-type xmlns="http://www.google.com/session/phone" id="117" name="red"/>
    15.       <payload-type xmlns="http://www.google.com/session/phone" id="106"
    16.                     name="audio/telephone-event"/>
    17.     </description>
    18.   </session>
    19. </iq>

    其中,id 就是后来 RTP 传输中的负载类型(Payload Type)。

  2. 然后双方进行 [ICE-Interactive Connectivity Establishment] 检查。ICE 是一个方法,它利用 [STUN][TURN] 来检查两端是否能够进行连接。比如两端处于 [NAT] 之后,那么语音数据必须得要穿过 NAT 才能到达对端。
    ICE 的原理这里不进行详细解释,只是简单说一下,以后还会单独进行探讨。首先双方要使用 STUN/TURN 协议拿到本端的一些包含协议类型、IP 以及端口的候选项(Candidate,分 local、stun 以及 relay 几种不同网络类型),还有用户名和密码,然后各自把本端的候选项发给对方,然后把本端和对端的候选项两两配对,检查是否可以连通。下面是一些例子:
    1. <iq to="yyy@gmail.com/Talk.v95CFB74394" type="set" id="145">
    2.   <session xmlns="http://www.google.com/session" type="candidates" id="2482103147"
    3.            initiator="xxx@gmail.com/Talk.v927553D771">
    4.     <candidate name="rtp" address="192.168.1.100" port="3625" username="IC2jv/pMuZWWgNUI"
    5.                password="Fw6vDd/2qyg388CR" preference="1" protocol="udp" type="local"
    6.                network="0" generation="0"/>
    7.   </session>
    8. </iq>
    9.  
    10. <iq to="yyy@gmail.com/Talk.v95CFB74394" type="set" id="146">
    11.   <session xmlns="http://www.google.com/session" type="candidates" id="2482103147"
    12.            initiator="xxx@gmail.com/Talk.v927553D771">
    13.     <candidate name="rtp" address="xx.xx.xx.xx" port="10423" username="tvZ7nbIYRbKLRQQM"
    14.                password="QNr79Ut1UCLmgGGe" preference="0.9" protocol="udp" type="stun"
    15.                network="0" generation="0"/>
    16.   </session>
    17. </iq>
    18.  
    19. <iq to="yyy@gmail.com/Talk.v95CFB74394" type="set" id="147">
    20.   <session xmlns="http://www.google.com/session" type="candidates" id="2482103147"
    21.            initiator="xxx@gmail.com/Talk.v927553D771">
    22.     <candidate name="rtp" address="216.239.37.126" port="19295" username="YmSTEgsiCHHXpeVA"
    23.                password="isGiNLyAX9puDcN1" preference="0.5" protocol="udp" type="relay"
    24.                network="0" generation="0"/>
    25.   </session>
    26. </iq>

    类型为 local 是本地地址,类型为 stun 的是 NAT 的外部地址,类型为 replay 的是双方通过这个地址进行数据转发,而不是直接连接。

    其中有一个值得注意的地方就是,最初的 STUN 服务器从哪里来?按理来讲,任何 STUN 服务器都可以的,但是 GTalk 用的是自己的,在进行 ICE 检查获取本地候选项之前,向 216.239.37.126 发送了一个 HTTP 请求:

    1. /* 请求 */
    2. GET /create_session HTTP/1.1
    3. Connection: Keep-Alive
    4. Content-Length: 0
    5. Host: 216.239.37.126
    6. User-Agent: Google Talk
    7. X-Google-Relay-Auth: xxxxxxxxxxxxxxxxxxxxxxxxx
    8. X-Talk-Google-Relay-Auth: yyyyyyyyyyyyyyyyyyyyyyyyyyy
    9.  
    10. /* 响应 */
    11. Content-Type: text/plain
    12. Date: Wed, 16 Aug 2006 12:54:12 GMT
    13. Server: MediaProxy
    14. Content-Length: 197
    15.  
    16. relay.ip=216.239.37.126
    17. relay.udp_port=19295
    18. relay.tcp_port=19294
    19. relay.ssltcp_port=443
    20. stun.ip=216.239.37.126
    21. stun.port=19302
    22. username=xxxxxxxxxxx
    23. password=yyyyyyyyyyy
    24. magic_cookie=xxxxxx

    这个服务器是 Google 的 relay server,从这里可以拿到相应的 stun 端口和 relay 端口。

  3. 如果双方的 ICE 检查通过,找到了互相连接的通路,那么接电话一方正式接受:
    1. <iq to="xxx@gmail.com/Talk.v927553D771" type="set" id="345"
    2.     from="yyy@gmail.com/Talk.v95CFB74394">
    3.   <session type="accept" id="2482103147"
    4.            initiator="xxx@gmail.com/Talk.v927553D771"
    5.            xmlns="http://www.google.com/session">
    6.     <description xml:lang="en" xmlns="http://www.google.com/session/phone">
    7.       <payload-type id="103" name="ISAC"/>
    8.       <payload-type id="97" name="IPCMWB"/>
    9.       <payload-type id="4" name="G723"/>
    10.       <payload-type id="100" name="EG711U"/>
    11.       <payload-type id="101" name="EG711A"/>
    12.       <payload-type id="0" name="PCMU"/>
    13.       <payload-type id="8" name="PCMA"/>
    14.       <payload-type id="13" name="CN"/>
    15.       <payload-type id="102" name="iLBC"/>
    16.     </description>
    17.   </session>
    18. </iq>

  4. 然后就在约定好的 RTP 链接上进行语音数据传输,其编解码器也是使用商定好的负载类型,象上面给出的例子中,双方提供的是一致的,那么就选择第一个,也就是 [url=][ISAC][/url],我们还看到 GTalk 还支持 [iLBC]
  5. 结束的时候将发送:

从上面的过程可以看出来,ICE 是其中比较重要的一部分。这将在以后会谈到。

所以要和 GTalk 进行互连,要做以下几个部分(如果不使用 libjingle 的话):

  • 一般 Jabber 协议支持(XML 解析、协议处理等等)
  • 上述 session 部分的协议
  • ICE 的支持,里面牵涉到 ICE 本身的一些方法以及 STUN/TURN 协议
  • RTP/RTCP,传输方面的支持
  • 编解码器(Codec),至少应该有 iLBC,(Jingle 协议中是 speex)

其中 Jabber/RTP/iLBC 有现成的东西,直接使用就可以,可能要处理的就是剩下的三部分,如果有现成的库就更好了。

X-GOOGLE-TOKEN

嗨,兄弟,最近在搞Gtalk的东西,search到你的bl

嗨,兄弟,最近在搞Gtalk的东西,search到你的blog, 首先表示感谢。
然后有些小问题。
看你的blog里Jabber请求好像都是明文,而我抓到的包,貌似全是加密的, 我也用pigin选择不使用SSL加密的方式发送请求,可是一样是密文。是不是现在的Jabber/XMPP强制使用加密方式?
另外如果我想过滤出语音包,如何能够获得remote host的ip address呢?貌似在voice请求的时候会发送一个http请求(Create_session),然后应答的http中提供的是reply.ip等信息。。。。

Tks & Regards,
Bo

确实是加密的

XMPP 使用 SSL/TLS 对消息进行加密,但当时 GTalk 为什么没用,我不记得了。Pidgin 可以直接在 Help/Debug Window 中看到所有的调试信息或者启动的时候使用 -d 参数也可以。

语音通道通常和 XMPP 不是一个(也就是 Out of Band),其中协商过程就是 Jingle (XEP-166)协议。而当时的 GTalk 使用的是自己的协议,与 Jingle 并不符合。不知道现在如何。发出的 HTTP 请求 create_session 只是 GTalk 自己的做法,去拿到相关的 STUN Server 以及 Relay Server 信息。通道找到以后会在 XMPP 的消息中体现出来的。当时的这篇文章没有把这部分的具体信息写出来。

我觉得可以直接看 Jingle 协议,以这个为准是最主要的。希望对你有所帮助。

thanks

这么快就回复了!!Thanks a lot

其实由于Gtalk是使用加密传输的,所以现在已经开始研究GMail/Gtalk, 也就是嵌入到GMail页面里面的chat,它支持voice chat 和 vedio chat, 但是不使用Jabber/XMPP,而是改用http,但是不知道voice&vedio是否仍使用Jingle协议。我现在的目的是如何从所有的ip消息中找出所有gtalk的语音/视频包。现在遇到一个问题,就是不知道remote端的ip和port,不知道remote ip & port是通过什么方式通知到gtalk的。

小弟从来没有接触过这些东东,兄台如有所了解,望告知!不胜感激。

Thanks & Regards,
Bo

抱歉

很抱歉,WEB 界面的 GTalk 没有研究过,对其后面的机制不是很清楚,帮不上什么忙了。不过 GTalk 使用的是 Libjingle,可以直接研究它的源代码。Pidgin 现在也是直接支持 GTalk 的音频和视频,可以参考 XMPP 相关的代码。

另外,找出语音视频包应该比较简单,基本上包最多的就是,通常来讲不是加密的,从中可以知道其地址和端口,但是怎么得到的就不好说了。

Post new comment

The content of this field is kept private and will not be shown publicly.
  • Allowed HTML tags: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd> <blockquote>
  • You can use BBCode tags in the text.
  • You can enable syntax highlighting of source code with the following tags: <code>, <blockcode>. Beside the tag style "<foo>" it is also possible to use "[foo]".
  • Web page addresses and e-mail addresses turn into links automatically.
  • Lines and paragraphs break automatically.

More information about formatting options

CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.
times one equals minus three
Solve this math question and enter the solution with digits. E.g. for "two plus four = ?" enter "6".