From c4922316b417ebe35ab006a2945de889a26b9d4e Mon Sep 17 00:00:00 2001 From: "henrike@webrtc.org" <henrike@webrtc.org> Date: Mon, 10 Nov 2014 15:31:24 +0000 Subject: [PATCH] Removes talk/xmllite, talk/xmpp and talk/p2p as they are no longer used by gyp/gn builds. TBR=niklas.enbom@webrtc.org BUG=3379 Review URL: https://webrtc-codereview.appspot.com/30959004 git-svn-id: http://webrtc.googlecode.com/svn/trunk@7670 4adac7df-926f-26a2-2b94-8c16560cd09d --- talk/p2p/base/asyncstuntcpsocket.cc | 170 -- talk/p2p/base/asyncstuntcpsocket.h | 67 - talk/p2p/base/asyncstuntcpsocket_unittest.cc | 280 -- talk/p2p/base/basicpacketsocketfactory.cc | 221 -- talk/p2p/base/basicpacketsocketfactory.h | 68 - talk/p2p/base/candidate.h | 229 -- talk/p2p/base/common.h | 37 - talk/p2p/base/constants.cc | 274 -- talk/p2p/base/constants.h | 276 -- talk/p2p/base/dtlstransport.h | 257 -- talk/p2p/base/dtlstransportchannel.cc | 641 ----- talk/p2p/base/dtlstransportchannel.h | 264 -- .../p2p/base/dtlstransportchannel_unittest.cc | 841 ------ talk/p2p/base/fakesession.h | 509 ---- talk/p2p/base/p2ptransport.cc | 263 -- talk/p2p/base/p2ptransport.h | 103 - talk/p2p/base/p2ptransportchannel.cc | 1291 --------- talk/p2p/base/p2ptransportchannel.h | 259 -- talk/p2p/base/p2ptransportchannel_unittest.cc | 1719 ----------- talk/p2p/base/packetsocketfactory.h | 69 - talk/p2p/base/parsing.cc | 158 -- talk/p2p/base/parsing.h | 157 -- talk/p2p/base/port.cc | 1447 ---------- talk/p2p/base/port.h | 619 ---- talk/p2p/base/port_unittest.cc | 2511 ----------------- talk/p2p/base/portallocator.cc | 109 - talk/p2p/base/portallocator.h | 209 -- talk/p2p/base/portallocatorsessionproxy.cc | 239 -- talk/p2p/base/portallocatorsessionproxy.h | 123 - .../portallocatorsessionproxy_unittest.cc | 163 -- talk/p2p/base/portinterface.h | 143 - talk/p2p/base/portproxy.cc | 180 -- talk/p2p/base/portproxy.h | 104 - talk/p2p/base/pseudotcp.cc | 1291 --------- talk/p2p/base/pseudotcp.h | 258 -- talk/p2p/base/pseudotcp_unittest.cc | 858 ------ talk/p2p/base/rawtransport.cc | 132 - talk/p2p/base/rawtransport.h | 81 - talk/p2p/base/rawtransportchannel.cc | 277 -- talk/p2p/base/rawtransportchannel.h | 206 -- talk/p2p/base/relayport.cc | 835 ------ talk/p2p/base/relayport.h | 118 - talk/p2p/base/relayport_unittest.cc | 289 -- talk/p2p/base/relayserver.cc | 763 ----- talk/p2p/base/relayserver.h | 252 -- talk/p2p/base/relayserver_unittest.cc | 536 ---- talk/p2p/base/session.cc | 1777 ------------ talk/p2p/base/session.h | 747 ----- talk/p2p/base/session_unittest.cc | 2447 ---------------- talk/p2p/base/sessionclient.h | 95 - talk/p2p/base/sessiondescription.cc | 239 -- talk/p2p/base/sessiondescription.h | 202 -- talk/p2p/base/sessionid.h | 37 - talk/p2p/base/sessionmanager.cc | 326 --- talk/p2p/base/sessionmanager.h | 211 -- talk/p2p/base/sessionmessages.cc | 1149 -------- talk/p2p/base/sessionmessages.h | 243 -- talk/p2p/base/stun.cc | 932 ------ talk/p2p/base/stun.h | 649 ----- talk/p2p/base/stun_unittest.cc | 1419 ---------- talk/p2p/base/stunport.cc | 468 --- talk/p2p/base/stunport.h | 255 -- talk/p2p/base/stunport_unittest.cc | 300 -- talk/p2p/base/stunrequest.cc | 210 -- talk/p2p/base/stunrequest.h | 133 - talk/p2p/base/stunrequest_unittest.cc | 220 -- talk/p2p/base/stunserver.cc | 116 - talk/p2p/base/stunserver.h | 83 - talk/p2p/base/stunserver_unittest.cc | 126 - talk/p2p/base/tcpport.cc | 341 --- talk/p2p/base/tcpport.h | 153 - talk/p2p/base/testrelayserver.h | 118 - talk/p2p/base/teststunserver.h | 75 - talk/p2p/base/testturnserver.h | 120 - talk/p2p/base/transport.cc | 977 ------- talk/p2p/base/transport.h | 530 ---- talk/p2p/base/transport_unittest.cc | 455 --- talk/p2p/base/transportchannel.cc | 60 - talk/p2p/base/transportchannel.h | 160 -- talk/p2p/base/transportchannelimpl.h | 128 - talk/p2p/base/transportchannelproxy.cc | 266 -- talk/p2p/base/transportchannelproxy.h | 112 - talk/p2p/base/transportdescription.cc | 72 - talk/p2p/base/transportdescription.h | 188 -- talk/p2p/base/transportdescriptionfactory.cc | 177 -- talk/p2p/base/transportdescriptionfactory.h | 83 - .../transportdescriptionfactory_unittest.cc | 382 --- talk/p2p/base/transportinfo.h | 60 - talk/p2p/base/turnport.cc | 1213 -------- talk/p2p/base/turnport.h | 254 -- talk/p2p/base/turnport_unittest.cc | 685 ----- talk/p2p/base/turnserver.cc | 1028 ------- talk/p2p/base/turnserver.h | 207 -- talk/p2p/base/udpport.h | 34 - talk/p2p/client/autoportallocator.h | 69 - talk/p2p/client/basicportallocator.cc | 1207 -------- talk/p2p/client/basicportallocator.h | 258 -- talk/p2p/client/connectivitychecker.cc | 584 ---- talk/p2p/client/connectivitychecker.h | 274 -- .../client/connectivitychecker_unittest.cc | 392 --- talk/p2p/client/fakeportallocator.h | 138 - talk/p2p/client/httpportallocator.cc | 343 --- talk/p2p/client/httpportallocator.h | 190 -- talk/p2p/client/portallocator_unittest.cc | 1083 ------- talk/p2p/client/sessionmanagertask.h | 93 - talk/p2p/client/sessionsendtask.h | 145 - talk/p2p/client/socketmonitor.cc | 114 - talk/p2p/client/socketmonitor.h | 71 - talk/xmllite/qname.cc | 95 - talk/xmllite/qname.h | 100 - talk/xmllite/qname_unittest.cc | 131 - talk/xmllite/xmlbuilder.cc | 147 - talk/xmllite/xmlbuilder.h | 78 - talk/xmllite/xmlbuilder_unittest.cc | 194 -- talk/xmllite/xmlconstants.cc | 42 - talk/xmllite/xmlconstants.h | 47 - talk/xmllite/xmlelement.cc | 513 ---- talk/xmllite/xmlelement.h | 251 -- talk/xmllite/xmlelement_unittest.cc | 275 -- talk/xmllite/xmlnsstack.cc | 195 -- talk/xmllite/xmlnsstack.h | 62 - talk/xmllite/xmlnsstack_unittest.cc | 258 -- talk/xmllite/xmlparser.cc | 278 -- talk/xmllite/xmlparser.h | 120 - talk/xmllite/xmlparser_unittest.cc | 302 -- talk/xmllite/xmlprinter.cc | 191 -- talk/xmllite/xmlprinter.h | 49 - talk/xmllite/xmlprinter_unittest.cc | 62 - talk/xmpp/asyncsocket.h | 89 - talk/xmpp/chatroommodule.h | 270 -- talk/xmpp/chatroommodule_unittest.cc | 297 -- talk/xmpp/chatroommoduleimpl.cc | 752 ----- talk/xmpp/constants.cc | 631 ----- talk/xmpp/constants.h | 568 ---- talk/xmpp/discoitemsquerytask.cc | 79 - talk/xmpp/discoitemsquerytask.h | 82 - talk/xmpp/fakexmppclient.h | 123 - talk/xmpp/hangoutpubsubclient.cc | 417 --- talk/xmpp/hangoutpubsubclient.h | 195 -- talk/xmpp/hangoutpubsubclient_unittest.cc | 746 ----- talk/xmpp/iqtask.cc | 86 - talk/xmpp/iqtask.h | 65 - talk/xmpp/jid.cc | 396 --- talk/xmpp/jid.h | 98 - talk/xmpp/jid_unittest.cc | 115 - talk/xmpp/jingleinfotask.cc | 138 - talk/xmpp/jingleinfotask.h | 61 - talk/xmpp/module.h | 52 - talk/xmpp/moduleimpl.cc | 65 - talk/xmpp/moduleimpl.h | 93 - talk/xmpp/mucroomconfigtask.cc | 91 - talk/xmpp/mucroomconfigtask.h | 64 - talk/xmpp/mucroomconfigtask_unittest.cc | 144 - talk/xmpp/mucroomdiscoverytask.cc | 83 - talk/xmpp/mucroomdiscoverytask.h | 58 - talk/xmpp/mucroomdiscoverytask_unittest.cc | 162 -- talk/xmpp/mucroomlookuptask.cc | 176 -- talk/xmpp/mucroomlookuptask.h | 93 - talk/xmpp/mucroomlookuptask_unittest.cc | 204 -- talk/xmpp/mucroomuniquehangoutidtask.cc | 44 - talk/xmpp/mucroomuniquehangoutidtask.h | 31 - .../mucroomuniquehangoutidtask_unittest.cc | 116 - talk/xmpp/pingtask.cc | 85 - talk/xmpp/pingtask.h | 71 - talk/xmpp/pingtask_unittest.cc | 118 - talk/xmpp/plainsaslhandler.h | 81 - talk/xmpp/presenceouttask.cc | 157 -- talk/xmpp/presenceouttask.h | 54 - talk/xmpp/presencereceivetask.cc | 158 -- talk/xmpp/presencereceivetask.h | 73 - talk/xmpp/presencestatus.cc | 62 - talk/xmpp/presencestatus.h | 205 -- talk/xmpp/prexmppauth.h | 88 - talk/xmpp/pubsub_task.cc | 217 -- talk/xmpp/pubsub_task.h | 75 - talk/xmpp/pubsubclient.cc | 146 - talk/xmpp/pubsubclient.h | 128 - talk/xmpp/pubsubclient_unittest.cc | 271 -- talk/xmpp/pubsubstateclient.cc | 42 - talk/xmpp/pubsubstateclient.h | 287 -- talk/xmpp/pubsubtasks.cc | 221 -- talk/xmpp/pubsubtasks.h | 131 - talk/xmpp/pubsubtasks_unittest.cc | 273 -- talk/xmpp/receivetask.cc | 51 - talk/xmpp/receivetask.h | 58 - talk/xmpp/rostermodule.h | 348 --- talk/xmpp/rostermodule_unittest.cc | 849 ------ talk/xmpp/rostermoduleimpl.cc | 1081 ------- talk/xmpp/rostermoduleimpl.h | 302 -- talk/xmpp/saslcookiemechanism.h | 86 - talk/xmpp/saslhandler.h | 59 - talk/xmpp/saslmechanism.cc | 72 - talk/xmpp/saslmechanism.h | 74 - talk/xmpp/saslplainmechanism.h | 65 - talk/xmpp/util_unittest.cc | 102 - talk/xmpp/util_unittest.h | 75 - talk/xmpp/xmppauth.cc | 105 - talk/xmpp/xmppauth.h | 78 - talk/xmpp/xmppclient.cc | 441 --- talk/xmpp/xmppclient.h | 165 -- talk/xmpp/xmppclientsettings.h | 128 - talk/xmpp/xmppengine.h | 349 --- talk/xmpp/xmppengine_unittest.cc | 318 --- talk/xmpp/xmppengineimpl.cc | 463 --- talk/xmpp/xmppengineimpl.h | 282 -- talk/xmpp/xmppengineimpl_iq.cc | 277 -- talk/xmpp/xmpplogintask.cc | 397 --- talk/xmpp/xmpplogintask.h | 104 - talk/xmpp/xmpplogintask_unittest.cc | 614 ---- talk/xmpp/xmpppump.cc | 84 - talk/xmpp/xmpppump.h | 79 - talk/xmpp/xmppsocket.cc | 262 -- talk/xmpp/xmppsocket.h | 89 - talk/xmpp/xmppstanzaparser.cc | 106 - talk/xmpp/xmppstanzaparser.h | 97 - talk/xmpp/xmppstanzaparser_unittest.cc | 168 -- talk/xmpp/xmpptask.cc | 175 -- talk/xmpp/xmpptask.h | 189 -- talk/xmpp/xmppthread.cc | 86 - talk/xmpp/xmppthread.h | 62 - 220 files changed, 66476 deletions(-) delete mode 100644 talk/p2p/base/asyncstuntcpsocket.cc delete mode 100644 talk/p2p/base/asyncstuntcpsocket.h delete mode 100644 talk/p2p/base/asyncstuntcpsocket_unittest.cc delete mode 100644 talk/p2p/base/basicpacketsocketfactory.cc delete mode 100644 talk/p2p/base/basicpacketsocketfactory.h delete mode 100644 talk/p2p/base/candidate.h delete mode 100644 talk/p2p/base/common.h delete mode 100644 talk/p2p/base/constants.cc delete mode 100644 talk/p2p/base/constants.h delete mode 100644 talk/p2p/base/dtlstransport.h delete mode 100644 talk/p2p/base/dtlstransportchannel.cc delete mode 100644 talk/p2p/base/dtlstransportchannel.h delete mode 100644 talk/p2p/base/dtlstransportchannel_unittest.cc delete mode 100644 talk/p2p/base/fakesession.h delete mode 100644 talk/p2p/base/p2ptransport.cc delete mode 100644 talk/p2p/base/p2ptransport.h delete mode 100644 talk/p2p/base/p2ptransportchannel.cc delete mode 100644 talk/p2p/base/p2ptransportchannel.h delete mode 100644 talk/p2p/base/p2ptransportchannel_unittest.cc delete mode 100644 talk/p2p/base/packetsocketfactory.h delete mode 100644 talk/p2p/base/parsing.cc delete mode 100644 talk/p2p/base/parsing.h delete mode 100644 talk/p2p/base/port.cc delete mode 100644 talk/p2p/base/port.h delete mode 100644 talk/p2p/base/port_unittest.cc delete mode 100644 talk/p2p/base/portallocator.cc delete mode 100644 talk/p2p/base/portallocator.h delete mode 100644 talk/p2p/base/portallocatorsessionproxy.cc delete mode 100644 talk/p2p/base/portallocatorsessionproxy.h delete mode 100644 talk/p2p/base/portallocatorsessionproxy_unittest.cc delete mode 100644 talk/p2p/base/portinterface.h delete mode 100644 talk/p2p/base/portproxy.cc delete mode 100644 talk/p2p/base/portproxy.h delete mode 100644 talk/p2p/base/pseudotcp.cc delete mode 100644 talk/p2p/base/pseudotcp.h delete mode 100644 talk/p2p/base/pseudotcp_unittest.cc delete mode 100644 talk/p2p/base/rawtransport.cc delete mode 100644 talk/p2p/base/rawtransport.h delete mode 100644 talk/p2p/base/rawtransportchannel.cc delete mode 100644 talk/p2p/base/rawtransportchannel.h delete mode 100644 talk/p2p/base/relayport.cc delete mode 100644 talk/p2p/base/relayport.h delete mode 100644 talk/p2p/base/relayport_unittest.cc delete mode 100644 talk/p2p/base/relayserver.cc delete mode 100644 talk/p2p/base/relayserver.h delete mode 100644 talk/p2p/base/relayserver_unittest.cc delete mode 100644 talk/p2p/base/session.cc delete mode 100644 talk/p2p/base/session.h delete mode 100644 talk/p2p/base/session_unittest.cc delete mode 100644 talk/p2p/base/sessionclient.h delete mode 100644 talk/p2p/base/sessiondescription.cc delete mode 100644 talk/p2p/base/sessiondescription.h delete mode 100644 talk/p2p/base/sessionid.h delete mode 100644 talk/p2p/base/sessionmanager.cc delete mode 100644 talk/p2p/base/sessionmanager.h delete mode 100644 talk/p2p/base/sessionmessages.cc delete mode 100644 talk/p2p/base/sessionmessages.h delete mode 100644 talk/p2p/base/stun.cc delete mode 100644 talk/p2p/base/stun.h delete mode 100644 talk/p2p/base/stun_unittest.cc delete mode 100644 talk/p2p/base/stunport.cc delete mode 100644 talk/p2p/base/stunport.h delete mode 100644 talk/p2p/base/stunport_unittest.cc delete mode 100644 talk/p2p/base/stunrequest.cc delete mode 100644 talk/p2p/base/stunrequest.h delete mode 100644 talk/p2p/base/stunrequest_unittest.cc delete mode 100644 talk/p2p/base/stunserver.cc delete mode 100644 talk/p2p/base/stunserver.h delete mode 100644 talk/p2p/base/stunserver_unittest.cc delete mode 100644 talk/p2p/base/tcpport.cc delete mode 100644 talk/p2p/base/tcpport.h delete mode 100644 talk/p2p/base/testrelayserver.h delete mode 100644 talk/p2p/base/teststunserver.h delete mode 100644 talk/p2p/base/testturnserver.h delete mode 100644 talk/p2p/base/transport.cc delete mode 100644 talk/p2p/base/transport.h delete mode 100644 talk/p2p/base/transport_unittest.cc delete mode 100644 talk/p2p/base/transportchannel.cc delete mode 100644 talk/p2p/base/transportchannel.h delete mode 100644 talk/p2p/base/transportchannelimpl.h delete mode 100644 talk/p2p/base/transportchannelproxy.cc delete mode 100644 talk/p2p/base/transportchannelproxy.h delete mode 100644 talk/p2p/base/transportdescription.cc delete mode 100644 talk/p2p/base/transportdescription.h delete mode 100644 talk/p2p/base/transportdescriptionfactory.cc delete mode 100644 talk/p2p/base/transportdescriptionfactory.h delete mode 100644 talk/p2p/base/transportdescriptionfactory_unittest.cc delete mode 100644 talk/p2p/base/transportinfo.h delete mode 100644 talk/p2p/base/turnport.cc delete mode 100644 talk/p2p/base/turnport.h delete mode 100644 talk/p2p/base/turnport_unittest.cc delete mode 100644 talk/p2p/base/turnserver.cc delete mode 100644 talk/p2p/base/turnserver.h delete mode 100644 talk/p2p/base/udpport.h delete mode 100644 talk/p2p/client/autoportallocator.h delete mode 100644 talk/p2p/client/basicportallocator.cc delete mode 100644 talk/p2p/client/basicportallocator.h delete mode 100644 talk/p2p/client/connectivitychecker.cc delete mode 100644 talk/p2p/client/connectivitychecker.h delete mode 100644 talk/p2p/client/connectivitychecker_unittest.cc delete mode 100644 talk/p2p/client/fakeportallocator.h delete mode 100644 talk/p2p/client/httpportallocator.cc delete mode 100644 talk/p2p/client/httpportallocator.h delete mode 100644 talk/p2p/client/portallocator_unittest.cc delete mode 100644 talk/p2p/client/sessionmanagertask.h delete mode 100644 talk/p2p/client/sessionsendtask.h delete mode 100644 talk/p2p/client/socketmonitor.cc delete mode 100644 talk/p2p/client/socketmonitor.h delete mode 100755 talk/xmllite/qname.cc delete mode 100755 talk/xmllite/qname.h delete mode 100755 talk/xmllite/qname_unittest.cc delete mode 100755 talk/xmllite/xmlbuilder.cc delete mode 100755 talk/xmllite/xmlbuilder.h delete mode 100755 talk/xmllite/xmlbuilder_unittest.cc delete mode 100755 talk/xmllite/xmlconstants.cc delete mode 100755 talk/xmllite/xmlconstants.h delete mode 100755 talk/xmllite/xmlelement.cc delete mode 100755 talk/xmllite/xmlelement.h delete mode 100755 talk/xmllite/xmlelement_unittest.cc delete mode 100755 talk/xmllite/xmlnsstack.cc delete mode 100755 talk/xmllite/xmlnsstack.h delete mode 100755 talk/xmllite/xmlnsstack_unittest.cc delete mode 100755 talk/xmllite/xmlparser.cc delete mode 100755 talk/xmllite/xmlparser.h delete mode 100755 talk/xmllite/xmlparser_unittest.cc delete mode 100755 talk/xmllite/xmlprinter.cc delete mode 100755 talk/xmllite/xmlprinter.h delete mode 100755 talk/xmllite/xmlprinter_unittest.cc delete mode 100644 talk/xmpp/asyncsocket.h delete mode 100644 talk/xmpp/chatroommodule.h delete mode 100644 talk/xmpp/chatroommodule_unittest.cc delete mode 100644 talk/xmpp/chatroommoduleimpl.cc delete mode 100644 talk/xmpp/constants.cc delete mode 100644 talk/xmpp/constants.h delete mode 100644 talk/xmpp/discoitemsquerytask.cc delete mode 100644 talk/xmpp/discoitemsquerytask.h delete mode 100644 talk/xmpp/fakexmppclient.h delete mode 100644 talk/xmpp/hangoutpubsubclient.cc delete mode 100644 talk/xmpp/hangoutpubsubclient.h delete mode 100644 talk/xmpp/hangoutpubsubclient_unittest.cc delete mode 100644 talk/xmpp/iqtask.cc delete mode 100644 talk/xmpp/iqtask.h delete mode 100644 talk/xmpp/jid.cc delete mode 100644 talk/xmpp/jid.h delete mode 100644 talk/xmpp/jid_unittest.cc delete mode 100644 talk/xmpp/jingleinfotask.cc delete mode 100644 talk/xmpp/jingleinfotask.h delete mode 100644 talk/xmpp/module.h delete mode 100644 talk/xmpp/moduleimpl.cc delete mode 100644 talk/xmpp/moduleimpl.h delete mode 100644 talk/xmpp/mucroomconfigtask.cc delete mode 100644 talk/xmpp/mucroomconfigtask.h delete mode 100644 talk/xmpp/mucroomconfigtask_unittest.cc delete mode 100644 talk/xmpp/mucroomdiscoverytask.cc delete mode 100644 talk/xmpp/mucroomdiscoverytask.h delete mode 100644 talk/xmpp/mucroomdiscoverytask_unittest.cc delete mode 100644 talk/xmpp/mucroomlookuptask.cc delete mode 100644 talk/xmpp/mucroomlookuptask.h delete mode 100644 talk/xmpp/mucroomlookuptask_unittest.cc delete mode 100644 talk/xmpp/mucroomuniquehangoutidtask.cc delete mode 100644 talk/xmpp/mucroomuniquehangoutidtask.h delete mode 100644 talk/xmpp/mucroomuniquehangoutidtask_unittest.cc delete mode 100644 talk/xmpp/pingtask.cc delete mode 100644 talk/xmpp/pingtask.h delete mode 100644 talk/xmpp/pingtask_unittest.cc delete mode 100644 talk/xmpp/plainsaslhandler.h delete mode 100644 talk/xmpp/presenceouttask.cc delete mode 100644 talk/xmpp/presenceouttask.h delete mode 100644 talk/xmpp/presencereceivetask.cc delete mode 100644 talk/xmpp/presencereceivetask.h delete mode 100644 talk/xmpp/presencestatus.cc delete mode 100644 talk/xmpp/presencestatus.h delete mode 100644 talk/xmpp/prexmppauth.h delete mode 100644 talk/xmpp/pubsub_task.cc delete mode 100644 talk/xmpp/pubsub_task.h delete mode 100644 talk/xmpp/pubsubclient.cc delete mode 100644 talk/xmpp/pubsubclient.h delete mode 100644 talk/xmpp/pubsubclient_unittest.cc delete mode 100644 talk/xmpp/pubsubstateclient.cc delete mode 100644 talk/xmpp/pubsubstateclient.h delete mode 100644 talk/xmpp/pubsubtasks.cc delete mode 100644 talk/xmpp/pubsubtasks.h delete mode 100644 talk/xmpp/pubsubtasks_unittest.cc delete mode 100644 talk/xmpp/receivetask.cc delete mode 100644 talk/xmpp/receivetask.h delete mode 100644 talk/xmpp/rostermodule.h delete mode 100644 talk/xmpp/rostermodule_unittest.cc delete mode 100644 talk/xmpp/rostermoduleimpl.cc delete mode 100644 talk/xmpp/rostermoduleimpl.h delete mode 100644 talk/xmpp/saslcookiemechanism.h delete mode 100644 talk/xmpp/saslhandler.h delete mode 100644 talk/xmpp/saslmechanism.cc delete mode 100644 talk/xmpp/saslmechanism.h delete mode 100644 talk/xmpp/saslplainmechanism.h delete mode 100644 talk/xmpp/util_unittest.cc delete mode 100644 talk/xmpp/util_unittest.h delete mode 100644 talk/xmpp/xmppauth.cc delete mode 100644 talk/xmpp/xmppauth.h delete mode 100644 talk/xmpp/xmppclient.cc delete mode 100644 talk/xmpp/xmppclient.h delete mode 100644 talk/xmpp/xmppclientsettings.h delete mode 100644 talk/xmpp/xmppengine.h delete mode 100644 talk/xmpp/xmppengine_unittest.cc delete mode 100644 talk/xmpp/xmppengineimpl.cc delete mode 100644 talk/xmpp/xmppengineimpl.h delete mode 100644 talk/xmpp/xmppengineimpl_iq.cc delete mode 100644 talk/xmpp/xmpplogintask.cc delete mode 100644 talk/xmpp/xmpplogintask.h delete mode 100644 talk/xmpp/xmpplogintask_unittest.cc delete mode 100644 talk/xmpp/xmpppump.cc delete mode 100644 talk/xmpp/xmpppump.h delete mode 100644 talk/xmpp/xmppsocket.cc delete mode 100644 talk/xmpp/xmppsocket.h delete mode 100644 talk/xmpp/xmppstanzaparser.cc delete mode 100644 talk/xmpp/xmppstanzaparser.h delete mode 100644 talk/xmpp/xmppstanzaparser_unittest.cc delete mode 100644 talk/xmpp/xmpptask.cc delete mode 100644 talk/xmpp/xmpptask.h delete mode 100644 talk/xmpp/xmppthread.cc delete mode 100644 talk/xmpp/xmppthread.h diff --git a/talk/p2p/base/asyncstuntcpsocket.cc b/talk/p2p/base/asyncstuntcpsocket.cc deleted file mode 100644 index 73bb1520c..000000000 --- a/talk/p2p/base/asyncstuntcpsocket.cc +++ /dev/null @@ -1,170 +0,0 @@ -/* - * libjingle - * Copyright 2013, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "webrtc/p2p/base/asyncstuntcpsocket.h" - -#include <string.h> - -#include "webrtc/p2p/base/stun.h" -#include "webrtc/base/common.h" -#include "webrtc/base/logging.h" - -namespace cricket { - -static const size_t kMaxPacketSize = 64 * 1024; - -typedef uint16 PacketLength; -static const size_t kPacketLenSize = sizeof(PacketLength); -static const size_t kPacketLenOffset = 2; -static const size_t kBufSize = kMaxPacketSize + kStunHeaderSize; -static const size_t kTurnChannelDataHdrSize = 4; - -inline bool IsStunMessage(uint16 msg_type) { - // The first two bits of a channel data message are 0b01. - return (msg_type & 0xC000) ? false : true; -} - -// AsyncStunTCPSocket -// Binds and connects |socket| and creates AsyncTCPSocket for -// it. Takes ownership of |socket|. Returns NULL if bind() or -// connect() fail (|socket| is destroyed in that case). -AsyncStunTCPSocket* AsyncStunTCPSocket::Create( - rtc::AsyncSocket* socket, - const rtc::SocketAddress& bind_address, - const rtc::SocketAddress& remote_address) { - return new AsyncStunTCPSocket(AsyncTCPSocketBase::ConnectSocket( - socket, bind_address, remote_address), false); -} - -AsyncStunTCPSocket::AsyncStunTCPSocket( - rtc::AsyncSocket* socket, bool listen) - : rtc::AsyncTCPSocketBase(socket, listen, kBufSize) { -} - -int AsyncStunTCPSocket::Send(const void *pv, size_t cb, - const rtc::PacketOptions& options) { - if (cb > kBufSize || cb < kPacketLenSize + kPacketLenOffset) { - SetError(EMSGSIZE); - return -1; - } - - // If we are blocking on send, then silently drop this packet - if (!IsOutBufferEmpty()) - return static_cast<int>(cb); - - int pad_bytes; - size_t expected_pkt_len = GetExpectedLength(pv, cb, &pad_bytes); - - // Accepts only complete STUN/ChannelData packets. - if (cb != expected_pkt_len) - return -1; - - AppendToOutBuffer(pv, cb); - - ASSERT(pad_bytes < 4); - char padding[4] = {0}; - AppendToOutBuffer(padding, pad_bytes); - - int res = FlushOutBuffer(); - if (res <= 0) { - // drop packet if we made no progress - ClearOutBuffer(); - return res; - } - - // We claim to have sent the whole thing, even if we only sent partial - return static_cast<int>(cb); -} - -void AsyncStunTCPSocket::ProcessInput(char* data, size_t* len) { - rtc::SocketAddress remote_addr(GetRemoteAddress()); - // STUN packet - First 4 bytes. Total header size is 20 bytes. - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - // |0 0| STUN Message Type | Message Length | - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - - // TURN ChannelData - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - // | Channel Number | Length | - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - - while (true) { - // We need at least 4 bytes to read the STUN or ChannelData packet length. - if (*len < kPacketLenOffset + kPacketLenSize) - return; - - int pad_bytes; - size_t expected_pkt_len = GetExpectedLength(data, *len, &pad_bytes); - size_t actual_length = expected_pkt_len + pad_bytes; - - if (*len < actual_length) { - return; - } - - SignalReadPacket(this, data, expected_pkt_len, remote_addr, - rtc::CreatePacketTime(0)); - - *len -= actual_length; - if (*len > 0) { - memmove(data, data + actual_length, *len); - } - } -} - -void AsyncStunTCPSocket::HandleIncomingConnection( - rtc::AsyncSocket* socket) { - SignalNewConnection(this, new AsyncStunTCPSocket(socket, false)); -} - -size_t AsyncStunTCPSocket::GetExpectedLength(const void* data, size_t len, - int* pad_bytes) { - *pad_bytes = 0; - PacketLength pkt_len = - rtc::GetBE16(static_cast<const char*>(data) + kPacketLenOffset); - size_t expected_pkt_len; - uint16 msg_type = rtc::GetBE16(data); - if (IsStunMessage(msg_type)) { - // STUN message. - expected_pkt_len = kStunHeaderSize + pkt_len; - } else { - // TURN ChannelData message. - expected_pkt_len = kTurnChannelDataHdrSize + pkt_len; - // From RFC 5766 section 11.5 - // Over TCP and TLS-over-TCP, the ChannelData message MUST be padded to - // a multiple of four bytes in order to ensure the alignment of - // subsequent messages. The padding is not reflected in the length - // field of the ChannelData message, so the actual size of a ChannelData - // message (including padding) is (4 + Length) rounded up to the nearest - // multiple of 4. Over UDP, the padding is not required but MAY be - // included. - if (expected_pkt_len % 4) - *pad_bytes = 4 - (expected_pkt_len % 4); - } - return expected_pkt_len; -} - -} // namespace cricket diff --git a/talk/p2p/base/asyncstuntcpsocket.h b/talk/p2p/base/asyncstuntcpsocket.h deleted file mode 100644 index 3675c9ec1..000000000 --- a/talk/p2p/base/asyncstuntcpsocket.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * libjingle - * Copyright 2013, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef WEBRTC_P2P_BASE_ASYNCSTUNTCPSOCKET_H_ -#define WEBRTC_P2P_BASE_ASYNCSTUNTCPSOCKET_H_ - -#include "webrtc/base/asynctcpsocket.h" -#include "webrtc/base/scoped_ptr.h" -#include "webrtc/base/socketfactory.h" - -namespace cricket { - -class AsyncStunTCPSocket : public rtc::AsyncTCPSocketBase { - public: - // Binds and connects |socket| and creates AsyncTCPSocket for - // it. Takes ownership of |socket|. Returns NULL if bind() or - // connect() fail (|socket| is destroyed in that case). - static AsyncStunTCPSocket* Create( - rtc::AsyncSocket* socket, - const rtc::SocketAddress& bind_address, - const rtc::SocketAddress& remote_address); - - AsyncStunTCPSocket(rtc::AsyncSocket* socket, bool listen); - virtual ~AsyncStunTCPSocket() {} - - virtual int Send(const void* pv, size_t cb, - const rtc::PacketOptions& options); - virtual void ProcessInput(char* data, size_t* len); - virtual void HandleIncomingConnection(rtc::AsyncSocket* socket); - - private: - // This method returns the message hdr + length written in the header. - // This method also returns the number of padding bytes needed/added to the - // turn message. |pad_bytes| should be used only when |is_turn| is true. - size_t GetExpectedLength(const void* data, size_t len, - int* pad_bytes); - - DISALLOW_EVIL_CONSTRUCTORS(AsyncStunTCPSocket); -}; - -} // namespace cricket - -#endif // WEBRTC_P2P_BASE_ASYNCSTUNTCPSOCKET_H_ diff --git a/talk/p2p/base/asyncstuntcpsocket_unittest.cc b/talk/p2p/base/asyncstuntcpsocket_unittest.cc deleted file mode 100644 index ba407e712..000000000 --- a/talk/p2p/base/asyncstuntcpsocket_unittest.cc +++ /dev/null @@ -1,280 +0,0 @@ -/* - * libjingle - * Copyright 2013, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "webrtc/p2p/base/asyncstuntcpsocket.h" -#include "webrtc/base/asyncsocket.h" -#include "webrtc/base/gunit.h" -#include "webrtc/base/physicalsocketserver.h" -#include "webrtc/base/virtualsocketserver.h" - -namespace cricket { - -static unsigned char kStunMessageWithZeroLength[] = { - 0x00, 0x01, 0x00, 0x00, // length of 0 (last 2 bytes) - 0x21, 0x12, 0xA4, 0x42, - '0', '1', '2', '3', - '4', '5', '6', '7', - '8', '9', 'a', 'b', -}; - - -static unsigned char kTurnChannelDataMessageWithZeroLength[] = { - 0x40, 0x00, 0x00, 0x00, // length of 0 (last 2 bytes) -}; - -static unsigned char kTurnChannelDataMessage[] = { - 0x40, 0x00, 0x00, 0x10, - 0x21, 0x12, 0xA4, 0x42, - '0', '1', '2', '3', - '4', '5', '6', '7', - '8', '9', 'a', 'b', -}; - -static unsigned char kStunMessageWithInvalidLength[] = { - 0x00, 0x01, 0x00, 0x10, - 0x21, 0x12, 0xA4, 0x42, - '0', '1', '2', '3', - '4', '5', '6', '7', - '8', '9', 'a', 'b', -}; - -static unsigned char kTurnChannelDataMessageWithInvalidLength[] = { - 0x80, 0x00, 0x00, 0x20, - 0x21, 0x12, 0xA4, 0x42, - '0', '1', '2', '3', - '4', '5', '6', '7', - '8', '9', 'a', 'b', -}; - -static unsigned char kTurnChannelDataMessageWithOddLength[] = { - 0x40, 0x00, 0x00, 0x05, - 0x21, 0x12, 0xA4, 0x42, - '0', -}; - - -static const rtc::SocketAddress kClientAddr("11.11.11.11", 0); -static const rtc::SocketAddress kServerAddr("22.22.22.22", 0); - -class AsyncStunTCPSocketTest : public testing::Test, - public sigslot::has_slots<> { - protected: - AsyncStunTCPSocketTest() - : vss_(new rtc::VirtualSocketServer(NULL)), - ss_scope_(vss_.get()) { - } - - virtual void SetUp() { - CreateSockets(); - } - - void CreateSockets() { - rtc::AsyncSocket* server = vss_->CreateAsyncSocket( - kServerAddr.family(), SOCK_STREAM); - server->Bind(kServerAddr); - recv_socket_.reset(new AsyncStunTCPSocket(server, true)); - recv_socket_->SignalNewConnection.connect( - this, &AsyncStunTCPSocketTest::OnNewConnection); - - rtc::AsyncSocket* client = vss_->CreateAsyncSocket( - kClientAddr.family(), SOCK_STREAM); - send_socket_.reset(AsyncStunTCPSocket::Create( - client, kClientAddr, recv_socket_->GetLocalAddress())); - ASSERT_TRUE(send_socket_.get() != NULL); - vss_->ProcessMessagesUntilIdle(); - } - - void OnReadPacket(rtc::AsyncPacketSocket* socket, const char* data, - size_t len, const rtc::SocketAddress& remote_addr, - const rtc::PacketTime& packet_time) { - recv_packets_.push_back(std::string(data, len)); - } - - void OnNewConnection(rtc::AsyncPacketSocket* server, - rtc::AsyncPacketSocket* new_socket) { - listen_socket_.reset(new_socket); - new_socket->SignalReadPacket.connect( - this, &AsyncStunTCPSocketTest::OnReadPacket); - } - - bool Send(const void* data, size_t len) { - rtc::PacketOptions options; - size_t ret = send_socket_->Send( - reinterpret_cast<const char*>(data), len, options); - vss_->ProcessMessagesUntilIdle(); - return (ret == len); - } - - bool CheckData(const void* data, int len) { - bool ret = false; - if (recv_packets_.size()) { - std::string packet = recv_packets_.front(); - recv_packets_.pop_front(); - ret = (memcmp(data, packet.c_str(), len) == 0); - } - return ret; - } - - rtc::scoped_ptr<rtc::VirtualSocketServer> vss_; - rtc::SocketServerScope ss_scope_; - rtc::scoped_ptr<AsyncStunTCPSocket> send_socket_; - rtc::scoped_ptr<AsyncStunTCPSocket> recv_socket_; - rtc::scoped_ptr<rtc::AsyncPacketSocket> listen_socket_; - std::list<std::string> recv_packets_; -}; - -// Testing a stun packet sent/recv properly. -TEST_F(AsyncStunTCPSocketTest, TestSingleStunPacket) { - EXPECT_TRUE(Send(kStunMessageWithZeroLength, - sizeof(kStunMessageWithZeroLength))); - EXPECT_EQ(1u, recv_packets_.size()); - EXPECT_TRUE(CheckData(kStunMessageWithZeroLength, - sizeof(kStunMessageWithZeroLength))); -} - -// Verify sending multiple packets. -TEST_F(AsyncStunTCPSocketTest, TestMultipleStunPackets) { - EXPECT_TRUE(Send(kStunMessageWithZeroLength, - sizeof(kStunMessageWithZeroLength))); - EXPECT_TRUE(Send(kStunMessageWithZeroLength, - sizeof(kStunMessageWithZeroLength))); - EXPECT_TRUE(Send(kStunMessageWithZeroLength, - sizeof(kStunMessageWithZeroLength))); - EXPECT_TRUE(Send(kStunMessageWithZeroLength, - sizeof(kStunMessageWithZeroLength))); - EXPECT_EQ(4u, recv_packets_.size()); -} - -// Verifying TURN channel data message with zero length. -TEST_F(AsyncStunTCPSocketTest, TestTurnChannelDataWithZeroLength) { - EXPECT_TRUE(Send(kTurnChannelDataMessageWithZeroLength, - sizeof(kTurnChannelDataMessageWithZeroLength))); - EXPECT_EQ(1u, recv_packets_.size()); - EXPECT_TRUE(CheckData(kTurnChannelDataMessageWithZeroLength, - sizeof(kTurnChannelDataMessageWithZeroLength))); -} - -// Verifying TURN channel data message. -TEST_F(AsyncStunTCPSocketTest, TestTurnChannelData) { - EXPECT_TRUE(Send(kTurnChannelDataMessage, - sizeof(kTurnChannelDataMessage))); - EXPECT_EQ(1u, recv_packets_.size()); - EXPECT_TRUE(CheckData(kTurnChannelDataMessage, - sizeof(kTurnChannelDataMessage))); -} - -// Verifying TURN channel messages which needs padding handled properly. -TEST_F(AsyncStunTCPSocketTest, TestTurnChannelDataPadding) { - EXPECT_TRUE(Send(kTurnChannelDataMessageWithOddLength, - sizeof(kTurnChannelDataMessageWithOddLength))); - EXPECT_EQ(1u, recv_packets_.size()); - EXPECT_TRUE(CheckData(kTurnChannelDataMessageWithOddLength, - sizeof(kTurnChannelDataMessageWithOddLength))); -} - -// Verifying stun message with invalid length. -TEST_F(AsyncStunTCPSocketTest, TestStunInvalidLength) { - EXPECT_FALSE(Send(kStunMessageWithInvalidLength, - sizeof(kStunMessageWithInvalidLength))); - EXPECT_EQ(0u, recv_packets_.size()); - - // Modify the message length to larger value. - kStunMessageWithInvalidLength[2] = 0xFF; - kStunMessageWithInvalidLength[3] = 0xFF; - EXPECT_FALSE(Send(kStunMessageWithInvalidLength, - sizeof(kStunMessageWithInvalidLength))); - - // Modify the message length to smaller value. - kStunMessageWithInvalidLength[2] = 0x00; - kStunMessageWithInvalidLength[3] = 0x01; - EXPECT_FALSE(Send(kStunMessageWithInvalidLength, - sizeof(kStunMessageWithInvalidLength))); -} - -// Verifying TURN channel data message with invalid length. -TEST_F(AsyncStunTCPSocketTest, TestTurnChannelDataWithInvalidLength) { - EXPECT_FALSE(Send(kTurnChannelDataMessageWithInvalidLength, - sizeof(kTurnChannelDataMessageWithInvalidLength))); - // Modify the length to larger value. - kTurnChannelDataMessageWithInvalidLength[2] = 0xFF; - kTurnChannelDataMessageWithInvalidLength[3] = 0xF0; - EXPECT_FALSE(Send(kTurnChannelDataMessageWithInvalidLength, - sizeof(kTurnChannelDataMessageWithInvalidLength))); - - // Modify the length to smaller value. - kTurnChannelDataMessageWithInvalidLength[2] = 0x00; - kTurnChannelDataMessageWithInvalidLength[3] = 0x00; - EXPECT_FALSE(Send(kTurnChannelDataMessageWithInvalidLength, - sizeof(kTurnChannelDataMessageWithInvalidLength))); -} - -// Verifying a small buffer handled (dropped) properly. This will be -// a common one for both stun and turn. -TEST_F(AsyncStunTCPSocketTest, TestTooSmallMessageBuffer) { - char data[1]; - EXPECT_FALSE(Send(data, sizeof(data))); -} - -// Verifying a legal large turn message. -TEST_F(AsyncStunTCPSocketTest, TestMaximumSizeTurnPacket) { - // We have problem in getting the SignalWriteEvent from the virtual socket - // server. So increasing the send buffer to 64k. - // TODO(mallinath) - Remove this setting after we fix vss issue. - vss_->set_send_buffer_capacity(64 * 1024); - unsigned char packet[65539]; - packet[0] = 0x40; - packet[1] = 0x00; - packet[2] = 0xFF; - packet[3] = 0xFF; - EXPECT_TRUE(Send(packet, sizeof(packet))); -} - -// Verifying a legal large stun message. -TEST_F(AsyncStunTCPSocketTest, TestMaximumSizeStunPacket) { - // We have problem in getting the SignalWriteEvent from the virtual socket - // server. So increasing the send buffer to 64k. - // TODO(mallinath) - Remove this setting after we fix vss issue. - vss_->set_send_buffer_capacity(64 * 1024); - unsigned char packet[65552]; - packet[0] = 0x00; - packet[1] = 0x01; - packet[2] = 0xFF; - packet[3] = 0xFC; - EXPECT_TRUE(Send(packet, sizeof(packet))); -} - -// Investigate why WriteEvent is not signaled from VSS. -TEST_F(AsyncStunTCPSocketTest, DISABLED_TestWithSmallSendBuffer) { - vss_->set_send_buffer_capacity(1); - Send(kTurnChannelDataMessageWithOddLength, - sizeof(kTurnChannelDataMessageWithOddLength)); - EXPECT_EQ(1u, recv_packets_.size()); - EXPECT_TRUE(CheckData(kTurnChannelDataMessageWithOddLength, - sizeof(kTurnChannelDataMessageWithOddLength))); -} - -} // namespace cricket diff --git a/talk/p2p/base/basicpacketsocketfactory.cc b/talk/p2p/base/basicpacketsocketfactory.cc deleted file mode 100644 index 1e0ddf8fa..000000000 --- a/talk/p2p/base/basicpacketsocketfactory.cc +++ /dev/null @@ -1,221 +0,0 @@ -/* - * libjingle - * Copyright 2011, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "webrtc/p2p/base/basicpacketsocketfactory.h" - -#include "webrtc/p2p/base/asyncstuntcpsocket.h" -#include "webrtc/p2p/base/stun.h" -#include "webrtc/base/asynctcpsocket.h" -#include "webrtc/base/asyncudpsocket.h" -#include "webrtc/base/logging.h" -#include "webrtc/base/nethelpers.h" -#include "webrtc/base/physicalsocketserver.h" -#include "webrtc/base/scoped_ptr.h" -#include "webrtc/base/socketadapters.h" -#include "webrtc/base/ssladapter.h" -#include "webrtc/base/thread.h" - -namespace rtc { - -BasicPacketSocketFactory::BasicPacketSocketFactory() - : thread_(Thread::Current()), - socket_factory_(NULL) { -} - -BasicPacketSocketFactory::BasicPacketSocketFactory(Thread* thread) - : thread_(thread), - socket_factory_(NULL) { -} - -BasicPacketSocketFactory::BasicPacketSocketFactory( - SocketFactory* socket_factory) - : thread_(NULL), - socket_factory_(socket_factory) { -} - -BasicPacketSocketFactory::~BasicPacketSocketFactory() { -} - -AsyncPacketSocket* BasicPacketSocketFactory::CreateUdpSocket( - const SocketAddress& address, int min_port, int max_port) { - // UDP sockets are simple. - rtc::AsyncSocket* socket = - socket_factory()->CreateAsyncSocket( - address.family(), SOCK_DGRAM); - if (!socket) { - return NULL; - } - if (BindSocket(socket, address, min_port, max_port) < 0) { - LOG(LS_ERROR) << "UDP bind failed with error " - << socket->GetError(); - delete socket; - return NULL; - } - return new rtc::AsyncUDPSocket(socket); -} - -AsyncPacketSocket* BasicPacketSocketFactory::CreateServerTcpSocket( - const SocketAddress& local_address, int min_port, int max_port, int opts) { - - // Fail if TLS is required. - if (opts & PacketSocketFactory::OPT_TLS) { - LOG(LS_ERROR) << "TLS support currently is not available."; - return NULL; - } - - rtc::AsyncSocket* socket = - socket_factory()->CreateAsyncSocket(local_address.family(), - SOCK_STREAM); - if (!socket) { - return NULL; - } - - if (BindSocket(socket, local_address, min_port, max_port) < 0) { - LOG(LS_ERROR) << "TCP bind failed with error " - << socket->GetError(); - delete socket; - return NULL; - } - - // If using SSLTCP, wrap the TCP socket in a pseudo-SSL socket. - if (opts & PacketSocketFactory::OPT_SSLTCP) { - ASSERT(!(opts & PacketSocketFactory::OPT_TLS)); - socket = new rtc::AsyncSSLSocket(socket); - } - - // Set TCP_NODELAY (via OPT_NODELAY) for improved performance. - // See http://go/gtalktcpnodelayexperiment - socket->SetOption(rtc::Socket::OPT_NODELAY, 1); - - if (opts & PacketSocketFactory::OPT_STUN) - return new cricket::AsyncStunTCPSocket(socket, true); - - return new rtc::AsyncTCPSocket(socket, true); -} - -AsyncPacketSocket* BasicPacketSocketFactory::CreateClientTcpSocket( - const SocketAddress& local_address, const SocketAddress& remote_address, - const ProxyInfo& proxy_info, const std::string& user_agent, int opts) { - - rtc::AsyncSocket* socket = - socket_factory()->CreateAsyncSocket(local_address.family(), SOCK_STREAM); - if (!socket) { - return NULL; - } - - if (BindSocket(socket, local_address, 0, 0) < 0) { - LOG(LS_ERROR) << "TCP bind failed with error " - << socket->GetError(); - delete socket; - return NULL; - } - - // If using a proxy, wrap the socket in a proxy socket. - if (proxy_info.type == rtc::PROXY_SOCKS5) { - socket = new rtc::AsyncSocksProxySocket( - socket, proxy_info.address, proxy_info.username, proxy_info.password); - } else if (proxy_info.type == rtc::PROXY_HTTPS) { - socket = new rtc::AsyncHttpsProxySocket( - socket, user_agent, proxy_info.address, - proxy_info.username, proxy_info.password); - } - - // If using TLS, wrap the socket in an SSL adapter. - if (opts & PacketSocketFactory::OPT_TLS) { - ASSERT(!(opts & PacketSocketFactory::OPT_SSLTCP)); - - rtc::SSLAdapter* ssl_adapter = rtc::SSLAdapter::Create(socket); - if (!ssl_adapter) { - return NULL; - } - - socket = ssl_adapter; - - if (ssl_adapter->StartSSL(remote_address.hostname().c_str(), false) != 0) { - delete ssl_adapter; - return NULL; - } - - // If using SSLTCP, wrap the TCP socket in a pseudo-SSL socket. - } else if (opts & PacketSocketFactory::OPT_SSLTCP) { - ASSERT(!(opts & PacketSocketFactory::OPT_TLS)); - socket = new rtc::AsyncSSLSocket(socket); - } - - if (socket->Connect(remote_address) < 0) { - LOG(LS_ERROR) << "TCP connect failed with error " - << socket->GetError(); - delete socket; - return NULL; - } - - // Finally, wrap that socket in a TCP or STUN TCP packet socket. - AsyncPacketSocket* tcp_socket; - if (opts & PacketSocketFactory::OPT_STUN) { - tcp_socket = new cricket::AsyncStunTCPSocket(socket, false); - } else { - tcp_socket = new rtc::AsyncTCPSocket(socket, false); - } - - // Set TCP_NODELAY (via OPT_NODELAY) for improved performance. - // See http://go/gtalktcpnodelayexperiment - tcp_socket->SetOption(rtc::Socket::OPT_NODELAY, 1); - - return tcp_socket; -} - -AsyncResolverInterface* BasicPacketSocketFactory::CreateAsyncResolver() { - return new rtc::AsyncResolver(); -} - -int BasicPacketSocketFactory::BindSocket( - AsyncSocket* socket, const SocketAddress& local_address, - int min_port, int max_port) { - int ret = -1; - if (min_port == 0 && max_port == 0) { - // If there's no port range, let the OS pick a port for us. - ret = socket->Bind(local_address); - } else { - // Otherwise, try to find a port in the provided range. - for (int port = min_port; ret < 0 && port <= max_port; ++port) { - ret = socket->Bind(rtc::SocketAddress(local_address.ipaddr(), - port)); - } - } - return ret; -} - -SocketFactory* BasicPacketSocketFactory::socket_factory() { - if (thread_) { - ASSERT(thread_ == Thread::Current()); - return thread_->socketserver(); - } else { - return socket_factory_; - } -} - -} // namespace rtc diff --git a/talk/p2p/base/basicpacketsocketfactory.h b/talk/p2p/base/basicpacketsocketfactory.h deleted file mode 100644 index f895efad7..000000000 --- a/talk/p2p/base/basicpacketsocketfactory.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * libjingle - * Copyright 2011, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef WEBRTC_P2P_BASE_BASICPACKETSOCKETFACTORY_H_ -#define WEBRTC_P2P_BASE_BASICPACKETSOCKETFACTORY_H_ - -#include "webrtc/p2p/base/packetsocketfactory.h" - -namespace rtc { - -class AsyncSocket; -class SocketFactory; -class Thread; - -class BasicPacketSocketFactory : public PacketSocketFactory { - public: - BasicPacketSocketFactory(); - explicit BasicPacketSocketFactory(Thread* thread); - explicit BasicPacketSocketFactory(SocketFactory* socket_factory); - virtual ~BasicPacketSocketFactory(); - - virtual AsyncPacketSocket* CreateUdpSocket( - const SocketAddress& local_address, int min_port, int max_port); - virtual AsyncPacketSocket* CreateServerTcpSocket( - const SocketAddress& local_address, int min_port, int max_port, int opts); - virtual AsyncPacketSocket* CreateClientTcpSocket( - const SocketAddress& local_address, const SocketAddress& remote_address, - const ProxyInfo& proxy_info, const std::string& user_agent, int opts); - - virtual AsyncResolverInterface* CreateAsyncResolver(); - - private: - int BindSocket(AsyncSocket* socket, const SocketAddress& local_address, - int min_port, int max_port); - - SocketFactory* socket_factory(); - - Thread* thread_; - SocketFactory* socket_factory_; -}; - -} // namespace rtc - -#endif // WEBRTC_P2P_BASE_BASICPACKETSOCKETFACTORY_H_ diff --git a/talk/p2p/base/candidate.h b/talk/p2p/base/candidate.h deleted file mode 100644 index 64872f3ce..000000000 --- a/talk/p2p/base/candidate.h +++ /dev/null @@ -1,229 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef WEBRTC_P2P_BASE_CANDIDATE_H_ -#define WEBRTC_P2P_BASE_CANDIDATE_H_ - -#include <limits.h> -#include <math.h> - -#include <iomanip> -#include <sstream> -#include <string> - -#include "webrtc/p2p/base/constants.h" -#include "webrtc/base/basictypes.h" -#include "webrtc/base/socketaddress.h" - -namespace cricket { - -// Candidate for ICE based connection discovery. - -class Candidate { - public: - // TODO: Match the ordering and param list as per RFC 5245 - // candidate-attribute syntax. http://tools.ietf.org/html/rfc5245#section-15.1 - Candidate() : component_(0), priority_(0), generation_(0) {} - Candidate(const std::string& id, int component, const std::string& protocol, - const rtc::SocketAddress& address, uint32 priority, - const std::string& username, const std::string& password, - const std::string& type, const std::string& network_name, - uint32 generation, const std::string& foundation) - : id_(id), component_(component), protocol_(protocol), address_(address), - priority_(priority), username_(username), password_(password), - type_(type), network_name_(network_name), generation_(generation), - foundation_(foundation) { - } - - const std::string & id() const { return id_; } - void set_id(const std::string & id) { id_ = id; } - - int component() const { return component_; } - void set_component(int component) { component_ = component; } - - const std::string & protocol() const { return protocol_; } - void set_protocol(const std::string & protocol) { protocol_ = protocol; } - - const rtc::SocketAddress & address() const { return address_; } - void set_address(const rtc::SocketAddress & address) { - address_ = address; - } - - uint32 priority() const { return priority_; } - void set_priority(const uint32 priority) { priority_ = priority; } - -// void set_type_preference(uint32 type_preference) { -// priority_ = GetPriority(type_preference); -// } - - // Maps old preference (which was 0.0-1.0) to match priority (which - // is 0-2^32-1) to to match RFC 5245, section 4.1.2.1. Also see - // https://docs.google.com/a/google.com/document/d/ - // 1iNQDiwDKMh0NQOrCqbj3DKKRT0Dn5_5UJYhmZO-t7Uc/edit - float preference() const { - // The preference value is clamped to two decimal precision. - return static_cast<float>(((priority_ >> 24) * 100 / 127) / 100.0); - } - - void set_preference(float preference) { - // Limiting priority to UINT_MAX when value exceeds uint32 max. - // This can happen for e.g. when preference = 3. - uint64 prio_val = static_cast<uint64>(preference * 127) << 24; - priority_ = static_cast<uint32>( - rtc::_min(prio_val, static_cast<uint64>(UINT_MAX))); - } - - const std::string & username() const { return username_; } - void set_username(const std::string & username) { username_ = username; } - - const std::string & password() const { return password_; } - void set_password(const std::string & password) { password_ = password; } - - const std::string & type() const { return type_; } - void set_type(const std::string & type) { type_ = type; } - - const std::string & network_name() const { return network_name_; } - void set_network_name(const std::string & network_name) { - network_name_ = network_name; - } - - // Candidates in a new generation replace those in the old generation. - uint32 generation() const { return generation_; } - void set_generation(uint32 generation) { generation_ = generation; } - const std::string generation_str() const { - std::ostringstream ost; - ost << generation_; - return ost.str(); - } - void set_generation_str(const std::string& str) { - std::istringstream ist(str); - ist >> generation_; - } - - const std::string& foundation() const { - return foundation_; - } - - void set_foundation(const std::string& foundation) { - foundation_ = foundation; - } - - const rtc::SocketAddress & related_address() const { - return related_address_; - } - void set_related_address( - const rtc::SocketAddress & related_address) { - related_address_ = related_address; - } - const std::string& tcptype() const { return tcptype_; } - void set_tcptype(const std::string& tcptype){ - tcptype_ = tcptype; - } - - // Determines whether this candidate is equivalent to the given one. - bool IsEquivalent(const Candidate& c) const { - // We ignore the network name, since that is just debug information, and - // the priority, since that should be the same if the rest is (and it's - // a float so equality checking is always worrisome). - return (id_ == c.id_) && - (component_ == c.component_) && - (protocol_ == c.protocol_) && - (address_ == c.address_) && - (username_ == c.username_) && - (password_ == c.password_) && - (type_ == c.type_) && - (generation_ == c.generation_) && - (foundation_ == c.foundation_) && - (related_address_ == c.related_address_); - } - - std::string ToString() const { - return ToStringInternal(false); - } - - std::string ToSensitiveString() const { - return ToStringInternal(true); - } - - uint32 GetPriority(uint32 type_preference, - int network_adapter_preference, - int relay_preference) const { - // RFC 5245 - 4.1.2.1. - // priority = (2^24)*(type preference) + - // (2^8)*(local preference) + - // (2^0)*(256 - component ID) - - // |local_preference| length is 2 bytes, 0-65535 inclusive. - // In our implemenation we will partion local_preference into - // 0 1 - // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - // | NIC Pref | Addr Pref | - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - // NIC Type - Type of the network adapter e.g. 3G/Wifi/Wired. - // Addr Pref - Address preference value as per RFC 3484. - // local preference = (NIC Type << 8 | Addr_Pref) - relay preference. - - int addr_pref = IPAddressPrecedence(address_.ipaddr()); - int local_preference = ((network_adapter_preference << 8) | addr_pref) + - relay_preference; - - return (type_preference << 24) | - (local_preference << 8) | - (256 - component_); - } - - private: - std::string ToStringInternal(bool sensitive) const { - std::ostringstream ost; - std::string address = sensitive ? address_.ToSensitiveString() : - address_.ToString(); - ost << "Cand[" << foundation_ << ":" << component_ << ":" - << protocol_ << ":" << priority_ << ":" - << address << ":" << type_ << ":" << related_address_ << ":" - << username_ << ":" << password_ << "]"; - return ost.str(); - } - - std::string id_; - int component_; - std::string protocol_; - rtc::SocketAddress address_; - uint32 priority_; - std::string username_; - std::string password_; - std::string type_; - std::string network_name_; - uint32 generation_; - std::string foundation_; - rtc::SocketAddress related_address_; - std::string tcptype_; -}; - -} // namespace cricket - -#endif // WEBRTC_P2P_BASE_CANDIDATE_H_ diff --git a/talk/p2p/base/common.h b/talk/p2p/base/common.h deleted file mode 100644 index 0aeb77ed3..000000000 --- a/talk/p2p/base/common.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef WEBRTC_P2P_BASE_COMMON_H_ -#define WEBRTC_P2P_BASE_COMMON_H_ - -#include "webrtc/base/logging.h" - -// Common log description format for jingle messages -#define LOG_J(sev, obj) LOG(sev) << "Jingle:" << obj->ToString() << ": " -#define LOG_JV(sev, obj) LOG_V(sev) << "Jingle:" << obj->ToString() << ": " - -#endif // WEBRTC_P2P_BASE_COMMON_H_ diff --git a/talk/p2p/base/constants.cc b/talk/p2p/base/constants.cc deleted file mode 100644 index 54cfb75bf..000000000 --- a/talk/p2p/base/constants.cc +++ /dev/null @@ -1,274 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "webrtc/p2p/base/constants.h" - -#include <string> - -#include "webrtc/libjingle/xmllite/qname.h" - -namespace cricket { - -const char NS_EMPTY[] = ""; -const char NS_JINGLE[] = "urn:xmpp:jingle:1"; -const char NS_JINGLE_DRAFT[] = "google:jingle"; -const char NS_GINGLE[] = "http://www.google.com/session"; - -// actions (aka <session> or <jingle>) -const buzz::StaticQName QN_ACTION = { NS_EMPTY, "action" }; -const char LN_INITIATOR[] = "initiator"; -const buzz::StaticQName QN_INITIATOR = { NS_EMPTY, LN_INITIATOR }; -const buzz::StaticQName QN_CREATOR = { NS_EMPTY, "creator" }; - -const buzz::StaticQName QN_JINGLE = { NS_JINGLE, "jingle" }; -const buzz::StaticQName QN_JINGLE_CONTENT = { NS_JINGLE, "content" }; -const buzz::StaticQName QN_JINGLE_CONTENT_NAME = { NS_EMPTY, "name" }; -const buzz::StaticQName QN_JINGLE_CONTENT_MEDIA = { NS_EMPTY, "media" }; -const buzz::StaticQName QN_JINGLE_REASON = { NS_JINGLE, "reason" }; -const buzz::StaticQName QN_JINGLE_DRAFT_GROUP = { NS_JINGLE_DRAFT, "group" }; -const buzz::StaticQName QN_JINGLE_DRAFT_GROUP_TYPE = { NS_EMPTY, "type" }; -const char JINGLE_CONTENT_MEDIA_AUDIO[] = "audio"; -const char JINGLE_CONTENT_MEDIA_VIDEO[] = "video"; -const char JINGLE_CONTENT_MEDIA_DATA[] = "data"; -const char JINGLE_ACTION_SESSION_INITIATE[] = "session-initiate"; -const char JINGLE_ACTION_SESSION_INFO[] = "session-info"; -const char JINGLE_ACTION_SESSION_ACCEPT[] = "session-accept"; -const char JINGLE_ACTION_SESSION_TERMINATE[] = "session-terminate"; -const char JINGLE_ACTION_TRANSPORT_INFO[] = "transport-info"; -const char JINGLE_ACTION_TRANSPORT_ACCEPT[] = "transport-accept"; -const char JINGLE_ACTION_DESCRIPTION_INFO[] = "description-info"; - -const buzz::StaticQName QN_GINGLE_SESSION = { NS_GINGLE, "session" }; -const char GINGLE_ACTION_INITIATE[] = "initiate"; -const char GINGLE_ACTION_INFO[] = "info"; -const char GINGLE_ACTION_ACCEPT[] = "accept"; -const char GINGLE_ACTION_REJECT[] = "reject"; -const char GINGLE_ACTION_TERMINATE[] = "terminate"; -const char GINGLE_ACTION_CANDIDATES[] = "candidates"; -const char GINGLE_ACTION_UPDATE[] = "update"; - -const char LN_ERROR[] = "error"; -const buzz::StaticQName QN_GINGLE_REDIRECT = { NS_GINGLE, "redirect" }; -const char STR_REDIRECT_PREFIX[] = "xmpp:"; - -// Session Contents (aka Gingle <session><description> -// or Jingle <content><description>) -const char LN_DESCRIPTION[] = "description"; -const char LN_PAYLOADTYPE[] = "payload-type"; -const buzz::StaticQName QN_ID = { NS_EMPTY, "id" }; -const buzz::StaticQName QN_SID = { NS_EMPTY, "sid" }; -const buzz::StaticQName QN_NAME = { NS_EMPTY, "name" }; -const buzz::StaticQName QN_CLOCKRATE = { NS_EMPTY, "clockrate" }; -const buzz::StaticQName QN_BITRATE = { NS_EMPTY, "bitrate" }; -const buzz::StaticQName QN_CHANNELS = { NS_EMPTY, "channels" }; -const buzz::StaticQName QN_WIDTH = { NS_EMPTY, "width" }; -const buzz::StaticQName QN_HEIGHT = { NS_EMPTY, "height" }; -const buzz::StaticQName QN_FRAMERATE = { NS_EMPTY, "framerate" }; -const char LN_NAME[] = "name"; -const char LN_VALUE[] = "value"; -const buzz::StaticQName QN_PAYLOADTYPE_PARAMETER_NAME = { NS_EMPTY, LN_NAME }; -const buzz::StaticQName QN_PAYLOADTYPE_PARAMETER_VALUE = { NS_EMPTY, LN_VALUE }; -const char PAYLOADTYPE_PARAMETER_BITRATE[] = "bitrate"; -const char PAYLOADTYPE_PARAMETER_HEIGHT[] = "height"; -const char PAYLOADTYPE_PARAMETER_WIDTH[] = "width"; -const char PAYLOADTYPE_PARAMETER_FRAMERATE[] = "framerate"; -const char LN_BANDWIDTH[] = "bandwidth"; - -const char CN_AUDIO[] = "audio"; -const char CN_VIDEO[] = "video"; -const char CN_DATA[] = "data"; -const char CN_OTHER[] = "main"; -// other SDP related strings -const char GROUP_TYPE_BUNDLE[] = "BUNDLE"; - -const char NS_JINGLE_RTP[] = "urn:xmpp:jingle:apps:rtp:1"; -const buzz::StaticQName QN_JINGLE_RTP_CONTENT = - { NS_JINGLE_RTP, LN_DESCRIPTION }; -const buzz::StaticQName QN_SSRC = { NS_EMPTY, "ssrc" }; -const buzz::StaticQName QN_JINGLE_RTP_PAYLOADTYPE = - { NS_JINGLE_RTP, LN_PAYLOADTYPE }; -const buzz::StaticQName QN_JINGLE_RTP_BANDWIDTH = - { NS_JINGLE_RTP, LN_BANDWIDTH }; -const buzz::StaticQName QN_JINGLE_RTCP_MUX = { NS_JINGLE_RTP, "rtcp-mux" }; -const buzz::StaticQName QN_JINGLE_RTCP_FB = { NS_JINGLE_RTP, "rtcp-fb" }; -const buzz::StaticQName QN_SUBTYPE = { NS_EMPTY, "subtype" }; -const buzz::StaticQName QN_PARAMETER = { NS_JINGLE_RTP, "parameter" }; -const buzz::StaticQName QN_JINGLE_RTP_HDREXT = - { NS_JINGLE_RTP, "rtp-hdrext" }; -const buzz::StaticQName QN_URI = { NS_EMPTY, "uri" }; - -const char NS_JINGLE_DRAFT_SCTP[] = "google:jingle:sctp"; -const buzz::StaticQName QN_JINGLE_DRAFT_SCTP_CONTENT = - { NS_JINGLE_DRAFT_SCTP, LN_DESCRIPTION }; -const buzz::StaticQName QN_JINGLE_DRAFT_SCTP_STREAM = - { NS_JINGLE_DRAFT_SCTP, "stream" }; - -const char NS_GINGLE_AUDIO[] = "http://www.google.com/session/phone"; -const buzz::StaticQName QN_GINGLE_AUDIO_CONTENT = - { NS_GINGLE_AUDIO, LN_DESCRIPTION }; -const buzz::StaticQName QN_GINGLE_AUDIO_PAYLOADTYPE = - { NS_GINGLE_AUDIO, LN_PAYLOADTYPE }; -const buzz::StaticQName QN_GINGLE_AUDIO_SRCID = { NS_GINGLE_AUDIO, "src-id" }; -const char NS_GINGLE_VIDEO[] = "http://www.google.com/session/video"; -const buzz::StaticQName QN_GINGLE_VIDEO_CONTENT = - { NS_GINGLE_VIDEO, LN_DESCRIPTION }; -const buzz::StaticQName QN_GINGLE_VIDEO_PAYLOADTYPE = - { NS_GINGLE_VIDEO, LN_PAYLOADTYPE }; -const buzz::StaticQName QN_GINGLE_VIDEO_SRCID = { NS_GINGLE_VIDEO, "src-id" }; -const buzz::StaticQName QN_GINGLE_VIDEO_BANDWIDTH = - { NS_GINGLE_VIDEO, LN_BANDWIDTH }; - -// Crypto support. -const buzz::StaticQName QN_ENCRYPTION = { NS_JINGLE_RTP, "encryption" }; -const buzz::StaticQName QN_ENCRYPTION_REQUIRED = { NS_EMPTY, "required" }; -const buzz::StaticQName QN_CRYPTO = { NS_JINGLE_RTP, "crypto" }; -const buzz::StaticQName QN_GINGLE_AUDIO_CRYPTO_USAGE = - { NS_GINGLE_AUDIO, "usage" }; -const buzz::StaticQName QN_GINGLE_VIDEO_CRYPTO_USAGE = - { NS_GINGLE_VIDEO, "usage" }; -const buzz::StaticQName QN_CRYPTO_SUITE = { NS_EMPTY, "crypto-suite" }; -const buzz::StaticQName QN_CRYPTO_KEY_PARAMS = { NS_EMPTY, "key-params" }; -const buzz::StaticQName QN_CRYPTO_TAG = { NS_EMPTY, "tag" }; -const buzz::StaticQName QN_CRYPTO_SESSION_PARAMS = - { NS_EMPTY, "session-params" }; - -// Transports and candidates. -const char LN_TRANSPORT[] = "transport"; -const char LN_CANDIDATE[] = "candidate"; -const buzz::StaticQName QN_UFRAG = { cricket::NS_EMPTY, "ufrag" }; -const buzz::StaticQName QN_PWD = { cricket::NS_EMPTY, "pwd" }; -const buzz::StaticQName QN_COMPONENT = { cricket::NS_EMPTY, "component" }; -const buzz::StaticQName QN_IP = { cricket::NS_EMPTY, "ip" }; -const buzz::StaticQName QN_PORT = { cricket::NS_EMPTY, "port" }; -const buzz::StaticQName QN_NETWORK = { cricket::NS_EMPTY, "network" }; -const buzz::StaticQName QN_GENERATION = { cricket::NS_EMPTY, "generation" }; -const buzz::StaticQName QN_PRIORITY = { cricket::NS_EMPTY, "priority" }; -const buzz::StaticQName QN_PROTOCOL = { cricket::NS_EMPTY, "protocol" }; -const char ICE_CANDIDATE_TYPE_PEER_STUN[] = "prflx"; -const char ICE_CANDIDATE_TYPE_SERVER_STUN[] = "srflx"; -// Minimum ufrag length is 4 characters as per RFC5245. We chose 16 because -// some internal systems expect username to be 16 bytes. -const int ICE_UFRAG_LENGTH = 16; -// Minimum password length of 22 characters as per RFC5245. We chose 24 because -// some internal systems expect password to be multiple of 4. -const int ICE_PWD_LENGTH = 24; -const size_t ICE_UFRAG_MIN_LENGTH = 4; -const size_t ICE_PWD_MIN_LENGTH = 22; -const size_t ICE_UFRAG_MAX_LENGTH = 255; -const size_t ICE_PWD_MAX_LENGTH = 256; -// TODO: This is media-specific, so might belong -// somewhere like media/base/constants.h -const int ICE_CANDIDATE_COMPONENT_RTP = 1; -const int ICE_CANDIDATE_COMPONENT_RTCP = 2; -const int ICE_CANDIDATE_COMPONENT_DEFAULT = 1; - -const buzz::StaticQName QN_FINGERPRINT = { cricket::NS_EMPTY, "fingerprint" }; -const buzz::StaticQName QN_FINGERPRINT_ALGORITHM = - { cricket::NS_EMPTY, "algorithm" }; -const buzz::StaticQName QN_FINGERPRINT_DIGEST = { cricket::NS_EMPTY, "digest" }; - -const char NS_JINGLE_ICE_UDP[] = "urn:xmpp:jingle:transports:ice-udp:1"; - -const char ICE_OPTION_GICE[] = "google-ice"; -const char NS_GINGLE_P2P[] = "http://www.google.com/transport/p2p"; -const buzz::StaticQName QN_GINGLE_P2P_TRANSPORT = - { NS_GINGLE_P2P, LN_TRANSPORT }; -const buzz::StaticQName QN_GINGLE_P2P_CANDIDATE = - { NS_GINGLE_P2P, LN_CANDIDATE }; -const buzz::StaticQName QN_GINGLE_P2P_UNKNOWN_CHANNEL_NAME = - { NS_GINGLE_P2P, "unknown-channel-name" }; -const buzz::StaticQName QN_GINGLE_CANDIDATE = { NS_GINGLE, LN_CANDIDATE }; -const buzz::StaticQName QN_ADDRESS = { cricket::NS_EMPTY, "address" }; -const buzz::StaticQName QN_USERNAME = { cricket::NS_EMPTY, "username" }; -const buzz::StaticQName QN_PASSWORD = { cricket::NS_EMPTY, "password" }; -const buzz::StaticQName QN_PREFERENCE = { cricket::NS_EMPTY, "preference" }; -const char GICE_CHANNEL_NAME_RTP[] = "rtp"; -const char GICE_CHANNEL_NAME_RTCP[] = "rtcp"; -const char GICE_CHANNEL_NAME_VIDEO_RTP[] = "video_rtp"; -const char GICE_CHANNEL_NAME_VIDEO_RTCP[] = "video_rtcp"; -const char GICE_CHANNEL_NAME_DATA_RTP[] = "data_rtp"; -const char GICE_CHANNEL_NAME_DATA_RTCP[] = "data_rtcp"; - -// terminate reasons and errors -const char JINGLE_ERROR_BAD_REQUEST[] = "bad-request"; -const char JINGLE_ERROR_OUT_OF_ORDER[] = "out-of-order"; -const char JINGLE_ERROR_UNKNOWN_SESSION[] = "unknown-session"; - -// Call terminate reasons from XEP-166 -const char STR_TERMINATE_DECLINE[] = "decline"; -const char STR_TERMINATE_SUCCESS[] = "success"; -const char STR_TERMINATE_ERROR[] = "general-error"; -const char STR_TERMINATE_INCOMPATIBLE_PARAMETERS[] = "incompatible-parameters"; - -// Old terminate reasons used by cricket -const char STR_TERMINATE_CALL_ENDED[] = "call-ended"; -const char STR_TERMINATE_RECIPIENT_UNAVAILABLE[] = "recipient-unavailable"; -const char STR_TERMINATE_RECIPIENT_BUSY[] = "recipient-busy"; -const char STR_TERMINATE_INSUFFICIENT_FUNDS[] = "insufficient-funds"; -const char STR_TERMINATE_NUMBER_MALFORMED[] = "number-malformed"; -const char STR_TERMINATE_NUMBER_DISALLOWED[] = "number-disallowed"; -const char STR_TERMINATE_PROTOCOL_ERROR[] = "protocol-error"; -const char STR_TERMINATE_INTERNAL_SERVER_ERROR[] = "internal-server-error"; -const char STR_TERMINATE_UNKNOWN_ERROR[] = "unknown-error"; - -// Draft view and notify messages. -const char STR_JINGLE_DRAFT_CONTENT_NAME_VIDEO[] = "video"; -const char STR_JINGLE_DRAFT_CONTENT_NAME_AUDIO[] = "audio"; -const buzz::StaticQName QN_NICK = { cricket::NS_EMPTY, "nick" }; -const buzz::StaticQName QN_TYPE = { cricket::NS_EMPTY, "type" }; -const buzz::StaticQName QN_JINGLE_DRAFT_VIEW = { NS_JINGLE_DRAFT, "view" }; -const char STR_JINGLE_DRAFT_VIEW_TYPE_NONE[] = "none"; -const char STR_JINGLE_DRAFT_VIEW_TYPE_STATIC[] = "static"; -const buzz::StaticQName QN_JINGLE_DRAFT_PARAMS = { NS_JINGLE_DRAFT, "params" }; -const buzz::StaticQName QN_JINGLE_DRAFT_STREAMS = { NS_JINGLE_DRAFT, "streams" }; -const buzz::StaticQName QN_JINGLE_DRAFT_STREAM = { NS_JINGLE_DRAFT, "stream" }; -const buzz::StaticQName QN_DISPLAY = { cricket::NS_EMPTY, "display" }; -const buzz::StaticQName QN_CNAME = { cricket::NS_EMPTY, "cname" }; -const buzz::StaticQName QN_JINGLE_DRAFT_SSRC = { NS_JINGLE_DRAFT, "ssrc" }; -const buzz::StaticQName QN_JINGLE_DRAFT_SSRC_GROUP = - { NS_JINGLE_DRAFT, "ssrc-group" }; -const buzz::StaticQName QN_SEMANTICS = { cricket::NS_EMPTY, "semantics" }; -const buzz::StaticQName QN_JINGLE_LEGACY_NOTIFY = { NS_JINGLE_DRAFT, "notify" }; -const buzz::StaticQName QN_JINGLE_LEGACY_SOURCE = { NS_JINGLE_DRAFT, "source" }; - -const char NS_GINGLE_RAW[] = "http://www.google.com/transport/raw-udp"; -const buzz::StaticQName QN_GINGLE_RAW_TRANSPORT = { NS_GINGLE_RAW, "transport" }; -const buzz::StaticQName QN_GINGLE_RAW_CHANNEL = { NS_GINGLE_RAW, "channel" }; - -// old stuff -#ifdef FEATURE_ENABLE_VOICEMAIL -const char NS_VOICEMAIL[] = "http://www.google.com/session/voicemail"; -const buzz::StaticQName QN_VOICEMAIL_REGARDING = { NS_VOICEMAIL, "regarding" }; -#endif - -// From RFC 4145, SDP setup attribute values. -const char CONNECTIONROLE_ACTIVE_STR[] = "active"; -const char CONNECTIONROLE_PASSIVE_STR[] = "passive"; -const char CONNECTIONROLE_ACTPASS_STR[] = "actpass"; -const char CONNECTIONROLE_HOLDCONN_STR[] = "holdconn"; - -} // namespace cricket diff --git a/talk/p2p/base/constants.h b/talk/p2p/base/constants.h deleted file mode 100644 index 9c53b7d8c..000000000 --- a/talk/p2p/base/constants.h +++ /dev/null @@ -1,276 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef WEBRTC_P2P_BASE_CONSTANTS_H_ -#define WEBRTC_P2P_BASE_CONSTANTS_H_ - -#include <string> -#include "webrtc/libjingle/xmllite/qname.h" - -// This file contains constants related to signaling that are used in various -// classes in this directory. - -namespace cricket { - -// NS_ == namespace -// QN_ == buzz::QName (namespace + name) -// LN_ == "local name" == QName::LocalPart() -// these are useful when you need to find a tag -// that has different namespaces (like <description> or <transport>) - -extern const char NS_EMPTY[]; -extern const char NS_JINGLE[]; -extern const char NS_JINGLE_DRAFT[]; -extern const char NS_GINGLE[]; - -enum SignalingProtocol { - PROTOCOL_JINGLE, - PROTOCOL_GINGLE, - PROTOCOL_HYBRID, -}; - -// actions (aka Gingle <session> or Jingle <jingle>) -extern const buzz::StaticQName QN_ACTION; -extern const char LN_INITIATOR[]; -extern const buzz::StaticQName QN_INITIATOR; -extern const buzz::StaticQName QN_CREATOR; - -extern const buzz::StaticQName QN_JINGLE; -extern const buzz::StaticQName QN_JINGLE_CONTENT; -extern const buzz::StaticQName QN_JINGLE_CONTENT_NAME; -extern const buzz::StaticQName QN_JINGLE_CONTENT_MEDIA; -extern const buzz::StaticQName QN_JINGLE_REASON; -extern const buzz::StaticQName QN_JINGLE_DRAFT_GROUP; -extern const buzz::StaticQName QN_JINGLE_DRAFT_GROUP_TYPE; -extern const char JINGLE_CONTENT_MEDIA_AUDIO[]; -extern const char JINGLE_CONTENT_MEDIA_VIDEO[]; -extern const char JINGLE_CONTENT_MEDIA_DATA[]; -extern const char JINGLE_ACTION_SESSION_INITIATE[]; -extern const char JINGLE_ACTION_SESSION_INFO[]; -extern const char JINGLE_ACTION_SESSION_ACCEPT[]; -extern const char JINGLE_ACTION_SESSION_TERMINATE[]; -extern const char JINGLE_ACTION_TRANSPORT_INFO[]; -extern const char JINGLE_ACTION_TRANSPORT_ACCEPT[]; -extern const char JINGLE_ACTION_DESCRIPTION_INFO[]; - -extern const buzz::StaticQName QN_GINGLE_SESSION; -extern const char GINGLE_ACTION_INITIATE[]; -extern const char GINGLE_ACTION_INFO[]; -extern const char GINGLE_ACTION_ACCEPT[]; -extern const char GINGLE_ACTION_REJECT[]; -extern const char GINGLE_ACTION_TERMINATE[]; -extern const char GINGLE_ACTION_CANDIDATES[]; -extern const char GINGLE_ACTION_UPDATE[]; - -extern const char LN_ERROR[]; -extern const buzz::StaticQName QN_GINGLE_REDIRECT; -extern const char STR_REDIRECT_PREFIX[]; - -// Session Contents (aka Gingle <session><description> -// or Jingle <content><description>) -extern const char LN_DESCRIPTION[]; -extern const char LN_PAYLOADTYPE[]; -extern const buzz::StaticQName QN_ID; -extern const buzz::StaticQName QN_SID; -extern const buzz::StaticQName QN_NAME; -extern const buzz::StaticQName QN_CLOCKRATE; -extern const buzz::StaticQName QN_BITRATE; -extern const buzz::StaticQName QN_CHANNELS; -extern const buzz::StaticQName QN_PARAMETER; -extern const char LN_NAME[]; -extern const char LN_VALUE[]; -extern const buzz::StaticQName QN_PAYLOADTYPE_PARAMETER_NAME; -extern const buzz::StaticQName QN_PAYLOADTYPE_PARAMETER_VALUE; -extern const char PAYLOADTYPE_PARAMETER_BITRATE[]; -extern const char PAYLOADTYPE_PARAMETER_HEIGHT[]; -extern const char PAYLOADTYPE_PARAMETER_WIDTH[]; -extern const char PAYLOADTYPE_PARAMETER_FRAMERATE[]; -extern const char LN_BANDWIDTH[]; - -// CN_ == "content name". When we initiate a session, we choose the -// name, and when we receive a Gingle session, we provide default -// names (since Gingle has no content names). But when we receive a -// Jingle call, the content name can be anything, so don't rely on -// these values being the same as the ones received. -extern const char CN_AUDIO[]; -extern const char CN_VIDEO[]; -extern const char CN_DATA[]; -extern const char CN_OTHER[]; -// other SDP related strings -// GN stands for group name -extern const char GROUP_TYPE_BUNDLE[]; - -extern const char NS_JINGLE_RTP[]; -extern const buzz::StaticQName QN_JINGLE_RTP_CONTENT; -extern const buzz::StaticQName QN_SSRC; -extern const buzz::StaticQName QN_JINGLE_RTP_PAYLOADTYPE; -extern const buzz::StaticQName QN_JINGLE_RTP_BANDWIDTH; -extern const buzz::StaticQName QN_JINGLE_RTCP_MUX; -extern const buzz::StaticQName QN_JINGLE_RTCP_FB; -extern const buzz::StaticQName QN_SUBTYPE; -extern const buzz::StaticQName QN_JINGLE_RTP_HDREXT; -extern const buzz::StaticQName QN_URI; - -extern const char NS_JINGLE_DRAFT_SCTP[]; -extern const buzz::StaticQName QN_JINGLE_DRAFT_SCTP_CONTENT; -extern const buzz::StaticQName QN_JINGLE_DRAFT_SCTP_STREAM; - -extern const char NS_GINGLE_AUDIO[]; -extern const buzz::StaticQName QN_GINGLE_AUDIO_CONTENT; -extern const buzz::StaticQName QN_GINGLE_AUDIO_PAYLOADTYPE; -extern const buzz::StaticQName QN_GINGLE_AUDIO_SRCID; -extern const char NS_GINGLE_VIDEO[]; -extern const buzz::StaticQName QN_GINGLE_VIDEO_CONTENT; -extern const buzz::StaticQName QN_GINGLE_VIDEO_PAYLOADTYPE; -extern const buzz::StaticQName QN_GINGLE_VIDEO_SRCID; -extern const buzz::StaticQName QN_GINGLE_VIDEO_BANDWIDTH; - -// Crypto support. -extern const buzz::StaticQName QN_ENCRYPTION; -extern const buzz::StaticQName QN_ENCRYPTION_REQUIRED; -extern const buzz::StaticQName QN_CRYPTO; -extern const buzz::StaticQName QN_GINGLE_AUDIO_CRYPTO_USAGE; -extern const buzz::StaticQName QN_GINGLE_VIDEO_CRYPTO_USAGE; -extern const buzz::StaticQName QN_CRYPTO_SUITE; -extern const buzz::StaticQName QN_CRYPTO_KEY_PARAMS; -extern const buzz::StaticQName QN_CRYPTO_TAG; -extern const buzz::StaticQName QN_CRYPTO_SESSION_PARAMS; - -// Transports and candidates. -extern const char LN_TRANSPORT[]; -extern const char LN_CANDIDATE[]; -extern const buzz::StaticQName QN_JINGLE_P2P_TRANSPORT; -extern const buzz::StaticQName QN_JINGLE_P2P_CANDIDATE; -extern const buzz::StaticQName QN_UFRAG; -extern const buzz::StaticQName QN_COMPONENT; -extern const buzz::StaticQName QN_PWD; -extern const buzz::StaticQName QN_IP; -extern const buzz::StaticQName QN_PORT; -extern const buzz::StaticQName QN_NETWORK; -extern const buzz::StaticQName QN_GENERATION; -extern const buzz::StaticQName QN_PRIORITY; -extern const buzz::StaticQName QN_PROTOCOL; -extern const char ICE_CANDIDATE_TYPE_PEER_STUN[]; -extern const char ICE_CANDIDATE_TYPE_SERVER_STUN[]; -extern const int ICE_UFRAG_LENGTH; -extern const int ICE_PWD_LENGTH; -extern const size_t ICE_UFRAG_MIN_LENGTH; -extern const size_t ICE_PWD_MIN_LENGTH; -extern const size_t ICE_UFRAG_MAX_LENGTH; -extern const size_t ICE_PWD_MAX_LENGTH; -extern const int ICE_CANDIDATE_COMPONENT_RTP; -extern const int ICE_CANDIDATE_COMPONENT_RTCP; -extern const int ICE_CANDIDATE_COMPONENT_DEFAULT; - -extern const buzz::StaticQName QN_FINGERPRINT; -extern const buzz::StaticQName QN_FINGERPRINT_ALGORITHM; -extern const buzz::StaticQName QN_FINGERPRINT_DIGEST; - -extern const char NS_JINGLE_ICE_UDP[]; - -extern const char ICE_OPTION_GICE[]; -extern const char NS_GINGLE_P2P[]; -extern const buzz::StaticQName QN_GINGLE_P2P_TRANSPORT; -extern const buzz::StaticQName QN_GINGLE_P2P_CANDIDATE; -extern const buzz::StaticQName QN_GINGLE_P2P_UNKNOWN_CHANNEL_NAME; -extern const buzz::StaticQName QN_GINGLE_CANDIDATE; -extern const buzz::StaticQName QN_ADDRESS; -extern const buzz::StaticQName QN_USERNAME; -extern const buzz::StaticQName QN_PASSWORD; -extern const buzz::StaticQName QN_PREFERENCE; -extern const char GINGLE_CANDIDATE_TYPE_STUN[]; -extern const char GICE_CHANNEL_NAME_RTP[]; -extern const char GICE_CHANNEL_NAME_RTCP[]; -extern const char GICE_CHANNEL_NAME_VIDEO_RTP[]; -extern const char GICE_CHANNEL_NAME_VIDEO_RTCP[]; -extern const char GICE_CHANNEL_NAME_DATA_RTP[]; -extern const char GICE_CHANNEL_NAME_DATA_RTCP[]; - -extern const char NS_GINGLE_RAW[]; -extern const buzz::StaticQName QN_GINGLE_RAW_TRANSPORT; -extern const buzz::StaticQName QN_GINGLE_RAW_CHANNEL; - -// terminate reasons and errors: see http://xmpp.org/extensions/xep-0166.html -extern const char JINGLE_ERROR_BAD_REQUEST[]; // like parse error -// got transport-info before session-initiate, for example -extern const char JINGLE_ERROR_OUT_OF_ORDER[]; -extern const char JINGLE_ERROR_UNKNOWN_SESSION[]; - -// Call terminate reasons from XEP-166 -extern const char STR_TERMINATE_DECLINE[]; // polite reject -extern const char STR_TERMINATE_SUCCESS[]; // polite hangup -extern const char STR_TERMINATE_ERROR[]; // something bad happened -extern const char STR_TERMINATE_INCOMPATIBLE_PARAMETERS[]; // no codecs? - -// Old terminate reasons used by cricket -extern const char STR_TERMINATE_CALL_ENDED[]; -extern const char STR_TERMINATE_RECIPIENT_UNAVAILABLE[]; -extern const char STR_TERMINATE_RECIPIENT_BUSY[]; -extern const char STR_TERMINATE_INSUFFICIENT_FUNDS[]; -extern const char STR_TERMINATE_NUMBER_MALFORMED[]; -extern const char STR_TERMINATE_NUMBER_DISALLOWED[]; -extern const char STR_TERMINATE_PROTOCOL_ERROR[]; -extern const char STR_TERMINATE_INTERNAL_SERVER_ERROR[]; -extern const char STR_TERMINATE_UNKNOWN_ERROR[]; - -// Draft view and notify messages. -extern const char STR_JINGLE_DRAFT_CONTENT_NAME_VIDEO[]; -extern const char STR_JINGLE_DRAFT_CONTENT_NAME_AUDIO[]; -extern const buzz::StaticQName QN_NICK; -extern const buzz::StaticQName QN_TYPE; -extern const buzz::StaticQName QN_JINGLE_DRAFT_VIEW; -extern const char STR_JINGLE_DRAFT_VIEW_TYPE_NONE[]; -extern const char STR_JINGLE_DRAFT_VIEW_TYPE_STATIC[]; -extern const buzz::StaticQName QN_JINGLE_DRAFT_PARAMS; -extern const buzz::StaticQName QN_WIDTH; -extern const buzz::StaticQName QN_HEIGHT; -extern const buzz::StaticQName QN_FRAMERATE; -extern const buzz::StaticQName QN_JINGLE_DRAFT_STREAM; -extern const buzz::StaticQName QN_JINGLE_DRAFT_STREAMS; -extern const buzz::StaticQName QN_DISPLAY; -extern const buzz::StaticQName QN_CNAME; -extern const buzz::StaticQName QN_JINGLE_DRAFT_SSRC; -extern const buzz::StaticQName QN_JINGLE_DRAFT_SSRC_GROUP; -extern const buzz::StaticQName QN_SEMANTICS; -extern const buzz::StaticQName QN_JINGLE_LEGACY_NOTIFY; -extern const buzz::StaticQName QN_JINGLE_LEGACY_SOURCE; - -// old stuff -#ifdef FEATURE_ENABLE_VOICEMAIL -extern const char NS_VOICEMAIL[]; -extern const buzz::StaticQName QN_VOICEMAIL_REGARDING; -#endif - -// RFC 4145, SDP setup attribute values. -extern const char CONNECTIONROLE_ACTIVE_STR[]; -extern const char CONNECTIONROLE_PASSIVE_STR[]; -extern const char CONNECTIONROLE_ACTPASS_STR[]; -extern const char CONNECTIONROLE_HOLDCONN_STR[]; - -} // namespace cricket - -#endif // WEBRTC_P2P_BASE_CONSTANTS_H_ diff --git a/talk/p2p/base/dtlstransport.h b/talk/p2p/base/dtlstransport.h deleted file mode 100644 index 66b08b4f9..000000000 --- a/talk/p2p/base/dtlstransport.h +++ /dev/null @@ -1,257 +0,0 @@ -/* - * libjingle - * Copyright 2012, Google, Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef WEBRTC_P2P_BASE_DTLSTRANSPORT_H_ -#define WEBRTC_P2P_BASE_DTLSTRANSPORT_H_ - -#include "webrtc/p2p/base/dtlstransportchannel.h" -#include "webrtc/p2p/base/transport.h" - -namespace rtc { -class SSLIdentity; -} - -namespace cricket { - -class PortAllocator; - -// Base should be a descendant of cricket::Transport -template<class Base> -class DtlsTransport : public Base { - public: - DtlsTransport(rtc::Thread* signaling_thread, - rtc::Thread* worker_thread, - const std::string& content_name, - PortAllocator* allocator, - rtc::SSLIdentity* identity) - : Base(signaling_thread, worker_thread, content_name, allocator), - identity_(identity), - secure_role_(rtc::SSL_CLIENT) { - } - - ~DtlsTransport() { - Base::DestroyAllChannels(); - } - virtual void SetIdentity_w(rtc::SSLIdentity* identity) { - identity_ = identity; - } - virtual bool GetIdentity_w(rtc::SSLIdentity** identity) { - if (!identity_) - return false; - - *identity = identity_->GetReference(); - return true; - } - - virtual bool ApplyLocalTransportDescription_w(TransportChannelImpl* channel, - std::string* error_desc) { - rtc::SSLFingerprint* local_fp = - Base::local_description()->identity_fingerprint.get(); - - if (local_fp) { - // Sanity check local fingerprint. - if (identity_) { - rtc::scoped_ptr<rtc::SSLFingerprint> local_fp_tmp( - rtc::SSLFingerprint::Create(local_fp->algorithm, - identity_)); - ASSERT(local_fp_tmp.get() != NULL); - if (!(*local_fp_tmp == *local_fp)) { - std::ostringstream desc; - desc << "Local fingerprint does not match identity. Expected: "; - desc << local_fp_tmp->ToString(); - desc << " Got: " << local_fp->ToString(); - return BadTransportDescription(desc.str(), error_desc); - } - } else { - return BadTransportDescription( - "Local fingerprint provided but no identity available.", - error_desc); - } - } else { - identity_ = NULL; - } - - if (!channel->SetLocalIdentity(identity_)) { - return BadTransportDescription("Failed to set local identity.", - error_desc); - } - - // Apply the description in the base class. - return Base::ApplyLocalTransportDescription_w(channel, error_desc); - } - - virtual bool NegotiateTransportDescription_w(ContentAction local_role, - std::string* error_desc) { - if (!Base::local_description() || !Base::remote_description()) { - const std::string msg = "Local and Remote description must be set before " - "transport descriptions are negotiated"; - return BadTransportDescription(msg, error_desc); - } - - rtc::SSLFingerprint* local_fp = - Base::local_description()->identity_fingerprint.get(); - rtc::SSLFingerprint* remote_fp = - Base::remote_description()->identity_fingerprint.get(); - - if (remote_fp && local_fp) { - remote_fingerprint_.reset(new rtc::SSLFingerprint(*remote_fp)); - - // From RFC 4145, section-4.1, The following are the values that the - // 'setup' attribute can take in an offer/answer exchange: - // Offer Answer - // ________________ - // active passive / holdconn - // passive active / holdconn - // actpass active / passive / holdconn - // holdconn holdconn - // - // Set the role that is most conformant with RFC 5763, Section 5, bullet 1 - // The endpoint MUST use the setup attribute defined in [RFC4145]. - // The endpoint that is the offerer MUST use the setup attribute - // value of setup:actpass and be prepared to receive a client_hello - // before it receives the answer. The answerer MUST use either a - // setup attribute value of setup:active or setup:passive. Note that - // if the answerer uses setup:passive, then the DTLS handshake will - // not begin until the answerer is received, which adds additional - // latency. setup:active allows the answer and the DTLS handshake to - // occur in parallel. Thus, setup:active is RECOMMENDED. Whichever - // party is active MUST initiate a DTLS handshake by sending a - // ClientHello over each flow (host/port quartet). - // IOW - actpass and passive modes should be treated as server and - // active as client. - ConnectionRole local_connection_role = - Base::local_description()->connection_role; - ConnectionRole remote_connection_role = - Base::remote_description()->connection_role; - - bool is_remote_server = false; - if (local_role == CA_OFFER) { - if (local_connection_role != CONNECTIONROLE_ACTPASS) { - return BadTransportDescription( - "Offerer must use actpass value for setup attribute.", - error_desc); - } - - if (remote_connection_role == CONNECTIONROLE_ACTIVE || - remote_connection_role == CONNECTIONROLE_PASSIVE || - remote_connection_role == CONNECTIONROLE_NONE) { - is_remote_server = (remote_connection_role == CONNECTIONROLE_PASSIVE); - } else { - const std::string msg = - "Answerer must use either active or passive value " - "for setup attribute."; - return BadTransportDescription(msg, error_desc); - } - // If remote is NONE or ACTIVE it will act as client. - } else { - if (remote_connection_role != CONNECTIONROLE_ACTPASS && - remote_connection_role != CONNECTIONROLE_NONE) { - return BadTransportDescription( - "Offerer must use actpass value for setup attribute.", - error_desc); - } - - if (local_connection_role == CONNECTIONROLE_ACTIVE || - local_connection_role == CONNECTIONROLE_PASSIVE) { - is_remote_server = (local_connection_role == CONNECTIONROLE_ACTIVE); - } else { - const std::string msg = - "Answerer must use either active or passive value " - "for setup attribute."; - return BadTransportDescription(msg, error_desc); - } - - // If local is passive, local will act as server. - } - - secure_role_ = is_remote_server ? rtc::SSL_CLIENT : - rtc::SSL_SERVER; - - } else if (local_fp && (local_role == CA_ANSWER)) { - return BadTransportDescription( - "Local fingerprint supplied when caller didn't offer DTLS.", - error_desc); - } else { - // We are not doing DTLS - remote_fingerprint_.reset(new rtc::SSLFingerprint( - "", NULL, 0)); - } - - // Now run the negotiation for the base class. - return Base::NegotiateTransportDescription_w(local_role, error_desc); - } - - virtual DtlsTransportChannelWrapper* CreateTransportChannel(int component) { - return new DtlsTransportChannelWrapper( - this, Base::CreateTransportChannel(component)); - } - - virtual void DestroyTransportChannel(TransportChannelImpl* channel) { - // Kind of ugly, but this lets us do the exact inverse of the create. - DtlsTransportChannelWrapper* dtls_channel = - static_cast<DtlsTransportChannelWrapper*>(channel); - TransportChannelImpl* base_channel = dtls_channel->channel(); - delete dtls_channel; - Base::DestroyTransportChannel(base_channel); - } - - virtual bool GetSslRole_w(rtc::SSLRole* ssl_role) const { - ASSERT(ssl_role != NULL); - *ssl_role = secure_role_; - return true; - } - - private: - virtual bool ApplyNegotiatedTransportDescription_w( - TransportChannelImpl* channel, - std::string* error_desc) { - // Set ssl role. Role must be set before fingerprint is applied, which - // initiates DTLS setup. - if (!channel->SetSslRole(secure_role_)) { - return BadTransportDescription("Failed to set ssl role for the channel.", - error_desc); - } - // Apply remote fingerprint. - if (!channel->SetRemoteFingerprint( - remote_fingerprint_->algorithm, - reinterpret_cast<const uint8 *>(remote_fingerprint_-> - digest.data()), - remote_fingerprint_->digest.length())) { - return BadTransportDescription("Failed to apply remote fingerprint.", - error_desc); - } - return Base::ApplyNegotiatedTransportDescription_w(channel, error_desc); - } - - rtc::SSLIdentity* identity_; - rtc::SSLRole secure_role_; - rtc::scoped_ptr<rtc::SSLFingerprint> remote_fingerprint_; -}; - -} // namespace cricket - -#endif // WEBRTC_P2P_BASE_DTLSTRANSPORT_H_ diff --git a/talk/p2p/base/dtlstransportchannel.cc b/talk/p2p/base/dtlstransportchannel.cc deleted file mode 100644 index 78d462202..000000000 --- a/talk/p2p/base/dtlstransportchannel.cc +++ /dev/null @@ -1,641 +0,0 @@ -/* - * libjingle - * Copyright 2011, Google Inc. - * Copyright 2011, RTFM, Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "webrtc/p2p/base/dtlstransportchannel.h" - -#include "webrtc/p2p/base/common.h" -#include "webrtc/base/buffer.h" -#include "webrtc/base/dscp.h" -#include "webrtc/base/messagequeue.h" -#include "webrtc/base/sslstreamadapter.h" -#include "webrtc/base/stream.h" -#include "webrtc/base/thread.h" - -namespace cricket { - -// We don't pull the RTP constants from rtputils.h, to avoid a layer violation. -static const size_t kDtlsRecordHeaderLen = 13; -static const size_t kMaxDtlsPacketLen = 2048; -static const size_t kMinRtpPacketLen = 12; - -static bool IsDtlsPacket(const char* data, size_t len) { - const uint8* u = reinterpret_cast<const uint8*>(data); - return (len >= kDtlsRecordHeaderLen && (u[0] > 19 && u[0] < 64)); -} -static bool IsRtpPacket(const char* data, size_t len) { - const uint8* u = reinterpret_cast<const uint8*>(data); - return (len >= kMinRtpPacketLen && (u[0] & 0xC0) == 0x80); -} - -rtc::StreamResult StreamInterfaceChannel::Read(void* buffer, - size_t buffer_len, - size_t* read, - int* error) { - if (state_ == rtc::SS_CLOSED) - return rtc::SR_EOS; - if (state_ == rtc::SS_OPENING) - return rtc::SR_BLOCK; - - return fifo_.Read(buffer, buffer_len, read, error); -} - -rtc::StreamResult StreamInterfaceChannel::Write(const void* data, - size_t data_len, - size_t* written, - int* error) { - // Always succeeds, since this is an unreliable transport anyway. - // TODO: Should this block if channel_'s temporarily unwritable? - rtc::PacketOptions packet_options; - channel_->SendPacket(static_cast<const char*>(data), data_len, - packet_options); - if (written) { - *written = data_len; - } - return rtc::SR_SUCCESS; -} - -bool StreamInterfaceChannel::OnPacketReceived(const char* data, size_t size) { - // We force a read event here to ensure that we don't overflow our FIFO. - // Under high packet rate this can occur if we wait for the FIFO to post its - // own SE_READ. - bool ret = (fifo_.WriteAll(data, size, NULL, NULL) == rtc::SR_SUCCESS); - if (ret) { - SignalEvent(this, rtc::SE_READ, 0); - } - return ret; -} - -void StreamInterfaceChannel::OnEvent(rtc::StreamInterface* stream, - int sig, int err) { - SignalEvent(this, sig, err); -} - -DtlsTransportChannelWrapper::DtlsTransportChannelWrapper( - Transport* transport, - TransportChannelImpl* channel) - : TransportChannelImpl(channel->content_name(), channel->component()), - transport_(transport), - worker_thread_(rtc::Thread::Current()), - channel_(channel), - downward_(NULL), - dtls_state_(STATE_NONE), - local_identity_(NULL), - ssl_role_(rtc::SSL_CLIENT) { - channel_->SignalReadableState.connect(this, - &DtlsTransportChannelWrapper::OnReadableState); - channel_->SignalWritableState.connect(this, - &DtlsTransportChannelWrapper::OnWritableState); - channel_->SignalReadPacket.connect(this, - &DtlsTransportChannelWrapper::OnReadPacket); - channel_->SignalReadyToSend.connect(this, - &DtlsTransportChannelWrapper::OnReadyToSend); - channel_->SignalRequestSignaling.connect(this, - &DtlsTransportChannelWrapper::OnRequestSignaling); - channel_->SignalCandidateReady.connect(this, - &DtlsTransportChannelWrapper::OnCandidateReady); - channel_->SignalCandidatesAllocationDone.connect(this, - &DtlsTransportChannelWrapper::OnCandidatesAllocationDone); - channel_->SignalRoleConflict.connect(this, - &DtlsTransportChannelWrapper::OnRoleConflict); - channel_->SignalRouteChange.connect(this, - &DtlsTransportChannelWrapper::OnRouteChange); - channel_->SignalConnectionRemoved.connect(this, - &DtlsTransportChannelWrapper::OnConnectionRemoved); -} - -DtlsTransportChannelWrapper::~DtlsTransportChannelWrapper() { -} - -void DtlsTransportChannelWrapper::Connect() { - // We should only get a single call to Connect. - ASSERT(dtls_state_ == STATE_NONE || - dtls_state_ == STATE_OFFERED || - dtls_state_ == STATE_ACCEPTED); - channel_->Connect(); -} - -void DtlsTransportChannelWrapper::Reset() { - channel_->Reset(); - set_writable(false); - set_readable(false); - - // Re-call SetupDtls() - if (!SetupDtls()) { - LOG_J(LS_ERROR, this) << "Error re-initializing DTLS"; - dtls_state_ = STATE_CLOSED; - return; - } - - dtls_state_ = STATE_ACCEPTED; -} - -bool DtlsTransportChannelWrapper::SetLocalIdentity( - rtc::SSLIdentity* identity) { - if (dtls_state_ != STATE_NONE) { - if (identity == local_identity_) { - // This may happen during renegotiation. - LOG_J(LS_INFO, this) << "Ignoring identical DTLS identity"; - return true; - } else { - LOG_J(LS_ERROR, this) << "Can't change DTLS local identity in this state"; - return false; - } - } - - if (identity) { - local_identity_ = identity; - dtls_state_ = STATE_OFFERED; - } else { - LOG_J(LS_INFO, this) << "NULL DTLS identity supplied. Not doing DTLS"; - } - - return true; -} - -bool DtlsTransportChannelWrapper::GetLocalIdentity( - rtc::SSLIdentity** identity) const { - if (!local_identity_) - return false; - - *identity = local_identity_->GetReference(); - return true; -} - -bool DtlsTransportChannelWrapper::SetSslRole(rtc::SSLRole role) { - if (dtls_state_ == STATE_OPEN) { - if (ssl_role_ != role) { - LOG(LS_ERROR) << "SSL Role can't be reversed after the session is setup."; - return false; - } - return true; - } - - ssl_role_ = role; - return true; -} - -bool DtlsTransportChannelWrapper::GetSslRole(rtc::SSLRole* role) const { - *role = ssl_role_; - return true; -} - -bool DtlsTransportChannelWrapper::SetRemoteFingerprint( - const std::string& digest_alg, - const uint8* digest, - size_t digest_len) { - - rtc::Buffer remote_fingerprint_value(digest, digest_len); - - if (dtls_state_ != STATE_NONE && - remote_fingerprint_value_ == remote_fingerprint_value && - !digest_alg.empty()) { - // This may happen during renegotiation. - LOG_J(LS_INFO, this) << "Ignoring identical remote DTLS fingerprint"; - return true; - } - - // Allow SetRemoteFingerprint with a NULL digest even if SetLocalIdentity - // hasn't been called. - if (dtls_state_ > STATE_OFFERED || - (dtls_state_ == STATE_NONE && !digest_alg.empty())) { - LOG_J(LS_ERROR, this) << "Can't set DTLS remote settings in this state."; - return false; - } - - if (digest_alg.empty()) { - LOG_J(LS_INFO, this) << "Other side didn't support DTLS."; - dtls_state_ = STATE_NONE; - return true; - } - - // At this point we know we are doing DTLS - remote_fingerprint_value.TransferTo(&remote_fingerprint_value_); - remote_fingerprint_algorithm_ = digest_alg; - - if (!SetupDtls()) { - dtls_state_ = STATE_CLOSED; - return false; - } - - dtls_state_ = STATE_ACCEPTED; - return true; -} - -bool DtlsTransportChannelWrapper::GetRemoteCertificate( - rtc::SSLCertificate** cert) const { - if (!dtls_) - return false; - - return dtls_->GetPeerCertificate(cert); -} - -bool DtlsTransportChannelWrapper::SetupDtls() { - StreamInterfaceChannel* downward = - new StreamInterfaceChannel(worker_thread_, channel_); - - dtls_.reset(rtc::SSLStreamAdapter::Create(downward)); - if (!dtls_) { - LOG_J(LS_ERROR, this) << "Failed to create DTLS adapter."; - delete downward; - return false; - } - - downward_ = downward; - - dtls_->SetIdentity(local_identity_->GetReference()); - dtls_->SetMode(rtc::SSL_MODE_DTLS); - dtls_->SetServerRole(ssl_role_); - dtls_->SignalEvent.connect(this, &DtlsTransportChannelWrapper::OnDtlsEvent); - if (!dtls_->SetPeerCertificateDigest( - remote_fingerprint_algorithm_, - reinterpret_cast<unsigned char *>(remote_fingerprint_value_.data()), - remote_fingerprint_value_.length())) { - LOG_J(LS_ERROR, this) << "Couldn't set DTLS certificate digest."; - return false; - } - - // Set up DTLS-SRTP, if it's been enabled. - if (!srtp_ciphers_.empty()) { - if (!dtls_->SetDtlsSrtpCiphers(srtp_ciphers_)) { - LOG_J(LS_ERROR, this) << "Couldn't set DTLS-SRTP ciphers."; - return false; - } - } else { - LOG_J(LS_INFO, this) << "Not using DTLS."; - } - - LOG_J(LS_INFO, this) << "DTLS setup complete."; - return true; -} - -bool DtlsTransportChannelWrapper::SetSrtpCiphers( - const std::vector<std::string>& ciphers) { - if (srtp_ciphers_ == ciphers) - return true; - - if (dtls_state_ == STATE_STARTED) { - LOG(LS_WARNING) << "Ignoring new SRTP ciphers while DTLS is negotiating"; - return true; - } - - if (dtls_state_ == STATE_OPEN) { - // We don't support DTLS renegotiation currently. If new set of srtp ciphers - // are different than what's being used currently, we will not use it. - // So for now, let's be happy (or sad) with a warning message. - std::string current_srtp_cipher; - if (!dtls_->GetDtlsSrtpCipher(¤t_srtp_cipher)) { - LOG(LS_ERROR) << "Failed to get the current SRTP cipher for DTLS channel"; - return false; - } - const std::vector<std::string>::const_iterator iter = - std::find(ciphers.begin(), ciphers.end(), current_srtp_cipher); - if (iter == ciphers.end()) { - std::string requested_str; - for (size_t i = 0; i < ciphers.size(); ++i) { - requested_str.append(" "); - requested_str.append(ciphers[i]); - requested_str.append(" "); - } - LOG(LS_WARNING) << "Ignoring new set of SRTP ciphers, as DTLS " - << "renegotiation is not supported currently " - << "current cipher = " << current_srtp_cipher << " and " - << "requested = " << "[" << requested_str << "]"; - } - return true; - } - - if (dtls_state_ != STATE_NONE && - dtls_state_ != STATE_OFFERED && - dtls_state_ != STATE_ACCEPTED) { - ASSERT(false); - return false; - } - - srtp_ciphers_ = ciphers; - return true; -} - -bool DtlsTransportChannelWrapper::GetSrtpCipher(std::string* cipher) { - if (dtls_state_ != STATE_OPEN) { - return false; - } - - return dtls_->GetDtlsSrtpCipher(cipher); -} - - -// Called from upper layers to send a media packet. -int DtlsTransportChannelWrapper::SendPacket( - const char* data, size_t size, - const rtc::PacketOptions& options, int flags) { - int result = -1; - - switch (dtls_state_) { - case STATE_OFFERED: - // We don't know if we are doing DTLS yet, so we can't send a packet. - // TODO(ekr@rtfm.com): assert here? - result = -1; - break; - - case STATE_STARTED: - case STATE_ACCEPTED: - // Can't send data until the connection is active - result = -1; - break; - - case STATE_OPEN: - if (flags & PF_SRTP_BYPASS) { - ASSERT(!srtp_ciphers_.empty()); - if (!IsRtpPacket(data, size)) { - result = -1; - break; - } - - result = channel_->SendPacket(data, size, options); - } else { - result = (dtls_->WriteAll(data, size, NULL, NULL) == - rtc::SR_SUCCESS) ? static_cast<int>(size) : -1; - } - break; - // Not doing DTLS. - case STATE_NONE: - result = channel_->SendPacket(data, size, options); - break; - - case STATE_CLOSED: // Can't send anything when we're closed. - return -1; - } - - return result; -} - -// The state transition logic here is as follows: -// (1) If we're not doing DTLS-SRTP, then the state is just the -// state of the underlying impl() -// (2) If we're doing DTLS-SRTP: -// - Prior to the DTLS handshake, the state is neither readable or -// writable -// - When the impl goes writable for the first time we -// start the DTLS handshake -// - Once the DTLS handshake completes, the state is that of the -// impl again -void DtlsTransportChannelWrapper::OnReadableState(TransportChannel* channel) { - ASSERT(rtc::Thread::Current() == worker_thread_); - ASSERT(channel == channel_); - LOG_J(LS_VERBOSE, this) - << "DTLSTransportChannelWrapper: channel readable state changed."; - - if (dtls_state_ == STATE_NONE || dtls_state_ == STATE_OPEN) { - set_readable(channel_->readable()); - // Note: SignalReadableState fired by set_readable. - } -} - -void DtlsTransportChannelWrapper::OnWritableState(TransportChannel* channel) { - ASSERT(rtc::Thread::Current() == worker_thread_); - ASSERT(channel == channel_); - LOG_J(LS_VERBOSE, this) - << "DTLSTransportChannelWrapper: channel writable state changed."; - - switch (dtls_state_) { - case STATE_NONE: - case STATE_OPEN: - set_writable(channel_->writable()); - // Note: SignalWritableState fired by set_writable. - break; - - case STATE_OFFERED: - // Do nothing - break; - - case STATE_ACCEPTED: - if (!MaybeStartDtls()) { - // This should never happen: - // Because we are operating in a nonblocking mode and all - // incoming packets come in via OnReadPacket(), which rejects - // packets in this state, the incoming queue must be empty. We - // ignore write errors, thus any errors must be because of - // configuration and therefore are our fault. - // Note that in non-debug configurations, failure in - // MaybeStartDtls() changes the state to STATE_CLOSED. - ASSERT(false); - } - break; - - case STATE_STARTED: - // Do nothing - break; - - case STATE_CLOSED: - // Should not happen. Do nothing - break; - } -} - -void DtlsTransportChannelWrapper::OnReadPacket( - TransportChannel* channel, const char* data, size_t size, - const rtc::PacketTime& packet_time, int flags) { - ASSERT(rtc::Thread::Current() == worker_thread_); - ASSERT(channel == channel_); - ASSERT(flags == 0); - - switch (dtls_state_) { - case STATE_NONE: - // We are not doing DTLS - SignalReadPacket(this, data, size, packet_time, 0); - break; - - case STATE_OFFERED: - // Currently drop the packet, but we might in future - // decide to take this as evidence that the other - // side is ready to do DTLS and start the handshake - // on our end - LOG_J(LS_WARNING, this) << "Received packet before we know if we are " - << "doing DTLS or not; dropping."; - break; - - case STATE_ACCEPTED: - // Drop packets received before DTLS has actually started - LOG_J(LS_INFO, this) << "Dropping packet received before DTLS started."; - break; - - case STATE_STARTED: - case STATE_OPEN: - // We should only get DTLS or SRTP packets; STUN's already been demuxed. - // Is this potentially a DTLS packet? - if (IsDtlsPacket(data, size)) { - if (!HandleDtlsPacket(data, size)) { - LOG_J(LS_ERROR, this) << "Failed to handle DTLS packet."; - return; - } - } else { - // Not a DTLS packet; our handshake should be complete by now. - if (dtls_state_ != STATE_OPEN) { - LOG_J(LS_ERROR, this) << "Received non-DTLS packet before DTLS " - << "complete."; - return; - } - - // And it had better be a SRTP packet. - if (!IsRtpPacket(data, size)) { - LOG_J(LS_ERROR, this) << "Received unexpected non-DTLS packet."; - return; - } - - // Sanity check. - ASSERT(!srtp_ciphers_.empty()); - - // Signal this upwards as a bypass packet. - SignalReadPacket(this, data, size, packet_time, PF_SRTP_BYPASS); - } - break; - case STATE_CLOSED: - // This shouldn't be happening. Drop the packet - break; - } -} - -void DtlsTransportChannelWrapper::OnReadyToSend(TransportChannel* channel) { - if (writable()) { - SignalReadyToSend(this); - } -} - -void DtlsTransportChannelWrapper::OnDtlsEvent(rtc::StreamInterface* dtls, - int sig, int err) { - ASSERT(rtc::Thread::Current() == worker_thread_); - ASSERT(dtls == dtls_.get()); - if (sig & rtc::SE_OPEN) { - // This is the first time. - LOG_J(LS_INFO, this) << "DTLS handshake complete."; - if (dtls_->GetState() == rtc::SS_OPEN) { - // The check for OPEN shouldn't be necessary but let's make - // sure we don't accidentally frob the state if it's closed. - dtls_state_ = STATE_OPEN; - - set_readable(true); - set_writable(true); - } - } - if (sig & rtc::SE_READ) { - char buf[kMaxDtlsPacketLen]; - size_t read; - if (dtls_->Read(buf, sizeof(buf), &read, NULL) == rtc::SR_SUCCESS) { - SignalReadPacket(this, buf, read, rtc::CreatePacketTime(0), 0); - } - } - if (sig & rtc::SE_CLOSE) { - ASSERT(sig == rtc::SE_CLOSE); // SE_CLOSE should be by itself. - if (!err) { - LOG_J(LS_INFO, this) << "DTLS channel closed"; - } else { - LOG_J(LS_INFO, this) << "DTLS channel error, code=" << err; - } - - set_readable(false); - set_writable(false); - dtls_state_ = STATE_CLOSED; - } -} - -bool DtlsTransportChannelWrapper::MaybeStartDtls() { - if (channel_->writable()) { - if (dtls_->StartSSLWithPeer()) { - LOG_J(LS_ERROR, this) << "Couldn't start DTLS handshake"; - dtls_state_ = STATE_CLOSED; - return false; - } - LOG_J(LS_INFO, this) - << "DtlsTransportChannelWrapper: Started DTLS handshake"; - - dtls_state_ = STATE_STARTED; - } - return true; -} - -// Called from OnReadPacket when a DTLS packet is received. -bool DtlsTransportChannelWrapper::HandleDtlsPacket(const char* data, - size_t size) { - // Sanity check we're not passing junk that - // just looks like DTLS. - const uint8* tmp_data = reinterpret_cast<const uint8* >(data); - size_t tmp_size = size; - while (tmp_size > 0) { - if (tmp_size < kDtlsRecordHeaderLen) - return false; // Too short for the header - - size_t record_len = (tmp_data[11] << 8) | (tmp_data[12]); - if ((record_len + kDtlsRecordHeaderLen) > tmp_size) - return false; // Body too short - - tmp_data += record_len + kDtlsRecordHeaderLen; - tmp_size -= record_len + kDtlsRecordHeaderLen; - } - - // Looks good. Pass to the SIC which ends up being passed to - // the DTLS stack. - return downward_->OnPacketReceived(data, size); -} - -void DtlsTransportChannelWrapper::OnRequestSignaling( - TransportChannelImpl* channel) { - ASSERT(channel == channel_); - SignalRequestSignaling(this); -} - -void DtlsTransportChannelWrapper::OnCandidateReady( - TransportChannelImpl* channel, const Candidate& c) { - ASSERT(channel == channel_); - SignalCandidateReady(this, c); -} - -void DtlsTransportChannelWrapper::OnCandidatesAllocationDone( - TransportChannelImpl* channel) { - ASSERT(channel == channel_); - SignalCandidatesAllocationDone(this); -} - -void DtlsTransportChannelWrapper::OnRoleConflict( - TransportChannelImpl* channel) { - ASSERT(channel == channel_); - SignalRoleConflict(this); -} - -void DtlsTransportChannelWrapper::OnRouteChange( - TransportChannel* channel, const Candidate& candidate) { - ASSERT(channel == channel_); - SignalRouteChange(this, candidate); -} - -void DtlsTransportChannelWrapper::OnConnectionRemoved( - TransportChannelImpl* channel) { - ASSERT(channel == channel_); - SignalConnectionRemoved(this); -} - -} // namespace cricket diff --git a/talk/p2p/base/dtlstransportchannel.h b/talk/p2p/base/dtlstransportchannel.h deleted file mode 100644 index 670601328..000000000 --- a/talk/p2p/base/dtlstransportchannel.h +++ /dev/null @@ -1,264 +0,0 @@ -/* - * libjingle - * Copyright 2011, Google Inc. - * Copyright 2011, RTFM, Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef WEBRTC_P2P_BASE_DTLSTRANSPORTCHANNEL_H_ -#define WEBRTC_P2P_BASE_DTLSTRANSPORTCHANNEL_H_ - -#include <string> -#include <vector> - -#include "webrtc/p2p/base/transportchannelimpl.h" -#include "webrtc/base/buffer.h" -#include "webrtc/base/scoped_ptr.h" -#include "webrtc/base/sslstreamadapter.h" -#include "webrtc/base/stream.h" - -namespace cricket { - -// A bridge between a packet-oriented/channel-type interface on -// the bottom and a StreamInterface on the top. -class StreamInterfaceChannel : public rtc::StreamInterface, - public sigslot::has_slots<> { - public: - StreamInterfaceChannel(rtc::Thread* owner, TransportChannel* channel) - : channel_(channel), - state_(rtc::SS_OPEN), - fifo_(kFifoSize, owner) { - fifo_.SignalEvent.connect(this, &StreamInterfaceChannel::OnEvent); - } - - // Push in a packet; this gets pulled out from Read(). - bool OnPacketReceived(const char* data, size_t size); - - // Implementations of StreamInterface - virtual rtc::StreamState GetState() const { return state_; } - virtual void Close() { state_ = rtc::SS_CLOSED; } - virtual rtc::StreamResult Read(void* buffer, size_t buffer_len, - size_t* read, int* error); - virtual rtc::StreamResult Write(const void* data, size_t data_len, - size_t* written, int* error); - - private: - static const size_t kFifoSize = 8192; - - // Forward events - virtual void OnEvent(rtc::StreamInterface* stream, int sig, int err); - - TransportChannel* channel_; // owned by DtlsTransportChannelWrapper - rtc::StreamState state_; - rtc::FifoBuffer fifo_; - - DISALLOW_COPY_AND_ASSIGN(StreamInterfaceChannel); -}; - - -// This class provides a DTLS SSLStreamAdapter inside a TransportChannel-style -// packet-based interface, wrapping an existing TransportChannel instance -// (e.g a P2PTransportChannel) -// Here's the way this works: -// -// DtlsTransportChannelWrapper { -// SSLStreamAdapter* dtls_ { -// StreamInterfaceChannel downward_ { -// TransportChannelImpl* channel_; -// } -// } -// } -// -// - Data which comes into DtlsTransportChannelWrapper from the underlying -// channel_ via OnReadPacket() is checked for whether it is DTLS -// or not, and if it is, is passed to DtlsTransportChannelWrapper:: -// HandleDtlsPacket, which pushes it into to downward_. -// dtls_ is listening for events on downward_, so it immediately calls -// downward_->Read(). -// -// - Data written to DtlsTransportChannelWrapper is passed either to -// downward_ or directly to channel_, depending on whether DTLS is -// negotiated and whether the flags include PF_SRTP_BYPASS -// -// - The SSLStreamAdapter writes to downward_->Write() -// which translates it into packet writes on channel_. -class DtlsTransportChannelWrapper : public TransportChannelImpl { - public: - enum State { - STATE_NONE, // No state or rejected. - STATE_OFFERED, // Our identity has been set. - STATE_ACCEPTED, // The other side sent a fingerprint. - STATE_STARTED, // We are negotiating. - STATE_OPEN, // Negotiation complete. - STATE_CLOSED // Connection closed. - }; - - // The parameters here are: - // transport -- the DtlsTransport that created us - // channel -- the TransportChannel we are wrapping - DtlsTransportChannelWrapper(Transport* transport, - TransportChannelImpl* channel); - virtual ~DtlsTransportChannelWrapper(); - - virtual void SetIceRole(IceRole role) { - channel_->SetIceRole(role); - } - virtual IceRole GetIceRole() const { - return channel_->GetIceRole(); - } - virtual size_t GetConnectionCount() const { - return channel_->GetConnectionCount(); - } - virtual bool SetLocalIdentity(rtc::SSLIdentity *identity); - virtual bool GetLocalIdentity(rtc::SSLIdentity** identity) const; - - virtual bool SetRemoteFingerprint(const std::string& digest_alg, - const uint8* digest, - size_t digest_len); - virtual bool IsDtlsActive() const { return dtls_state_ != STATE_NONE; } - - // Called to send a packet (via DTLS, if turned on). - virtual int SendPacket(const char* data, size_t size, - const rtc::PacketOptions& options, - int flags); - - // TransportChannel calls that we forward to the wrapped transport. - virtual int SetOption(rtc::Socket::Option opt, int value) { - return channel_->SetOption(opt, value); - } - virtual int GetError() { - return channel_->GetError(); - } - virtual bool GetStats(ConnectionInfos* infos) { - return channel_->GetStats(infos); - } - virtual const std::string SessionId() const { - return channel_->SessionId(); - } - - // Set up the ciphers to use for DTLS-SRTP. If this method is not called - // before DTLS starts, or |ciphers| is empty, SRTP keys won't be negotiated. - // This method should be called before SetupDtls. - virtual bool SetSrtpCiphers(const std::vector<std::string>& ciphers); - - // Find out which DTLS-SRTP cipher was negotiated - virtual bool GetSrtpCipher(std::string* cipher); - - virtual bool GetSslRole(rtc::SSLRole* role) const; - virtual bool SetSslRole(rtc::SSLRole role); - - // Once DTLS has been established, this method retrieves the certificate in - // use by the remote peer, for use in external identity verification. - virtual bool GetRemoteCertificate(rtc::SSLCertificate** cert) const; - - // Once DTLS has established (i.e., this channel is writable), this method - // extracts the keys negotiated during the DTLS handshake, for use in external - // encryption. DTLS-SRTP uses this to extract the needed SRTP keys. - // See the SSLStreamAdapter documentation for info on the specific parameters. - virtual bool ExportKeyingMaterial(const std::string& label, - const uint8* context, - size_t context_len, - bool use_context, - uint8* result, - size_t result_len) { - return (dtls_.get()) ? dtls_->ExportKeyingMaterial(label, context, - context_len, - use_context, - result, result_len) - : false; - } - - // TransportChannelImpl calls. - virtual Transport* GetTransport() { - return transport_; - } - virtual void SetIceTiebreaker(uint64 tiebreaker) { - channel_->SetIceTiebreaker(tiebreaker); - } - virtual bool GetIceProtocolType(IceProtocolType* type) const { - return channel_->GetIceProtocolType(type); - } - virtual void SetIceProtocolType(IceProtocolType type) { - channel_->SetIceProtocolType(type); - } - virtual void SetIceCredentials(const std::string& ice_ufrag, - const std::string& ice_pwd) { - channel_->SetIceCredentials(ice_ufrag, ice_pwd); - } - virtual void SetRemoteIceCredentials(const std::string& ice_ufrag, - const std::string& ice_pwd) { - channel_->SetRemoteIceCredentials(ice_ufrag, ice_pwd); - } - virtual void SetRemoteIceMode(IceMode mode) { - channel_->SetRemoteIceMode(mode); - } - - virtual void Connect(); - virtual void Reset(); - - virtual void OnSignalingReady() { - channel_->OnSignalingReady(); - } - virtual void OnCandidate(const Candidate& candidate) { - channel_->OnCandidate(candidate); - } - - // Needed by DtlsTransport. - TransportChannelImpl* channel() { return channel_; } - - private: - void OnReadableState(TransportChannel* channel); - void OnWritableState(TransportChannel* channel); - void OnReadPacket(TransportChannel* channel, const char* data, size_t size, - const rtc::PacketTime& packet_time, int flags); - void OnReadyToSend(TransportChannel* channel); - void OnDtlsEvent(rtc::StreamInterface* stream_, int sig, int err); - bool SetupDtls(); - bool MaybeStartDtls(); - bool HandleDtlsPacket(const char* data, size_t size); - void OnRequestSignaling(TransportChannelImpl* channel); - void OnCandidateReady(TransportChannelImpl* channel, const Candidate& c); - void OnCandidatesAllocationDone(TransportChannelImpl* channel); - void OnRoleConflict(TransportChannelImpl* channel); - void OnRouteChange(TransportChannel* channel, const Candidate& candidate); - void OnConnectionRemoved(TransportChannelImpl* channel); - - Transport* transport_; // The transport_ that created us. - rtc::Thread* worker_thread_; // Everything should occur on this thread. - TransportChannelImpl* channel_; // Underlying channel, owned by transport_. - rtc::scoped_ptr<rtc::SSLStreamAdapter> dtls_; // The DTLS stream - StreamInterfaceChannel* downward_; // Wrapper for channel_, owned by dtls_. - std::vector<std::string> srtp_ciphers_; // SRTP ciphers to use with DTLS. - State dtls_state_; - rtc::SSLIdentity* local_identity_; - rtc::SSLRole ssl_role_; - rtc::Buffer remote_fingerprint_value_; - std::string remote_fingerprint_algorithm_; - - DISALLOW_COPY_AND_ASSIGN(DtlsTransportChannelWrapper); -}; - -} // namespace cricket - -#endif // WEBRTC_P2P_BASE_DTLSTRANSPORTCHANNEL_H_ diff --git a/talk/p2p/base/dtlstransportchannel_unittest.cc b/talk/p2p/base/dtlstransportchannel_unittest.cc deleted file mode 100644 index 44854c71b..000000000 --- a/talk/p2p/base/dtlstransportchannel_unittest.cc +++ /dev/null @@ -1,841 +0,0 @@ -/* - * libjingle - * Copyright 2011, Google Inc. - * Copyright 2011, RTFM, Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <set> - -#include "webrtc/p2p/base/dtlstransport.h" -#include "webrtc/p2p/base/fakesession.h" -#include "webrtc/base/common.h" -#include "webrtc/base/dscp.h" -#include "webrtc/base/gunit.h" -#include "webrtc/base/helpers.h" -#include "webrtc/base/scoped_ptr.h" -#include "webrtc/base/ssladapter.h" -#include "webrtc/base/sslidentity.h" -#include "webrtc/base/sslstreamadapter.h" -#include "webrtc/base/stringutils.h" -#include "webrtc/base/thread.h" - -#define MAYBE_SKIP_TEST(feature) \ - if (!(rtc::SSLStreamAdapter::feature())) { \ - LOG(LS_INFO) << "Feature disabled... skipping"; \ - return; \ - } - -static const char AES_CM_128_HMAC_SHA1_80[] = "AES_CM_128_HMAC_SHA1_80"; -static const char kIceUfrag1[] = "TESTICEUFRAG0001"; -static const char kIcePwd1[] = "TESTICEPWD00000000000001"; -static const size_t kPacketNumOffset = 8; -static const size_t kPacketHeaderLen = 12; - -static bool IsRtpLeadByte(uint8 b) { - return ((b & 0xC0) == 0x80); -} - -using cricket::ConnectionRole; - -enum Flags { NF_REOFFER = 0x1, NF_EXPECT_FAILURE = 0x2 }; - -class DtlsTestClient : public sigslot::has_slots<> { - public: - DtlsTestClient(const std::string& name, - rtc::Thread* signaling_thread, - rtc::Thread* worker_thread) : - name_(name), - signaling_thread_(signaling_thread), - worker_thread_(worker_thread), - protocol_(cricket::ICEPROTO_GOOGLE), - packet_size_(0), - use_dtls_srtp_(false), - negotiated_dtls_(false), - received_dtls_client_hello_(false), - received_dtls_server_hello_(false) { - } - void SetIceProtocol(cricket::TransportProtocol proto) { - protocol_ = proto; - } - void CreateIdentity() { - identity_.reset(rtc::SSLIdentity::Generate(name_)); - } - rtc::SSLIdentity* identity() { return identity_.get(); } - void SetupSrtp() { - ASSERT(identity_.get() != NULL); - use_dtls_srtp_ = true; - } - void SetupChannels(int count, cricket::IceRole role) { - transport_.reset(new cricket::DtlsTransport<cricket::FakeTransport>( - signaling_thread_, worker_thread_, "dtls content name", NULL, - identity_.get())); - transport_->SetAsync(true); - transport_->SetIceRole(role); - transport_->SetIceTiebreaker( - (role == cricket::ICEROLE_CONTROLLING) ? 1 : 2); - transport_->SignalWritableState.connect(this, - &DtlsTestClient::OnTransportWritableState); - - for (int i = 0; i < count; ++i) { - cricket::DtlsTransportChannelWrapper* channel = - static_cast<cricket::DtlsTransportChannelWrapper*>( - transport_->CreateChannel(i)); - ASSERT_TRUE(channel != NULL); - channel->SignalWritableState.connect(this, - &DtlsTestClient::OnTransportChannelWritableState); - channel->SignalReadPacket.connect(this, - &DtlsTestClient::OnTransportChannelReadPacket); - channels_.push_back(channel); - - // Hook the raw packets so that we can verify they are encrypted. - channel->channel()->SignalReadPacket.connect( - this, &DtlsTestClient::OnFakeTransportChannelReadPacket); - } - } - - cricket::Transport* transport() { return transport_.get(); } - - cricket::FakeTransportChannel* GetFakeChannel(int component) { - cricket::TransportChannelImpl* ch = transport_->GetChannel(component); - cricket::DtlsTransportChannelWrapper* wrapper = - static_cast<cricket::DtlsTransportChannelWrapper*>(ch); - return (wrapper) ? - static_cast<cricket::FakeTransportChannel*>(wrapper->channel()) : NULL; - } - - // Offer DTLS if we have an identity; pass in a remote fingerprint only if - // both sides support DTLS. - void Negotiate(DtlsTestClient* peer, cricket::ContentAction action, - ConnectionRole local_role, ConnectionRole remote_role, - int flags) { - Negotiate(identity_.get(), (identity_) ? peer->identity_.get() : NULL, - action, local_role, remote_role, flags); - } - - // Allow any DTLS configuration to be specified (including invalid ones). - void Negotiate(rtc::SSLIdentity* local_identity, - rtc::SSLIdentity* remote_identity, - cricket::ContentAction action, - ConnectionRole local_role, - ConnectionRole remote_role, - int flags) { - rtc::scoped_ptr<rtc::SSLFingerprint> local_fingerprint; - rtc::scoped_ptr<rtc::SSLFingerprint> remote_fingerprint; - if (local_identity) { - local_fingerprint.reset(rtc::SSLFingerprint::Create( - rtc::DIGEST_SHA_1, local_identity)); - ASSERT_TRUE(local_fingerprint.get() != NULL); - } - if (remote_identity) { - remote_fingerprint.reset(rtc::SSLFingerprint::Create( - rtc::DIGEST_SHA_1, remote_identity)); - ASSERT_TRUE(remote_fingerprint.get() != NULL); - } - - if (use_dtls_srtp_ && !(flags & NF_REOFFER)) { - // SRTP ciphers will be set only in the beginning. - for (std::vector<cricket::DtlsTransportChannelWrapper*>::iterator it = - channels_.begin(); it != channels_.end(); ++it) { - std::vector<std::string> ciphers; - ciphers.push_back(AES_CM_128_HMAC_SHA1_80); - ASSERT_TRUE((*it)->SetSrtpCiphers(ciphers)); - } - } - - std::string transport_type = (protocol_ == cricket::ICEPROTO_GOOGLE) ? - cricket::NS_GINGLE_P2P : cricket::NS_JINGLE_ICE_UDP; - cricket::TransportDescription local_desc( - transport_type, std::vector<std::string>(), kIceUfrag1, kIcePwd1, - cricket::ICEMODE_FULL, local_role, - // If remote if the offerer and has no DTLS support, answer will be - // without any fingerprint. - (action == cricket::CA_ANSWER && !remote_identity) ? - NULL : local_fingerprint.get(), - cricket::Candidates()); - - cricket::TransportDescription remote_desc( - transport_type, std::vector<std::string>(), kIceUfrag1, kIcePwd1, - cricket::ICEMODE_FULL, remote_role, remote_fingerprint.get(), - cricket::Candidates()); - - bool expect_success = (flags & NF_EXPECT_FAILURE) ? false : true; - // If |expect_success| is false, expect SRTD or SLTD to fail when - // content action is CA_ANSWER. - if (action == cricket::CA_OFFER) { - ASSERT_TRUE(transport_->SetLocalTransportDescription( - local_desc, cricket::CA_OFFER, NULL)); - ASSERT_EQ(expect_success, transport_->SetRemoteTransportDescription( - remote_desc, cricket::CA_ANSWER, NULL)); - } else { - ASSERT_TRUE(transport_->SetRemoteTransportDescription( - remote_desc, cricket::CA_OFFER, NULL)); - ASSERT_EQ(expect_success, transport_->SetLocalTransportDescription( - local_desc, cricket::CA_ANSWER, NULL)); - } - negotiated_dtls_ = (local_identity && remote_identity); - } - - bool Connect(DtlsTestClient* peer) { - transport_->ConnectChannels(); - transport_->SetDestination(peer->transport_.get()); - return true; - } - - bool writable() const { return transport_->writable(); } - - void CheckRole(rtc::SSLRole role) { - if (role == rtc::SSL_CLIENT) { - ASSERT_FALSE(received_dtls_client_hello_); - ASSERT_TRUE(received_dtls_server_hello_); - } else { - ASSERT_TRUE(received_dtls_client_hello_); - ASSERT_FALSE(received_dtls_server_hello_); - } - } - - void CheckSrtp(const std::string& expected_cipher) { - for (std::vector<cricket::DtlsTransportChannelWrapper*>::iterator it = - channels_.begin(); it != channels_.end(); ++it) { - std::string cipher; - - bool rv = (*it)->GetSrtpCipher(&cipher); - if (negotiated_dtls_ && !expected_cipher.empty()) { - ASSERT_TRUE(rv); - - ASSERT_EQ(cipher, expected_cipher); - } else { - ASSERT_FALSE(rv); - } - } - } - - void SendPackets(size_t channel, size_t size, size_t count, bool srtp) { - ASSERT(channel < channels_.size()); - rtc::scoped_ptr<char[]> packet(new char[size]); - size_t sent = 0; - do { - // Fill the packet with a known value and a sequence number to check - // against, and make sure that it doesn't look like DTLS. - memset(packet.get(), sent & 0xff, size); - packet[0] = (srtp) ? 0x80 : 0x00; - rtc::SetBE32(packet.get() + kPacketNumOffset, - static_cast<uint32>(sent)); - - // Only set the bypass flag if we've activated DTLS. - int flags = (identity_.get() && srtp) ? cricket::PF_SRTP_BYPASS : 0; - rtc::PacketOptions packet_options; - int rv = channels_[channel]->SendPacket( - packet.get(), size, packet_options, flags); - ASSERT_GT(rv, 0); - ASSERT_EQ(size, static_cast<size_t>(rv)); - ++sent; - } while (sent < count); - } - - int SendInvalidSrtpPacket(size_t channel, size_t size) { - ASSERT(channel < channels_.size()); - rtc::scoped_ptr<char[]> packet(new char[size]); - // Fill the packet with 0 to form an invalid SRTP packet. - memset(packet.get(), 0, size); - - rtc::PacketOptions packet_options; - return channels_[channel]->SendPacket( - packet.get(), size, packet_options, cricket::PF_SRTP_BYPASS); - } - - void ExpectPackets(size_t channel, size_t size) { - packet_size_ = size; - received_.clear(); - } - - size_t NumPacketsReceived() { - return received_.size(); - } - - bool VerifyPacket(const char* data, size_t size, uint32* out_num) { - if (size != packet_size_ || - (data[0] != 0 && static_cast<uint8>(data[0]) != 0x80)) { - return false; - } - uint32 packet_num = rtc::GetBE32(data + kPacketNumOffset); - for (size_t i = kPacketHeaderLen; i < size; ++i) { - if (static_cast<uint8>(data[i]) != (packet_num & 0xff)) { - return false; - } - } - if (out_num) { - *out_num = packet_num; - } - return true; - } - bool VerifyEncryptedPacket(const char* data, size_t size) { - // This is an encrypted data packet; let's make sure it's mostly random; - // less than 10% of the bytes should be equal to the cleartext packet. - if (size <= packet_size_) { - return false; - } - uint32 packet_num = rtc::GetBE32(data + kPacketNumOffset); - int num_matches = 0; - for (size_t i = kPacketNumOffset; i < size; ++i) { - if (static_cast<uint8>(data[i]) == (packet_num & 0xff)) { - ++num_matches; - } - } - return (num_matches < ((static_cast<int>(size) - 5) / 10)); - } - - // Transport callbacks - void OnTransportWritableState(cricket::Transport* transport) { - LOG(LS_INFO) << name_ << ": is writable"; - } - - // Transport channel callbacks - void OnTransportChannelWritableState(cricket::TransportChannel* channel) { - LOG(LS_INFO) << name_ << ": Channel '" << channel->component() - << "' is writable"; - } - - void OnTransportChannelReadPacket(cricket::TransportChannel* channel, - const char* data, size_t size, - const rtc::PacketTime& packet_time, - int flags) { - uint32 packet_num = 0; - ASSERT_TRUE(VerifyPacket(data, size, &packet_num)); - received_.insert(packet_num); - // Only DTLS-SRTP packets should have the bypass flag set. - int expected_flags = (identity_.get() && IsRtpLeadByte(data[0])) ? - cricket::PF_SRTP_BYPASS : 0; - ASSERT_EQ(expected_flags, flags); - } - - // Hook into the raw packet stream to make sure DTLS packets are encrypted. - void OnFakeTransportChannelReadPacket(cricket::TransportChannel* channel, - const char* data, size_t size, - const rtc::PacketTime& time, - int flags) { - // Flags shouldn't be set on the underlying TransportChannel packets. - ASSERT_EQ(0, flags); - - // Look at the handshake packets to see what role we played. - // Check that non-handshake packets are DTLS data or SRTP bypass. - if (negotiated_dtls_) { - if (data[0] == 22 && size > 17) { - if (data[13] == 1) { - received_dtls_client_hello_ = true; - } else if (data[13] == 2) { - received_dtls_server_hello_ = true; - } - } else if (!(data[0] >= 20 && data[0] <= 22)) { - ASSERT_TRUE(data[0] == 23 || IsRtpLeadByte(data[0])); - if (data[0] == 23) { - ASSERT_TRUE(VerifyEncryptedPacket(data, size)); - } else if (IsRtpLeadByte(data[0])) { - ASSERT_TRUE(VerifyPacket(data, size, NULL)); - } - } - } - } - - private: - std::string name_; - rtc::Thread* signaling_thread_; - rtc::Thread* worker_thread_; - cricket::TransportProtocol protocol_; - rtc::scoped_ptr<rtc::SSLIdentity> identity_; - rtc::scoped_ptr<cricket::FakeTransport> transport_; - std::vector<cricket::DtlsTransportChannelWrapper*> channels_; - size_t packet_size_; - std::set<int> received_; - bool use_dtls_srtp_; - bool negotiated_dtls_; - bool received_dtls_client_hello_; - bool received_dtls_server_hello_; -}; - - -class DtlsTransportChannelTest : public testing::Test { - public: - DtlsTransportChannelTest() : - client1_("P1", rtc::Thread::Current(), - rtc::Thread::Current()), - client2_("P2", rtc::Thread::Current(), - rtc::Thread::Current()), - channel_ct_(1), - use_dtls_(false), - use_dtls_srtp_(false) { - } - - void SetChannelCount(size_t channel_ct) { - channel_ct_ = static_cast<int>(channel_ct); - } - void PrepareDtls(bool c1, bool c2) { - if (c1) { - client1_.CreateIdentity(); - } - if (c2) { - client2_.CreateIdentity(); - } - if (c1 && c2) - use_dtls_ = true; - } - void PrepareDtlsSrtp(bool c1, bool c2) { - if (!use_dtls_) - return; - - if (c1) - client1_.SetupSrtp(); - if (c2) - client2_.SetupSrtp(); - - if (c1 && c2) - use_dtls_srtp_ = true; - } - - bool Connect(ConnectionRole client1_role, ConnectionRole client2_role) { - Negotiate(client1_role, client2_role); - - bool rv = client1_.Connect(&client2_); - EXPECT_TRUE(rv); - if (!rv) - return false; - - EXPECT_TRUE_WAIT(client1_.writable() && client2_.writable(), 10000); - if (!client1_.writable() || !client2_.writable()) - return false; - - // Check that we used the right roles. - if (use_dtls_) { - rtc::SSLRole client1_ssl_role = - (client1_role == cricket::CONNECTIONROLE_ACTIVE || - (client2_role == cricket::CONNECTIONROLE_PASSIVE && - client1_role == cricket::CONNECTIONROLE_ACTPASS)) ? - rtc::SSL_CLIENT : rtc::SSL_SERVER; - - rtc::SSLRole client2_ssl_role = - (client2_role == cricket::CONNECTIONROLE_ACTIVE || - (client1_role == cricket::CONNECTIONROLE_PASSIVE && - client2_role == cricket::CONNECTIONROLE_ACTPASS)) ? - rtc::SSL_CLIENT : rtc::SSL_SERVER; - - client1_.CheckRole(client1_ssl_role); - client2_.CheckRole(client2_ssl_role); - } - - // Check that we negotiated the right ciphers. - if (use_dtls_srtp_) { - client1_.CheckSrtp(AES_CM_128_HMAC_SHA1_80); - client2_.CheckSrtp(AES_CM_128_HMAC_SHA1_80); - } else { - client1_.CheckSrtp(""); - client2_.CheckSrtp(""); - } - - return true; - } - - bool Connect() { - // By default, Client1 will be Server and Client2 will be Client. - return Connect(cricket::CONNECTIONROLE_ACTPASS, - cricket::CONNECTIONROLE_ACTIVE); - } - - void Negotiate() { - Negotiate(cricket::CONNECTIONROLE_ACTPASS, cricket::CONNECTIONROLE_ACTIVE); - } - - void Negotiate(ConnectionRole client1_role, ConnectionRole client2_role) { - client1_.SetupChannels(channel_ct_, cricket::ICEROLE_CONTROLLING); - client2_.SetupChannels(channel_ct_, cricket::ICEROLE_CONTROLLED); - // Expect success from SLTD and SRTD. - client1_.Negotiate(&client2_, cricket::CA_OFFER, - client1_role, client2_role, 0); - client2_.Negotiate(&client1_, cricket::CA_ANSWER, - client2_role, client1_role, 0); - } - - // Negotiate with legacy client |client2|. Legacy client doesn't use setup - // attributes, except NONE. - void NegotiateWithLegacy() { - client1_.SetupChannels(channel_ct_, cricket::ICEROLE_CONTROLLING); - client2_.SetupChannels(channel_ct_, cricket::ICEROLE_CONTROLLED); - // Expect success from SLTD and SRTD. - client1_.Negotiate(&client2_, cricket::CA_OFFER, - cricket::CONNECTIONROLE_ACTPASS, - cricket::CONNECTIONROLE_NONE, 0); - client2_.Negotiate(&client1_, cricket::CA_ANSWER, - cricket::CONNECTIONROLE_ACTIVE, - cricket::CONNECTIONROLE_NONE, 0); - } - - void Renegotiate(DtlsTestClient* reoffer_initiator, - ConnectionRole client1_role, ConnectionRole client2_role, - int flags) { - if (reoffer_initiator == &client1_) { - client1_.Negotiate(&client2_, cricket::CA_OFFER, - client1_role, client2_role, flags); - client2_.Negotiate(&client1_, cricket::CA_ANSWER, - client2_role, client1_role, flags); - } else { - client2_.Negotiate(&client1_, cricket::CA_OFFER, - client2_role, client1_role, flags); - client1_.Negotiate(&client2_, cricket::CA_ANSWER, - client1_role, client2_role, flags); - } - } - - void TestTransfer(size_t channel, size_t size, size_t count, bool srtp) { - LOG(LS_INFO) << "Expect packets, size=" << size; - client2_.ExpectPackets(channel, size); - client1_.SendPackets(channel, size, count, srtp); - EXPECT_EQ_WAIT(count, client2_.NumPacketsReceived(), 10000); - } - - protected: - DtlsTestClient client1_; - DtlsTestClient client2_; - int channel_ct_; - bool use_dtls_; - bool use_dtls_srtp_; -}; - -// Test that transport negotiation of ICE, no DTLS works properly. -TEST_F(DtlsTransportChannelTest, TestChannelSetupIce) { - client1_.SetIceProtocol(cricket::ICEPROTO_RFC5245); - client2_.SetIceProtocol(cricket::ICEPROTO_RFC5245); - Negotiate(); - cricket::FakeTransportChannel* channel1 = client1_.GetFakeChannel(0); - cricket::FakeTransportChannel* channel2 = client2_.GetFakeChannel(0); - ASSERT_TRUE(channel1 != NULL); - ASSERT_TRUE(channel2 != NULL); - EXPECT_EQ(cricket::ICEROLE_CONTROLLING, channel1->GetIceRole()); - EXPECT_EQ(1U, channel1->IceTiebreaker()); - EXPECT_EQ(cricket::ICEPROTO_RFC5245, channel1->protocol()); - EXPECT_EQ(kIceUfrag1, channel1->ice_ufrag()); - EXPECT_EQ(kIcePwd1, channel1->ice_pwd()); - EXPECT_EQ(cricket::ICEROLE_CONTROLLED, channel2->GetIceRole()); - EXPECT_EQ(2U, channel2->IceTiebreaker()); - EXPECT_EQ(cricket::ICEPROTO_RFC5245, channel2->protocol()); -} - -// Test that transport negotiation of GICE, no DTLS works properly. -TEST_F(DtlsTransportChannelTest, TestChannelSetupGice) { - client1_.SetIceProtocol(cricket::ICEPROTO_GOOGLE); - client2_.SetIceProtocol(cricket::ICEPROTO_GOOGLE); - Negotiate(); - cricket::FakeTransportChannel* channel1 = client1_.GetFakeChannel(0); - cricket::FakeTransportChannel* channel2 = client2_.GetFakeChannel(0); - ASSERT_TRUE(channel1 != NULL); - ASSERT_TRUE(channel2 != NULL); - EXPECT_EQ(cricket::ICEROLE_CONTROLLING, channel1->GetIceRole()); - EXPECT_EQ(1U, channel1->IceTiebreaker()); - EXPECT_EQ(cricket::ICEPROTO_GOOGLE, channel1->protocol()); - EXPECT_EQ(kIceUfrag1, channel1->ice_ufrag()); - EXPECT_EQ(kIcePwd1, channel1->ice_pwd()); - EXPECT_EQ(cricket::ICEROLE_CONTROLLED, channel2->GetIceRole()); - EXPECT_EQ(2U, channel2->IceTiebreaker()); - EXPECT_EQ(cricket::ICEPROTO_GOOGLE, channel2->protocol()); -} - -// Connect without DTLS, and transfer some data. -TEST_F(DtlsTransportChannelTest, TestTransfer) { - ASSERT_TRUE(Connect()); - TestTransfer(0, 1000, 100, false); -} - -// Create two channels without DTLS, and transfer some data. -TEST_F(DtlsTransportChannelTest, TestTransferTwoChannels) { - SetChannelCount(2); - ASSERT_TRUE(Connect()); - TestTransfer(0, 1000, 100, false); - TestTransfer(1, 1000, 100, false); -} - -// Connect without DTLS, and transfer SRTP data. -TEST_F(DtlsTransportChannelTest, TestTransferSrtp) { - ASSERT_TRUE(Connect()); - TestTransfer(0, 1000, 100, true); -} - -// Create two channels without DTLS, and transfer SRTP data. -TEST_F(DtlsTransportChannelTest, TestTransferSrtpTwoChannels) { - SetChannelCount(2); - ASSERT_TRUE(Connect()); - TestTransfer(0, 1000, 100, true); - TestTransfer(1, 1000, 100, true); -} - -// Connect with DTLS, and transfer some data. -TEST_F(DtlsTransportChannelTest, TestTransferDtls) { - MAYBE_SKIP_TEST(HaveDtls); - PrepareDtls(true, true); - ASSERT_TRUE(Connect()); - TestTransfer(0, 1000, 100, false); -} - -// Create two channels with DTLS, and transfer some data. -TEST_F(DtlsTransportChannelTest, TestTransferDtlsTwoChannels) { - MAYBE_SKIP_TEST(HaveDtls); - SetChannelCount(2); - PrepareDtls(true, true); - ASSERT_TRUE(Connect()); - TestTransfer(0, 1000, 100, false); - TestTransfer(1, 1000, 100, false); -} - -// Connect with A doing DTLS and B not, and transfer some data. -TEST_F(DtlsTransportChannelTest, TestTransferDtlsRejected) { - PrepareDtls(true, false); - ASSERT_TRUE(Connect()); - TestTransfer(0, 1000, 100, false); -} - -// Connect with B doing DTLS and A not, and transfer some data. -TEST_F(DtlsTransportChannelTest, TestTransferDtlsNotOffered) { - PrepareDtls(false, true); - ASSERT_TRUE(Connect()); - TestTransfer(0, 1000, 100, false); -} - -// Connect with DTLS, negotiate DTLS-SRTP, and transfer SRTP using bypass. -TEST_F(DtlsTransportChannelTest, TestTransferDtlsSrtp) { - MAYBE_SKIP_TEST(HaveDtlsSrtp); - PrepareDtls(true, true); - PrepareDtlsSrtp(true, true); - ASSERT_TRUE(Connect()); - TestTransfer(0, 1000, 100, true); -} - -// Connect with DTLS-SRTP, transfer an invalid SRTP packet, and expects -1 -// returned. -TEST_F(DtlsTransportChannelTest, TestTransferDtlsInvalidSrtpPacket) { - MAYBE_SKIP_TEST(HaveDtls); - PrepareDtls(true, true); - PrepareDtlsSrtp(true, true); - ASSERT_TRUE(Connect()); - int result = client1_.SendInvalidSrtpPacket(0, 100); - ASSERT_EQ(-1, result); -} - -// Connect with DTLS. A does DTLS-SRTP but B does not. -TEST_F(DtlsTransportChannelTest, TestTransferDtlsSrtpRejected) { - MAYBE_SKIP_TEST(HaveDtlsSrtp); - PrepareDtls(true, true); - PrepareDtlsSrtp(true, false); - ASSERT_TRUE(Connect()); -} - -// Connect with DTLS. B does DTLS-SRTP but A does not. -TEST_F(DtlsTransportChannelTest, TestTransferDtlsSrtpNotOffered) { - MAYBE_SKIP_TEST(HaveDtlsSrtp); - PrepareDtls(true, true); - PrepareDtlsSrtp(false, true); - ASSERT_TRUE(Connect()); -} - -// Create two channels with DTLS, negotiate DTLS-SRTP, and transfer bypass SRTP. -TEST_F(DtlsTransportChannelTest, TestTransferDtlsSrtpTwoChannels) { - MAYBE_SKIP_TEST(HaveDtlsSrtp); - SetChannelCount(2); - PrepareDtls(true, true); - PrepareDtlsSrtp(true, true); - ASSERT_TRUE(Connect()); - TestTransfer(0, 1000, 100, true); - TestTransfer(1, 1000, 100, true); -} - -// Create a single channel with DTLS, and send normal data and SRTP data on it. -TEST_F(DtlsTransportChannelTest, TestTransferDtlsSrtpDemux) { - MAYBE_SKIP_TEST(HaveDtlsSrtp); - PrepareDtls(true, true); - PrepareDtlsSrtp(true, true); - ASSERT_TRUE(Connect()); - TestTransfer(0, 1000, 100, false); - TestTransfer(0, 1000, 100, true); -} - -// Testing when the remote is passive. -TEST_F(DtlsTransportChannelTest, TestTransferDtlsAnswererIsPassive) { - MAYBE_SKIP_TEST(HaveDtlsSrtp); - SetChannelCount(2); - PrepareDtls(true, true); - PrepareDtlsSrtp(true, true); - ASSERT_TRUE(Connect(cricket::CONNECTIONROLE_ACTPASS, - cricket::CONNECTIONROLE_PASSIVE)); - TestTransfer(0, 1000, 100, true); - TestTransfer(1, 1000, 100, true); -} - -// Testing with the legacy DTLS client which doesn't use setup attribute. -// In this case legacy is the answerer. -TEST_F(DtlsTransportChannelTest, TestDtlsSetupWithLegacyAsAnswerer) { - MAYBE_SKIP_TEST(HaveDtlsSrtp); - PrepareDtls(true, true); - NegotiateWithLegacy(); - rtc::SSLRole channel1_role; - rtc::SSLRole channel2_role; - EXPECT_TRUE(client1_.transport()->GetSslRole(&channel1_role)); - EXPECT_TRUE(client2_.transport()->GetSslRole(&channel2_role)); - EXPECT_EQ(rtc::SSL_SERVER, channel1_role); - EXPECT_EQ(rtc::SSL_CLIENT, channel2_role); -} - -// Testing re offer/answer after the session is estbalished. Roles will be -// kept same as of the previous negotiation. -TEST_F(DtlsTransportChannelTest, TestDtlsReOfferFromOfferer) { - MAYBE_SKIP_TEST(HaveDtlsSrtp); - SetChannelCount(2); - PrepareDtls(true, true); - PrepareDtlsSrtp(true, true); - // Initial role for client1 is ACTPASS and client2 is ACTIVE. - ASSERT_TRUE(Connect(cricket::CONNECTIONROLE_ACTPASS, - cricket::CONNECTIONROLE_ACTIVE)); - TestTransfer(0, 1000, 100, true); - TestTransfer(1, 1000, 100, true); - // Using input roles for the re-offer. - Renegotiate(&client1_, cricket::CONNECTIONROLE_ACTPASS, - cricket::CONNECTIONROLE_ACTIVE, NF_REOFFER); - TestTransfer(0, 1000, 100, true); - TestTransfer(1, 1000, 100, true); -} - -TEST_F(DtlsTransportChannelTest, TestDtlsReOfferFromAnswerer) { - MAYBE_SKIP_TEST(HaveDtlsSrtp); - SetChannelCount(2); - PrepareDtls(true, true); - PrepareDtlsSrtp(true, true); - // Initial role for client1 is ACTPASS and client2 is ACTIVE. - ASSERT_TRUE(Connect(cricket::CONNECTIONROLE_ACTPASS, - cricket::CONNECTIONROLE_ACTIVE)); - TestTransfer(0, 1000, 100, true); - TestTransfer(1, 1000, 100, true); - // Using input roles for the re-offer. - Renegotiate(&client2_, cricket::CONNECTIONROLE_PASSIVE, - cricket::CONNECTIONROLE_ACTPASS, NF_REOFFER); - TestTransfer(0, 1000, 100, true); - TestTransfer(1, 1000, 100, true); -} - -// Test that any change in role after the intial setup will result in failure. -TEST_F(DtlsTransportChannelTest, TestDtlsRoleReversal) { - MAYBE_SKIP_TEST(HaveDtlsSrtp); - SetChannelCount(2); - PrepareDtls(true, true); - PrepareDtlsSrtp(true, true); - ASSERT_TRUE(Connect(cricket::CONNECTIONROLE_ACTPASS, - cricket::CONNECTIONROLE_PASSIVE)); - - // Renegotiate from client2 with actpass and client1 as active. - Renegotiate(&client2_, cricket::CONNECTIONROLE_ACTPASS, - cricket::CONNECTIONROLE_ACTIVE, - NF_REOFFER | NF_EXPECT_FAILURE); -} - -// Test that using different setup attributes which results in similar ssl -// role as the initial negotiation will result in success. -TEST_F(DtlsTransportChannelTest, TestDtlsReOfferWithDifferentSetupAttr) { - MAYBE_SKIP_TEST(HaveDtlsSrtp); - SetChannelCount(2); - PrepareDtls(true, true); - PrepareDtlsSrtp(true, true); - ASSERT_TRUE(Connect(cricket::CONNECTIONROLE_ACTPASS, - cricket::CONNECTIONROLE_PASSIVE)); - // Renegotiate from client2 with actpass and client1 as active. - Renegotiate(&client2_, cricket::CONNECTIONROLE_ACTIVE, - cricket::CONNECTIONROLE_ACTPASS, NF_REOFFER); - TestTransfer(0, 1000, 100, true); - TestTransfer(1, 1000, 100, true); -} - -// Test that re-negotiation can be started before the clients become connected -// in the first negotiation. -TEST_F(DtlsTransportChannelTest, TestRenegotiateBeforeConnect) { - MAYBE_SKIP_TEST(HaveDtlsSrtp); - SetChannelCount(2); - PrepareDtls(true, true); - PrepareDtlsSrtp(true, true); - Negotiate(); - - Renegotiate(&client1_, cricket::CONNECTIONROLE_ACTPASS, - cricket::CONNECTIONROLE_ACTIVE, NF_REOFFER); - bool rv = client1_.Connect(&client2_); - EXPECT_TRUE(rv); - EXPECT_TRUE_WAIT(client1_.writable() && client2_.writable(), 10000); - - TestTransfer(0, 1000, 100, true); - TestTransfer(1, 1000, 100, true); -} - -// Test Certificates state after negotiation but before connection. -TEST_F(DtlsTransportChannelTest, TestCertificatesBeforeConnect) { - MAYBE_SKIP_TEST(HaveDtls); - PrepareDtls(true, true); - Negotiate(); - - rtc::scoped_ptr<rtc::SSLIdentity> identity1; - rtc::scoped_ptr<rtc::SSLIdentity> identity2; - rtc::scoped_ptr<rtc::SSLCertificate> remote_cert1; - rtc::scoped_ptr<rtc::SSLCertificate> remote_cert2; - - // After negotiation, each side has a distinct local certificate, but still no - // remote certificate, because connection has not yet occurred. - ASSERT_TRUE(client1_.transport()->GetIdentity(identity1.accept())); - ASSERT_TRUE(client2_.transport()->GetIdentity(identity2.accept())); - ASSERT_NE(identity1->certificate().ToPEMString(), - identity2->certificate().ToPEMString()); - ASSERT_FALSE( - client1_.transport()->GetRemoteCertificate(remote_cert1.accept())); - ASSERT_FALSE(remote_cert1 != NULL); - ASSERT_FALSE( - client2_.transport()->GetRemoteCertificate(remote_cert2.accept())); - ASSERT_FALSE(remote_cert2 != NULL); -} - -// Test Certificates state after connection. -TEST_F(DtlsTransportChannelTest, TestCertificatesAfterConnect) { - MAYBE_SKIP_TEST(HaveDtls); - PrepareDtls(true, true); - ASSERT_TRUE(Connect()); - - rtc::scoped_ptr<rtc::SSLIdentity> identity1; - rtc::scoped_ptr<rtc::SSLIdentity> identity2; - rtc::scoped_ptr<rtc::SSLCertificate> remote_cert1; - rtc::scoped_ptr<rtc::SSLCertificate> remote_cert2; - - // After connection, each side has a distinct local certificate. - ASSERT_TRUE(client1_.transport()->GetIdentity(identity1.accept())); - ASSERT_TRUE(client2_.transport()->GetIdentity(identity2.accept())); - ASSERT_NE(identity1->certificate().ToPEMString(), - identity2->certificate().ToPEMString()); - - // Each side's remote certificate is the other side's local certificate. - ASSERT_TRUE( - client1_.transport()->GetRemoteCertificate(remote_cert1.accept())); - ASSERT_EQ(remote_cert1->ToPEMString(), - identity2->certificate().ToPEMString()); - ASSERT_TRUE( - client2_.transport()->GetRemoteCertificate(remote_cert2.accept())); - ASSERT_EQ(remote_cert2->ToPEMString(), - identity1->certificate().ToPEMString()); -} diff --git a/talk/p2p/base/fakesession.h b/talk/p2p/base/fakesession.h deleted file mode 100644 index cb9111f03..000000000 --- a/talk/p2p/base/fakesession.h +++ /dev/null @@ -1,509 +0,0 @@ -/* - * libjingle - * Copyright 2009, Google, Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef WEBRTC_P2P_BASE_FAKESESSION_H_ -#define WEBRTC_P2P_BASE_FAKESESSION_H_ - -#include <map> -#include <string> -#include <vector> - -#include "webrtc/p2p/base/session.h" -#include "webrtc/p2p/base/transport.h" -#include "webrtc/p2p/base/transportchannel.h" -#include "webrtc/p2p/base/transportchannelimpl.h" -#include "webrtc/base/buffer.h" -#include "webrtc/base/fakesslidentity.h" -#include "webrtc/base/messagequeue.h" -#include "webrtc/base/sigslot.h" -#include "webrtc/base/sslfingerprint.h" - -namespace cricket { - -class FakeTransport; - -struct PacketMessageData : public rtc::MessageData { - PacketMessageData(const char* data, size_t len) : packet(data, len) { - } - rtc::Buffer packet; -}; - -// Fake transport channel class, which can be passed to anything that needs a -// transport channel. Can be informed of another FakeTransportChannel via -// SetDestination. -class FakeTransportChannel : public TransportChannelImpl, - public rtc::MessageHandler { - public: - explicit FakeTransportChannel(Transport* transport, - const std::string& content_name, - int component) - : TransportChannelImpl(content_name, component), - transport_(transport), - dest_(NULL), - state_(STATE_INIT), - async_(false), - identity_(NULL), - do_dtls_(false), - role_(ICEROLE_UNKNOWN), - tiebreaker_(0), - ice_proto_(ICEPROTO_HYBRID), - remote_ice_mode_(ICEMODE_FULL), - dtls_fingerprint_("", NULL, 0), - ssl_role_(rtc::SSL_CLIENT), - connection_count_(0) { - } - ~FakeTransportChannel() { - Reset(); - } - - uint64 IceTiebreaker() const { return tiebreaker_; } - TransportProtocol protocol() const { return ice_proto_; } - IceMode remote_ice_mode() const { return remote_ice_mode_; } - const std::string& ice_ufrag() const { return ice_ufrag_; } - const std::string& ice_pwd() const { return ice_pwd_; } - const std::string& remote_ice_ufrag() const { return remote_ice_ufrag_; } - const std::string& remote_ice_pwd() const { return remote_ice_pwd_; } - const rtc::SSLFingerprint& dtls_fingerprint() const { - return dtls_fingerprint_; - } - - void SetAsync(bool async) { - async_ = async; - } - - virtual Transport* GetTransport() { - return transport_; - } - - virtual void SetIceRole(IceRole role) { role_ = role; } - virtual IceRole GetIceRole() const { return role_; } - virtual size_t GetConnectionCount() const { return connection_count_; } - virtual void SetIceTiebreaker(uint64 tiebreaker) { tiebreaker_ = tiebreaker; } - virtual bool GetIceProtocolType(IceProtocolType* type) const { - *type = ice_proto_; - return true; - } - virtual void SetIceProtocolType(IceProtocolType type) { ice_proto_ = type; } - virtual void SetIceCredentials(const std::string& ice_ufrag, - const std::string& ice_pwd) { - ice_ufrag_ = ice_ufrag; - ice_pwd_ = ice_pwd; - } - virtual void SetRemoteIceCredentials(const std::string& ice_ufrag, - const std::string& ice_pwd) { - remote_ice_ufrag_ = ice_ufrag; - remote_ice_pwd_ = ice_pwd; - } - - virtual void SetRemoteIceMode(IceMode mode) { remote_ice_mode_ = mode; } - virtual bool SetRemoteFingerprint(const std::string& alg, const uint8* digest, - size_t digest_len) { - dtls_fingerprint_ = rtc::SSLFingerprint(alg, digest, digest_len); - return true; - } - virtual bool SetSslRole(rtc::SSLRole role) { - ssl_role_ = role; - return true; - } - virtual bool GetSslRole(rtc::SSLRole* role) const { - *role = ssl_role_; - return true; - } - - virtual void Connect() { - if (state_ == STATE_INIT) { - state_ = STATE_CONNECTING; - } - } - virtual void Reset() { - if (state_ != STATE_INIT) { - state_ = STATE_INIT; - if (dest_) { - dest_->state_ = STATE_INIT; - dest_->dest_ = NULL; - dest_ = NULL; - } - } - } - - void SetWritable(bool writable) { - set_writable(writable); - } - - void SetDestination(FakeTransportChannel* dest) { - if (state_ == STATE_CONNECTING && dest) { - // This simulates the delivery of candidates. - dest_ = dest; - dest_->dest_ = this; - if (identity_ && dest_->identity_) { - do_dtls_ = true; - dest_->do_dtls_ = true; - NegotiateSrtpCiphers(); - } - state_ = STATE_CONNECTED; - dest_->state_ = STATE_CONNECTED; - set_writable(true); - dest_->set_writable(true); - } else if (state_ == STATE_CONNECTED && !dest) { - // Simulates loss of connectivity, by asymmetrically forgetting dest_. - dest_ = NULL; - state_ = STATE_CONNECTING; - set_writable(false); - } - } - - void SetConnectionCount(size_t connection_count) { - size_t old_connection_count = connection_count_; - connection_count_ = connection_count; - if (connection_count_ < old_connection_count) - SignalConnectionRemoved(this); - } - - virtual int SendPacket(const char* data, size_t len, - const rtc::PacketOptions& options, int flags) { - if (state_ != STATE_CONNECTED) { - return -1; - } - - if (flags != PF_SRTP_BYPASS && flags != 0) { - return -1; - } - - PacketMessageData* packet = new PacketMessageData(data, len); - if (async_) { - rtc::Thread::Current()->Post(this, 0, packet); - } else { - rtc::Thread::Current()->Send(this, 0, packet); - } - return static_cast<int>(len); - } - virtual int SetOption(rtc::Socket::Option opt, int value) { - return true; - } - virtual int GetError() { - return 0; - } - - virtual void OnSignalingReady() { - } - virtual void OnCandidate(const Candidate& candidate) { - } - - virtual void OnMessage(rtc::Message* msg) { - PacketMessageData* data = static_cast<PacketMessageData*>( - msg->pdata); - dest_->SignalReadPacket(dest_, data->packet.data(), - data->packet.length(), - rtc::CreatePacketTime(0), 0); - delete data; - } - - bool SetLocalIdentity(rtc::SSLIdentity* identity) { - identity_ = identity; - return true; - } - - - void SetRemoteCertificate(rtc::FakeSSLCertificate* cert) { - remote_cert_ = cert; - } - - virtual bool IsDtlsActive() const { - return do_dtls_; - } - - virtual bool SetSrtpCiphers(const std::vector<std::string>& ciphers) { - srtp_ciphers_ = ciphers; - return true; - } - - virtual bool GetSrtpCipher(std::string* cipher) { - if (!chosen_srtp_cipher_.empty()) { - *cipher = chosen_srtp_cipher_; - return true; - } - return false; - } - - virtual bool GetLocalIdentity(rtc::SSLIdentity** identity) const { - if (!identity_) - return false; - - *identity = identity_->GetReference(); - return true; - } - - virtual bool GetRemoteCertificate(rtc::SSLCertificate** cert) const { - if (!remote_cert_) - return false; - - *cert = remote_cert_->GetReference(); - return true; - } - - virtual bool ExportKeyingMaterial(const std::string& label, - const uint8* context, - size_t context_len, - bool use_context, - uint8* result, - size_t result_len) { - if (!chosen_srtp_cipher_.empty()) { - memset(result, 0xff, result_len); - return true; - } - - return false; - } - - virtual void NegotiateSrtpCiphers() { - for (std::vector<std::string>::const_iterator it1 = srtp_ciphers_.begin(); - it1 != srtp_ciphers_.end(); ++it1) { - for (std::vector<std::string>::const_iterator it2 = - dest_->srtp_ciphers_.begin(); - it2 != dest_->srtp_ciphers_.end(); ++it2) { - if (*it1 == *it2) { - chosen_srtp_cipher_ = *it1; - dest_->chosen_srtp_cipher_ = *it2; - return; - } - } - } - } - - virtual bool GetStats(ConnectionInfos* infos) OVERRIDE { - ConnectionInfo info; - infos->clear(); - infos->push_back(info); - return true; - } - - private: - enum State { STATE_INIT, STATE_CONNECTING, STATE_CONNECTED }; - Transport* transport_; - FakeTransportChannel* dest_; - State state_; - bool async_; - rtc::SSLIdentity* identity_; - rtc::FakeSSLCertificate* remote_cert_; - bool do_dtls_; - std::vector<std::string> srtp_ciphers_; - std::string chosen_srtp_cipher_; - IceRole role_; - uint64 tiebreaker_; - IceProtocolType ice_proto_; - std::string ice_ufrag_; - std::string ice_pwd_; - std::string remote_ice_ufrag_; - std::string remote_ice_pwd_; - IceMode remote_ice_mode_; - rtc::SSLFingerprint dtls_fingerprint_; - rtc::SSLRole ssl_role_; - size_t connection_count_; -}; - -// Fake transport class, which can be passed to anything that needs a Transport. -// Can be informed of another FakeTransport via SetDestination (low-tech way -// of doing candidates) -class FakeTransport : public Transport { - public: - typedef std::map<int, FakeTransportChannel*> ChannelMap; - FakeTransport(rtc::Thread* signaling_thread, - rtc::Thread* worker_thread, - const std::string& content_name, - PortAllocator* alllocator = NULL) - : Transport(signaling_thread, worker_thread, - content_name, "test_type", NULL), - dest_(NULL), - async_(false), - identity_(NULL) { - } - ~FakeTransport() { - DestroyAllChannels(); - } - - const ChannelMap& channels() const { return channels_; } - - void SetAsync(bool async) { async_ = async; } - void SetDestination(FakeTransport* dest) { - dest_ = dest; - for (ChannelMap::iterator it = channels_.begin(); it != channels_.end(); - ++it) { - it->second->SetLocalIdentity(identity_); - SetChannelDestination(it->first, it->second); - } - } - - void SetWritable(bool writable) { - for (ChannelMap::iterator it = channels_.begin(); it != channels_.end(); - ++it) { - it->second->SetWritable(writable); - } - } - - void set_identity(rtc::SSLIdentity* identity) { - identity_ = identity; - } - - using Transport::local_description; - using Transport::remote_description; - - protected: - virtual TransportChannelImpl* CreateTransportChannel(int component) { - if (channels_.find(component) != channels_.end()) { - return NULL; - } - FakeTransportChannel* channel = - new FakeTransportChannel(this, content_name(), component); - channel->SetAsync(async_); - SetChannelDestination(component, channel); - channels_[component] = channel; - return channel; - } - virtual void DestroyTransportChannel(TransportChannelImpl* channel) { - channels_.erase(channel->component()); - delete channel; - } - virtual void SetIdentity_w(rtc::SSLIdentity* identity) { - identity_ = identity; - } - virtual bool GetIdentity_w(rtc::SSLIdentity** identity) { - if (!identity_) - return false; - - *identity = identity_->GetReference(); - return true; - } - - private: - FakeTransportChannel* GetFakeChannel(int component) { - ChannelMap::iterator it = channels_.find(component); - return (it != channels_.end()) ? it->second : NULL; - } - void SetChannelDestination(int component, - FakeTransportChannel* channel) { - FakeTransportChannel* dest_channel = NULL; - if (dest_) { - dest_channel = dest_->GetFakeChannel(component); - if (dest_channel) { - dest_channel->SetLocalIdentity(dest_->identity_); - } - } - channel->SetDestination(dest_channel); - } - - // Note, this is distinct from the Channel map owned by Transport. - // This map just tracks the FakeTransportChannels created by this class. - ChannelMap channels_; - FakeTransport* dest_; - bool async_; - rtc::SSLIdentity* identity_; -}; - -// Fake session class, which can be passed into a BaseChannel object for -// test purposes. Can be connected to other FakeSessions via Connect(). -class FakeSession : public BaseSession { - public: - explicit FakeSession() - : BaseSession(rtc::Thread::Current(), - rtc::Thread::Current(), - NULL, "", "", true), - fail_create_channel_(false) { - } - explicit FakeSession(bool initiator) - : BaseSession(rtc::Thread::Current(), - rtc::Thread::Current(), - NULL, "", "", initiator), - fail_create_channel_(false) { - } - FakeSession(rtc::Thread* worker_thread, bool initiator) - : BaseSession(rtc::Thread::Current(), - worker_thread, - NULL, "", "", initiator), - fail_create_channel_(false) { - } - - FakeTransport* GetTransport(const std::string& content_name) { - return static_cast<FakeTransport*>( - BaseSession::GetTransport(content_name)); - } - - void Connect(FakeSession* dest) { - // Simulate the exchange of candidates. - CompleteNegotiation(); - dest->CompleteNegotiation(); - for (TransportMap::const_iterator it = transport_proxies().begin(); - it != transport_proxies().end(); ++it) { - static_cast<FakeTransport*>(it->second->impl())->SetDestination( - dest->GetTransport(it->first)); - } - } - - virtual TransportChannel* CreateChannel( - const std::string& content_name, - const std::string& channel_name, - int component) { - if (fail_create_channel_) { - return NULL; - } - return BaseSession::CreateChannel(content_name, channel_name, component); - } - - void set_fail_channel_creation(bool fail_channel_creation) { - fail_create_channel_ = fail_channel_creation; - } - - // TODO: Hoist this into Session when we re-work the Session code. - void set_ssl_identity(rtc::SSLIdentity* identity) { - for (TransportMap::const_iterator it = transport_proxies().begin(); - it != transport_proxies().end(); ++it) { - // We know that we have a FakeTransport* - - static_cast<FakeTransport*>(it->second->impl())->set_identity - (identity); - } - } - - protected: - virtual Transport* CreateTransport(const std::string& content_name) { - return new FakeTransport(signaling_thread(), worker_thread(), content_name); - } - - void CompleteNegotiation() { - for (TransportMap::const_iterator it = transport_proxies().begin(); - it != transport_proxies().end(); ++it) { - it->second->CompleteNegotiation(); - it->second->ConnectChannels(); - } - } - - private: - bool fail_create_channel_; -}; - -} // namespace cricket - -#endif // WEBRTC_P2P_BASE_FAKESESSION_H_ diff --git a/talk/p2p/base/p2ptransport.cc b/talk/p2p/base/p2ptransport.cc deleted file mode 100644 index bc316cfe9..000000000 --- a/talk/p2p/base/p2ptransport.cc +++ /dev/null @@ -1,263 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "webrtc/p2p/base/p2ptransport.h" - -#include <string> -#include <vector> - -#include "webrtc/p2p/base/constants.h" -#include "webrtc/p2p/base/p2ptransportchannel.h" -#include "webrtc/p2p/base/parsing.h" -#include "webrtc/p2p/base/sessionmanager.h" -#include "webrtc/p2p/base/sessionmessages.h" -#include "webrtc/libjingle/xmllite/qname.h" -#include "webrtc/libjingle/xmllite/xmlelement.h" -#include "webrtc/libjingle/xmpp/constants.h" -#include "webrtc/base/base64.h" -#include "webrtc/base/common.h" -#include "webrtc/base/stringencode.h" -#include "webrtc/base/stringutils.h" - -namespace { - -// Limits for GICE and ICE username sizes. -const size_t kMaxGiceUsernameSize = 16; -const size_t kMaxIceUsernameSize = 512; - -} // namespace - -namespace cricket { - -static buzz::XmlElement* NewTransportElement(const std::string& name) { - return new buzz::XmlElement(buzz::QName(name, LN_TRANSPORT), true); -} - -P2PTransport::P2PTransport(rtc::Thread* signaling_thread, - rtc::Thread* worker_thread, - const std::string& content_name, - PortAllocator* allocator) - : Transport(signaling_thread, worker_thread, - content_name, NS_GINGLE_P2P, allocator) { -} - -P2PTransport::~P2PTransport() { - DestroyAllChannels(); -} - -TransportChannelImpl* P2PTransport::CreateTransportChannel(int component) { - return new P2PTransportChannel(content_name(), component, this, - port_allocator()); -} - -void P2PTransport::DestroyTransportChannel(TransportChannelImpl* channel) { - delete channel; -} - -bool P2PTransportParser::ParseTransportDescription( - const buzz::XmlElement* elem, - const CandidateTranslator* translator, - TransportDescription* desc, - ParseError* error) { - ASSERT(elem->Name().LocalPart() == LN_TRANSPORT); - desc->transport_type = elem->Name().Namespace(); - if (desc->transport_type != NS_GINGLE_P2P) - return BadParse("Unsupported transport type", error); - - for (const buzz::XmlElement* candidate_elem = elem->FirstElement(); - candidate_elem != NULL; - candidate_elem = candidate_elem->NextElement()) { - // Only look at local part because the namespace might (eventually) - // be NS_GINGLE_P2P or NS_JINGLE_ICE_UDP. - if (candidate_elem->Name().LocalPart() == LN_CANDIDATE) { - Candidate candidate; - if (!ParseCandidate(ICEPROTO_GOOGLE, candidate_elem, translator, - &candidate, error)) { - return false; - } - - desc->candidates.push_back(candidate); - } - } - return true; -} - -bool P2PTransportParser::WriteTransportDescription( - const TransportDescription& desc, - const CandidateTranslator* translator, - buzz::XmlElement** out_elem, - WriteError* error) { - TransportProtocol proto = TransportProtocolFromDescription(&desc); - rtc::scoped_ptr<buzz::XmlElement> trans_elem( - NewTransportElement(desc.transport_type)); - - // Fail if we get HYBRID or ICE right now. - // TODO(juberti): Add ICE and HYBRID serialization. - if (proto != ICEPROTO_GOOGLE) { - LOG(LS_ERROR) << "Failed to serialize non-GICE TransportDescription"; - return false; - } - - for (std::vector<Candidate>::const_iterator iter = desc.candidates.begin(); - iter != desc.candidates.end(); ++iter) { - rtc::scoped_ptr<buzz::XmlElement> cand_elem( - new buzz::XmlElement(QN_GINGLE_P2P_CANDIDATE)); - if (!WriteCandidate(proto, *iter, translator, cand_elem.get(), error)) { - return false; - } - trans_elem->AddElement(cand_elem.release()); - } - - *out_elem = trans_elem.release(); - return true; -} - -bool P2PTransportParser::ParseGingleCandidate( - const buzz::XmlElement* elem, - const CandidateTranslator* translator, - Candidate* candidate, - ParseError* error) { - return ParseCandidate(ICEPROTO_GOOGLE, elem, translator, candidate, error); -} - -bool P2PTransportParser::WriteGingleCandidate( - const Candidate& candidate, - const CandidateTranslator* translator, - buzz::XmlElement** out_elem, - WriteError* error) { - rtc::scoped_ptr<buzz::XmlElement> elem( - new buzz::XmlElement(QN_GINGLE_CANDIDATE)); - bool ret = WriteCandidate(ICEPROTO_GOOGLE, candidate, translator, elem.get(), - error); - if (ret) { - *out_elem = elem.release(); - } - return ret; -} - -bool P2PTransportParser::VerifyUsernameFormat(TransportProtocol proto, - const std::string& username, - ParseError* error) { - if (proto == ICEPROTO_GOOGLE || proto == ICEPROTO_HYBRID) { - if (username.size() > kMaxGiceUsernameSize) - return BadParse("candidate username is too long", error); - if (!rtc::Base64::IsBase64Encoded(username)) - return BadParse("candidate username has non-base64 encoded characters", - error); - } else if (proto == ICEPROTO_RFC5245) { - if (username.size() > kMaxIceUsernameSize) - return BadParse("candidate username is too long", error); - } - return true; -} - -bool P2PTransportParser::ParseCandidate(TransportProtocol proto, - const buzz::XmlElement* elem, - const CandidateTranslator* translator, - Candidate* candidate, - ParseError* error) { - ASSERT(proto == ICEPROTO_GOOGLE); - ASSERT(translator != NULL); - - if (!elem->HasAttr(buzz::QN_NAME) || - !elem->HasAttr(QN_ADDRESS) || - !elem->HasAttr(QN_PORT) || - !elem->HasAttr(QN_USERNAME) || - !elem->HasAttr(QN_PROTOCOL) || - !elem->HasAttr(QN_GENERATION)) { - return BadParse("candidate missing required attribute", error); - } - - rtc::SocketAddress address; - if (!ParseAddress(elem, QN_ADDRESS, QN_PORT, &address, error)) - return false; - - std::string channel_name = elem->Attr(buzz::QN_NAME); - int component = 0; - if (!translator || - !translator->GetComponentFromChannelName(channel_name, &component)) { - return BadParse("candidate has unknown channel name " + channel_name, - error); - } - - float preference = 0.0; - if (!GetXmlAttr(elem, QN_PREFERENCE, 0.0f, &preference)) { - return BadParse("candidate has unknown preference", error); - } - - candidate->set_component(component); - candidate->set_address(address); - candidate->set_username(elem->Attr(QN_USERNAME)); - candidate->set_preference(preference); - candidate->set_protocol(elem->Attr(QN_PROTOCOL)); - candidate->set_generation_str(elem->Attr(QN_GENERATION)); - if (elem->HasAttr(QN_PASSWORD)) - candidate->set_password(elem->Attr(QN_PASSWORD)); - if (elem->HasAttr(buzz::QN_TYPE)) - candidate->set_type(elem->Attr(buzz::QN_TYPE)); - if (elem->HasAttr(QN_NETWORK)) - candidate->set_network_name(elem->Attr(QN_NETWORK)); - - if (!VerifyUsernameFormat(proto, candidate->username(), error)) - return false; - - return true; -} - -bool P2PTransportParser::WriteCandidate(TransportProtocol proto, - const Candidate& candidate, - const CandidateTranslator* translator, - buzz::XmlElement* elem, - WriteError* error) { - ASSERT(proto == ICEPROTO_GOOGLE); - ASSERT(translator != NULL); - - std::string channel_name; - if (!translator || - !translator->GetChannelNameFromComponent( - candidate.component(), &channel_name)) { - return BadWrite("Cannot write candidate because of unknown component.", - error); - } - - elem->SetAttr(buzz::QN_NAME, channel_name); - elem->SetAttr(QN_ADDRESS, candidate.address().ipaddr().ToString()); - elem->SetAttr(QN_PORT, candidate.address().PortAsString()); - AddXmlAttr(elem, QN_PREFERENCE, candidate.preference()); - elem->SetAttr(QN_USERNAME, candidate.username()); - elem->SetAttr(QN_PROTOCOL, candidate.protocol()); - elem->SetAttr(QN_GENERATION, candidate.generation_str()); - if (!candidate.password().empty()) - elem->SetAttr(QN_PASSWORD, candidate.password()); - elem->SetAttr(buzz::QN_TYPE, candidate.type()); - if (!candidate.network_name().empty()) - elem->SetAttr(QN_NETWORK, candidate.network_name()); - - return true; -} - -} // namespace cricket diff --git a/talk/p2p/base/p2ptransport.h b/talk/p2p/base/p2ptransport.h deleted file mode 100644 index fc65babdf..000000000 --- a/talk/p2p/base/p2ptransport.h +++ /dev/null @@ -1,103 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef WEBRTC_P2P_BASE_P2PTRANSPORT_H_ -#define WEBRTC_P2P_BASE_P2PTRANSPORT_H_ - -#include <string> -#include <vector> -#include "webrtc/p2p/base/transport.h" - -namespace cricket { - -class P2PTransport : public Transport { - public: - P2PTransport(rtc::Thread* signaling_thread, - rtc::Thread* worker_thread, - const std::string& content_name, - PortAllocator* allocator); - virtual ~P2PTransport(); - - protected: - // Creates and destroys P2PTransportChannel. - virtual TransportChannelImpl* CreateTransportChannel(int component); - virtual void DestroyTransportChannel(TransportChannelImpl* channel); - - friend class P2PTransportChannel; - - DISALLOW_EVIL_CONSTRUCTORS(P2PTransport); -}; - -class P2PTransportParser : public TransportParser { - public: - P2PTransportParser() {} - // Translator may be null, in which case ParseCandidates should - // return false if there are candidates to parse. We can't not call - // ParseCandidates because there's no way to know ahead of time if - // there are candidates or not. - - // Jingle-specific functions; can be used with either ICE, GICE, or HYBRID. - virtual bool ParseTransportDescription(const buzz::XmlElement* elem, - const CandidateTranslator* translator, - TransportDescription* desc, - ParseError* error); - virtual bool WriteTransportDescription(const TransportDescription& desc, - const CandidateTranslator* translator, - buzz::XmlElement** elem, - WriteError* error); - - // Legacy Gingle functions; only can be used with GICE. - virtual bool ParseGingleCandidate(const buzz::XmlElement* elem, - const CandidateTranslator* translator, - Candidate* candidate, - ParseError* error); - virtual bool WriteGingleCandidate(const Candidate& candidate, - const CandidateTranslator* translator, - buzz::XmlElement** elem, - WriteError* error); - - private: - bool ParseCandidate(TransportProtocol proto, - const buzz::XmlElement* elem, - const CandidateTranslator* translator, - Candidate* candidate, - ParseError* error); - bool WriteCandidate(TransportProtocol proto, - const Candidate& candidate, - const CandidateTranslator* translator, - buzz::XmlElement* elem, - WriteError* error); - bool VerifyUsernameFormat(TransportProtocol proto, - const std::string& username, - ParseError* error); - - DISALLOW_EVIL_CONSTRUCTORS(P2PTransportParser); -}; - -} // namespace cricket - -#endif // WEBRTC_P2P_BASE_P2PTRANSPORT_H_ diff --git a/talk/p2p/base/p2ptransportchannel.cc b/talk/p2p/base/p2ptransportchannel.cc deleted file mode 100644 index daedbeb3c..000000000 --- a/talk/p2p/base/p2ptransportchannel.cc +++ /dev/null @@ -1,1291 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "webrtc/p2p/base/p2ptransportchannel.h" - -#include <set> -#include "webrtc/p2p/base/common.h" -#include "webrtc/p2p/base/relayport.h" // For RELAY_PORT_TYPE. -#include "webrtc/p2p/base/stunport.h" // For STUN_PORT_TYPE. -#include "webrtc/base/common.h" -#include "webrtc/base/crc32.h" -#include "webrtc/base/logging.h" -#include "webrtc/base/stringencode.h" - -namespace { - -// messages for queuing up work for ourselves -enum { - MSG_SORT = 1, - MSG_PING, -}; - -// When the socket is unwritable, we will use 10 Kbps (ignoring IP+UDP headers) -// for pinging. When the socket is writable, we will use only 1 Kbps because -// we don't want to degrade the quality on a modem. These numbers should work -// well on a 28.8K modem, which is the slowest connection on which the voice -// quality is reasonable at all. -static const uint32 PING_PACKET_SIZE = 60 * 8; -static const uint32 WRITABLE_DELAY = 1000 * PING_PACKET_SIZE / 1000; // 480ms -static const uint32 UNWRITABLE_DELAY = 1000 * PING_PACKET_SIZE / 10000; // 50ms - -// If there is a current writable connection, then we will also try hard to -// make sure it is pinged at this rate. -static const uint32 MAX_CURRENT_WRITABLE_DELAY = 900; // 2*WRITABLE_DELAY - bit - -// The minimum improvement in RTT that justifies a switch. -static const double kMinImprovement = 10; - -cricket::PortInterface::CandidateOrigin GetOrigin(cricket::PortInterface* port, - cricket::PortInterface* origin_port) { - if (!origin_port) - return cricket::PortInterface::ORIGIN_MESSAGE; - else if (port == origin_port) - return cricket::PortInterface::ORIGIN_THIS_PORT; - else - return cricket::PortInterface::ORIGIN_OTHER_PORT; -} - -// Compares two connections based only on static information about them. -int CompareConnectionCandidates(cricket::Connection* a, - cricket::Connection* b) { - // Compare connection priority. Lower values get sorted last. - if (a->priority() > b->priority()) - return 1; - if (a->priority() < b->priority()) - return -1; - - // If we're still tied at this point, prefer a younger generation. - return (a->remote_candidate().generation() + a->port()->generation()) - - (b->remote_candidate().generation() + b->port()->generation()); -} - -// Compare two connections based on their writability and static preferences. -int CompareConnections(cricket::Connection *a, cricket::Connection *b) { - // Sort based on write-state. Better states have lower values. - if (a->write_state() < b->write_state()) - return 1; - if (a->write_state() > b->write_state()) - return -1; - - // Compare the candidate information. - return CompareConnectionCandidates(a, b); -} - -// Wraps the comparison connection into a less than operator that puts higher -// priority writable connections first. -class ConnectionCompare { - public: - bool operator()(const cricket::Connection *ca, - const cricket::Connection *cb) { - cricket::Connection* a = const_cast<cricket::Connection*>(ca); - cricket::Connection* b = const_cast<cricket::Connection*>(cb); - - ASSERT(a->port()->IceProtocol() == b->port()->IceProtocol()); - - // Compare first on writability and static preferences. - int cmp = CompareConnections(a, b); - if (cmp > 0) - return true; - if (cmp < 0) - return false; - - // Otherwise, sort based on latency estimate. - return a->rtt() < b->rtt(); - - // Should we bother checking for the last connection that last received - // data? It would help rendezvous on the connection that is also receiving - // packets. - // - // TODO: Yes we should definitely do this. The TCP protocol gains - // efficiency by being used bidirectionally, as opposed to two separate - // unidirectional streams. This test should probably occur before - // comparison of local prefs (assuming combined prefs are the same). We - // need to be careful though, not to bounce back and forth with both sides - // trying to rendevous with the other. - } -}; - -// Determines whether we should switch between two connections, based first on -// static preferences and then (if those are equal) on latency estimates. -bool ShouldSwitch(cricket::Connection* a_conn, cricket::Connection* b_conn) { - if (a_conn == b_conn) - return false; - - if (!a_conn || !b_conn) // don't think the latter should happen - return true; - - int prefs_cmp = CompareConnections(a_conn, b_conn); - if (prefs_cmp < 0) - return true; - if (prefs_cmp > 0) - return false; - - return b_conn->rtt() <= a_conn->rtt() + kMinImprovement; -} - -} // unnamed namespace - -namespace cricket { - -P2PTransportChannel::P2PTransportChannel(const std::string& content_name, - int component, - P2PTransport* transport, - PortAllocator *allocator) : - TransportChannelImpl(content_name, component), - transport_(transport), - allocator_(allocator), - worker_thread_(rtc::Thread::Current()), - incoming_only_(false), - waiting_for_signaling_(false), - error_(0), - best_connection_(NULL), - pending_best_connection_(NULL), - sort_dirty_(false), - was_writable_(false), - protocol_type_(ICEPROTO_HYBRID), - remote_ice_mode_(ICEMODE_FULL), - ice_role_(ICEROLE_UNKNOWN), - tiebreaker_(0), - remote_candidate_generation_(0) { -} - -P2PTransportChannel::~P2PTransportChannel() { - ASSERT(worker_thread_ == rtc::Thread::Current()); - - for (uint32 i = 0; i < allocator_sessions_.size(); ++i) - delete allocator_sessions_[i]; -} - -// Add the allocator session to our list so that we know which sessions -// are still active. -void P2PTransportChannel::AddAllocatorSession(PortAllocatorSession* session) { - session->set_generation(static_cast<uint32>(allocator_sessions_.size())); - allocator_sessions_.push_back(session); - - // We now only want to apply new candidates that we receive to the ports - // created by this new session because these are replacing those of the - // previous sessions. - ports_.clear(); - - session->SignalPortReady.connect(this, &P2PTransportChannel::OnPortReady); - session->SignalCandidatesReady.connect( - this, &P2PTransportChannel::OnCandidatesReady); - session->SignalCandidatesAllocationDone.connect( - this, &P2PTransportChannel::OnCandidatesAllocationDone); - session->StartGettingPorts(); -} - -void P2PTransportChannel::AddConnection(Connection* connection) { - connections_.push_back(connection); - connection->set_remote_ice_mode(remote_ice_mode_); - connection->SignalReadPacket.connect( - this, &P2PTransportChannel::OnReadPacket); - connection->SignalReadyToSend.connect( - this, &P2PTransportChannel::OnReadyToSend); - connection->SignalStateChange.connect( - this, &P2PTransportChannel::OnConnectionStateChange); - connection->SignalDestroyed.connect( - this, &P2PTransportChannel::OnConnectionDestroyed); - connection->SignalUseCandidate.connect( - this, &P2PTransportChannel::OnUseCandidate); -} - -void P2PTransportChannel::SetIceRole(IceRole ice_role) { - ASSERT(worker_thread_ == rtc::Thread::Current()); - if (ice_role_ != ice_role) { - ice_role_ = ice_role; - for (std::vector<PortInterface *>::iterator it = ports_.begin(); - it != ports_.end(); ++it) { - (*it)->SetIceRole(ice_role); - } - } -} - -void P2PTransportChannel::SetIceTiebreaker(uint64 tiebreaker) { - ASSERT(worker_thread_ == rtc::Thread::Current()); - if (!ports_.empty()) { - LOG(LS_ERROR) - << "Attempt to change tiebreaker after Port has been allocated."; - return; - } - - tiebreaker_ = tiebreaker; -} - -bool P2PTransportChannel::GetIceProtocolType(IceProtocolType* type) const { - *type = protocol_type_; - return true; -} - -void P2PTransportChannel::SetIceProtocolType(IceProtocolType type) { - ASSERT(worker_thread_ == rtc::Thread::Current()); - - protocol_type_ = type; - for (std::vector<PortInterface *>::iterator it = ports_.begin(); - it != ports_.end(); ++it) { - (*it)->SetIceProtocolType(protocol_type_); - } -} - -void P2PTransportChannel::SetIceCredentials(const std::string& ice_ufrag, - const std::string& ice_pwd) { - ASSERT(worker_thread_ == rtc::Thread::Current()); - bool ice_restart = false; - if (!ice_ufrag_.empty() && !ice_pwd_.empty()) { - // Restart candidate allocation if there is any change in either - // ice ufrag or password. - ice_restart = - IceCredentialsChanged(ice_ufrag_, ice_pwd_, ice_ufrag, ice_pwd); - } - - ice_ufrag_ = ice_ufrag; - ice_pwd_ = ice_pwd; - - if (ice_restart) { - // Restart candidate gathering. - Allocate(); - } -} - -void P2PTransportChannel::SetRemoteIceCredentials(const std::string& ice_ufrag, - const std::string& ice_pwd) { - ASSERT(worker_thread_ == rtc::Thread::Current()); - bool ice_restart = false; - if (!remote_ice_ufrag_.empty() && !remote_ice_pwd_.empty()) { - ice_restart = (remote_ice_ufrag_ != ice_ufrag) || - (remote_ice_pwd_!= ice_pwd); - } - - remote_ice_ufrag_ = ice_ufrag; - remote_ice_pwd_ = ice_pwd; - - if (ice_restart) { - // |candidate.generation()| is not signaled in ICEPROTO_RFC5245. - // Therefore we need to keep track of the remote ice restart so - // newer connections are prioritized over the older. - ++remote_candidate_generation_; - } -} - -void P2PTransportChannel::SetRemoteIceMode(IceMode mode) { - remote_ice_mode_ = mode; -} - -// Go into the state of processing candidates, and running in general -void P2PTransportChannel::Connect() { - ASSERT(worker_thread_ == rtc::Thread::Current()); - if (ice_ufrag_.empty() || ice_pwd_.empty()) { - ASSERT(false); - LOG(LS_ERROR) << "P2PTransportChannel::Connect: The ice_ufrag_ and the " - << "ice_pwd_ are not set."; - return; - } - - // Kick off an allocator session - Allocate(); - - // Start pinging as the ports come in. - thread()->Post(this, MSG_PING); -} - -// Reset the socket, clear up any previous allocations and start over -void P2PTransportChannel::Reset() { - ASSERT(worker_thread_ == rtc::Thread::Current()); - - // Get rid of all the old allocators. This should clean up everything. - for (uint32 i = 0; i < allocator_sessions_.size(); ++i) - delete allocator_sessions_[i]; - - allocator_sessions_.clear(); - ports_.clear(); - connections_.clear(); - best_connection_ = NULL; - - // Forget about all of the candidates we got before. - remote_candidates_.clear(); - - // Revert to the initial state. - set_readable(false); - set_writable(false); - - // Reinitialize the rest of our state. - waiting_for_signaling_ = false; - sort_dirty_ = false; - - // If we allocated before, start a new one now. - if (transport_->connect_requested()) - Allocate(); - - // Start pinging as the ports come in. - thread()->Clear(this); - thread()->Post(this, MSG_PING); -} - -// A new port is available, attempt to make connections for it -void P2PTransportChannel::OnPortReady(PortAllocatorSession *session, - PortInterface* port) { - ASSERT(worker_thread_ == rtc::Thread::Current()); - - // Set in-effect options on the new port - for (OptionMap::const_iterator it = options_.begin(); - it != options_.end(); - ++it) { - int val = port->SetOption(it->first, it->second); - if (val < 0) { - LOG_J(LS_WARNING, port) << "SetOption(" << it->first - << ", " << it->second - << ") failed: " << port->GetError(); - } - } - - // Remember the ports and candidates, and signal that candidates are ready. - // The session will handle this, and send an initiate/accept/modify message - // if one is pending. - - port->SetIceProtocolType(protocol_type_); - port->SetIceRole(ice_role_); - port->SetIceTiebreaker(tiebreaker_); - ports_.push_back(port); - port->SignalUnknownAddress.connect( - this, &P2PTransportChannel::OnUnknownAddress); - port->SignalDestroyed.connect(this, &P2PTransportChannel::OnPortDestroyed); - port->SignalRoleConflict.connect( - this, &P2PTransportChannel::OnRoleConflict); - - // Attempt to create a connection from this new port to all of the remote - // candidates that we were given so far. - - std::vector<RemoteCandidate>::iterator iter; - for (iter = remote_candidates_.begin(); iter != remote_candidates_.end(); - ++iter) { - CreateConnection(port, *iter, iter->origin_port(), false); - } - - SortConnections(); -} - -// A new candidate is available, let listeners know -void P2PTransportChannel::OnCandidatesReady( - PortAllocatorSession *session, const std::vector<Candidate>& candidates) { - ASSERT(worker_thread_ == rtc::Thread::Current()); - for (size_t i = 0; i < candidates.size(); ++i) { - SignalCandidateReady(this, candidates[i]); - } -} - -void P2PTransportChannel::OnCandidatesAllocationDone( - PortAllocatorSession* session) { - ASSERT(worker_thread_ == rtc::Thread::Current()); - SignalCandidatesAllocationDone(this); -} - -// Handle stun packets -void P2PTransportChannel::OnUnknownAddress( - PortInterface* port, - const rtc::SocketAddress& address, ProtocolType proto, - IceMessage* stun_msg, const std::string &remote_username, - bool port_muxed) { - ASSERT(worker_thread_ == rtc::Thread::Current()); - - // Port has received a valid stun packet from an address that no Connection - // is currently available for. See if we already have a candidate with the - // address. If it isn't we need to create new candidate for it. - - // Determine if the remote candidates use shared ufrag. - bool ufrag_per_port = false; - std::vector<RemoteCandidate>::iterator it; - if (remote_candidates_.size() > 0) { - it = remote_candidates_.begin(); - std::string username = it->username(); - for (; it != remote_candidates_.end(); ++it) { - if (it->username() != username) { - ufrag_per_port = true; - break; - } - } - } - - const Candidate* candidate = NULL; - bool known_username = false; - std::string remote_password; - for (it = remote_candidates_.begin(); it != remote_candidates_.end(); ++it) { - if (it->username() == remote_username) { - remote_password = it->password(); - known_username = true; - if (ufrag_per_port || - (it->address() == address && - it->protocol() == ProtoToString(proto))) { - candidate = &(*it); - break; - } - // We don't want to break here because we may find a match of the address - // later. - } - } - - if (!known_username) { - if (port_muxed) { - // When Ports are muxed, SignalUnknownAddress is delivered to all - // P2PTransportChannel belong to a session. Return from here will - // save us from sending stun binding error message from incorrect channel. - return; - } - // Don't know about this username, the request is bogus - // This sometimes happens if a binding response comes in before the ACCEPT - // message. It is totally valid; the retry state machine will try again. - port->SendBindingErrorResponse(stun_msg, address, - STUN_ERROR_STALE_CREDENTIALS, STUN_ERROR_REASON_STALE_CREDENTIALS); - return; - } - - Candidate new_remote_candidate; - if (candidate != NULL) { - new_remote_candidate = *candidate; - if (ufrag_per_port) { - new_remote_candidate.set_address(address); - } - } else { - // Create a new candidate with this address. - std::string type; - if (port->IceProtocol() == ICEPROTO_RFC5245) { - type = PRFLX_PORT_TYPE; - } else { - // G-ICE doesn't support prflx candidate. - // We set candidate type to STUN_PORT_TYPE if the binding request comes - // from a relay port or the shared socket is used. Otherwise we use the - // port's type as the candidate type. - if (port->Type() == RELAY_PORT_TYPE || port->SharedSocket()) { - type = STUN_PORT_TYPE; - } else { - type = port->Type(); - } - } - - std::string id = rtc::CreateRandomString(8); - new_remote_candidate = Candidate( - id, component(), ProtoToString(proto), address, - 0, remote_username, remote_password, type, - port->Network()->name(), 0U, - rtc::ToString<uint32>(rtc::ComputeCrc32(id))); - new_remote_candidate.set_priority( - new_remote_candidate.GetPriority(ICE_TYPE_PREFERENCE_SRFLX, - port->Network()->preference(), 0)); - } - - if (port->IceProtocol() == ICEPROTO_RFC5245) { - // RFC 5245 - // If the source transport address of the request does not match any - // existing remote candidates, it represents a new peer reflexive remote - // candidate. - - // The priority of the candidate is set to the PRIORITY attribute - // from the request. - const StunUInt32Attribute* priority_attr = - stun_msg->GetUInt32(STUN_ATTR_PRIORITY); - if (!priority_attr) { - LOG(LS_WARNING) << "P2PTransportChannel::OnUnknownAddress - " - << "No STUN_ATTR_PRIORITY found in the " - << "stun request message"; - port->SendBindingErrorResponse(stun_msg, address, - STUN_ERROR_BAD_REQUEST, - STUN_ERROR_REASON_BAD_REQUEST); - return; - } - new_remote_candidate.set_priority(priority_attr->value()); - - // RFC5245, the agent constructs a pair whose local candidate is equal to - // the transport address on which the STUN request was received, and a - // remote candidate equal to the source transport address where the - // request came from. - - // There shouldn't be an existing connection with this remote address. - // When ports are muxed, this channel might get multiple unknown address - // signals. In that case if the connection is already exists, we should - // simply ignore the signal othewise send server error. - if (port->GetConnection(new_remote_candidate.address())) { - if (port_muxed) { - LOG(LS_INFO) << "Connection already exists for peer reflexive " - << "candidate: " << new_remote_candidate.ToString(); - return; - } else { - ASSERT(false); - port->SendBindingErrorResponse(stun_msg, address, - STUN_ERROR_SERVER_ERROR, - STUN_ERROR_REASON_SERVER_ERROR); - return; - } - } - - Connection* connection = port->CreateConnection( - new_remote_candidate, cricket::PortInterface::ORIGIN_THIS_PORT); - if (!connection) { - ASSERT(false); - port->SendBindingErrorResponse(stun_msg, address, - STUN_ERROR_SERVER_ERROR, - STUN_ERROR_REASON_SERVER_ERROR); - return; - } - - AddConnection(connection); - connection->ReceivedPing(); - - // Send the pinger a successful stun response. - port->SendBindingResponse(stun_msg, address); - - // Update the list of connections since we just added another. We do this - // after sending the response since it could (in principle) delete the - // connection in question. - SortConnections(); - } else { - // Check for connectivity to this address. Create connections - // to this address across all local ports. First, add this as a new remote - // address - if (!CreateConnections(new_remote_candidate, port, true)) { - // Hopefully this won't occur, because changing a destination address - // shouldn't cause a new connection to fail - ASSERT(false); - port->SendBindingErrorResponse(stun_msg, address, STUN_ERROR_SERVER_ERROR, - STUN_ERROR_REASON_SERVER_ERROR); - return; - } - - // Send the pinger a successful stun response. - port->SendBindingResponse(stun_msg, address); - - // Update the list of connections since we just added another. We do this - // after sending the response since it could (in principle) delete the - // connection in question. - SortConnections(); - } -} - -void P2PTransportChannel::OnRoleConflict(PortInterface* port) { - SignalRoleConflict(this); // STUN ping will be sent when SetRole is called - // from Transport. -} - -// When the signalling channel is ready, we can really kick off the allocator -void P2PTransportChannel::OnSignalingReady() { - ASSERT(worker_thread_ == rtc::Thread::Current()); - if (waiting_for_signaling_) { - waiting_for_signaling_ = false; - AddAllocatorSession(allocator_->CreateSession( - SessionId(), content_name(), component(), ice_ufrag_, ice_pwd_)); - } -} - -void P2PTransportChannel::OnUseCandidate(Connection* conn) { - ASSERT(worker_thread_ == rtc::Thread::Current()); - ASSERT(ice_role_ == ICEROLE_CONTROLLED); - ASSERT(protocol_type_ == ICEPROTO_RFC5245); - if (conn->write_state() == Connection::STATE_WRITABLE) { - if (best_connection_ != conn) { - pending_best_connection_ = NULL; - SwitchBestConnectionTo(conn); - // Now we have selected the best connection, time to prune other existing - // connections and update the read/write state of the channel. - RequestSort(); - } - } else { - pending_best_connection_ = conn; - } -} - -void P2PTransportChannel::OnCandidate(const Candidate& candidate) { - ASSERT(worker_thread_ == rtc::Thread::Current()); - - // Create connections to this remote candidate. - CreateConnections(candidate, NULL, false); - - // Resort the connections list, which may have new elements. - SortConnections(); -} - -// Creates connections from all of the ports that we care about to the given -// remote candidate. The return value is true if we created a connection from -// the origin port. -bool P2PTransportChannel::CreateConnections(const Candidate& remote_candidate, - PortInterface* origin_port, - bool readable) { - ASSERT(worker_thread_ == rtc::Thread::Current()); - - Candidate new_remote_candidate(remote_candidate); - new_remote_candidate.set_generation( - GetRemoteCandidateGeneration(remote_candidate)); - // ICE candidates don't need to have username and password set, but - // the code below this (specifically, ConnectionRequest::Prepare in - // port.cc) uses the remote candidates's username. So, we set it - // here. - if (remote_candidate.username().empty()) { - new_remote_candidate.set_username(remote_ice_ufrag_); - } - if (remote_candidate.password().empty()) { - new_remote_candidate.set_password(remote_ice_pwd_); - } - - // If we've already seen the new remote candidate (in the current candidate - // generation), then we shouldn't try creating connections for it. - // We either already have a connection for it, or we previously created one - // and then later pruned it. If we don't return, the channel will again - // re-create any connections that were previously pruned, which will then - // immediately be re-pruned, churning the network for no purpose. - // This only applies to candidates received over signaling (i.e. origin_port - // is NULL). - if (!origin_port && IsDuplicateRemoteCandidate(new_remote_candidate)) { - // return true to indicate success, without creating any new connections. - return true; - } - - // Add a new connection for this candidate to every port that allows such a - // connection (i.e., if they have compatible protocols) and that does not - // already have a connection to an equivalent candidate. We must be careful - // to make sure that the origin port is included, even if it was pruned, - // since that may be the only port that can create this connection. - bool created = false; - std::vector<PortInterface *>::reverse_iterator it; - for (it = ports_.rbegin(); it != ports_.rend(); ++it) { - if (CreateConnection(*it, new_remote_candidate, origin_port, readable)) { - if (*it == origin_port) - created = true; - } - } - - if ((origin_port != NULL) && - std::find(ports_.begin(), ports_.end(), origin_port) == ports_.end()) { - if (CreateConnection( - origin_port, new_remote_candidate, origin_port, readable)) - created = true; - } - - // Remember this remote candidate so that we can add it to future ports. - RememberRemoteCandidate(new_remote_candidate, origin_port); - - return created; -} - -// Setup a connection object for the local and remote candidate combination. -// And then listen to connection object for changes. -bool P2PTransportChannel::CreateConnection(PortInterface* port, - const Candidate& remote_candidate, - PortInterface* origin_port, - bool readable) { - // Look for an existing connection with this remote address. If one is not - // found, then we can create a new connection for this address. - Connection* connection = port->GetConnection(remote_candidate.address()); - if (connection != NULL) { - // It is not legal to try to change any of the parameters of an existing - // connection; however, the other side can send a duplicate candidate. - if (!remote_candidate.IsEquivalent(connection->remote_candidate())) { - LOG(INFO) << "Attempt to change a remote candidate." - << " Existing remote candidate: " - << connection->remote_candidate().ToString() - << "New remote candidate: " - << remote_candidate.ToString(); - return false; - } - } else { - PortInterface::CandidateOrigin origin = GetOrigin(port, origin_port); - - // Don't create connection if this is a candidate we received in a - // message and we are not allowed to make outgoing connections. - if (origin == cricket::PortInterface::ORIGIN_MESSAGE && incoming_only_) - return false; - - connection = port->CreateConnection(remote_candidate, origin); - if (!connection) - return false; - - AddConnection(connection); - - LOG_J(LS_INFO, this) << "Created connection with origin=" << origin << ", (" - << connections_.size() << " total)"; - } - - // If we are readable, it is because we are creating this in response to a - // ping from the other side. This will cause the state to become readable. - if (readable) - connection->ReceivedPing(); - - return true; -} - -bool P2PTransportChannel::FindConnection( - cricket::Connection* connection) const { - std::vector<Connection*>::const_iterator citer = - std::find(connections_.begin(), connections_.end(), connection); - return citer != connections_.end(); -} - -uint32 P2PTransportChannel::GetRemoteCandidateGeneration( - const Candidate& candidate) { - if (protocol_type_ == ICEPROTO_GOOGLE) { - // The Candidate.generation() can be trusted. Nothing needs to be done. - return candidate.generation(); - } - // |candidate.generation()| is not signaled in ICEPROTO_RFC5245. - // Therefore we need to keep track of the remote ice restart so - // newer connections are prioritized over the older. - ASSERT(candidate.generation() == 0 || - candidate.generation() == remote_candidate_generation_); - return remote_candidate_generation_; -} - -// Check if remote candidate is already cached. -bool P2PTransportChannel::IsDuplicateRemoteCandidate( - const Candidate& candidate) { - for (uint32 i = 0; i < remote_candidates_.size(); ++i) { - if (remote_candidates_[i].IsEquivalent(candidate)) { - return true; - } - } - return false; -} - -// Maintain our remote candidate list, adding this new remote one. -void P2PTransportChannel::RememberRemoteCandidate( - const Candidate& remote_candidate, PortInterface* origin_port) { - // Remove any candidates whose generation is older than this one. The - // presence of a new generation indicates that the old ones are not useful. - uint32 i = 0; - while (i < remote_candidates_.size()) { - if (remote_candidates_[i].generation() < remote_candidate.generation()) { - LOG(INFO) << "Pruning candidate from old generation: " - << remote_candidates_[i].address().ToSensitiveString(); - remote_candidates_.erase(remote_candidates_.begin() + i); - } else { - i += 1; - } - } - - // Make sure this candidate is not a duplicate. - if (IsDuplicateRemoteCandidate(remote_candidate)) { - LOG(INFO) << "Duplicate candidate: " << remote_candidate.ToString(); - return; - } - - // Try this candidate for all future ports. - remote_candidates_.push_back(RemoteCandidate(remote_candidate, origin_port)); -} - -// Set options on ourselves is simply setting options on all of our available -// port objects. -int P2PTransportChannel::SetOption(rtc::Socket::Option opt, int value) { - OptionMap::iterator it = options_.find(opt); - if (it == options_.end()) { - options_.insert(std::make_pair(opt, value)); - } else if (it->second == value) { - return 0; - } else { - it->second = value; - } - - for (uint32 i = 0; i < ports_.size(); ++i) { - int val = ports_[i]->SetOption(opt, value); - if (val < 0) { - // Because this also occurs deferred, probably no point in reporting an - // error - LOG(WARNING) << "SetOption(" << opt << ", " << value << ") failed: " - << ports_[i]->GetError(); - } - } - return 0; -} - -// Send data to the other side, using our best connection. -int P2PTransportChannel::SendPacket(const char *data, size_t len, - const rtc::PacketOptions& options, - int flags) { - ASSERT(worker_thread_ == rtc::Thread::Current()); - if (flags != 0) { - error_ = EINVAL; - return -1; - } - if (best_connection_ == NULL) { - error_ = EWOULDBLOCK; - return -1; - } - - int sent = best_connection_->Send(data, len, options); - if (sent <= 0) { - ASSERT(sent < 0); - error_ = best_connection_->GetError(); - } - return sent; -} - -bool P2PTransportChannel::GetStats(ConnectionInfos *infos) { - ASSERT(worker_thread_ == rtc::Thread::Current()); - // Gather connection infos. - infos->clear(); - - std::vector<Connection *>::const_iterator it; - for (it = connections_.begin(); it != connections_.end(); ++it) { - Connection *connection = *it; - ConnectionInfo info; - info.best_connection = (best_connection_ == connection); - info.readable = - (connection->read_state() == Connection::STATE_READABLE); - info.writable = - (connection->write_state() == Connection::STATE_WRITABLE); - info.timeout = - (connection->write_state() == Connection::STATE_WRITE_TIMEOUT); - info.new_connection = !connection->reported(); - connection->set_reported(true); - info.rtt = connection->rtt(); - info.sent_total_bytes = connection->sent_total_bytes(); - info.sent_bytes_second = connection->sent_bytes_second(); - info.recv_total_bytes = connection->recv_total_bytes(); - info.recv_bytes_second = connection->recv_bytes_second(); - info.local_candidate = connection->local_candidate(); - info.remote_candidate = connection->remote_candidate(); - info.key = connection; - infos->push_back(info); - } - - return true; -} - -rtc::DiffServCodePoint P2PTransportChannel::DefaultDscpValue() const { - OptionMap::const_iterator it = options_.find(rtc::Socket::OPT_DSCP); - if (it == options_.end()) { - return rtc::DSCP_NO_CHANGE; - } - return static_cast<rtc::DiffServCodePoint> (it->second); -} - -// Begin allocate (or immediately re-allocate, if MSG_ALLOCATE pending) -void P2PTransportChannel::Allocate() { - // Time for a new allocator, lets make sure we have a signalling channel - // to communicate candidates through first. - waiting_for_signaling_ = true; - SignalRequestSignaling(this); -} - -// Monitor connection states. -void P2PTransportChannel::UpdateConnectionStates() { - uint32 now = rtc::Time(); - - // We need to copy the list of connections since some may delete themselves - // when we call UpdateState. - for (uint32 i = 0; i < connections_.size(); ++i) - connections_[i]->UpdateState(now); -} - -// Prepare for best candidate sorting. -void P2PTransportChannel::RequestSort() { - if (!sort_dirty_) { - worker_thread_->Post(this, MSG_SORT); - sort_dirty_ = true; - } -} - -// Sort the available connections to find the best one. We also monitor -// the number of available connections and the current state. -void P2PTransportChannel::SortConnections() { - ASSERT(worker_thread_ == rtc::Thread::Current()); - - // Make sure the connection states are up-to-date since this affects how they - // will be sorted. - UpdateConnectionStates(); - - if (protocol_type_ == ICEPROTO_HYBRID) { - // If we are in hybrid mode, we are not sending any ping requests, so there - // is no point in sorting the connections. In hybrid state, ports can have - // different protocol than hybrid and protocol may differ from one another. - // Instead just update the state of this channel - UpdateChannelState(); - return; - } - - // Any changes after this point will require a re-sort. - sort_dirty_ = false; - - // Get a list of the networks that we are using. - std::set<rtc::Network*> networks; - for (uint32 i = 0; i < connections_.size(); ++i) - networks.insert(connections_[i]->port()->Network()); - - // Find the best alternative connection by sorting. It is important to note - // that amongst equal preference, writable connections, this will choose the - // one whose estimated latency is lowest. So it is the only one that we - // need to consider switching to. - - ConnectionCompare cmp; - std::stable_sort(connections_.begin(), connections_.end(), cmp); - LOG(LS_VERBOSE) << "Sorting available connections:"; - for (uint32 i = 0; i < connections_.size(); ++i) { - LOG(LS_VERBOSE) << connections_[i]->ToString(); - } - - Connection* top_connection = NULL; - if (connections_.size() > 0) - top_connection = connections_[0]; - - // We don't want to pick the best connections if channel is using RFC5245 - // and it's mode is CONTROLLED, as connections will be selected by the - // CONTROLLING agent. - - // If necessary, switch to the new choice. - if (protocol_type_ != ICEPROTO_RFC5245 || ice_role_ == ICEROLE_CONTROLLING) { - if (ShouldSwitch(best_connection_, top_connection)) - SwitchBestConnectionTo(top_connection); - } - - // We can prune any connection for which there is a writable connection on - // the same network with better or equal priority. We leave those with - // better priority just in case they become writable later (at which point, - // we would prune out the current best connection). We leave connections on - // other networks because they may not be using the same resources and they - // may represent very distinct paths over which we can switch. - std::set<rtc::Network*>::iterator network; - for (network = networks.begin(); network != networks.end(); ++network) { - Connection* primier = GetBestConnectionOnNetwork(*network); - if (!primier || (primier->write_state() != Connection::STATE_WRITABLE)) - continue; - - for (uint32 i = 0; i < connections_.size(); ++i) { - if ((connections_[i] != primier) && - (connections_[i]->port()->Network() == *network) && - (CompareConnectionCandidates(primier, connections_[i]) >= 0)) { - connections_[i]->Prune(); - } - } - } - - // Check if all connections are timedout. - bool all_connections_timedout = true; - for (uint32 i = 0; i < connections_.size(); ++i) { - if (connections_[i]->write_state() != Connection::STATE_WRITE_TIMEOUT) { - all_connections_timedout = false; - break; - } - } - - // Now update the writable state of the channel with the information we have - // so far. - if (best_connection_ && best_connection_->writable()) { - HandleWritable(); - } else if (all_connections_timedout) { - HandleAllTimedOut(); - } else { - HandleNotWritable(); - } - - // Update the state of this channel. This method is called whenever the - // state of any connection changes, so this is a good place to do this. - UpdateChannelState(); -} - - -// Track the best connection, and let listeners know -void P2PTransportChannel::SwitchBestConnectionTo(Connection* conn) { - // Note: if conn is NULL, the previous best_connection_ has been destroyed, - // so don't use it. - Connection* old_best_connection = best_connection_; - best_connection_ = conn; - if (best_connection_) { - if (old_best_connection) { - LOG_J(LS_INFO, this) << "Previous best connection: " - << old_best_connection->ToString(); - } - LOG_J(LS_INFO, this) << "New best connection: " - << best_connection_->ToString(); - SignalRouteChange(this, best_connection_->remote_candidate()); - } else { - LOG_J(LS_INFO, this) << "No best connection"; - } -} - -void P2PTransportChannel::UpdateChannelState() { - // The Handle* functions already set the writable state. We'll just double- - // check it here. - bool writable = ((best_connection_ != NULL) && - (best_connection_->write_state() == - Connection::STATE_WRITABLE)); - ASSERT(writable == this->writable()); - if (writable != this->writable()) - LOG(LS_ERROR) << "UpdateChannelState: writable state mismatch"; - - bool readable = false; - for (uint32 i = 0; i < connections_.size(); ++i) { - if (connections_[i]->read_state() == Connection::STATE_READABLE) { - readable = true; - break; - } - } - set_readable(readable); -} - -// We checked the status of our connections and we had at least one that -// was writable, go into the writable state. -void P2PTransportChannel::HandleWritable() { - ASSERT(worker_thread_ == rtc::Thread::Current()); - if (!writable()) { - for (uint32 i = 0; i < allocator_sessions_.size(); ++i) { - if (allocator_sessions_[i]->IsGettingPorts()) { - allocator_sessions_[i]->StopGettingPorts(); - } - } - } - - was_writable_ = true; - set_writable(true); -} - -// Notify upper layer about channel not writable state, if it was before. -void P2PTransportChannel::HandleNotWritable() { - ASSERT(worker_thread_ == rtc::Thread::Current()); - if (was_writable_) { - was_writable_ = false; - set_writable(false); - } -} - -void P2PTransportChannel::HandleAllTimedOut() { - // Currently we are treating this as channel not writable. - HandleNotWritable(); -} - -// If we have a best connection, return it, otherwise return top one in the -// list (later we will mark it best). -Connection* P2PTransportChannel::GetBestConnectionOnNetwork( - rtc::Network* network) { - // If the best connection is on this network, then it wins. - if (best_connection_ && (best_connection_->port()->Network() == network)) - return best_connection_; - - // Otherwise, we return the top-most in sorted order. - for (uint32 i = 0; i < connections_.size(); ++i) { - if (connections_[i]->port()->Network() == network) - return connections_[i]; - } - - return NULL; -} - -// Handle any queued up requests -void P2PTransportChannel::OnMessage(rtc::Message *pmsg) { - switch (pmsg->message_id) { - case MSG_SORT: - OnSort(); - break; - case MSG_PING: - OnPing(); - break; - default: - ASSERT(false); - break; - } -} - -// Handle queued up sort request -void P2PTransportChannel::OnSort() { - // Resort the connections based on the new statistics. - SortConnections(); -} - -// Handle queued up ping request -void P2PTransportChannel::OnPing() { - // Make sure the states of the connections are up-to-date (since this affects - // which ones are pingable). - UpdateConnectionStates(); - - // Find the oldest pingable connection and have it do a ping. - Connection* conn = FindNextPingableConnection(); - if (conn) - PingConnection(conn); - - // Post ourselves a message to perform the next ping. - uint32 delay = writable() ? WRITABLE_DELAY : UNWRITABLE_DELAY; - thread()->PostDelayed(delay, this, MSG_PING); -} - -// Is the connection in a state for us to even consider pinging the other side? -bool P2PTransportChannel::IsPingable(Connection* conn) { - // An unconnected connection cannot be written to at all, so pinging is out - // of the question. - if (!conn->connected()) - return false; - - if (writable()) { - // If we are writable, then we only want to ping connections that could be - // better than this one, i.e., the ones that were not pruned. - return (conn->write_state() != Connection::STATE_WRITE_TIMEOUT); - } else { - // If we are not writable, then we need to try everything that might work. - // This includes both connections that do not have write timeout as well as - // ones that do not have read timeout. A connection could be readable but - // be in write-timeout if we pruned it before. Since the other side is - // still pinging it, it very well might still work. - return (conn->write_state() != Connection::STATE_WRITE_TIMEOUT) || - (conn->read_state() != Connection::STATE_READ_TIMEOUT); - } -} - -// Returns the next pingable connection to ping. This will be the oldest -// pingable connection unless we have a writable connection that is past the -// maximum acceptable ping delay. -Connection* P2PTransportChannel::FindNextPingableConnection() { - uint32 now = rtc::Time(); - if (best_connection_ && - (best_connection_->write_state() == Connection::STATE_WRITABLE) && - (best_connection_->last_ping_sent() - + MAX_CURRENT_WRITABLE_DELAY <= now)) { - return best_connection_; - } - - Connection* oldest_conn = NULL; - uint32 oldest_time = 0xFFFFFFFF; - for (uint32 i = 0; i < connections_.size(); ++i) { - if (IsPingable(connections_[i])) { - if (connections_[i]->last_ping_sent() < oldest_time) { - oldest_time = connections_[i]->last_ping_sent(); - oldest_conn = connections_[i]; - } - } - } - return oldest_conn; -} - -// Apart from sending ping from |conn| this method also updates -// |use_candidate_attr| flag. The criteria to update this flag is -// explained below. -// Set USE-CANDIDATE if doing ICE AND this channel is in CONTROLLING AND -// a) Channel is in FULL ICE AND -// a.1) |conn| is the best connection OR -// a.2) there is no best connection OR -// a.3) the best connection is unwritable OR -// a.4) |conn| has higher priority than best_connection. -// b) we're doing LITE ICE AND -// b.1) |conn| is the best_connection AND -// b.2) |conn| is writable. -void P2PTransportChannel::PingConnection(Connection* conn) { - bool use_candidate = false; - if (protocol_type_ == ICEPROTO_RFC5245) { - if (remote_ice_mode_ == ICEMODE_FULL && ice_role_ == ICEROLE_CONTROLLING) { - use_candidate = (conn == best_connection_) || - (best_connection_ == NULL) || - (!best_connection_->writable()) || - (conn->priority() > best_connection_->priority()); - } else if (remote_ice_mode_ == ICEMODE_LITE && conn == best_connection_) { - use_candidate = best_connection_->writable(); - } - } - conn->set_use_candidate_attr(use_candidate); - conn->Ping(rtc::Time()); -} - -// When a connection's state changes, we need to figure out who to use as -// the best connection again. It could have become usable, or become unusable. -void P2PTransportChannel::OnConnectionStateChange(Connection* connection) { - ASSERT(worker_thread_ == rtc::Thread::Current()); - - // Update the best connection if the state change is from pending best - // connection and role is controlled. - if (protocol_type_ == ICEPROTO_RFC5245 && ice_role_ == ICEROLE_CONTROLLED) { - if (connection == pending_best_connection_ && connection->writable()) { - pending_best_connection_ = NULL; - SwitchBestConnectionTo(connection); - } - } - - // We have to unroll the stack before doing this because we may be changing - // the state of connections while sorting. - RequestSort(); -} - -// When a connection is removed, edit it out, and then update our best -// connection. -void P2PTransportChannel::OnConnectionDestroyed(Connection* connection) { - ASSERT(worker_thread_ == rtc::Thread::Current()); - - // Note: the previous best_connection_ may be destroyed by now, so don't - // use it. - - // Remove this connection from the list. - std::vector<Connection*>::iterator iter = - std::find(connections_.begin(), connections_.end(), connection); - ASSERT(iter != connections_.end()); - connections_.erase(iter); - - LOG_J(LS_INFO, this) << "Removed connection (" - << static_cast<int>(connections_.size()) << " remaining)"; - - if (pending_best_connection_ == connection) { - pending_best_connection_ = NULL; - } - - // If this is currently the best connection, then we need to pick a new one. - // The call to SortConnections will pick a new one. It looks at the current - // best connection in order to avoid switching between fairly similar ones. - // Since this connection is no longer an option, we can just set best to NULL - // and re-choose a best assuming that there was no best connection. - if (best_connection_ == connection) { - SwitchBestConnectionTo(NULL); - RequestSort(); - } - - SignalConnectionRemoved(this); -} - -// When a port is destroyed remove it from our list of ports to use for -// connection attempts. -void P2PTransportChannel::OnPortDestroyed(PortInterface* port) { - ASSERT(worker_thread_ == rtc::Thread::Current()); - - // Remove this port from the list (if we didn't drop it already). - std::vector<PortInterface*>::iterator iter = - std::find(ports_.begin(), ports_.end(), port); - if (iter != ports_.end()) - ports_.erase(iter); - - LOG(INFO) << "Removed port from p2p socket: " - << static_cast<int>(ports_.size()) << " remaining"; -} - -// We data is available, let listeners know -void P2PTransportChannel::OnReadPacket( - Connection *connection, const char *data, size_t len, - const rtc::PacketTime& packet_time) { - ASSERT(worker_thread_ == rtc::Thread::Current()); - - // Do not deliver, if packet doesn't belong to the correct transport channel. - if (!FindConnection(connection)) - return; - - // Let the client know of an incoming packet - SignalReadPacket(this, data, len, packet_time, 0); -} - -void P2PTransportChannel::OnReadyToSend(Connection* connection) { - if (connection == best_connection_ && writable()) { - SignalReadyToSend(this); - } -} - -} // namespace cricket diff --git a/talk/p2p/base/p2ptransportchannel.h b/talk/p2p/base/p2ptransportchannel.h deleted file mode 100644 index 6d459996b..000000000 --- a/talk/p2p/base/p2ptransportchannel.h +++ /dev/null @@ -1,259 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -// P2PTransportChannel wraps up the state management of the connection between -// two P2P clients. Clients have candidate ports for connecting, and -// connections which are combinations of candidates from each end (Alice and -// Bob each have candidates, one candidate from Alice and one candidate from -// Bob are used to make a connection, repeat to make many connections). -// -// When all of the available connections become invalid (non-writable), we -// kick off a process of determining more candidates and more connections. -// -#ifndef WEBRTC_P2P_BASE_P2PTRANSPORTCHANNEL_H_ -#define WEBRTC_P2P_BASE_P2PTRANSPORTCHANNEL_H_ - -#include <map> -#include <string> -#include <vector> -#include "webrtc/p2p/base/candidate.h" -#include "webrtc/p2p/base/p2ptransport.h" -#include "webrtc/p2p/base/portallocator.h" -#include "webrtc/p2p/base/portinterface.h" -#include "webrtc/p2p/base/transport.h" -#include "webrtc/p2p/base/transportchannelimpl.h" -#include "webrtc/base/asyncpacketsocket.h" -#include "webrtc/base/sigslot.h" - -namespace cricket { - -// Adds the port on which the candidate originated. -class RemoteCandidate : public Candidate { - public: - RemoteCandidate(const Candidate& c, PortInterface* origin_port) - : Candidate(c), origin_port_(origin_port) {} - - PortInterface* origin_port() { return origin_port_; } - - private: - PortInterface* origin_port_; -}; - -// P2PTransportChannel manages the candidates and connection process to keep -// two P2P clients connected to each other. -class P2PTransportChannel : public TransportChannelImpl, - public rtc::MessageHandler { - public: - P2PTransportChannel(const std::string& content_name, - int component, - P2PTransport* transport, - PortAllocator *allocator); - virtual ~P2PTransportChannel(); - - // From TransportChannelImpl: - virtual Transport* GetTransport() { return transport_; } - virtual void SetIceRole(IceRole role); - virtual IceRole GetIceRole() const { return ice_role_; } - virtual void SetIceTiebreaker(uint64 tiebreaker); - virtual size_t GetConnectionCount() const { return connections_.size(); } - virtual bool GetIceProtocolType(IceProtocolType* type) const; - virtual void SetIceProtocolType(IceProtocolType type); - virtual void SetIceCredentials(const std::string& ice_ufrag, - const std::string& ice_pwd); - virtual void SetRemoteIceCredentials(const std::string& ice_ufrag, - const std::string& ice_pwd); - virtual void SetRemoteIceMode(IceMode mode); - virtual void Connect(); - virtual void Reset(); - virtual void OnSignalingReady(); - virtual void OnCandidate(const Candidate& candidate); - - // From TransportChannel: - virtual int SendPacket(const char *data, size_t len, - const rtc::PacketOptions& options, int flags); - virtual int SetOption(rtc::Socket::Option opt, int value); - virtual int GetError() { return error_; } - virtual bool GetStats(std::vector<ConnectionInfo>* stats); - - const Connection* best_connection() const { return best_connection_; } - void set_incoming_only(bool value) { incoming_only_ = value; } - - // Note: This is only for testing purpose. - // |ports_| should not be changed from outside. - const std::vector<PortInterface *>& ports() { return ports_; } - - IceMode remote_ice_mode() const { return remote_ice_mode_; } - - // DTLS methods. - virtual bool IsDtlsActive() const { return false; } - - // Default implementation. - virtual bool GetSslRole(rtc::SSLRole* role) const { - return false; - } - - virtual bool SetSslRole(rtc::SSLRole role) { - return false; - } - - // Set up the ciphers to use for DTLS-SRTP. - virtual bool SetSrtpCiphers(const std::vector<std::string>& ciphers) { - return false; - } - - // Find out which DTLS-SRTP cipher was negotiated - virtual bool GetSrtpCipher(std::string* cipher) { - return false; - } - - // Returns false because the channel is not encrypted by default. - virtual bool GetLocalIdentity(rtc::SSLIdentity** identity) const { - return false; - } - - virtual bool GetRemoteCertificate(rtc::SSLCertificate** cert) const { - return false; - } - - // Allows key material to be extracted for external encryption. - virtual bool ExportKeyingMaterial( - const std::string& label, - const uint8* context, - size_t context_len, - bool use_context, - uint8* result, - size_t result_len) { - return false; - } - - virtual bool SetLocalIdentity(rtc::SSLIdentity* identity) { - return false; - } - - // Set DTLS Remote fingerprint. Must be after local identity set. - virtual bool SetRemoteFingerprint( - const std::string& digest_alg, - const uint8* digest, - size_t digest_len) { - return false; - } - - // Helper method used only in unittest. - rtc::DiffServCodePoint DefaultDscpValue() const; - - private: - rtc::Thread* thread() { return worker_thread_; } - PortAllocatorSession* allocator_session() { - return allocator_sessions_.back(); - } - - void Allocate(); - void UpdateConnectionStates(); - void RequestSort(); - void SortConnections(); - void SwitchBestConnectionTo(Connection* conn); - void UpdateChannelState(); - void HandleWritable(); - void HandleNotWritable(); - void HandleAllTimedOut(); - - Connection* GetBestConnectionOnNetwork(rtc::Network* network); - bool CreateConnections(const Candidate &remote_candidate, - PortInterface* origin_port, bool readable); - bool CreateConnection(PortInterface* port, const Candidate& remote_candidate, - PortInterface* origin_port, bool readable); - bool FindConnection(cricket::Connection* connection) const; - - uint32 GetRemoteCandidateGeneration(const Candidate& candidate); - bool IsDuplicateRemoteCandidate(const Candidate& candidate); - void RememberRemoteCandidate(const Candidate& remote_candidate, - PortInterface* origin_port); - bool IsPingable(Connection* conn); - Connection* FindNextPingableConnection(); - void PingConnection(Connection* conn); - void AddAllocatorSession(PortAllocatorSession* session); - void AddConnection(Connection* connection); - - void OnPortReady(PortAllocatorSession *session, PortInterface* port); - void OnCandidatesReady(PortAllocatorSession *session, - const std::vector<Candidate>& candidates); - void OnCandidatesAllocationDone(PortAllocatorSession* session); - void OnUnknownAddress(PortInterface* port, - const rtc::SocketAddress& addr, - ProtocolType proto, - IceMessage* stun_msg, - const std::string& remote_username, - bool port_muxed); - void OnPortDestroyed(PortInterface* port); - void OnRoleConflict(PortInterface* port); - - void OnConnectionStateChange(Connection* connection); - void OnReadPacket(Connection *connection, const char *data, size_t len, - const rtc::PacketTime& packet_time); - void OnReadyToSend(Connection* connection); - void OnConnectionDestroyed(Connection *connection); - - void OnUseCandidate(Connection* conn); - - virtual void OnMessage(rtc::Message *pmsg); - void OnSort(); - void OnPing(); - - P2PTransport* transport_; - PortAllocator *allocator_; - rtc::Thread *worker_thread_; - bool incoming_only_; - bool waiting_for_signaling_; - int error_; - std::vector<PortAllocatorSession*> allocator_sessions_; - std::vector<PortInterface *> ports_; - std::vector<Connection *> connections_; - Connection* best_connection_; - // Connection selected by the controlling agent. This should be used only - // at controlled side when protocol type is RFC5245. - Connection* pending_best_connection_; - std::vector<RemoteCandidate> remote_candidates_; - bool sort_dirty_; // indicates whether another sort is needed right now - bool was_writable_; - typedef std::map<rtc::Socket::Option, int> OptionMap; - OptionMap options_; - std::string ice_ufrag_; - std::string ice_pwd_; - std::string remote_ice_ufrag_; - std::string remote_ice_pwd_; - IceProtocolType protocol_type_; - IceMode remote_ice_mode_; - IceRole ice_role_; - uint64 tiebreaker_; - uint32 remote_candidate_generation_; - - DISALLOW_EVIL_CONSTRUCTORS(P2PTransportChannel); -}; - -} // namespace cricket - -#endif // WEBRTC_P2P_BASE_P2PTRANSPORTCHANNEL_H_ diff --git a/talk/p2p/base/p2ptransportchannel_unittest.cc b/talk/p2p/base/p2ptransportchannel_unittest.cc deleted file mode 100644 index d7c0b9ffe..000000000 --- a/talk/p2p/base/p2ptransportchannel_unittest.cc +++ /dev/null @@ -1,1719 +0,0 @@ -/* - * libjingle - * Copyright 2009 Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "webrtc/p2p/base/p2ptransportchannel.h" -#include "webrtc/p2p/base/testrelayserver.h" -#include "webrtc/p2p/base/teststunserver.h" -#include "webrtc/p2p/base/testturnserver.h" -#include "webrtc/p2p/client/basicportallocator.h" -#include "webrtc/base/dscp.h" -#include "webrtc/base/fakenetwork.h" -#include "webrtc/base/firewallsocketserver.h" -#include "webrtc/base/gunit.h" -#include "webrtc/base/helpers.h" -#include "webrtc/base/logging.h" -#include "webrtc/base/natserver.h" -#include "webrtc/base/natsocketfactory.h" -#include "webrtc/base/physicalsocketserver.h" -#include "webrtc/base/proxyserver.h" -#include "webrtc/base/socketaddress.h" -#include "webrtc/base/ssladapter.h" -#include "webrtc/base/thread.h" -#include "webrtc/base/virtualsocketserver.h" - -using cricket::kDefaultPortAllocatorFlags; -using cricket::kMinimumStepDelay; -using cricket::kDefaultStepDelay; -using cricket::PORTALLOCATOR_ENABLE_SHARED_UFRAG; -using cricket::PORTALLOCATOR_ENABLE_SHARED_SOCKET; -using cricket::ServerAddresses; -using rtc::SocketAddress; - -static const int kDefaultTimeout = 1000; -static const int kOnlyLocalPorts = cricket::PORTALLOCATOR_DISABLE_STUN | - cricket::PORTALLOCATOR_DISABLE_RELAY | - cricket::PORTALLOCATOR_DISABLE_TCP; -// Addresses on the public internet. -static const SocketAddress kPublicAddrs[2] = - { SocketAddress("11.11.11.11", 0), SocketAddress("22.22.22.22", 0) }; -// IPv6 Addresses on the public internet. -static const SocketAddress kIPv6PublicAddrs[2] = { - SocketAddress("2400:4030:1:2c00:be30:abcd:efab:cdef", 0), - SocketAddress("2620:0:1000:1b03:2e41:38ff:fea6:f2a4", 0) -}; -// For configuring multihomed clients. -static const SocketAddress kAlternateAddrs[2] = - { SocketAddress("11.11.11.101", 0), SocketAddress("22.22.22.202", 0) }; -// Addresses for HTTP proxy servers. -static const SocketAddress kHttpsProxyAddrs[2] = - { SocketAddress("11.11.11.1", 443), SocketAddress("22.22.22.1", 443) }; -// Addresses for SOCKS proxy servers. -static const SocketAddress kSocksProxyAddrs[2] = - { SocketAddress("11.11.11.1", 1080), SocketAddress("22.22.22.1", 1080) }; -// Internal addresses for NAT boxes. -static const SocketAddress kNatAddrs[2] = - { SocketAddress("192.168.1.1", 0), SocketAddress("192.168.2.1", 0) }; -// Private addresses inside the NAT private networks. -static const SocketAddress kPrivateAddrs[2] = - { SocketAddress("192.168.1.11", 0), SocketAddress("192.168.2.22", 0) }; -// For cascaded NATs, the internal addresses of the inner NAT boxes. -static const SocketAddress kCascadedNatAddrs[2] = - { SocketAddress("192.168.10.1", 0), SocketAddress("192.168.20.1", 0) }; -// For cascaded NATs, private addresses inside the inner private networks. -static const SocketAddress kCascadedPrivateAddrs[2] = - { SocketAddress("192.168.10.11", 0), SocketAddress("192.168.20.22", 0) }; -// The address of the public STUN server. -static const SocketAddress kStunAddr("99.99.99.1", cricket::STUN_SERVER_PORT); -// The addresses for the public relay server. -static const SocketAddress kRelayUdpIntAddr("99.99.99.2", 5000); -static const SocketAddress kRelayUdpExtAddr("99.99.99.3", 5001); -static const SocketAddress kRelayTcpIntAddr("99.99.99.2", 5002); -static const SocketAddress kRelayTcpExtAddr("99.99.99.3", 5003); -static const SocketAddress kRelaySslTcpIntAddr("99.99.99.2", 5004); -static const SocketAddress kRelaySslTcpExtAddr("99.99.99.3", 5005); -// The addresses for the public turn server. -static const SocketAddress kTurnUdpIntAddr("99.99.99.4", - cricket::STUN_SERVER_PORT); -static const SocketAddress kTurnUdpExtAddr("99.99.99.5", 0); -static const cricket::RelayCredentials kRelayCredentials("test", "test"); - -// Based on ICE_UFRAG_LENGTH -static const char* kIceUfrag[4] = {"TESTICEUFRAG0000", "TESTICEUFRAG0001", - "TESTICEUFRAG0002", "TESTICEUFRAG0003"}; -// Based on ICE_PWD_LENGTH -static const char* kIcePwd[4] = {"TESTICEPWD00000000000000", - "TESTICEPWD00000000000001", - "TESTICEPWD00000000000002", - "TESTICEPWD00000000000003"}; - -static const uint64 kTiebreaker1 = 11111; -static const uint64 kTiebreaker2 = 22222; - -// This test simulates 2 P2P endpoints that want to establish connectivity -// with each other over various network topologies and conditions, which can be -// specified in each individial test. -// A virtual network (via VirtualSocketServer) along with virtual firewalls and -// NATs (via Firewall/NATSocketServer) are used to simulate the various network -// conditions. We can configure the IP addresses of the endpoints, -// block various types of connectivity, or add arbitrary levels of NAT. -// We also run a STUN server and a relay server on the virtual network to allow -// our typical P2P mechanisms to do their thing. -// For each case, we expect the P2P stack to eventually settle on a specific -// form of connectivity to the other side. The test checks that the P2P -// negotiation successfully establishes connectivity within a certain time, -// and that the result is what we expect. -// Note that this class is a base class for use by other tests, who will provide -// specialized test behavior. -class P2PTransportChannelTestBase : public testing::Test, - public rtc::MessageHandler, - public sigslot::has_slots<> { - public: - P2PTransportChannelTestBase() - : main_(rtc::Thread::Current()), - pss_(new rtc::PhysicalSocketServer), - vss_(new rtc::VirtualSocketServer(pss_.get())), - nss_(new rtc::NATSocketServer(vss_.get())), - ss_(new rtc::FirewallSocketServer(nss_.get())), - ss_scope_(ss_.get()), - stun_server_(cricket::TestStunServer::Create(main_, kStunAddr)), - turn_server_(main_, kTurnUdpIntAddr, kTurnUdpExtAddr), - relay_server_(main_, kRelayUdpIntAddr, kRelayUdpExtAddr, - kRelayTcpIntAddr, kRelayTcpExtAddr, - kRelaySslTcpIntAddr, kRelaySslTcpExtAddr), - socks_server1_(ss_.get(), kSocksProxyAddrs[0], - ss_.get(), kSocksProxyAddrs[0]), - socks_server2_(ss_.get(), kSocksProxyAddrs[1], - ss_.get(), kSocksProxyAddrs[1]), - clear_remote_candidates_ufrag_pwd_(false), - force_relay_(false) { - ep1_.role_ = cricket::ICEROLE_CONTROLLING; - ep2_.role_ = cricket::ICEROLE_CONTROLLED; - - ServerAddresses stun_servers; - stun_servers.insert(kStunAddr); - ep1_.allocator_.reset(new cricket::BasicPortAllocator( - &ep1_.network_manager_, - stun_servers, kRelayUdpIntAddr, kRelayTcpIntAddr, kRelaySslTcpIntAddr)); - ep2_.allocator_.reset(new cricket::BasicPortAllocator( - &ep2_.network_manager_, - stun_servers, kRelayUdpIntAddr, kRelayTcpIntAddr, kRelaySslTcpIntAddr)); - } - - protected: - enum Config { - OPEN, // Open to the Internet - NAT_FULL_CONE, // NAT, no filtering - NAT_ADDR_RESTRICTED, // NAT, must send to an addr to recv - NAT_PORT_RESTRICTED, // NAT, must send to an addr+port to recv - NAT_SYMMETRIC, // NAT, endpoint-dependent bindings - NAT_DOUBLE_CONE, // Double NAT, both cone - NAT_SYMMETRIC_THEN_CONE, // Double NAT, symmetric outer, cone inner - BLOCK_UDP, // Firewall, UDP in/out blocked - BLOCK_UDP_AND_INCOMING_TCP, // Firewall, UDP in/out and TCP in blocked - BLOCK_ALL_BUT_OUTGOING_HTTP, // Firewall, only TCP out on 80/443 - PROXY_HTTPS, // All traffic through HTTPS proxy - PROXY_SOCKS, // All traffic through SOCKS proxy - NUM_CONFIGS - }; - - struct Result { - Result(const std::string& lt, const std::string& lp, - const std::string& rt, const std::string& rp, - const std::string& lt2, const std::string& lp2, - const std::string& rt2, const std::string& rp2, int wait) - : local_type(lt), local_proto(lp), remote_type(rt), remote_proto(rp), - local_type2(lt2), local_proto2(lp2), remote_type2(rt2), - remote_proto2(rp2), connect_wait(wait) { - } - std::string local_type; - std::string local_proto; - std::string remote_type; - std::string remote_proto; - std::string local_type2; - std::string local_proto2; - std::string remote_type2; - std::string remote_proto2; - int connect_wait; - }; - - struct ChannelData { - bool CheckData(const char* data, int len) { - bool ret = false; - if (!ch_packets_.empty()) { - std::string packet = ch_packets_.front(); - ret = (packet == std::string(data, len)); - ch_packets_.pop_front(); - } - return ret; - } - - std::string name_; // TODO - Currently not used. - std::list<std::string> ch_packets_; - rtc::scoped_ptr<cricket::P2PTransportChannel> ch_; - }; - - struct Endpoint { - Endpoint() : signaling_delay_(0), role_(cricket::ICEROLE_UNKNOWN), - tiebreaker_(0), role_conflict_(false), - protocol_type_(cricket::ICEPROTO_GOOGLE) {} - bool HasChannel(cricket::TransportChannel* ch) { - return (ch == cd1_.ch_.get() || ch == cd2_.ch_.get()); - } - ChannelData* GetChannelData(cricket::TransportChannel* ch) { - if (!HasChannel(ch)) return NULL; - if (cd1_.ch_.get() == ch) - return &cd1_; - else - return &cd2_; - } - void SetSignalingDelay(int delay) { signaling_delay_ = delay; } - - void SetIceRole(cricket::IceRole role) { role_ = role; } - cricket::IceRole ice_role() { return role_; } - void SetIceProtocolType(cricket::IceProtocolType type) { - protocol_type_ = type; - } - cricket::IceProtocolType protocol_type() { return protocol_type_; } - void SetIceTiebreaker(uint64 tiebreaker) { tiebreaker_ = tiebreaker; } - uint64 GetIceTiebreaker() { return tiebreaker_; } - void OnRoleConflict(bool role_conflict) { role_conflict_ = role_conflict; } - bool role_conflict() { return role_conflict_; } - void SetAllocationStepDelay(uint32 delay) { - allocator_->set_step_delay(delay); - } - void SetAllowTcpListen(bool allow_tcp_listen) { - allocator_->set_allow_tcp_listen(allow_tcp_listen); - } - - rtc::FakeNetworkManager network_manager_; - rtc::scoped_ptr<cricket::BasicPortAllocator> allocator_; - ChannelData cd1_; - ChannelData cd2_; - int signaling_delay_; - cricket::IceRole role_; - uint64 tiebreaker_; - bool role_conflict_; - cricket::IceProtocolType protocol_type_; - }; - - struct CandidateData : public rtc::MessageData { - CandidateData(cricket::TransportChannel* ch, const cricket::Candidate& c) - : channel(ch), candidate(c) { - } - cricket::TransportChannel* channel; - cricket::Candidate candidate; - }; - - ChannelData* GetChannelData(cricket::TransportChannel* channel) { - if (ep1_.HasChannel(channel)) - return ep1_.GetChannelData(channel); - else - return ep2_.GetChannelData(channel); - } - - void CreateChannels(int num) { - std::string ice_ufrag_ep1_cd1_ch = kIceUfrag[0]; - std::string ice_pwd_ep1_cd1_ch = kIcePwd[0]; - std::string ice_ufrag_ep2_cd1_ch = kIceUfrag[1]; - std::string ice_pwd_ep2_cd1_ch = kIcePwd[1]; - ep1_.cd1_.ch_.reset(CreateChannel( - 0, cricket::ICE_CANDIDATE_COMPONENT_DEFAULT, - ice_ufrag_ep1_cd1_ch, ice_pwd_ep1_cd1_ch, - ice_ufrag_ep2_cd1_ch, ice_pwd_ep2_cd1_ch)); - ep2_.cd1_.ch_.reset(CreateChannel( - 1, cricket::ICE_CANDIDATE_COMPONENT_DEFAULT, - ice_ufrag_ep2_cd1_ch, ice_pwd_ep2_cd1_ch, - ice_ufrag_ep1_cd1_ch, ice_pwd_ep1_cd1_ch)); - if (num == 2) { - std::string ice_ufrag_ep1_cd2_ch = kIceUfrag[2]; - std::string ice_pwd_ep1_cd2_ch = kIcePwd[2]; - std::string ice_ufrag_ep2_cd2_ch = kIceUfrag[3]; - std::string ice_pwd_ep2_cd2_ch = kIcePwd[3]; - // In BUNDLE each endpoint must share common ICE credentials. - if (ep1_.allocator_->flags() & cricket::PORTALLOCATOR_ENABLE_BUNDLE) { - ice_ufrag_ep1_cd2_ch = ice_ufrag_ep1_cd1_ch; - ice_pwd_ep1_cd2_ch = ice_pwd_ep1_cd1_ch; - } - if (ep2_.allocator_->flags() & cricket::PORTALLOCATOR_ENABLE_BUNDLE) { - ice_ufrag_ep2_cd2_ch = ice_ufrag_ep2_cd1_ch; - ice_pwd_ep2_cd2_ch = ice_pwd_ep2_cd1_ch; - } - ep1_.cd2_.ch_.reset(CreateChannel( - 0, cricket::ICE_CANDIDATE_COMPONENT_DEFAULT, - ice_ufrag_ep1_cd2_ch, ice_pwd_ep1_cd2_ch, - ice_ufrag_ep2_cd2_ch, ice_pwd_ep2_cd2_ch)); - ep2_.cd2_.ch_.reset(CreateChannel( - 1, cricket::ICE_CANDIDATE_COMPONENT_DEFAULT, - ice_ufrag_ep2_cd2_ch, ice_pwd_ep2_cd2_ch, - ice_ufrag_ep1_cd2_ch, ice_pwd_ep1_cd2_ch)); - } - } - cricket::P2PTransportChannel* CreateChannel( - int endpoint, - int component, - const std::string& local_ice_ufrag, - const std::string& local_ice_pwd, - const std::string& remote_ice_ufrag, - const std::string& remote_ice_pwd) { - cricket::P2PTransportChannel* channel = new cricket::P2PTransportChannel( - "test content name", component, NULL, GetAllocator(endpoint)); - channel->SignalRequestSignaling.connect( - this, &P2PTransportChannelTestBase::OnChannelRequestSignaling); - channel->SignalCandidateReady.connect(this, - &P2PTransportChannelTestBase::OnCandidate); - channel->SignalReadPacket.connect( - this, &P2PTransportChannelTestBase::OnReadPacket); - channel->SignalRoleConflict.connect( - this, &P2PTransportChannelTestBase::OnRoleConflict); - channel->SetIceProtocolType(GetEndpoint(endpoint)->protocol_type()); - channel->SetIceCredentials(local_ice_ufrag, local_ice_pwd); - if (clear_remote_candidates_ufrag_pwd_) { - // This only needs to be set if we're clearing them from the - // candidates. Some unit tests rely on this not being set. - channel->SetRemoteIceCredentials(remote_ice_ufrag, remote_ice_pwd); - } - channel->SetIceRole(GetEndpoint(endpoint)->ice_role()); - channel->SetIceTiebreaker(GetEndpoint(endpoint)->GetIceTiebreaker()); - channel->Connect(); - return channel; - } - void DestroyChannels() { - ep1_.cd1_.ch_.reset(); - ep2_.cd1_.ch_.reset(); - ep1_.cd2_.ch_.reset(); - ep2_.cd2_.ch_.reset(); - } - cricket::P2PTransportChannel* ep1_ch1() { return ep1_.cd1_.ch_.get(); } - cricket::P2PTransportChannel* ep1_ch2() { return ep1_.cd2_.ch_.get(); } - cricket::P2PTransportChannel* ep2_ch1() { return ep2_.cd1_.ch_.get(); } - cricket::P2PTransportChannel* ep2_ch2() { return ep2_.cd2_.ch_.get(); } - - // Common results. - static const Result kLocalUdpToLocalUdp; - static const Result kLocalUdpToStunUdp; - static const Result kLocalUdpToPrflxUdp; - static const Result kPrflxUdpToLocalUdp; - static const Result kStunUdpToLocalUdp; - static const Result kStunUdpToStunUdp; - static const Result kPrflxUdpToStunUdp; - static const Result kLocalUdpToRelayUdp; - static const Result kPrflxUdpToRelayUdp; - static const Result kLocalTcpToLocalTcp; - static const Result kLocalTcpToPrflxTcp; - static const Result kPrflxTcpToLocalTcp; - - rtc::NATSocketServer* nat() { return nss_.get(); } - rtc::FirewallSocketServer* fw() { return ss_.get(); } - - Endpoint* GetEndpoint(int endpoint) { - if (endpoint == 0) { - return &ep1_; - } else if (endpoint == 1) { - return &ep2_; - } else { - return NULL; - } - } - cricket::PortAllocator* GetAllocator(int endpoint) { - return GetEndpoint(endpoint)->allocator_.get(); - } - void AddAddress(int endpoint, const SocketAddress& addr) { - GetEndpoint(endpoint)->network_manager_.AddInterface(addr); - } - void RemoveAddress(int endpoint, const SocketAddress& addr) { - GetEndpoint(endpoint)->network_manager_.RemoveInterface(addr); - } - void SetProxy(int endpoint, rtc::ProxyType type) { - rtc::ProxyInfo info; - info.type = type; - info.address = (type == rtc::PROXY_HTTPS) ? - kHttpsProxyAddrs[endpoint] : kSocksProxyAddrs[endpoint]; - GetAllocator(endpoint)->set_proxy("unittest/1.0", info); - } - void SetAllocatorFlags(int endpoint, int flags) { - GetAllocator(endpoint)->set_flags(flags); - } - void SetSignalingDelay(int endpoint, int delay) { - GetEndpoint(endpoint)->SetSignalingDelay(delay); - } - void SetIceProtocol(int endpoint, cricket::IceProtocolType type) { - GetEndpoint(endpoint)->SetIceProtocolType(type); - } - void SetIceRole(int endpoint, cricket::IceRole role) { - GetEndpoint(endpoint)->SetIceRole(role); - } - void SetIceTiebreaker(int endpoint, uint64 tiebreaker) { - GetEndpoint(endpoint)->SetIceTiebreaker(tiebreaker); - } - bool GetRoleConflict(int endpoint) { - return GetEndpoint(endpoint)->role_conflict(); - } - void SetAllocationStepDelay(int endpoint, uint32 delay) { - return GetEndpoint(endpoint)->SetAllocationStepDelay(delay); - } - void SetAllowTcpListen(int endpoint, bool allow_tcp_listen) { - return GetEndpoint(endpoint)->SetAllowTcpListen(allow_tcp_listen); - } - - void Test(const Result& expected) { - int32 connect_start = rtc::Time(), connect_time; - - // Create the channels and wait for them to connect. - CreateChannels(1); - EXPECT_TRUE_WAIT_MARGIN(ep1_ch1() != NULL && - ep2_ch1() != NULL && - ep1_ch1()->readable() && - ep1_ch1()->writable() && - ep2_ch1()->readable() && - ep2_ch1()->writable(), - expected.connect_wait, - 1000); - connect_time = rtc::TimeSince(connect_start); - if (connect_time < expected.connect_wait) { - LOG(LS_INFO) << "Connect time: " << connect_time << " ms"; - } else { - LOG(LS_INFO) << "Connect time: " << "TIMEOUT (" - << expected.connect_wait << " ms)"; - } - - // Allow a few turns of the crank for the best connections to emerge. - // This may take up to 2 seconds. - if (ep1_ch1()->best_connection() && - ep2_ch1()->best_connection()) { - int32 converge_start = rtc::Time(), converge_time; - int converge_wait = 2000; - EXPECT_TRUE_WAIT_MARGIN( - LocalCandidate(ep1_ch1())->type() == expected.local_type && - LocalCandidate(ep1_ch1())->protocol() == expected.local_proto && - RemoteCandidate(ep1_ch1())->type() == expected.remote_type && - RemoteCandidate(ep1_ch1())->protocol() == expected.remote_proto, - converge_wait, - converge_wait); - - // Also do EXPECT_EQ on each part so that failures are more verbose. - EXPECT_EQ(expected.local_type, LocalCandidate(ep1_ch1())->type()); - EXPECT_EQ(expected.local_proto, LocalCandidate(ep1_ch1())->protocol()); - EXPECT_EQ(expected.remote_type, RemoteCandidate(ep1_ch1())->type()); - EXPECT_EQ(expected.remote_proto, RemoteCandidate(ep1_ch1())->protocol()); - - // Verifying remote channel best connection information. This is done - // only for the RFC 5245 as controlled agent will use USE-CANDIDATE - // from controlling (ep1) agent. We can easily predict from EP1 result - // matrix. - if (ep2_.protocol_type_ == cricket::ICEPROTO_RFC5245) { - // Checking for best connection candidates information at remote. - EXPECT_TRUE_WAIT( - LocalCandidate(ep2_ch1())->type() == expected.local_type2 && - LocalCandidate(ep2_ch1())->protocol() == expected.local_proto2 && - RemoteCandidate(ep2_ch1())->protocol() == expected.remote_proto2, - kDefaultTimeout); - - // For verbose - EXPECT_EQ(expected.local_type2, LocalCandidate(ep2_ch1())->type()); - EXPECT_EQ(expected.local_proto2, LocalCandidate(ep2_ch1())->protocol()); - EXPECT_EQ(expected.remote_proto2, - RemoteCandidate(ep2_ch1())->protocol()); - // Removed remote_type comparision aginst best connection remote - // candidate. This is done to handle remote type discrepancy from - // local to stun based on the test type. - // For example in case of Open -> NAT, ep2 channels will have LULU - // and in other cases like NAT -> NAT it will be LUSU. To avoid these - // mismatches and we are doing comparision in different way. - // i.e. when don't match its remote type is either local or stun. - // TODO(ronghuawu): Refine the test criteria. - // https://code.google.com/p/webrtc/issues/detail?id=1953 - if (expected.remote_type2 != RemoteCandidate(ep2_ch1())->type()) { - EXPECT_TRUE(expected.remote_type2 == cricket::LOCAL_PORT_TYPE || - expected.remote_type2 == cricket::STUN_PORT_TYPE); - EXPECT_TRUE( - RemoteCandidate(ep2_ch1())->type() == cricket::LOCAL_PORT_TYPE || - RemoteCandidate(ep2_ch1())->type() == cricket::STUN_PORT_TYPE || - RemoteCandidate(ep2_ch1())->type() == cricket::PRFLX_PORT_TYPE); - } - } - - converge_time = rtc::TimeSince(converge_start); - if (converge_time < converge_wait) { - LOG(LS_INFO) << "Converge time: " << converge_time << " ms"; - } else { - LOG(LS_INFO) << "Converge time: " << "TIMEOUT (" - << converge_wait << " ms)"; - } - } - // Try sending some data to other end. - TestSendRecv(1); - - // Destroy the channels, and wait for them to be fully cleaned up. - DestroyChannels(); - } - - void TestSendRecv(int channels) { - for (int i = 0; i < 10; ++i) { - const char* data = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"; - int len = static_cast<int>(strlen(data)); - // local_channel1 <==> remote_channel1 - EXPECT_EQ_WAIT(len, SendData(ep1_ch1(), data, len), 1000); - EXPECT_TRUE_WAIT(CheckDataOnChannel(ep2_ch1(), data, len), 1000); - EXPECT_EQ_WAIT(len, SendData(ep2_ch1(), data, len), 1000); - EXPECT_TRUE_WAIT(CheckDataOnChannel(ep1_ch1(), data, len), 1000); - if (channels == 2 && ep1_ch2() && ep2_ch2()) { - // local_channel2 <==> remote_channel2 - EXPECT_EQ_WAIT(len, SendData(ep1_ch2(), data, len), 1000); - EXPECT_TRUE_WAIT(CheckDataOnChannel(ep2_ch2(), data, len), 1000); - EXPECT_EQ_WAIT(len, SendData(ep2_ch2(), data, len), 1000); - EXPECT_TRUE_WAIT(CheckDataOnChannel(ep1_ch2(), data, len), 1000); - } - } - } - - // This test waits for the transport to become readable and writable on both - // end points. Once they are, the end points set new local ice credentials to - // restart the ice gathering. Finally it waits for the transport to select a - // new connection using the newly generated ice candidates. - // Before calling this function the end points must be configured. - void TestHandleIceUfragPasswordChanged() { - ep1_ch1()->SetRemoteIceCredentials(kIceUfrag[1], kIcePwd[1]); - ep2_ch1()->SetRemoteIceCredentials(kIceUfrag[0], kIcePwd[0]); - EXPECT_TRUE_WAIT_MARGIN(ep1_ch1()->readable() && ep1_ch1()->writable() && - ep2_ch1()->readable() && ep2_ch1()->writable(), - 1000, 1000); - - const cricket::Candidate* old_local_candidate1 = LocalCandidate(ep1_ch1()); - const cricket::Candidate* old_local_candidate2 = LocalCandidate(ep2_ch1()); - const cricket::Candidate* old_remote_candidate1 = - RemoteCandidate(ep1_ch1()); - const cricket::Candidate* old_remote_candidate2 = - RemoteCandidate(ep2_ch1()); - - ep1_ch1()->SetIceCredentials(kIceUfrag[2], kIcePwd[2]); - ep1_ch1()->SetRemoteIceCredentials(kIceUfrag[3], kIcePwd[3]); - ep2_ch1()->SetIceCredentials(kIceUfrag[3], kIcePwd[3]); - ep2_ch1()->SetRemoteIceCredentials(kIceUfrag[2], kIcePwd[2]); - - EXPECT_TRUE_WAIT_MARGIN(LocalCandidate(ep1_ch1())->generation() != - old_local_candidate1->generation(), - 1000, 1000); - EXPECT_TRUE_WAIT_MARGIN(LocalCandidate(ep2_ch1())->generation() != - old_local_candidate2->generation(), - 1000, 1000); - EXPECT_TRUE_WAIT_MARGIN(RemoteCandidate(ep1_ch1())->generation() != - old_remote_candidate1->generation(), - 1000, 1000); - EXPECT_TRUE_WAIT_MARGIN(RemoteCandidate(ep2_ch1())->generation() != - old_remote_candidate2->generation(), - 1000, 1000); - EXPECT_EQ(1u, RemoteCandidate(ep2_ch1())->generation()); - EXPECT_EQ(1u, RemoteCandidate(ep1_ch1())->generation()); - } - - void TestSignalRoleConflict() { - SetIceProtocol(0, cricket::ICEPROTO_RFC5245); - SetIceTiebreaker(0, kTiebreaker1); // Default EP1 is in controlling state. - - SetIceProtocol(1, cricket::ICEPROTO_RFC5245); - SetIceRole(1, cricket::ICEROLE_CONTROLLING); - SetIceTiebreaker(1, kTiebreaker2); - - // Creating channels with both channels role set to CONTROLLING. - CreateChannels(1); - // Since both the channels initiated with controlling state and channel2 - // has higher tiebreaker value, channel1 should receive SignalRoleConflict. - EXPECT_TRUE_WAIT(GetRoleConflict(0), 1000); - EXPECT_FALSE(GetRoleConflict(1)); - - EXPECT_TRUE_WAIT(ep1_ch1()->readable() && - ep1_ch1()->writable() && - ep2_ch1()->readable() && - ep2_ch1()->writable(), - 1000); - - EXPECT_TRUE(ep1_ch1()->best_connection() && - ep2_ch1()->best_connection()); - - TestSendRecv(1); - } - - void TestHybridConnectivity(cricket::IceProtocolType proto) { - AddAddress(0, kPublicAddrs[0]); - AddAddress(1, kPublicAddrs[1]); - - SetAllocationStepDelay(0, kMinimumStepDelay); - SetAllocationStepDelay(1, kMinimumStepDelay); - - SetIceRole(0, cricket::ICEROLE_CONTROLLING); - SetIceProtocol(0, cricket::ICEPROTO_HYBRID); - SetIceTiebreaker(0, kTiebreaker1); - SetIceRole(1, cricket::ICEROLE_CONTROLLED); - SetIceProtocol(1, proto); - SetIceTiebreaker(1, kTiebreaker2); - - CreateChannels(1); - // When channel is in hybrid and it's controlling agent, channel will - // receive ping request from the remote. Hence connection is readable. - // Since channel is in hybrid, it will not send any pings, so no writable - // connection. Since channel2 is in controlled state, it will not have - // any connections which are readable or writable, as it didn't received - // pings (or none) with USE-CANDIDATE attribute. - EXPECT_TRUE_WAIT(ep1_ch1()->readable(), 1000); - - // Set real protocol type. - ep1_ch1()->SetIceProtocolType(proto); - - // Channel should able to send ping requests and connections become writable - // in both directions. - EXPECT_TRUE_WAIT(ep1_ch1()->readable() && ep1_ch1()->writable() && - ep2_ch1()->readable() && ep2_ch1()->writable(), - 1000); - EXPECT_TRUE( - ep1_ch1()->best_connection() && ep2_ch1()->best_connection() && - LocalCandidate(ep1_ch1())->address().EqualIPs(kPublicAddrs[0]) && - RemoteCandidate(ep1_ch1())->address().EqualIPs(kPublicAddrs[1])); - - TestSendRecv(1); - DestroyChannels(); - } - - void OnChannelRequestSignaling(cricket::TransportChannelImpl* channel) { - channel->OnSignalingReady(); - } - // We pass the candidates directly to the other side. - void OnCandidate(cricket::TransportChannelImpl* ch, - const cricket::Candidate& c) { - if (force_relay_ && c.type() != cricket::RELAY_PORT_TYPE) - return; - - main_->PostDelayed(GetEndpoint(ch)->signaling_delay_, this, 0, - new CandidateData(ch, c)); - } - void OnMessage(rtc::Message* msg) { - rtc::scoped_ptr<CandidateData> data( - static_cast<CandidateData*>(msg->pdata)); - cricket::P2PTransportChannel* rch = GetRemoteChannel(data->channel); - cricket::Candidate c = data->candidate; - if (clear_remote_candidates_ufrag_pwd_) { - c.set_username(""); - c.set_password(""); - } - LOG(LS_INFO) << "Candidate(" << data->channel->component() << "->" - << rch->component() << "): " << c.type() << ", " << c.protocol() - << ", " << c.address().ToString() << ", " << c.username() - << ", " << c.generation(); - rch->OnCandidate(c); - } - void OnReadPacket(cricket::TransportChannel* channel, const char* data, - size_t len, const rtc::PacketTime& packet_time, - int flags) { - std::list<std::string>& packets = GetPacketList(channel); - packets.push_front(std::string(data, len)); - } - void OnRoleConflict(cricket::TransportChannelImpl* channel) { - GetEndpoint(channel)->OnRoleConflict(true); - cricket::IceRole new_role = - GetEndpoint(channel)->ice_role() == cricket::ICEROLE_CONTROLLING ? - cricket::ICEROLE_CONTROLLED : cricket::ICEROLE_CONTROLLING; - channel->SetIceRole(new_role); - } - int SendData(cricket::TransportChannel* channel, - const char* data, size_t len) { - rtc::PacketOptions options; - return channel->SendPacket(data, len, options, 0); - } - bool CheckDataOnChannel(cricket::TransportChannel* channel, - const char* data, int len) { - return GetChannelData(channel)->CheckData(data, len); - } - static const cricket::Candidate* LocalCandidate( - cricket::P2PTransportChannel* ch) { - return (ch && ch->best_connection()) ? - &ch->best_connection()->local_candidate() : NULL; - } - static const cricket::Candidate* RemoteCandidate( - cricket::P2PTransportChannel* ch) { - return (ch && ch->best_connection()) ? - &ch->best_connection()->remote_candidate() : NULL; - } - Endpoint* GetEndpoint(cricket::TransportChannel* ch) { - if (ep1_.HasChannel(ch)) { - return &ep1_; - } else if (ep2_.HasChannel(ch)) { - return &ep2_; - } else { - return NULL; - } - } - cricket::P2PTransportChannel* GetRemoteChannel( - cricket::TransportChannel* ch) { - if (ch == ep1_ch1()) - return ep2_ch1(); - else if (ch == ep1_ch2()) - return ep2_ch2(); - else if (ch == ep2_ch1()) - return ep1_ch1(); - else if (ch == ep2_ch2()) - return ep1_ch2(); - else - return NULL; - } - std::list<std::string>& GetPacketList(cricket::TransportChannel* ch) { - return GetChannelData(ch)->ch_packets_; - } - - void set_clear_remote_candidates_ufrag_pwd(bool clear) { - clear_remote_candidates_ufrag_pwd_ = clear; - } - - void set_force_relay(bool relay) { - force_relay_ = relay; - } - - private: - rtc::Thread* main_; - rtc::scoped_ptr<rtc::PhysicalSocketServer> pss_; - rtc::scoped_ptr<rtc::VirtualSocketServer> vss_; - rtc::scoped_ptr<rtc::NATSocketServer> nss_; - rtc::scoped_ptr<rtc::FirewallSocketServer> ss_; - rtc::SocketServerScope ss_scope_; - rtc::scoped_ptr<cricket::TestStunServer> stun_server_; - cricket::TestTurnServer turn_server_; - cricket::TestRelayServer relay_server_; - rtc::SocksProxyServer socks_server1_; - rtc::SocksProxyServer socks_server2_; - Endpoint ep1_; - Endpoint ep2_; - bool clear_remote_candidates_ufrag_pwd_; - bool force_relay_; -}; - -// The tests have only a few outcomes, which we predefine. -const P2PTransportChannelTestBase::Result P2PTransportChannelTestBase:: - kLocalUdpToLocalUdp("local", "udp", "local", "udp", - "local", "udp", "local", "udp", 1000); -const P2PTransportChannelTestBase::Result P2PTransportChannelTestBase:: - kLocalUdpToStunUdp("local", "udp", "stun", "udp", - "local", "udp", "stun", "udp", 1000); -const P2PTransportChannelTestBase::Result P2PTransportChannelTestBase:: - kLocalUdpToPrflxUdp("local", "udp", "prflx", "udp", - "prflx", "udp", "local", "udp", 1000); -const P2PTransportChannelTestBase::Result P2PTransportChannelTestBase:: - kPrflxUdpToLocalUdp("prflx", "udp", "local", "udp", - "local", "udp", "prflx", "udp", 1000); -const P2PTransportChannelTestBase::Result P2PTransportChannelTestBase:: - kStunUdpToLocalUdp("stun", "udp", "local", "udp", - "local", "udp", "stun", "udp", 1000); -const P2PTransportChannelTestBase::Result P2PTransportChannelTestBase:: - kStunUdpToStunUdp("stun", "udp", "stun", "udp", - "stun", "udp", "stun", "udp", 1000); -const P2PTransportChannelTestBase::Result P2PTransportChannelTestBase:: - kPrflxUdpToStunUdp("prflx", "udp", "stun", "udp", - "local", "udp", "prflx", "udp", 1000); -const P2PTransportChannelTestBase::Result P2PTransportChannelTestBase:: - kLocalUdpToRelayUdp("local", "udp", "relay", "udp", - "relay", "udp", "local", "udp", 2000); -const P2PTransportChannelTestBase::Result P2PTransportChannelTestBase:: - kPrflxUdpToRelayUdp("prflx", "udp", "relay", "udp", - "relay", "udp", "prflx", "udp", 2000); -const P2PTransportChannelTestBase::Result P2PTransportChannelTestBase:: - kLocalTcpToLocalTcp("local", "tcp", "local", "tcp", - "local", "tcp", "local", "tcp", 3000); -const P2PTransportChannelTestBase::Result P2PTransportChannelTestBase:: - kLocalTcpToPrflxTcp("local", "tcp", "prflx", "tcp", - "prflx", "tcp", "local", "tcp", 3000); -const P2PTransportChannelTestBase::Result P2PTransportChannelTestBase:: - kPrflxTcpToLocalTcp("prflx", "tcp", "local", "tcp", - "local", "tcp", "prflx", "tcp", 3000); - -// Test the matrix of all the connectivity types we expect to see in the wild. -// Just test every combination of the configs in the Config enum. -class P2PTransportChannelTest : public P2PTransportChannelTestBase { - protected: - static const Result* kMatrix[NUM_CONFIGS][NUM_CONFIGS]; - static const Result* kMatrixSharedUfrag[NUM_CONFIGS][NUM_CONFIGS]; - static const Result* kMatrixSharedSocketAsGice[NUM_CONFIGS][NUM_CONFIGS]; - static const Result* kMatrixSharedSocketAsIce[NUM_CONFIGS][NUM_CONFIGS]; - void ConfigureEndpoints(Config config1, Config config2, - int allocator_flags1, int allocator_flags2, - int delay1, int delay2, - cricket::IceProtocolType type) { - // Ideally we want to use TURN server for both GICE and ICE, but in case - // of GICE, TURN server usage is not producing results reliabally. - // TODO(mallinath): Remove Relay and use TURN server for all tests. - ServerAddresses stun_servers; - stun_servers.insert(kStunAddr); - GetEndpoint(0)->allocator_.reset( - new cricket::BasicPortAllocator(&(GetEndpoint(0)->network_manager_), - stun_servers, - rtc::SocketAddress(), rtc::SocketAddress(), - rtc::SocketAddress())); - GetEndpoint(1)->allocator_.reset( - new cricket::BasicPortAllocator(&(GetEndpoint(1)->network_manager_), - stun_servers, - rtc::SocketAddress(), rtc::SocketAddress(), - rtc::SocketAddress())); - - cricket::RelayServerConfig relay_server(cricket::RELAY_GTURN); - if (type == cricket::ICEPROTO_RFC5245) { - relay_server.type = cricket::RELAY_TURN; - relay_server.credentials = kRelayCredentials; - relay_server.ports.push_back(cricket::ProtocolAddress( - kTurnUdpIntAddr, cricket::PROTO_UDP, false)); - } else { - relay_server.ports.push_back(cricket::ProtocolAddress( - kRelayUdpIntAddr, cricket::PROTO_UDP, false)); - relay_server.ports.push_back(cricket::ProtocolAddress( - kRelayTcpIntAddr, cricket::PROTO_TCP, false)); - relay_server.ports.push_back(cricket::ProtocolAddress( - kRelaySslTcpIntAddr, cricket::PROTO_SSLTCP, false)); - } - GetEndpoint(0)->allocator_->AddRelay(relay_server); - GetEndpoint(1)->allocator_->AddRelay(relay_server); - - ConfigureEndpoint(0, config1); - SetIceProtocol(0, type); - SetAllocatorFlags(0, allocator_flags1); - SetAllocationStepDelay(0, delay1); - ConfigureEndpoint(1, config2); - SetIceProtocol(1, type); - SetAllocatorFlags(1, allocator_flags2); - SetAllocationStepDelay(1, delay2); - } - void ConfigureEndpoint(int endpoint, Config config) { - switch (config) { - case OPEN: - AddAddress(endpoint, kPublicAddrs[endpoint]); - break; - case NAT_FULL_CONE: - case NAT_ADDR_RESTRICTED: - case NAT_PORT_RESTRICTED: - case NAT_SYMMETRIC: - AddAddress(endpoint, kPrivateAddrs[endpoint]); - // Add a single NAT of the desired type - nat()->AddTranslator(kPublicAddrs[endpoint], kNatAddrs[endpoint], - static_cast<rtc::NATType>(config - NAT_FULL_CONE))-> - AddClient(kPrivateAddrs[endpoint]); - break; - case NAT_DOUBLE_CONE: - case NAT_SYMMETRIC_THEN_CONE: - AddAddress(endpoint, kCascadedPrivateAddrs[endpoint]); - // Add a two cascaded NATs of the desired types - nat()->AddTranslator(kPublicAddrs[endpoint], kNatAddrs[endpoint], - (config == NAT_DOUBLE_CONE) ? - rtc::NAT_OPEN_CONE : rtc::NAT_SYMMETRIC)-> - AddTranslator(kPrivateAddrs[endpoint], kCascadedNatAddrs[endpoint], - rtc::NAT_OPEN_CONE)-> - AddClient(kCascadedPrivateAddrs[endpoint]); - break; - case BLOCK_UDP: - case BLOCK_UDP_AND_INCOMING_TCP: - case BLOCK_ALL_BUT_OUTGOING_HTTP: - case PROXY_HTTPS: - case PROXY_SOCKS: - AddAddress(endpoint, kPublicAddrs[endpoint]); - // Block all UDP - fw()->AddRule(false, rtc::FP_UDP, rtc::FD_ANY, - kPublicAddrs[endpoint]); - if (config == BLOCK_UDP_AND_INCOMING_TCP) { - // Block TCP inbound to the endpoint - fw()->AddRule(false, rtc::FP_TCP, SocketAddress(), - kPublicAddrs[endpoint]); - } else if (config == BLOCK_ALL_BUT_OUTGOING_HTTP) { - // Block all TCP to/from the endpoint except 80/443 out - fw()->AddRule(true, rtc::FP_TCP, kPublicAddrs[endpoint], - SocketAddress(rtc::IPAddress(INADDR_ANY), 80)); - fw()->AddRule(true, rtc::FP_TCP, kPublicAddrs[endpoint], - SocketAddress(rtc::IPAddress(INADDR_ANY), 443)); - fw()->AddRule(false, rtc::FP_TCP, rtc::FD_ANY, - kPublicAddrs[endpoint]); - } else if (config == PROXY_HTTPS) { - // Block all TCP to/from the endpoint except to the proxy server - fw()->AddRule(true, rtc::FP_TCP, kPublicAddrs[endpoint], - kHttpsProxyAddrs[endpoint]); - fw()->AddRule(false, rtc::FP_TCP, rtc::FD_ANY, - kPublicAddrs[endpoint]); - SetProxy(endpoint, rtc::PROXY_HTTPS); - } else if (config == PROXY_SOCKS) { - // Block all TCP to/from the endpoint except to the proxy server - fw()->AddRule(true, rtc::FP_TCP, kPublicAddrs[endpoint], - kSocksProxyAddrs[endpoint]); - fw()->AddRule(false, rtc::FP_TCP, rtc::FD_ANY, - kPublicAddrs[endpoint]); - SetProxy(endpoint, rtc::PROXY_SOCKS5); - } - break; - default: - break; - } - } -}; - -// Shorthands for use in the test matrix. -#define LULU &kLocalUdpToLocalUdp -#define LUSU &kLocalUdpToStunUdp -#define LUPU &kLocalUdpToPrflxUdp -#define PULU &kPrflxUdpToLocalUdp -#define SULU &kStunUdpToLocalUdp -#define SUSU &kStunUdpToStunUdp -#define PUSU &kPrflxUdpToStunUdp -#define LURU &kLocalUdpToRelayUdp -#define PURU &kPrflxUdpToRelayUdp -#define LTLT &kLocalTcpToLocalTcp -#define LTPT &kLocalTcpToPrflxTcp -#define PTLT &kPrflxTcpToLocalTcp -// TODO: Enable these once TestRelayServer can accept external TCP. -#define LTRT NULL -#define LSRS NULL - -// Test matrix. Originator behavior defined by rows, receiever by columns. - -// Currently the p2ptransportchannel.cc (specifically the -// P2PTransportChannel::OnUnknownAddress) operates in 2 modes depend on the -// remote candidates - ufrag per port or shared ufrag. -// For example, if the remote candidates have the shared ufrag, for the unknown -// address reaches the OnUnknownAddress, we will try to find the matched -// remote candidate based on the address and protocol, if not found, a new -// remote candidate will be created for this address. But if the remote -// candidates have different ufrags, we will try to find the matched remote -// candidate by comparing the ufrag. If not found, an error will be returned. -// Because currently the shared ufrag feature is under the experiment and will -// be rolled out gradually. We want to test the different combinations of peers -// with/without the shared ufrag enabled. And those different combinations have -// different expectation of the best connection. For example in the OpenToCONE -// case, an unknown address will be updated to a "host" remote candidate if the -// remote peer uses different ufrag per port. But in the shared ufrag case, -// a "stun" (should be peer-reflexive eventually) candidate will be created for -// that. So the expected best candidate will be LUSU instead of LULU. -// With all these, we have to keep 2 test matrixes for the tests: -// kMatrix - for the tests that the remote peer uses different ufrag per port. -// kMatrixSharedUfrag - for the tests that remote peer uses shared ufrag. -// The different between the two matrixes are on: -// OPToCONE, OPTo2CON, -// COToCONE, COToADDR, COToPORT, COToSYMM, COTo2CON, COToSCON, -// ADToCONE, ADToADDR, ADTo2CON, -// POToADDR, -// SYToADDR, -// 2CToCONE, 2CToADDR, 2CToPORT, 2CToSYMM, 2CTo2CON, 2CToSCON, -// SCToADDR, - -// TODO: Fix NULLs caused by lack of TCP support in NATSocket. -// TODO: Fix NULLs caused by no HTTP proxy support. -// TODO: Rearrange rows/columns from best to worst. -// TODO(ronghuawu): Keep only one test matrix once the shared ufrag is enabled. -const P2PTransportChannelTest::Result* - P2PTransportChannelTest::kMatrix[NUM_CONFIGS][NUM_CONFIGS] = { -// OPEN CONE ADDR PORT SYMM 2CON SCON !UDP !TCP HTTP PRXH PRXS -/*OP*/ {LULU, LULU, LULU, LULU, LULU, LULU, LULU, LTLT, LTLT, LSRS, NULL, LTLT}, -/*CO*/ {LULU, LULU, LULU, SULU, SULU, LULU, SULU, NULL, NULL, LSRS, NULL, LTRT}, -/*AD*/ {LULU, LULU, LULU, SUSU, SUSU, LULU, SUSU, NULL, NULL, LSRS, NULL, LTRT}, -/*PO*/ {LULU, LUSU, LUSU, SUSU, LURU, LUSU, LURU, NULL, NULL, LSRS, NULL, LTRT}, -/*SY*/ {LULU, LUSU, LUSU, LURU, LURU, LUSU, LURU, NULL, NULL, LSRS, NULL, LTRT}, -/*2C*/ {LULU, LULU, LULU, SULU, SULU, LULU, SULU, NULL, NULL, LSRS, NULL, LTRT}, -/*SC*/ {LULU, LUSU, LUSU, LURU, LURU, LUSU, LURU, NULL, NULL, LSRS, NULL, LTRT}, -/*!U*/ {LTLT, NULL, NULL, NULL, NULL, NULL, NULL, LTLT, LTLT, LSRS, NULL, LTRT}, -/*!T*/ {LTRT, NULL, NULL, NULL, NULL, NULL, NULL, LTLT, LTRT, LSRS, NULL, LTRT}, -/*HT*/ {LSRS, LSRS, LSRS, LSRS, LSRS, LSRS, LSRS, LSRS, LSRS, LSRS, NULL, LSRS}, -/*PR*/ {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, -/*PR*/ {LTRT, LTRT, LTRT, LTRT, LTRT, LTRT, LTRT, LTRT, LTRT, LSRS, NULL, LTRT}, -}; -const P2PTransportChannelTest::Result* - P2PTransportChannelTest::kMatrixSharedUfrag[NUM_CONFIGS][NUM_CONFIGS] = { -// OPEN CONE ADDR PORT SYMM 2CON SCON !UDP !TCP HTTP PRXH PRXS -/*OP*/ {LULU, LUSU, LULU, LULU, LULU, LUSU, LULU, LTLT, LTLT, LSRS, NULL, LTLT}, -/*CO*/ {LULU, LUSU, LUSU, SUSU, SUSU, LUSU, SUSU, NULL, NULL, LSRS, NULL, LTRT}, -/*AD*/ {LULU, LUSU, LUSU, SUSU, SUSU, LUSU, SUSU, NULL, NULL, LSRS, NULL, LTRT}, -/*PO*/ {LULU, LUSU, LUSU, SUSU, LURU, LUSU, LURU, NULL, NULL, LSRS, NULL, LTRT}, -/*SY*/ {LULU, LUSU, LUSU, LURU, LURU, LUSU, LURU, NULL, NULL, LSRS, NULL, LTRT}, -/*2C*/ {LULU, LUSU, LUSU, SUSU, SUSU, LUSU, SUSU, NULL, NULL, LSRS, NULL, LTRT}, -/*SC*/ {LULU, LUSU, LUSU, LURU, LURU, LUSU, LURU, NULL, NULL, LSRS, NULL, LTRT}, -/*!U*/ {LTLT, NULL, NULL, NULL, NULL, NULL, NULL, LTLT, LTLT, LSRS, NULL, LTRT}, -/*!T*/ {LTRT, NULL, NULL, NULL, NULL, NULL, NULL, LTLT, LTRT, LSRS, NULL, LTRT}, -/*HT*/ {LSRS, LSRS, LSRS, LSRS, LSRS, LSRS, LSRS, LSRS, LSRS, LSRS, NULL, LSRS}, -/*PR*/ {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, -/*PR*/ {LTRT, LTRT, LTRT, LTRT, LTRT, LTRT, LTRT, LTRT, LTRT, LSRS, NULL, LTRT}, -}; -const P2PTransportChannelTest::Result* - P2PTransportChannelTest::kMatrixSharedSocketAsGice - [NUM_CONFIGS][NUM_CONFIGS] = { -// OPEN CONE ADDR PORT SYMM 2CON SCON !UDP !TCP HTTP PRXH PRXS -/*OP*/ {LULU, LUSU, LUSU, LUSU, LUSU, LUSU, LUSU, LTLT, LTLT, LSRS, NULL, LTLT}, -/*CO*/ {LULU, LUSU, LUSU, LUSU, LUSU, LUSU, LUSU, NULL, NULL, LSRS, NULL, LTRT}, -/*AD*/ {LULU, LUSU, LUSU, LUSU, LUSU, LUSU, LUSU, NULL, NULL, LSRS, NULL, LTRT}, -/*PO*/ {LULU, LUSU, LUSU, LUSU, LURU, LUSU, LURU, NULL, NULL, LSRS, NULL, LTRT}, -/*SY*/ {LULU, LUSU, LUSU, LURU, LURU, LUSU, LURU, NULL, NULL, LSRS, NULL, LTRT}, -/*2C*/ {LULU, LUSU, LUSU, LUSU, LUSU, LUSU, LUSU, NULL, NULL, LSRS, NULL, LTRT}, -/*SC*/ {LULU, LUSU, LUSU, LURU, LURU, LUSU, LURU, NULL, NULL, LSRS, NULL, LTRT}, -/*!U*/ {LTLT, NULL, NULL, NULL, NULL, NULL, NULL, LTLT, LTLT, LSRS, NULL, LTRT}, -/*!T*/ {LTRT, NULL, NULL, NULL, NULL, NULL, NULL, LTLT, LTRT, LSRS, NULL, LTRT}, -/*HT*/ {LSRS, LSRS, LSRS, LSRS, LSRS, LSRS, LSRS, LSRS, LSRS, LSRS, NULL, LSRS}, -/*PR*/ {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, -/*PR*/ {LTRT, LTRT, LTRT, LTRT, LTRT, LTRT, LTRT, LTRT, LTRT, LSRS, NULL, LTRT}, -}; -const P2PTransportChannelTest::Result* - P2PTransportChannelTest::kMatrixSharedSocketAsIce - [NUM_CONFIGS][NUM_CONFIGS] = { -// OPEN CONE ADDR PORT SYMM 2CON SCON !UDP !TCP HTTP PRXH PRXS -/*OP*/ {LULU, LUSU, LUSU, LUSU, LUPU, LUSU, LUPU, PTLT, LTPT, LSRS, NULL, PTLT}, -/*CO*/ {LULU, LUSU, LUSU, LUSU, LUPU, LUSU, LUPU, NULL, NULL, LSRS, NULL, LTRT}, -/*AD*/ {LULU, LUSU, LUSU, LUSU, LUPU, LUSU, LUPU, NULL, NULL, LSRS, NULL, LTRT}, -/*PO*/ {LULU, LUSU, LUSU, LUSU, LURU, LUSU, LURU, NULL, NULL, LSRS, NULL, LTRT}, -/*SY*/ {PULU, PUSU, PUSU, PURU, PURU, PUSU, PURU, NULL, NULL, LSRS, NULL, LTRT}, -/*2C*/ {LULU, LUSU, LUSU, LUSU, LUPU, LUSU, LUPU, NULL, NULL, LSRS, NULL, LTRT}, -/*SC*/ {PULU, PUSU, PUSU, PURU, PURU, PUSU, PURU, NULL, NULL, LSRS, NULL, LTRT}, -/*!U*/ {PTLT, NULL, NULL, NULL, NULL, NULL, NULL, PTLT, LTPT, LSRS, NULL, LTRT}, -/*!T*/ {LTRT, NULL, NULL, NULL, NULL, NULL, NULL, PTLT, LTRT, LSRS, NULL, LTRT}, -/*HT*/ {LSRS, LSRS, LSRS, LSRS, LSRS, LSRS, LSRS, LSRS, LSRS, LSRS, NULL, LSRS}, -/*PR*/ {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, -/*PR*/ {LTRT, LTRT, LTRT, LTRT, LTRT, LTRT, LTRT, LTRT, LTRT, LSRS, NULL, LTRT}, -}; - -// The actual tests that exercise all the various configurations. -// Test names are of the form P2PTransportChannelTest_TestOPENToNAT_FULL_CONE -// Same test case is run in both GICE and ICE mode. -// kDefaultStepDelay - is used for all Gice cases. -// kMinimumStepDelay - is used when both end points have -// PORTALLOCATOR_ENABLE_SHARED_UFRAG flag enabled. -// Technically we should be able to use kMinimumStepDelay irrespective of -// protocol type. But which might need modifications to current result matrices -// for tests in this file. -#define P2P_TEST_DECLARATION(x, y, z) \ - TEST_F(P2PTransportChannelTest, z##Test##x##To##y##AsGiceNoneSharedUfrag) { \ - ConfigureEndpoints(x, y, kDefaultPortAllocatorFlags, \ - kDefaultPortAllocatorFlags, \ - kDefaultStepDelay, kDefaultStepDelay, \ - cricket::ICEPROTO_GOOGLE); \ - if (kMatrix[x][y] != NULL) \ - Test(*kMatrix[x][y]); \ - else \ - LOG(LS_WARNING) << "Not yet implemented"; \ - } \ - TEST_F(P2PTransportChannelTest, z##Test##x##To##y##AsGiceP0SharedUfrag) { \ - ConfigureEndpoints(x, y, PORTALLOCATOR_ENABLE_SHARED_UFRAG, \ - kDefaultPortAllocatorFlags, \ - kDefaultStepDelay, kDefaultStepDelay, \ - cricket::ICEPROTO_GOOGLE); \ - if (kMatrix[x][y] != NULL) \ - Test(*kMatrix[x][y]); \ - else \ - LOG(LS_WARNING) << "Not yet implemented"; \ - } \ - TEST_F(P2PTransportChannelTest, z##Test##x##To##y##AsGiceP1SharedUfrag) { \ - ConfigureEndpoints(x, y, kDefaultPortAllocatorFlags, \ - PORTALLOCATOR_ENABLE_SHARED_UFRAG, \ - kDefaultStepDelay, kDefaultStepDelay, \ - cricket::ICEPROTO_GOOGLE); \ - if (kMatrixSharedUfrag[x][y] != NULL) \ - Test(*kMatrixSharedUfrag[x][y]); \ - else \ - LOG(LS_WARNING) << "Not yet implemented"; \ - } \ - TEST_F(P2PTransportChannelTest, z##Test##x##To##y##AsGiceBothSharedUfrag) { \ - ConfigureEndpoints(x, y, PORTALLOCATOR_ENABLE_SHARED_UFRAG, \ - PORTALLOCATOR_ENABLE_SHARED_UFRAG, \ - kDefaultStepDelay, kDefaultStepDelay, \ - cricket::ICEPROTO_GOOGLE); \ - if (kMatrixSharedUfrag[x][y] != NULL) \ - Test(*kMatrixSharedUfrag[x][y]); \ - else \ - LOG(LS_WARNING) << "Not yet implemented"; \ - } \ - TEST_F(P2PTransportChannelTest, \ - z##Test##x##To##y##AsGiceBothSharedUfragWithMinimumStepDelay) { \ - ConfigureEndpoints(x, y, PORTALLOCATOR_ENABLE_SHARED_UFRAG, \ - PORTALLOCATOR_ENABLE_SHARED_UFRAG, \ - kMinimumStepDelay, kMinimumStepDelay, \ - cricket::ICEPROTO_GOOGLE); \ - if (kMatrixSharedUfrag[x][y] != NULL) \ - Test(*kMatrixSharedUfrag[x][y]); \ - else \ - LOG(LS_WARNING) << "Not yet implemented"; \ - } \ - TEST_F(P2PTransportChannelTest, \ - z##Test##x##To##y##AsGiceBothSharedUfragSocket) { \ - ConfigureEndpoints(x, y, PORTALLOCATOR_ENABLE_SHARED_UFRAG | \ - PORTALLOCATOR_ENABLE_SHARED_SOCKET, \ - PORTALLOCATOR_ENABLE_SHARED_UFRAG | \ - PORTALLOCATOR_ENABLE_SHARED_SOCKET, \ - kMinimumStepDelay, kMinimumStepDelay, \ - cricket::ICEPROTO_GOOGLE); \ - if (kMatrixSharedSocketAsGice[x][y] != NULL) \ - Test(*kMatrixSharedSocketAsGice[x][y]); \ - else \ - LOG(LS_WARNING) << "Not yet implemented"; \ - } \ - TEST_F(P2PTransportChannelTest, z##Test##x##To##y##AsIce) { \ - ConfigureEndpoints(x, y, PORTALLOCATOR_ENABLE_SHARED_UFRAG | \ - PORTALLOCATOR_ENABLE_SHARED_SOCKET, \ - PORTALLOCATOR_ENABLE_SHARED_UFRAG | \ - PORTALLOCATOR_ENABLE_SHARED_SOCKET, \ - kMinimumStepDelay, kMinimumStepDelay, \ - cricket::ICEPROTO_RFC5245); \ - if (kMatrixSharedSocketAsIce[x][y] != NULL) \ - Test(*kMatrixSharedSocketAsIce[x][y]); \ - else \ - LOG(LS_WARNING) << "Not yet implemented"; \ - } - -#define P2P_TEST(x, y) \ - P2P_TEST_DECLARATION(x, y,) - -#define FLAKY_P2P_TEST(x, y) \ - P2P_TEST_DECLARATION(x, y, DISABLED_) - -// TODO(holmer): Disabled due to randomly failing on webrtc buildbots. -// Issue: webrtc/2383 -#define P2P_TEST_SET(x) \ - P2P_TEST(x, OPEN) \ - FLAKY_P2P_TEST(x, NAT_FULL_CONE) \ - FLAKY_P2P_TEST(x, NAT_ADDR_RESTRICTED) \ - FLAKY_P2P_TEST(x, NAT_PORT_RESTRICTED) \ - P2P_TEST(x, NAT_SYMMETRIC) \ - FLAKY_P2P_TEST(x, NAT_DOUBLE_CONE) \ - P2P_TEST(x, NAT_SYMMETRIC_THEN_CONE) \ - P2P_TEST(x, BLOCK_UDP) \ - P2P_TEST(x, BLOCK_UDP_AND_INCOMING_TCP) \ - P2P_TEST(x, BLOCK_ALL_BUT_OUTGOING_HTTP) \ - P2P_TEST(x, PROXY_HTTPS) \ - P2P_TEST(x, PROXY_SOCKS) - -#define FLAKY_P2P_TEST_SET(x) \ - P2P_TEST(x, OPEN) \ - P2P_TEST(x, NAT_FULL_CONE) \ - P2P_TEST(x, NAT_ADDR_RESTRICTED) \ - P2P_TEST(x, NAT_PORT_RESTRICTED) \ - P2P_TEST(x, NAT_SYMMETRIC) \ - P2P_TEST(x, NAT_DOUBLE_CONE) \ - P2P_TEST(x, NAT_SYMMETRIC_THEN_CONE) \ - P2P_TEST(x, BLOCK_UDP) \ - P2P_TEST(x, BLOCK_UDP_AND_INCOMING_TCP) \ - P2P_TEST(x, BLOCK_ALL_BUT_OUTGOING_HTTP) \ - P2P_TEST(x, PROXY_HTTPS) \ - P2P_TEST(x, PROXY_SOCKS) - -P2P_TEST_SET(OPEN) -P2P_TEST_SET(NAT_FULL_CONE) -P2P_TEST_SET(NAT_ADDR_RESTRICTED) -P2P_TEST_SET(NAT_PORT_RESTRICTED) -P2P_TEST_SET(NAT_SYMMETRIC) -P2P_TEST_SET(NAT_DOUBLE_CONE) -P2P_TEST_SET(NAT_SYMMETRIC_THEN_CONE) -P2P_TEST_SET(BLOCK_UDP) -P2P_TEST_SET(BLOCK_UDP_AND_INCOMING_TCP) -P2P_TEST_SET(BLOCK_ALL_BUT_OUTGOING_HTTP) -P2P_TEST_SET(PROXY_HTTPS) -P2P_TEST_SET(PROXY_SOCKS) - -// Test that we restart candidate allocation when local ufrag&pwd changed. -// Standard Ice protocol is used. -TEST_F(P2PTransportChannelTest, HandleUfragPwdChangeAsIce) { - ConfigureEndpoints(OPEN, OPEN, - PORTALLOCATOR_ENABLE_SHARED_UFRAG, - PORTALLOCATOR_ENABLE_SHARED_UFRAG, - kMinimumStepDelay, kMinimumStepDelay, - cricket::ICEPROTO_RFC5245); - CreateChannels(1); - TestHandleIceUfragPasswordChanged(); - DestroyChannels(); -} - -// Test that we restart candidate allocation when local ufrag&pwd changed. -// Standard Ice protocol is used. -TEST_F(P2PTransportChannelTest, HandleUfragPwdChangeBundleAsIce) { - ConfigureEndpoints(OPEN, OPEN, - PORTALLOCATOR_ENABLE_SHARED_UFRAG, - PORTALLOCATOR_ENABLE_SHARED_UFRAG, - kMinimumStepDelay, kMinimumStepDelay, - cricket::ICEPROTO_RFC5245); - SetAllocatorFlags(0, cricket::PORTALLOCATOR_ENABLE_BUNDLE); - SetAllocatorFlags(1, cricket::PORTALLOCATOR_ENABLE_BUNDLE); - - CreateChannels(2); - TestHandleIceUfragPasswordChanged(); - DestroyChannels(); -} - -// Test that we restart candidate allocation when local ufrag&pwd changed. -// Google Ice protocol is used. -TEST_F(P2PTransportChannelTest, HandleUfragPwdChangeAsGice) { - ConfigureEndpoints(OPEN, OPEN, - PORTALLOCATOR_ENABLE_SHARED_UFRAG, - PORTALLOCATOR_ENABLE_SHARED_UFRAG, - kDefaultStepDelay, kDefaultStepDelay, - cricket::ICEPROTO_GOOGLE); - CreateChannels(1); - TestHandleIceUfragPasswordChanged(); - DestroyChannels(); -} - -// Test that ICE restart works when bundle is enabled. -// Google Ice protocol is used. -TEST_F(P2PTransportChannelTest, HandleUfragPwdChangeBundleAsGice) { - ConfigureEndpoints(OPEN, OPEN, - PORTALLOCATOR_ENABLE_SHARED_UFRAG, - PORTALLOCATOR_ENABLE_SHARED_UFRAG, - kDefaultStepDelay, kDefaultStepDelay, - cricket::ICEPROTO_GOOGLE); - SetAllocatorFlags(0, cricket::PORTALLOCATOR_ENABLE_BUNDLE); - SetAllocatorFlags(1, cricket::PORTALLOCATOR_ENABLE_BUNDLE); - - CreateChannels(2); - TestHandleIceUfragPasswordChanged(); - DestroyChannels(); -} - -// Test the operation of GetStats. -TEST_F(P2PTransportChannelTest, GetStats) { - ConfigureEndpoints(OPEN, OPEN, - kDefaultPortAllocatorFlags, - kDefaultPortAllocatorFlags, - kDefaultStepDelay, kDefaultStepDelay, - cricket::ICEPROTO_GOOGLE); - CreateChannels(1); - EXPECT_TRUE_WAIT_MARGIN(ep1_ch1()->readable() && ep1_ch1()->writable() && - ep2_ch1()->readable() && ep2_ch1()->writable(), - 1000, 1000); - TestSendRecv(1); - cricket::ConnectionInfos infos; - ASSERT_TRUE(ep1_ch1()->GetStats(&infos)); - ASSERT_EQ(1U, infos.size()); - EXPECT_TRUE(infos[0].new_connection); - EXPECT_TRUE(infos[0].best_connection); - EXPECT_TRUE(infos[0].readable); - EXPECT_TRUE(infos[0].writable); - EXPECT_FALSE(infos[0].timeout); - EXPECT_EQ(10 * 36U, infos[0].sent_total_bytes); - EXPECT_EQ(10 * 36U, infos[0].recv_total_bytes); - EXPECT_GT(infos[0].rtt, 0U); - DestroyChannels(); -} - -// Test that we properly handle getting a STUN error due to slow signaling. -TEST_F(P2PTransportChannelTest, DISABLED_SlowSignaling) { - ConfigureEndpoints(OPEN, NAT_SYMMETRIC, - kDefaultPortAllocatorFlags, - kDefaultPortAllocatorFlags, - kDefaultStepDelay, kDefaultStepDelay, - cricket::ICEPROTO_GOOGLE); - // Make signaling from the callee take 500ms, so that the initial STUN pings - // from the callee beat the signaling, and so the caller responds with a - // unknown username error. We should just eat that and carry on; mishandling - // this will instead cause all the callee's connections to be discarded. - SetSignalingDelay(1, 1000); - CreateChannels(1); - const cricket::Connection* best_connection = NULL; - // Wait until the callee's connections are created. - WAIT((best_connection = ep2_ch1()->best_connection()) != NULL, 1000); - // Wait to see if they get culled; they shouldn't. - WAIT(ep2_ch1()->best_connection() != best_connection, 1000); - EXPECT_TRUE(ep2_ch1()->best_connection() == best_connection); - DestroyChannels(); -} - -// Test that if remote candidates don't have ufrag and pwd, we still work. -TEST_F(P2PTransportChannelTest, RemoteCandidatesWithoutUfragPwd) { - set_clear_remote_candidates_ufrag_pwd(true); - ConfigureEndpoints(OPEN, OPEN, - PORTALLOCATOR_ENABLE_SHARED_UFRAG, - PORTALLOCATOR_ENABLE_SHARED_UFRAG, - kMinimumStepDelay, kMinimumStepDelay, - cricket::ICEPROTO_GOOGLE); - CreateChannels(1); - const cricket::Connection* best_connection = NULL; - // Wait until the callee's connections are created. - WAIT((best_connection = ep2_ch1()->best_connection()) != NULL, 1000); - // Wait to see if they get culled; they shouldn't. - WAIT(ep2_ch1()->best_connection() != best_connection, 1000); - EXPECT_TRUE(ep2_ch1()->best_connection() == best_connection); - DestroyChannels(); -} - -// Test that a host behind NAT cannot be reached when incoming_only -// is set to true. -TEST_F(P2PTransportChannelTest, IncomingOnlyBlocked) { - ConfigureEndpoints(NAT_FULL_CONE, OPEN, - kDefaultPortAllocatorFlags, - kDefaultPortAllocatorFlags, - kDefaultStepDelay, kDefaultStepDelay, - cricket::ICEPROTO_GOOGLE); - - SetAllocatorFlags(0, kOnlyLocalPorts); - CreateChannels(1); - ep1_ch1()->set_incoming_only(true); - - // Pump for 1 second and verify that the channels are not connected. - rtc::Thread::Current()->ProcessMessages(1000); - - EXPECT_FALSE(ep1_ch1()->readable()); - EXPECT_FALSE(ep1_ch1()->writable()); - EXPECT_FALSE(ep2_ch1()->readable()); - EXPECT_FALSE(ep2_ch1()->writable()); - - DestroyChannels(); -} - -// Test that a peer behind NAT can connect to a peer that has -// incoming_only flag set. -TEST_F(P2PTransportChannelTest, IncomingOnlyOpen) { - ConfigureEndpoints(OPEN, NAT_FULL_CONE, - kDefaultPortAllocatorFlags, - kDefaultPortAllocatorFlags, - kDefaultStepDelay, kDefaultStepDelay, - cricket::ICEPROTO_GOOGLE); - - SetAllocatorFlags(0, kOnlyLocalPorts); - CreateChannels(1); - ep1_ch1()->set_incoming_only(true); - - EXPECT_TRUE_WAIT_MARGIN(ep1_ch1() != NULL && ep2_ch1() != NULL && - ep1_ch1()->readable() && ep1_ch1()->writable() && - ep2_ch1()->readable() && ep2_ch1()->writable(), - 1000, 1000); - - DestroyChannels(); -} - -TEST_F(P2PTransportChannelTest, TestTcpConnectionsFromActiveToPassive) { - AddAddress(0, kPublicAddrs[0]); - AddAddress(1, kPublicAddrs[1]); - - SetAllocationStepDelay(0, kMinimumStepDelay); - SetAllocationStepDelay(1, kMinimumStepDelay); - - int kOnlyLocalTcpPorts = cricket::PORTALLOCATOR_DISABLE_UDP | - cricket::PORTALLOCATOR_DISABLE_STUN | - cricket::PORTALLOCATOR_DISABLE_RELAY | - cricket::PORTALLOCATOR_ENABLE_SHARED_UFRAG; - // Disable all protocols except TCP. - SetAllocatorFlags(0, kOnlyLocalTcpPorts); - SetAllocatorFlags(1, kOnlyLocalTcpPorts); - - SetAllowTcpListen(0, true); // actpass. - SetAllowTcpListen(1, false); // active. - - CreateChannels(1); - - EXPECT_TRUE_WAIT(ep1_ch1()->readable() && ep1_ch1()->writable() && - ep2_ch1()->readable() && ep2_ch1()->writable(), - 1000); - EXPECT_TRUE( - ep1_ch1()->best_connection() && ep2_ch1()->best_connection() && - LocalCandidate(ep1_ch1())->address().EqualIPs(kPublicAddrs[0]) && - RemoteCandidate(ep1_ch1())->address().EqualIPs(kPublicAddrs[1])); - - std::string kTcpProtocol = "tcp"; - EXPECT_EQ(kTcpProtocol, RemoteCandidate(ep1_ch1())->protocol()); - EXPECT_EQ(kTcpProtocol, LocalCandidate(ep1_ch1())->protocol()); - EXPECT_EQ(kTcpProtocol, RemoteCandidate(ep2_ch1())->protocol()); - EXPECT_EQ(kTcpProtocol, LocalCandidate(ep2_ch1())->protocol()); - - TestSendRecv(1); - DestroyChannels(); -} - -TEST_F(P2PTransportChannelTest, TestBundleAllocatorToBundleAllocator) { - AddAddress(0, kPublicAddrs[0]); - AddAddress(1, kPublicAddrs[1]); - SetAllocatorFlags(0, cricket::PORTALLOCATOR_ENABLE_BUNDLE); - SetAllocatorFlags(1, cricket::PORTALLOCATOR_ENABLE_BUNDLE); - - CreateChannels(2); - - EXPECT_TRUE_WAIT(ep1_ch1()->readable() && - ep1_ch1()->writable() && - ep2_ch1()->readable() && - ep2_ch1()->writable(), - 1000); - EXPECT_TRUE(ep1_ch1()->best_connection() && - ep2_ch1()->best_connection()); - - EXPECT_FALSE(ep1_ch2()->readable()); - EXPECT_FALSE(ep1_ch2()->writable()); - EXPECT_FALSE(ep2_ch2()->readable()); - EXPECT_FALSE(ep2_ch2()->writable()); - - TestSendRecv(1); // Only 1 channel is writable per Endpoint. - DestroyChannels(); -} - -TEST_F(P2PTransportChannelTest, TestBundleAllocatorToNonBundleAllocator) { - AddAddress(0, kPublicAddrs[0]); - AddAddress(1, kPublicAddrs[1]); - // Enable BUNDLE flag at one side. - SetAllocatorFlags(0, cricket::PORTALLOCATOR_ENABLE_BUNDLE); - - CreateChannels(2); - - EXPECT_TRUE_WAIT(ep1_ch1()->readable() && - ep1_ch1()->writable() && - ep2_ch1()->readable() && - ep2_ch1()->writable(), - 1000); - EXPECT_TRUE_WAIT(ep1_ch2()->readable() && - ep1_ch2()->writable() && - ep2_ch2()->readable() && - ep2_ch2()->writable(), - 1000); - - EXPECT_TRUE(ep1_ch1()->best_connection() && - ep2_ch1()->best_connection()); - EXPECT_TRUE(ep1_ch2()->best_connection() && - ep2_ch2()->best_connection()); - - TestSendRecv(2); - DestroyChannels(); -} - -TEST_F(P2PTransportChannelTest, TestIceRoleConflictWithoutBundle) { - AddAddress(0, kPublicAddrs[0]); - AddAddress(1, kPublicAddrs[1]); - TestSignalRoleConflict(); -} - -TEST_F(P2PTransportChannelTest, TestIceRoleConflictWithBundle) { - AddAddress(0, kPublicAddrs[0]); - AddAddress(1, kPublicAddrs[1]); - SetAllocatorFlags(0, cricket::PORTALLOCATOR_ENABLE_BUNDLE); - SetAllocatorFlags(1, cricket::PORTALLOCATOR_ENABLE_BUNDLE); - TestSignalRoleConflict(); -} - -// Tests that the ice configs (protocol, tiebreaker and role) can be passed -// down to ports. -TEST_F(P2PTransportChannelTest, TestIceConfigWillPassDownToPort) { - AddAddress(0, kPublicAddrs[0]); - AddAddress(1, kPublicAddrs[1]); - - SetIceRole(0, cricket::ICEROLE_CONTROLLING); - SetIceProtocol(0, cricket::ICEPROTO_GOOGLE); - SetIceTiebreaker(0, kTiebreaker1); - SetIceRole(1, cricket::ICEROLE_CONTROLLING); - SetIceProtocol(1, cricket::ICEPROTO_RFC5245); - SetIceTiebreaker(1, kTiebreaker2); - - CreateChannels(1); - - EXPECT_EQ_WAIT(2u, ep1_ch1()->ports().size(), 1000); - - const std::vector<cricket::PortInterface *> ports_before = ep1_ch1()->ports(); - for (size_t i = 0; i < ports_before.size(); ++i) { - EXPECT_EQ(cricket::ICEROLE_CONTROLLING, ports_before[i]->GetIceRole()); - EXPECT_EQ(cricket::ICEPROTO_GOOGLE, ports_before[i]->IceProtocol()); - EXPECT_EQ(kTiebreaker1, ports_before[i]->IceTiebreaker()); - } - - ep1_ch1()->SetIceRole(cricket::ICEROLE_CONTROLLED); - ep1_ch1()->SetIceProtocolType(cricket::ICEPROTO_RFC5245); - ep1_ch1()->SetIceTiebreaker(kTiebreaker2); - - const std::vector<cricket::PortInterface *> ports_after = ep1_ch1()->ports(); - for (size_t i = 0; i < ports_after.size(); ++i) { - EXPECT_EQ(cricket::ICEROLE_CONTROLLED, ports_before[i]->GetIceRole()); - EXPECT_EQ(cricket::ICEPROTO_RFC5245, ports_before[i]->IceProtocol()); - // SetIceTiebreaker after Connect() has been called will fail. So expect the - // original value. - EXPECT_EQ(kTiebreaker1, ports_before[i]->IceTiebreaker()); - } - - EXPECT_TRUE_WAIT(ep1_ch1()->readable() && - ep1_ch1()->writable() && - ep2_ch1()->readable() && - ep2_ch1()->writable(), - 1000); - - EXPECT_TRUE(ep1_ch1()->best_connection() && - ep2_ch1()->best_connection()); - - TestSendRecv(1); - DestroyChannels(); -} - -// This test verifies channel can handle ice messages when channel is in -// hybrid mode. -TEST_F(P2PTransportChannelTest, TestConnectivityBetweenHybridandIce) { - TestHybridConnectivity(cricket::ICEPROTO_RFC5245); -} - -// This test verifies channel can handle Gice messages when channel is in -// hybrid mode. -TEST_F(P2PTransportChannelTest, TestConnectivityBetweenHybridandGice) { - TestHybridConnectivity(cricket::ICEPROTO_GOOGLE); -} - -// Verify that we can set DSCP value and retrieve properly from P2PTC. -TEST_F(P2PTransportChannelTest, TestDefaultDscpValue) { - AddAddress(0, kPublicAddrs[0]); - AddAddress(1, kPublicAddrs[1]); - - CreateChannels(1); - EXPECT_EQ(rtc::DSCP_NO_CHANGE, - GetEndpoint(0)->cd1_.ch_->DefaultDscpValue()); - EXPECT_EQ(rtc::DSCP_NO_CHANGE, - GetEndpoint(1)->cd1_.ch_->DefaultDscpValue()); - GetEndpoint(0)->cd1_.ch_->SetOption( - rtc::Socket::OPT_DSCP, rtc::DSCP_CS6); - GetEndpoint(1)->cd1_.ch_->SetOption( - rtc::Socket::OPT_DSCP, rtc::DSCP_CS6); - EXPECT_EQ(rtc::DSCP_CS6, - GetEndpoint(0)->cd1_.ch_->DefaultDscpValue()); - EXPECT_EQ(rtc::DSCP_CS6, - GetEndpoint(1)->cd1_.ch_->DefaultDscpValue()); - GetEndpoint(0)->cd1_.ch_->SetOption( - rtc::Socket::OPT_DSCP, rtc::DSCP_AF41); - GetEndpoint(1)->cd1_.ch_->SetOption( - rtc::Socket::OPT_DSCP, rtc::DSCP_AF41); - EXPECT_EQ(rtc::DSCP_AF41, - GetEndpoint(0)->cd1_.ch_->DefaultDscpValue()); - EXPECT_EQ(rtc::DSCP_AF41, - GetEndpoint(1)->cd1_.ch_->DefaultDscpValue()); -} - -// Verify IPv6 connection is preferred over IPv4. -// Flaky: https://code.google.com/p/webrtc/issues/detail?id=3317 -TEST_F(P2PTransportChannelTest, DISABLED_TestIPv6Connections) { - AddAddress(0, kIPv6PublicAddrs[0]); - AddAddress(0, kPublicAddrs[0]); - AddAddress(1, kIPv6PublicAddrs[1]); - AddAddress(1, kPublicAddrs[1]); - - SetAllocationStepDelay(0, kMinimumStepDelay); - SetAllocationStepDelay(1, kMinimumStepDelay); - - // Enable IPv6 - SetAllocatorFlags(0, cricket::PORTALLOCATOR_ENABLE_IPV6); - SetAllocatorFlags(1, cricket::PORTALLOCATOR_ENABLE_IPV6); - - CreateChannels(1); - - EXPECT_TRUE_WAIT(ep1_ch1()->readable() && ep1_ch1()->writable() && - ep2_ch1()->readable() && ep2_ch1()->writable(), - 1000); - EXPECT_TRUE( - ep1_ch1()->best_connection() && ep2_ch1()->best_connection() && - LocalCandidate(ep1_ch1())->address().EqualIPs(kIPv6PublicAddrs[0]) && - RemoteCandidate(ep1_ch1())->address().EqualIPs(kIPv6PublicAddrs[1])); - - TestSendRecv(1); - DestroyChannels(); -} - -// Testing forceful TURN connections. -TEST_F(P2PTransportChannelTest, TestForceTurn) { - ConfigureEndpoints(NAT_PORT_RESTRICTED, NAT_SYMMETRIC, - kDefaultPortAllocatorFlags | - cricket::PORTALLOCATOR_ENABLE_SHARED_SOCKET | - cricket::PORTALLOCATOR_ENABLE_SHARED_UFRAG, - kDefaultPortAllocatorFlags | - cricket::PORTALLOCATOR_ENABLE_SHARED_SOCKET | - cricket::PORTALLOCATOR_ENABLE_SHARED_UFRAG, - kDefaultStepDelay, kDefaultStepDelay, - cricket::ICEPROTO_RFC5245); - set_force_relay(true); - - SetAllocationStepDelay(0, kMinimumStepDelay); - SetAllocationStepDelay(1, kMinimumStepDelay); - - CreateChannels(1); - - EXPECT_TRUE_WAIT(ep1_ch1()->readable() && - ep1_ch1()->writable() && - ep2_ch1()->readable() && - ep2_ch1()->writable(), - 1000); - - EXPECT_TRUE(ep1_ch1()->best_connection() && - ep2_ch1()->best_connection()); - - EXPECT_EQ("relay", RemoteCandidate(ep1_ch1())->type()); - EXPECT_EQ("relay", LocalCandidate(ep1_ch1())->type()); - EXPECT_EQ("relay", RemoteCandidate(ep2_ch1())->type()); - EXPECT_EQ("relay", LocalCandidate(ep2_ch1())->type()); - - TestSendRecv(1); - DestroyChannels(); -} - -// Test what happens when we have 2 users behind the same NAT. This can lead -// to interesting behavior because the STUN server will only give out the -// address of the outermost NAT. -class P2PTransportChannelSameNatTest : public P2PTransportChannelTestBase { - protected: - void ConfigureEndpoints(Config nat_type, Config config1, Config config2) { - ASSERT(nat_type >= NAT_FULL_CONE && nat_type <= NAT_SYMMETRIC); - rtc::NATSocketServer::Translator* outer_nat = - nat()->AddTranslator(kPublicAddrs[0], kNatAddrs[0], - static_cast<rtc::NATType>(nat_type - NAT_FULL_CONE)); - ConfigureEndpoint(outer_nat, 0, config1); - ConfigureEndpoint(outer_nat, 1, config2); - } - void ConfigureEndpoint(rtc::NATSocketServer::Translator* nat, - int endpoint, Config config) { - ASSERT(config <= NAT_SYMMETRIC); - if (config == OPEN) { - AddAddress(endpoint, kPrivateAddrs[endpoint]); - nat->AddClient(kPrivateAddrs[endpoint]); - } else { - AddAddress(endpoint, kCascadedPrivateAddrs[endpoint]); - nat->AddTranslator(kPrivateAddrs[endpoint], kCascadedNatAddrs[endpoint], - static_cast<rtc::NATType>(config - NAT_FULL_CONE))->AddClient( - kCascadedPrivateAddrs[endpoint]); - } - } -}; - -TEST_F(P2PTransportChannelSameNatTest, TestConesBehindSameCone) { - ConfigureEndpoints(NAT_FULL_CONE, NAT_FULL_CONE, NAT_FULL_CONE); - Test(kLocalUdpToStunUdp); -} - -// Test what happens when we have multiple available pathways. -// In the future we will try different RTTs and configs for the different -// interfaces, so that we can simulate a user with Ethernet and VPN networks. -class P2PTransportChannelMultihomedTest : public P2PTransportChannelTestBase { -}; - -// Test that we can establish connectivity when both peers are multihomed. -TEST_F(P2PTransportChannelMultihomedTest, DISABLED_TestBasic) { - AddAddress(0, kPublicAddrs[0]); - AddAddress(0, kAlternateAddrs[0]); - AddAddress(1, kPublicAddrs[1]); - AddAddress(1, kAlternateAddrs[1]); - Test(kLocalUdpToLocalUdp); -} - -// Test that we can quickly switch links if an interface goes down. -TEST_F(P2PTransportChannelMultihomedTest, TestFailover) { - AddAddress(0, kPublicAddrs[0]); - // Adding alternate address will make sure |kPublicAddrs| has the higher - // priority than others. This is due to FakeNetwork::AddInterface method. - AddAddress(1, kAlternateAddrs[1]); - AddAddress(1, kPublicAddrs[1]); - - // Use only local ports for simplicity. - SetAllocatorFlags(0, kOnlyLocalPorts); - SetAllocatorFlags(1, kOnlyLocalPorts); - - // Create channels and let them go writable, as usual. - CreateChannels(1); - EXPECT_TRUE_WAIT(ep1_ch1()->readable() && ep1_ch1()->writable() && - ep2_ch1()->readable() && ep2_ch1()->writable(), - 1000); - EXPECT_TRUE( - ep1_ch1()->best_connection() && ep2_ch1()->best_connection() && - LocalCandidate(ep1_ch1())->address().EqualIPs(kPublicAddrs[0]) && - RemoteCandidate(ep1_ch1())->address().EqualIPs(kPublicAddrs[1])); - - // Blackhole any traffic to or from the public addrs. - LOG(LS_INFO) << "Failing over..."; - fw()->AddRule(false, rtc::FP_ANY, rtc::FD_ANY, - kPublicAddrs[1]); - - // We should detect loss of connectivity within 5 seconds or so. - EXPECT_TRUE_WAIT(!ep1_ch1()->writable(), 7000); - - // We should switch over to use the alternate addr immediately - // when we lose writability. - EXPECT_TRUE_WAIT( - ep1_ch1()->best_connection() && ep2_ch1()->best_connection() && - LocalCandidate(ep1_ch1())->address().EqualIPs(kPublicAddrs[0]) && - RemoteCandidate(ep1_ch1())->address().EqualIPs(kAlternateAddrs[1]), - 3000); - - DestroyChannels(); -} - -// Test that we can switch links in a coordinated fashion. -TEST_F(P2PTransportChannelMultihomedTest, TestDrain) { - AddAddress(0, kPublicAddrs[0]); - AddAddress(1, kPublicAddrs[1]); - // Use only local ports for simplicity. - SetAllocatorFlags(0, kOnlyLocalPorts); - SetAllocatorFlags(1, kOnlyLocalPorts); - - // Create channels and let them go writable, as usual. - CreateChannels(1); - EXPECT_TRUE_WAIT(ep1_ch1()->readable() && ep1_ch1()->writable() && - ep2_ch1()->readable() && ep2_ch1()->writable(), - 1000); - EXPECT_TRUE( - ep1_ch1()->best_connection() && ep2_ch1()->best_connection() && - LocalCandidate(ep1_ch1())->address().EqualIPs(kPublicAddrs[0]) && - RemoteCandidate(ep1_ch1())->address().EqualIPs(kPublicAddrs[1])); - - // Remove the public interface, add the alternate interface, and allocate - // a new generation of candidates for the new interface (via Connect()). - LOG(LS_INFO) << "Draining..."; - AddAddress(1, kAlternateAddrs[1]); - RemoveAddress(1, kPublicAddrs[1]); - ep2_ch1()->Connect(); - - // We should switch over to use the alternate address after - // an exchange of pings. - EXPECT_TRUE_WAIT( - ep1_ch1()->best_connection() && ep2_ch1()->best_connection() && - LocalCandidate(ep1_ch1())->address().EqualIPs(kPublicAddrs[0]) && - RemoteCandidate(ep1_ch1())->address().EqualIPs(kAlternateAddrs[1]), - 3000); - - DestroyChannels(); -} diff --git a/talk/p2p/base/packetsocketfactory.h b/talk/p2p/base/packetsocketfactory.h deleted file mode 100644 index 0160cacdf..000000000 --- a/talk/p2p/base/packetsocketfactory.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * libjingle - * Copyright 2011, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef WEBRTC_P2P_BASE_PACKETSOCKETFACTORY_H_ -#define WEBRTC_P2P_BASE_PACKETSOCKETFACTORY_H_ - -#include "webrtc/base/proxyinfo.h" - -namespace rtc { - -class AsyncPacketSocket; -class AsyncResolverInterface; - -class PacketSocketFactory { - public: - enum Options { - OPT_SSLTCP = 0x01, // Pseudo-TLS. - OPT_TLS = 0x02, - OPT_STUN = 0x04, - }; - - PacketSocketFactory() { } - virtual ~PacketSocketFactory() { } - - virtual AsyncPacketSocket* CreateUdpSocket( - const SocketAddress& address, int min_port, int max_port) = 0; - virtual AsyncPacketSocket* CreateServerTcpSocket( - const SocketAddress& local_address, int min_port, int max_port, - int opts) = 0; - - // TODO: |proxy_info| and |user_agent| should be set - // per-factory and not when socket is created. - virtual AsyncPacketSocket* CreateClientTcpSocket( - const SocketAddress& local_address, const SocketAddress& remote_address, - const ProxyInfo& proxy_info, const std::string& user_agent, int opts) = 0; - - virtual AsyncResolverInterface* CreateAsyncResolver() = 0; - - private: - DISALLOW_EVIL_CONSTRUCTORS(PacketSocketFactory); -}; - -} // namespace rtc - -#endif // WEBRTC_P2P_BASE_PACKETSOCKETFACTORY_H_ diff --git a/talk/p2p/base/parsing.cc b/talk/p2p/base/parsing.cc deleted file mode 100644 index eace88bca..000000000 --- a/talk/p2p/base/parsing.cc +++ /dev/null @@ -1,158 +0,0 @@ -/* - * libjingle - * Copyright 2010, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "webrtc/p2p/base/parsing.h" - -#include <stdlib.h> -#include <algorithm> -#include "webrtc/base/stringutils.h" - -namespace { -static const char kTrue[] = "true"; -static const char kOne[] = "1"; -} - -namespace cricket { - -bool BadParse(const std::string& text, ParseError* err) { - if (err != NULL) { - err->text = text; - } - return false; -} - -bool BadWrite(const std::string& text, WriteError* err) { - if (err != NULL) { - err->text = text; - } - return false; -} - -std::string GetXmlAttr(const buzz::XmlElement* elem, - const buzz::QName& name, - const std::string& def) { - std::string val = elem->Attr(name); - return val.empty() ? def : val; -} - -std::string GetXmlAttr(const buzz::XmlElement* elem, - const buzz::QName& name, - const char* def) { - return GetXmlAttr(elem, name, std::string(def)); -} - -bool GetXmlAttr(const buzz::XmlElement* elem, - const buzz::QName& name, bool def) { - std::string val = elem->Attr(name); - std::transform(val.begin(), val.end(), val.begin(), tolower); - - return val.empty() ? def : (val == kTrue || val == kOne); -} - -int GetXmlAttr(const buzz::XmlElement* elem, - const buzz::QName& name, int def) { - std::string val = elem->Attr(name); - return val.empty() ? def : atoi(val.c_str()); -} - -const buzz::XmlElement* GetXmlChild(const buzz::XmlElement* parent, - const std::string& name) { - for (const buzz::XmlElement* child = parent->FirstElement(); - child != NULL; - child = child->NextElement()) { - if (child->Name().LocalPart() == name) { - return child; - } - } - return NULL; -} - -bool RequireXmlChild(const buzz::XmlElement* parent, - const std::string& name, - const buzz::XmlElement** child, - ParseError* error) { - *child = GetXmlChild(parent, name); - if (*child == NULL) { - return BadParse("element '" + parent->Name().Merged() + - "' missing required child '" + name, - error); - } else { - return true; - } -} - -bool RequireXmlAttr(const buzz::XmlElement* elem, - const buzz::QName& name, - std::string* value, - ParseError* error) { - if (!elem->HasAttr(name)) { - return BadParse("element '" + elem->Name().Merged() + - "' missing required attribute '" - + name.Merged() + "'", - error); - } else { - *value = elem->Attr(name); - return true; - } -} - -void AddXmlAttrIfNonEmpty(buzz::XmlElement* elem, - const buzz::QName name, - const std::string& value) { - if (!value.empty()) { - elem->AddAttr(name, value); - } -} - -void AddXmlChildren(buzz::XmlElement* parent, - const std::vector<buzz::XmlElement*>& children) { - for (std::vector<buzz::XmlElement*>::const_iterator iter = children.begin(); - iter != children.end(); - iter++) { - parent->AddElement(*iter); - } -} - -void CopyXmlChildren(const buzz::XmlElement* source, buzz::XmlElement* dest) { - for (const buzz::XmlElement* child = source->FirstElement(); - child != NULL; - child = child->NextElement()) { - dest->AddElement(new buzz::XmlElement(*child)); - } -} - -std::vector<buzz::XmlElement*> CopyOfXmlChildren(const buzz::XmlElement* elem) { - std::vector<buzz::XmlElement*> children; - for (const buzz::XmlElement* child = elem->FirstElement(); - child != NULL; - child = child->NextElement()) { - children.push_back(new buzz::XmlElement(*child)); - } - return children; -} - -} // namespace cricket diff --git a/talk/p2p/base/parsing.h b/talk/p2p/base/parsing.h deleted file mode 100644 index f150747aa..000000000 --- a/talk/p2p/base/parsing.h +++ /dev/null @@ -1,157 +0,0 @@ -/* - * libjingle - * Copyright 2010, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef WEBRTC_P2P_BASE_PARSING_H_ -#define WEBRTC_P2P_BASE_PARSING_H_ - -#include <string> -#include <vector> -#include "webrtc/libjingle/xmllite/xmlelement.h" // Needed to delete ParseError.extra. -#include "webrtc/base/basictypes.h" -#include "webrtc/base/stringencode.h" - -namespace cricket { - -typedef std::vector<buzz::XmlElement*> XmlElements; - -// We decided "bool Parse(in, out*, error*)" is generally the best -// parse signature. "out Parse(in)" doesn't allow for errors. -// "error* Parse(in, out*)" doesn't allow flexible memory management. - -// The error type for parsing. -struct ParseError { - public: - // explains the error - std::string text; - // provide details about what wasn't parsable - const buzz::XmlElement* extra; - - ParseError() : extra(NULL) {} - - ~ParseError() { - delete extra; - } - - void SetText(const std::string& text) { - this->text = text; - } -}; - -// The error type for writing. -struct WriteError { - std::string text; - - void SetText(const std::string& text) { - this->text = text; - } -}; - -// Convenience method for returning a message when parsing fails. -bool BadParse(const std::string& text, ParseError* err); - -// Convenience method for returning a message when writing fails. -bool BadWrite(const std::string& text, WriteError* error); - -// helper XML functions -std::string GetXmlAttr(const buzz::XmlElement* elem, - const buzz::QName& name, - const std::string& def); -std::string GetXmlAttr(const buzz::XmlElement* elem, - const buzz::QName& name, - const char* def); -// Return true if the value is "true" or "1". -bool GetXmlAttr(const buzz::XmlElement* elem, - const buzz::QName& name, bool def); -int GetXmlAttr(const buzz::XmlElement* elem, - const buzz::QName& name, int def); - -template <class T> -bool GetXmlAttr(const buzz::XmlElement* elem, - const buzz::QName& name, - T* val_out) { - if (!elem->HasAttr(name)) { - return false; - } - std::string unparsed = elem->Attr(name); - return rtc::FromString(unparsed, val_out); -} - -template <class T> -bool GetXmlAttr(const buzz::XmlElement* elem, - const buzz::QName& name, - const T& def, - T* val_out) { - if (!elem->HasAttr(name)) { - *val_out = def; - return true; - } - return GetXmlAttr(elem, name, val_out); -} - -template <class T> -bool AddXmlAttr(buzz::XmlElement* elem, - const buzz::QName& name, const T& val) { - std::string buf; - if (!rtc::ToString(val, &buf)) { - return false; - } - elem->AddAttr(name, buf); - return true; -} - -template <class T> -bool SetXmlBody(buzz::XmlElement* elem, const T& val) { - std::string buf; - if (!rtc::ToString(val, &buf)) { - return false; - } - elem->SetBodyText(buf); - return true; -} - -const buzz::XmlElement* GetXmlChild(const buzz::XmlElement* parent, - const std::string& name); - -bool RequireXmlChild(const buzz::XmlElement* parent, - const std::string& name, - const buzz::XmlElement** child, - ParseError* error); -bool RequireXmlAttr(const buzz::XmlElement* elem, - const buzz::QName& name, - std::string* value, - ParseError* error); -void AddXmlAttrIfNonEmpty(buzz::XmlElement* elem, - const buzz::QName name, - const std::string& value); -void AddXmlChildren(buzz::XmlElement* parent, - const std::vector<buzz::XmlElement*>& children); -void CopyXmlChildren(const buzz::XmlElement* source, buzz::XmlElement* dest); -std::vector<buzz::XmlElement*> CopyOfXmlChildren(const buzz::XmlElement* elem); - -} // namespace cricket - -#endif // WEBRTC_P2P_BASE_PARSING_H_ diff --git a/talk/p2p/base/port.cc b/talk/p2p/base/port.cc deleted file mode 100644 index aa88872ff..000000000 --- a/talk/p2p/base/port.cc +++ /dev/null @@ -1,1447 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "webrtc/p2p/base/port.h" - -#include <algorithm> -#include <vector> - -#include "webrtc/p2p/base/common.h" -#include "webrtc/p2p/base/portallocator.h" -#include "webrtc/base/base64.h" -#include "webrtc/base/crc32.h" -#include "webrtc/base/helpers.h" -#include "webrtc/base/logging.h" -#include "webrtc/base/messagedigest.h" -#include "webrtc/base/scoped_ptr.h" -#include "webrtc/base/stringencode.h" -#include "webrtc/base/stringutils.h" - -namespace { - -// Determines whether we have seen at least the given maximum number of -// pings fail to have a response. -inline bool TooManyFailures( - const std::vector<uint32>& pings_since_last_response, - uint32 maximum_failures, - uint32 rtt_estimate, - uint32 now) { - - // If we haven't sent that many pings, then we can't have failed that many. - if (pings_since_last_response.size() < maximum_failures) - return false; - - // Check if the window in which we would expect a response to the ping has - // already elapsed. - return pings_since_last_response[maximum_failures - 1] + rtt_estimate < now; -} - -// Determines whether we have gone too long without seeing any response. -inline bool TooLongWithoutResponse( - const std::vector<uint32>& pings_since_last_response, - uint32 maximum_time, - uint32 now) { - - if (pings_since_last_response.size() == 0) - return false; - - return pings_since_last_response[0] + maximum_time < now; -} - -// GICE(ICEPROTO_GOOGLE) requires different username for RTP and RTCP. -// This function generates a different username by +1 on the last character of -// the given username (|rtp_ufrag|). -std::string GetRtcpUfragFromRtpUfrag(const std::string& rtp_ufrag) { - ASSERT(!rtp_ufrag.empty()); - if (rtp_ufrag.empty()) { - return rtp_ufrag; - } - // Change the last character to the one next to it in the base64 table. - char new_last_char; - if (!rtc::Base64::GetNextBase64Char(rtp_ufrag[rtp_ufrag.size() - 1], - &new_last_char)) { - // Should not be here. - ASSERT(false); - } - std::string rtcp_ufrag = rtp_ufrag; - rtcp_ufrag[rtcp_ufrag.size() - 1] = new_last_char; - ASSERT(rtcp_ufrag != rtp_ufrag); - return rtcp_ufrag; -} - -// We will restrict RTT estimates (when used for determining state) to be -// within a reasonable range. -const uint32 MINIMUM_RTT = 100; // 0.1 seconds -const uint32 MAXIMUM_RTT = 3000; // 3 seconds - -// When we don't have any RTT data, we have to pick something reasonable. We -// use a large value just in case the connection is really slow. -const uint32 DEFAULT_RTT = MAXIMUM_RTT; - -// Computes our estimate of the RTT given the current estimate. -inline uint32 ConservativeRTTEstimate(uint32 rtt) { - return rtc::_max(MINIMUM_RTT, rtc::_min(MAXIMUM_RTT, 2 * rtt)); -} - -// Weighting of the old rtt value to new data. -const int RTT_RATIO = 3; // 3 : 1 - -// The delay before we begin checking if this port is useless. -const int kPortTimeoutDelay = 30 * 1000; // 30 seconds - -// Used by the Connection. -const uint32 MSG_DELETE = 1; -} - -namespace cricket { - -// TODO(ronghuawu): Use "host", "srflx", "prflx" and "relay". But this requires -// the signaling part be updated correspondingly as well. -const char LOCAL_PORT_TYPE[] = "local"; -const char STUN_PORT_TYPE[] = "stun"; -const char PRFLX_PORT_TYPE[] = "prflx"; -const char RELAY_PORT_TYPE[] = "relay"; - -const char UDP_PROTOCOL_NAME[] = "udp"; -const char TCP_PROTOCOL_NAME[] = "tcp"; -const char SSLTCP_PROTOCOL_NAME[] = "ssltcp"; - -static const char* const PROTO_NAMES[] = { UDP_PROTOCOL_NAME, - TCP_PROTOCOL_NAME, - SSLTCP_PROTOCOL_NAME }; - -const char* ProtoToString(ProtocolType proto) { - return PROTO_NAMES[proto]; -} - -bool StringToProto(const char* value, ProtocolType* proto) { - for (size_t i = 0; i <= PROTO_LAST; ++i) { - if (_stricmp(PROTO_NAMES[i], value) == 0) { - *proto = static_cast<ProtocolType>(i); - return true; - } - } - return false; -} - -// RFC 6544, TCP candidate encoding rules. -const int DISCARD_PORT = 9; -const char TCPTYPE_ACTIVE_STR[] = "active"; -const char TCPTYPE_PASSIVE_STR[] = "passive"; -const char TCPTYPE_SIMOPEN_STR[] = "so"; - -// Foundation: An arbitrary string that is the same for two candidates -// that have the same type, base IP address, protocol (UDP, TCP, -// etc.), and STUN or TURN server. If any of these are different, -// then the foundation will be different. Two candidate pairs with -// the same foundation pairs are likely to have similar network -// characteristics. Foundations are used in the frozen algorithm. -static std::string ComputeFoundation( - const std::string& type, - const std::string& protocol, - const rtc::SocketAddress& base_address) { - std::ostringstream ost; - ost << type << base_address.ipaddr().ToString() << protocol; - return rtc::ToString<uint32>(rtc::ComputeCrc32(ost.str())); -} - -Port::Port(rtc::Thread* thread, rtc::PacketSocketFactory* factory, - rtc::Network* network, const rtc::IPAddress& ip, - const std::string& username_fragment, const std::string& password) - : thread_(thread), - factory_(factory), - send_retransmit_count_attribute_(false), - network_(network), - ip_(ip), - min_port_(0), - max_port_(0), - component_(ICE_CANDIDATE_COMPONENT_DEFAULT), - generation_(0), - ice_username_fragment_(username_fragment), - password_(password), - timeout_delay_(kPortTimeoutDelay), - enable_port_packets_(false), - ice_protocol_(ICEPROTO_HYBRID), - ice_role_(ICEROLE_UNKNOWN), - tiebreaker_(0), - shared_socket_(true), - candidate_filter_(CF_ALL) { - Construct(); -} - -Port::Port(rtc::Thread* thread, const std::string& type, - rtc::PacketSocketFactory* factory, - rtc::Network* network, const rtc::IPAddress& ip, - int min_port, int max_port, const std::string& username_fragment, - const std::string& password) - : thread_(thread), - factory_(factory), - type_(type), - send_retransmit_count_attribute_(false), - network_(network), - ip_(ip), - min_port_(min_port), - max_port_(max_port), - component_(ICE_CANDIDATE_COMPONENT_DEFAULT), - generation_(0), - ice_username_fragment_(username_fragment), - password_(password), - timeout_delay_(kPortTimeoutDelay), - enable_port_packets_(false), - ice_protocol_(ICEPROTO_HYBRID), - ice_role_(ICEROLE_UNKNOWN), - tiebreaker_(0), - shared_socket_(false), - candidate_filter_(CF_ALL) { - ASSERT(factory_ != NULL); - Construct(); -} - -void Port::Construct() { - // If the username_fragment and password are empty, we should just create one. - if (ice_username_fragment_.empty()) { - ASSERT(password_.empty()); - ice_username_fragment_ = rtc::CreateRandomString(ICE_UFRAG_LENGTH); - password_ = rtc::CreateRandomString(ICE_PWD_LENGTH); - } - LOG_J(LS_INFO, this) << "Port created"; -} - -Port::~Port() { - // Delete all of the remaining connections. We copy the list up front - // because each deletion will cause it to be modified. - - std::vector<Connection*> list; - - AddressMap::iterator iter = connections_.begin(); - while (iter != connections_.end()) { - list.push_back(iter->second); - ++iter; - } - - for (uint32 i = 0; i < list.size(); i++) - delete list[i]; -} - -Connection* Port::GetConnection(const rtc::SocketAddress& remote_addr) { - AddressMap::const_iterator iter = connections_.find(remote_addr); - if (iter != connections_.end()) - return iter->second; - else - return NULL; -} - -void Port::AddAddress(const rtc::SocketAddress& address, - const rtc::SocketAddress& base_address, - const rtc::SocketAddress& related_address, - const std::string& protocol, - const std::string& tcptype, - const std::string& type, - uint32 type_preference, - uint32 relay_preference, - bool final) { - if (protocol == TCP_PROTOCOL_NAME && type == LOCAL_PORT_TYPE) { - ASSERT(!tcptype.empty()); - } - - Candidate c; - c.set_id(rtc::CreateRandomString(8)); - c.set_component(component_); - c.set_type(type); - c.set_protocol(protocol); - c.set_tcptype(tcptype); - c.set_address(address); - c.set_priority(c.GetPriority(type_preference, network_->preference(), - relay_preference)); - c.set_username(username_fragment()); - c.set_password(password_); - c.set_network_name(network_->name()); - c.set_generation(generation_); - c.set_related_address(related_address); - c.set_foundation(ComputeFoundation(type, protocol, base_address)); - candidates_.push_back(c); - SignalCandidateReady(this, c); - - if (final) { - SignalPortComplete(this); - } -} - -void Port::AddConnection(Connection* conn) { - connections_[conn->remote_candidate().address()] = conn; - conn->SignalDestroyed.connect(this, &Port::OnConnectionDestroyed); - SignalConnectionCreated(this, conn); -} - -void Port::OnReadPacket( - const char* data, size_t size, const rtc::SocketAddress& addr, - ProtocolType proto) { - // If the user has enabled port packets, just hand this over. - if (enable_port_packets_) { - SignalReadPacket(this, data, size, addr); - return; - } - - // If this is an authenticated STUN request, then signal unknown address and - // send back a proper binding response. - rtc::scoped_ptr<IceMessage> msg; - std::string remote_username; - if (!GetStunMessage(data, size, addr, msg.accept(), &remote_username)) { - LOG_J(LS_ERROR, this) << "Received non-STUN packet from unknown address (" - << addr.ToSensitiveString() << ")"; - } else if (!msg) { - // STUN message handled already - } else if (msg->type() == STUN_BINDING_REQUEST) { - // Check for role conflicts. - if (IsStandardIce() && - !MaybeIceRoleConflict(addr, msg.get(), remote_username)) { - LOG(LS_INFO) << "Received conflicting role from the peer."; - return; - } - - SignalUnknownAddress(this, addr, proto, msg.get(), remote_username, false); - } else { - // NOTE(tschmelcher): STUN_BINDING_RESPONSE is benign. It occurs if we - // pruned a connection for this port while it had STUN requests in flight, - // because we then get back responses for them, which this code correctly - // does not handle. - if (msg->type() != STUN_BINDING_RESPONSE) { - LOG_J(LS_ERROR, this) << "Received unexpected STUN message type (" - << msg->type() << ") from unknown address (" - << addr.ToSensitiveString() << ")"; - } - } -} - -void Port::OnReadyToSend() { - AddressMap::iterator iter = connections_.begin(); - for (; iter != connections_.end(); ++iter) { - iter->second->OnReadyToSend(); - } -} - -size_t Port::AddPrflxCandidate(const Candidate& local) { - candidates_.push_back(local); - return (candidates_.size() - 1); -} - -bool Port::IsStandardIce() const { - return (ice_protocol_ == ICEPROTO_RFC5245); -} - -bool Port::IsGoogleIce() const { - return (ice_protocol_ == ICEPROTO_GOOGLE); -} - -bool Port::IsHybridIce() const { - return (ice_protocol_ == ICEPROTO_HYBRID); -} - -bool Port::GetStunMessage(const char* data, size_t size, - const rtc::SocketAddress& addr, - IceMessage** out_msg, std::string* out_username) { - // NOTE: This could clearly be optimized to avoid allocating any memory. - // However, at the data rates we'll be looking at on the client side, - // this probably isn't worth worrying about. - ASSERT(out_msg != NULL); - ASSERT(out_username != NULL); - *out_msg = NULL; - out_username->clear(); - - // Don't bother parsing the packet if we can tell it's not STUN. - // In ICE mode, all STUN packets will have a valid fingerprint. - if (IsStandardIce() && !StunMessage::ValidateFingerprint(data, size)) { - return false; - } - - // Parse the request message. If the packet is not a complete and correct - // STUN message, then ignore it. - rtc::scoped_ptr<IceMessage> stun_msg(new IceMessage()); - rtc::ByteBuffer buf(data, size); - if (!stun_msg->Read(&buf) || (buf.Length() > 0)) { - return false; - } - - if (stun_msg->type() == STUN_BINDING_REQUEST) { - // Check for the presence of USERNAME and MESSAGE-INTEGRITY (if ICE) first. - // If not present, fail with a 400 Bad Request. - if (!stun_msg->GetByteString(STUN_ATTR_USERNAME) || - (IsStandardIce() && - !stun_msg->GetByteString(STUN_ATTR_MESSAGE_INTEGRITY))) { - LOG_J(LS_ERROR, this) << "Received STUN request without username/M-I " - << "from " << addr.ToSensitiveString(); - SendBindingErrorResponse(stun_msg.get(), addr, STUN_ERROR_BAD_REQUEST, - STUN_ERROR_REASON_BAD_REQUEST); - return true; - } - - // If the username is bad or unknown, fail with a 401 Unauthorized. - std::string local_ufrag; - std::string remote_ufrag; - IceProtocolType remote_protocol_type; - if (!ParseStunUsername(stun_msg.get(), &local_ufrag, &remote_ufrag, - &remote_protocol_type) || - local_ufrag != username_fragment()) { - LOG_J(LS_ERROR, this) << "Received STUN request with bad local username " - << local_ufrag << " from " - << addr.ToSensitiveString(); - SendBindingErrorResponse(stun_msg.get(), addr, STUN_ERROR_UNAUTHORIZED, - STUN_ERROR_REASON_UNAUTHORIZED); - return true; - } - - // Port is initialized to GOOGLE-ICE protocol type. If pings from remote - // are received before the signal message, protocol type may be different. - // Based on the STUN username, we can determine what's the remote protocol. - // This also enables us to send the response back using the same protocol - // as the request. - if (IsHybridIce()) { - SetIceProtocolType(remote_protocol_type); - } - - // If ICE, and the MESSAGE-INTEGRITY is bad, fail with a 401 Unauthorized - if (IsStandardIce() && - !stun_msg->ValidateMessageIntegrity(data, size, password_)) { - LOG_J(LS_ERROR, this) << "Received STUN request with bad M-I " - << "from " << addr.ToSensitiveString(); - SendBindingErrorResponse(stun_msg.get(), addr, STUN_ERROR_UNAUTHORIZED, - STUN_ERROR_REASON_UNAUTHORIZED); - return true; - } - out_username->assign(remote_ufrag); - } else if ((stun_msg->type() == STUN_BINDING_RESPONSE) || - (stun_msg->type() == STUN_BINDING_ERROR_RESPONSE)) { - if (stun_msg->type() == STUN_BINDING_ERROR_RESPONSE) { - if (const StunErrorCodeAttribute* error_code = stun_msg->GetErrorCode()) { - LOG_J(LS_ERROR, this) << "Received STUN binding error:" - << " class=" << error_code->eclass() - << " number=" << error_code->number() - << " reason='" << error_code->reason() << "'" - << " from " << addr.ToSensitiveString(); - // Return message to allow error-specific processing - } else { - LOG_J(LS_ERROR, this) << "Received STUN binding error without a error " - << "code from " << addr.ToSensitiveString(); - return true; - } - } - // NOTE: Username should not be used in verifying response messages. - out_username->clear(); - } else if (stun_msg->type() == STUN_BINDING_INDICATION) { - LOG_J(LS_VERBOSE, this) << "Received STUN binding indication:" - << " from " << addr.ToSensitiveString(); - out_username->clear(); - // No stun attributes will be verified, if it's stun indication message. - // Returning from end of the this method. - } else { - LOG_J(LS_ERROR, this) << "Received STUN packet with invalid type (" - << stun_msg->type() << ") from " - << addr.ToSensitiveString(); - return true; - } - - // Return the STUN message found. - *out_msg = stun_msg.release(); - return true; -} - -bool Port::IsCompatibleAddress(const rtc::SocketAddress& addr) { - int family = ip().family(); - // We use single-stack sockets, so families must match. - if (addr.family() != family) { - return false; - } - // Link-local IPv6 ports can only connect to other link-local IPv6 ports. - if (family == AF_INET6 && (IPIsPrivate(ip()) != IPIsPrivate(addr.ipaddr()))) { - return false; - } - return true; -} - -bool Port::ParseStunUsername(const StunMessage* stun_msg, - std::string* local_ufrag, - std::string* remote_ufrag, - IceProtocolType* remote_protocol_type) const { - // The packet must include a username that either begins or ends with our - // fragment. It should begin with our fragment if it is a request and it - // should end with our fragment if it is a response. - local_ufrag->clear(); - remote_ufrag->clear(); - const StunByteStringAttribute* username_attr = - stun_msg->GetByteString(STUN_ATTR_USERNAME); - if (username_attr == NULL) - return false; - - const std::string username_attr_str = username_attr->GetString(); - size_t colon_pos = username_attr_str.find(":"); - // If we are in hybrid mode set the appropriate ice protocol type based on - // the username argument style. - if (IsHybridIce()) { - *remote_protocol_type = (colon_pos != std::string::npos) ? - ICEPROTO_RFC5245 : ICEPROTO_GOOGLE; - } else { - *remote_protocol_type = ice_protocol_; - } - if (*remote_protocol_type == ICEPROTO_RFC5245) { - if (colon_pos != std::string::npos) { // RFRAG:LFRAG - *local_ufrag = username_attr_str.substr(0, colon_pos); - *remote_ufrag = username_attr_str.substr( - colon_pos + 1, username_attr_str.size()); - } else { - return false; - } - } else if (*remote_protocol_type == ICEPROTO_GOOGLE) { - int remote_frag_len = static_cast<int>(username_attr_str.size()); - remote_frag_len -= static_cast<int>(username_fragment().size()); - if (remote_frag_len < 0) - return false; - - *local_ufrag = username_attr_str.substr(0, username_fragment().size()); - *remote_ufrag = username_attr_str.substr( - username_fragment().size(), username_attr_str.size()); - } - return true; -} - -bool Port::MaybeIceRoleConflict( - const rtc::SocketAddress& addr, IceMessage* stun_msg, - const std::string& remote_ufrag) { - // Validate ICE_CONTROLLING or ICE_CONTROLLED attributes. - bool ret = true; - IceRole remote_ice_role = ICEROLE_UNKNOWN; - uint64 remote_tiebreaker = 0; - const StunUInt64Attribute* stun_attr = - stun_msg->GetUInt64(STUN_ATTR_ICE_CONTROLLING); - if (stun_attr) { - remote_ice_role = ICEROLE_CONTROLLING; - remote_tiebreaker = stun_attr->value(); - } - - // If |remote_ufrag| is same as port local username fragment and - // tie breaker value received in the ping message matches port - // tiebreaker value this must be a loopback call. - // We will treat this as valid scenario. - if (remote_ice_role == ICEROLE_CONTROLLING && - username_fragment() == remote_ufrag && - remote_tiebreaker == IceTiebreaker()) { - return true; - } - - stun_attr = stun_msg->GetUInt64(STUN_ATTR_ICE_CONTROLLED); - if (stun_attr) { - remote_ice_role = ICEROLE_CONTROLLED; - remote_tiebreaker = stun_attr->value(); - } - - switch (ice_role_) { - case ICEROLE_CONTROLLING: - if (ICEROLE_CONTROLLING == remote_ice_role) { - if (remote_tiebreaker >= tiebreaker_) { - SignalRoleConflict(this); - } else { - // Send Role Conflict (487) error response. - SendBindingErrorResponse(stun_msg, addr, - STUN_ERROR_ROLE_CONFLICT, STUN_ERROR_REASON_ROLE_CONFLICT); - ret = false; - } - } - break; - case ICEROLE_CONTROLLED: - if (ICEROLE_CONTROLLED == remote_ice_role) { - if (remote_tiebreaker < tiebreaker_) { - SignalRoleConflict(this); - } else { - // Send Role Conflict (487) error response. - SendBindingErrorResponse(stun_msg, addr, - STUN_ERROR_ROLE_CONFLICT, STUN_ERROR_REASON_ROLE_CONFLICT); - ret = false; - } - } - break; - default: - ASSERT(false); - } - return ret; -} - -void Port::CreateStunUsername(const std::string& remote_username, - std::string* stun_username_attr_str) const { - stun_username_attr_str->clear(); - *stun_username_attr_str = remote_username; - if (IsStandardIce()) { - // Connectivity checks from L->R will have username RFRAG:LFRAG. - stun_username_attr_str->append(":"); - } - stun_username_attr_str->append(username_fragment()); -} - -void Port::SendBindingResponse(StunMessage* request, - const rtc::SocketAddress& addr) { - ASSERT(request->type() == STUN_BINDING_REQUEST); - - // Retrieve the username from the request. - const StunByteStringAttribute* username_attr = - request->GetByteString(STUN_ATTR_USERNAME); - ASSERT(username_attr != NULL); - if (username_attr == NULL) { - // No valid username, skip the response. - return; - } - - // Fill in the response message. - StunMessage response; - response.SetType(STUN_BINDING_RESPONSE); - response.SetTransactionID(request->transaction_id()); - const StunUInt32Attribute* retransmit_attr = - request->GetUInt32(STUN_ATTR_RETRANSMIT_COUNT); - if (retransmit_attr) { - // Inherit the incoming retransmit value in the response so the other side - // can see our view of lost pings. - response.AddAttribute(new StunUInt32Attribute( - STUN_ATTR_RETRANSMIT_COUNT, retransmit_attr->value())); - - if (retransmit_attr->value() > CONNECTION_WRITE_CONNECT_FAILURES) { - LOG_J(LS_INFO, this) - << "Received a remote ping with high retransmit count: " - << retransmit_attr->value(); - } - } - - // Only GICE messages have USERNAME and MAPPED-ADDRESS in the response. - // ICE messages use XOR-MAPPED-ADDRESS, and add MESSAGE-INTEGRITY. - if (IsStandardIce()) { - response.AddAttribute( - new StunXorAddressAttribute(STUN_ATTR_XOR_MAPPED_ADDRESS, addr)); - response.AddMessageIntegrity(password_); - response.AddFingerprint(); - } else if (IsGoogleIce()) { - response.AddAttribute( - new StunAddressAttribute(STUN_ATTR_MAPPED_ADDRESS, addr)); - response.AddAttribute(new StunByteStringAttribute( - STUN_ATTR_USERNAME, username_attr->GetString())); - } - - // Send the response message. - rtc::ByteBuffer buf; - response.Write(&buf); - rtc::PacketOptions options(DefaultDscpValue()); - if (SendTo(buf.Data(), buf.Length(), addr, options, false) < 0) { - LOG_J(LS_ERROR, this) << "Failed to send STUN ping response to " - << addr.ToSensitiveString(); - } - - // The fact that we received a successful request means that this connection - // (if one exists) should now be readable. - Connection* conn = GetConnection(addr); - ASSERT(conn != NULL); - if (conn) - conn->ReceivedPing(); -} - -void Port::SendBindingErrorResponse(StunMessage* request, - const rtc::SocketAddress& addr, - int error_code, const std::string& reason) { - ASSERT(request->type() == STUN_BINDING_REQUEST); - - // Fill in the response message. - StunMessage response; - response.SetType(STUN_BINDING_ERROR_RESPONSE); - response.SetTransactionID(request->transaction_id()); - - // When doing GICE, we need to write out the error code incorrectly to - // maintain backwards compatiblility. - StunErrorCodeAttribute* error_attr = StunAttribute::CreateErrorCode(); - if (IsStandardIce()) { - error_attr->SetCode(error_code); - } else if (IsGoogleIce()) { - error_attr->SetClass(error_code / 256); - error_attr->SetNumber(error_code % 256); - } - error_attr->SetReason(reason); - response.AddAttribute(error_attr); - - if (IsStandardIce()) { - // Per Section 10.1.2, certain error cases don't get a MESSAGE-INTEGRITY, - // because we don't have enough information to determine the shared secret. - if (error_code != STUN_ERROR_BAD_REQUEST && - error_code != STUN_ERROR_UNAUTHORIZED) - response.AddMessageIntegrity(password_); - response.AddFingerprint(); - } else if (IsGoogleIce()) { - // GICE responses include a username, if one exists. - const StunByteStringAttribute* username_attr = - request->GetByteString(STUN_ATTR_USERNAME); - if (username_attr) - response.AddAttribute(new StunByteStringAttribute( - STUN_ATTR_USERNAME, username_attr->GetString())); - } - - // Send the response message. - rtc::ByteBuffer buf; - response.Write(&buf); - rtc::PacketOptions options(DefaultDscpValue()); - SendTo(buf.Data(), buf.Length(), addr, options, false); - LOG_J(LS_INFO, this) << "Sending STUN binding error: reason=" << reason - << " to " << addr.ToSensitiveString(); -} - -void Port::OnMessage(rtc::Message *pmsg) { - ASSERT(pmsg->message_id == MSG_CHECKTIMEOUT); - CheckTimeout(); -} - -std::string Port::ToString() const { - std::stringstream ss; - ss << "Port[" << content_name_ << ":" << component_ - << ":" << generation_ << ":" << type_ - << ":" << network_->ToString() << "]"; - return ss.str(); -} - -void Port::EnablePortPackets() { - enable_port_packets_ = true; -} - -void Port::OnConnectionDestroyed(Connection* conn) { - AddressMap::iterator iter = - connections_.find(conn->remote_candidate().address()); - ASSERT(iter != connections_.end()); - connections_.erase(iter); - - // On the controlled side, ports time out, but only after all connections - // fail. Note: If a new connection is added after this message is posted, - // but it fails and is removed before kPortTimeoutDelay, then this message - // will still cause the Port to be destroyed. - if (ice_role_ == ICEROLE_CONTROLLED) - thread_->PostDelayed(timeout_delay_, this, MSG_CHECKTIMEOUT); -} - -void Port::Destroy() { - ASSERT(connections_.empty()); - LOG_J(LS_INFO, this) << "Port deleted"; - SignalDestroyed(this); - delete this; -} - -void Port::CheckTimeout() { - ASSERT(ice_role_ == ICEROLE_CONTROLLED); - // If this port has no connections, then there's no reason to keep it around. - // When the connections time out (both read and write), they will delete - // themselves, so if we have any connections, they are either readable or - // writable (or still connecting). - if (connections_.empty()) - Destroy(); -} - -const std::string Port::username_fragment() const { - if (!IsStandardIce() && - component_ == ICE_CANDIDATE_COMPONENT_RTCP) { - // In GICE mode, we should adjust username fragment for rtcp component. - return GetRtcpUfragFromRtpUfrag(ice_username_fragment_); - } else { - return ice_username_fragment_; - } -} - -// A ConnectionRequest is a simple STUN ping used to determine writability. -class ConnectionRequest : public StunRequest { - public: - explicit ConnectionRequest(Connection* connection) - : StunRequest(new IceMessage()), - connection_(connection) { - } - - virtual ~ConnectionRequest() { - } - - virtual void Prepare(StunMessage* request) { - request->SetType(STUN_BINDING_REQUEST); - std::string username; - connection_->port()->CreateStunUsername( - connection_->remote_candidate().username(), &username); - request->AddAttribute( - new StunByteStringAttribute(STUN_ATTR_USERNAME, username)); - - // connection_ already holds this ping, so subtract one from count. - if (connection_->port()->send_retransmit_count_attribute()) { - request->AddAttribute(new StunUInt32Attribute( - STUN_ATTR_RETRANSMIT_COUNT, - static_cast<uint32>( - connection_->pings_since_last_response_.size() - 1))); - } - - // Adding ICE-specific attributes to the STUN request message. - if (connection_->port()->IsStandardIce()) { - // Adding ICE_CONTROLLED or ICE_CONTROLLING attribute based on the role. - if (connection_->port()->GetIceRole() == ICEROLE_CONTROLLING) { - request->AddAttribute(new StunUInt64Attribute( - STUN_ATTR_ICE_CONTROLLING, connection_->port()->IceTiebreaker())); - // Since we are trying aggressive nomination, sending USE-CANDIDATE - // attribute in every ping. - // If we are dealing with a ice-lite end point, nomination flag - // in Connection will be set to false by default. Once the connection - // becomes "best connection", nomination flag will be turned on. - if (connection_->use_candidate_attr()) { - request->AddAttribute(new StunByteStringAttribute( - STUN_ATTR_USE_CANDIDATE)); - } - } else if (connection_->port()->GetIceRole() == ICEROLE_CONTROLLED) { - request->AddAttribute(new StunUInt64Attribute( - STUN_ATTR_ICE_CONTROLLED, connection_->port()->IceTiebreaker())); - } else { - ASSERT(false); - } - - // Adding PRIORITY Attribute. - // Changing the type preference to Peer Reflexive and local preference - // and component id information is unchanged from the original priority. - // priority = (2^24)*(type preference) + - // (2^8)*(local preference) + - // (2^0)*(256 - component ID) - uint32 prflx_priority = ICE_TYPE_PREFERENCE_PRFLX << 24 | - (connection_->local_candidate().priority() & 0x00FFFFFF); - request->AddAttribute( - new StunUInt32Attribute(STUN_ATTR_PRIORITY, prflx_priority)); - - // Adding Message Integrity attribute. - request->AddMessageIntegrity(connection_->remote_candidate().password()); - // Adding Fingerprint. - request->AddFingerprint(); - } - } - - virtual void OnResponse(StunMessage* response) { - connection_->OnConnectionRequestResponse(this, response); - } - - virtual void OnErrorResponse(StunMessage* response) { - connection_->OnConnectionRequestErrorResponse(this, response); - } - - virtual void OnTimeout() { - connection_->OnConnectionRequestTimeout(this); - } - - virtual int GetNextDelay() { - // Each request is sent only once. After a single delay , the request will - // time out. - timeout_ = true; - return CONNECTION_RESPONSE_TIMEOUT; - } - - private: - Connection* connection_; -}; - -// -// Connection -// - -Connection::Connection(Port* port, size_t index, - const Candidate& remote_candidate) - : port_(port), local_candidate_index_(index), - remote_candidate_(remote_candidate), read_state_(STATE_READ_INIT), - write_state_(STATE_WRITE_INIT), connected_(true), pruned_(false), - use_candidate_attr_(false), remote_ice_mode_(ICEMODE_FULL), - requests_(port->thread()), rtt_(DEFAULT_RTT), last_ping_sent_(0), - last_ping_received_(0), last_data_received_(0), - last_ping_response_received_(0), reported_(false), state_(STATE_WAITING) { - // All of our connections start in WAITING state. - // TODO(mallinath) - Start connections from STATE_FROZEN. - // Wire up to send stun packets - requests_.SignalSendPacket.connect(this, &Connection::OnSendStunPacket); - LOG_J(LS_INFO, this) << "Connection created"; -} - -Connection::~Connection() { -} - -const Candidate& Connection::local_candidate() const { - ASSERT(local_candidate_index_ < port_->Candidates().size()); - return port_->Candidates()[local_candidate_index_]; -} - -uint64 Connection::priority() const { - uint64 priority = 0; - // RFC 5245 - 5.7.2. Computing Pair Priority and Ordering Pairs - // Let G be the priority for the candidate provided by the controlling - // agent. Let D be the priority for the candidate provided by the - // controlled agent. - // pair priority = 2^32*MIN(G,D) + 2*MAX(G,D) + (G>D?1:0) - IceRole role = port_->GetIceRole(); - if (role != ICEROLE_UNKNOWN) { - uint32 g = 0; - uint32 d = 0; - if (role == ICEROLE_CONTROLLING) { - g = local_candidate().priority(); - d = remote_candidate_.priority(); - } else { - g = remote_candidate_.priority(); - d = local_candidate().priority(); - } - priority = rtc::_min(g, d); - priority = priority << 32; - priority += 2 * rtc::_max(g, d) + (g > d ? 1 : 0); - } - return priority; -} - -void Connection::set_read_state(ReadState value) { - ReadState old_value = read_state_; - read_state_ = value; - if (value != old_value) { - LOG_J(LS_VERBOSE, this) << "set_read_state"; - SignalStateChange(this); - CheckTimeout(); - } -} - -void Connection::set_write_state(WriteState value) { - WriteState old_value = write_state_; - write_state_ = value; - if (value != old_value) { - LOG_J(LS_VERBOSE, this) << "set_write_state"; - SignalStateChange(this); - CheckTimeout(); - } -} - -void Connection::set_state(State state) { - State old_state = state_; - state_ = state; - if (state != old_state) { - LOG_J(LS_VERBOSE, this) << "set_state"; - } -} - -void Connection::set_connected(bool value) { - bool old_value = connected_; - connected_ = value; - if (value != old_value) { - LOG_J(LS_VERBOSE, this) << "set_connected"; - } -} - -void Connection::set_use_candidate_attr(bool enable) { - use_candidate_attr_ = enable; -} - -void Connection::OnSendStunPacket(const void* data, size_t size, - StunRequest* req) { - rtc::PacketOptions options(port_->DefaultDscpValue()); - if (port_->SendTo(data, size, remote_candidate_.address(), - options, false) < 0) { - LOG_J(LS_WARNING, this) << "Failed to send STUN ping " << req->id(); - } -} - -void Connection::OnReadPacket( - const char* data, size_t size, const rtc::PacketTime& packet_time) { - rtc::scoped_ptr<IceMessage> msg; - std::string remote_ufrag; - const rtc::SocketAddress& addr(remote_candidate_.address()); - if (!port_->GetStunMessage(data, size, addr, msg.accept(), &remote_ufrag)) { - // The packet did not parse as a valid STUN message - - // If this connection is readable, then pass along the packet. - if (read_state_ == STATE_READABLE) { - // readable means data from this address is acceptable - // Send it on! - - last_data_received_ = rtc::Time(); - recv_rate_tracker_.Update(size); - SignalReadPacket(this, data, size, packet_time); - - // If timed out sending writability checks, start up again - if (!pruned_ && (write_state_ == STATE_WRITE_TIMEOUT)) { - LOG(LS_WARNING) << "Received a data packet on a timed-out Connection. " - << "Resetting state to STATE_WRITE_INIT."; - set_write_state(STATE_WRITE_INIT); - } - } else { - // Not readable means the remote address hasn't sent a valid - // binding request yet. - - LOG_J(LS_WARNING, this) - << "Received non-STUN packet from an unreadable connection."; - } - } else if (!msg) { - // The packet was STUN, but failed a check and was handled internally. - } else { - // The packet is STUN and passed the Port checks. - // Perform our own checks to ensure this packet is valid. - // If this is a STUN request, then update the readable bit and respond. - // If this is a STUN response, then update the writable bit. - switch (msg->type()) { - case STUN_BINDING_REQUEST: - if (remote_ufrag == remote_candidate_.username()) { - // Check for role conflicts. - if (port_->IsStandardIce() && - !port_->MaybeIceRoleConflict(addr, msg.get(), remote_ufrag)) { - // Received conflicting role from the peer. - LOG(LS_INFO) << "Received conflicting role from the peer."; - return; - } - - // Incoming, validated stun request from remote peer. - // This call will also set the connection readable. - port_->SendBindingResponse(msg.get(), addr); - - // If timed out sending writability checks, start up again - if (!pruned_ && (write_state_ == STATE_WRITE_TIMEOUT)) - set_write_state(STATE_WRITE_INIT); - - if ((port_->IsStandardIce()) && - (port_->GetIceRole() == ICEROLE_CONTROLLED)) { - const StunByteStringAttribute* use_candidate_attr = - msg->GetByteString(STUN_ATTR_USE_CANDIDATE); - if (use_candidate_attr) - SignalUseCandidate(this); - } - } else { - // The packet had the right local username, but the remote username - // was not the right one for the remote address. - LOG_J(LS_ERROR, this) - << "Received STUN request with bad remote username " - << remote_ufrag; - port_->SendBindingErrorResponse(msg.get(), addr, - STUN_ERROR_UNAUTHORIZED, - STUN_ERROR_REASON_UNAUTHORIZED); - - } - break; - - // Response from remote peer. Does it match request sent? - // This doesn't just check, it makes callbacks if transaction - // id's match. - case STUN_BINDING_RESPONSE: - case STUN_BINDING_ERROR_RESPONSE: - if (port_->IsGoogleIce() || - msg->ValidateMessageIntegrity( - data, size, remote_candidate().password())) { - requests_.CheckResponse(msg.get()); - } - // Otherwise silently discard the response message. - break; - - // Remote end point sent an STUN indication instead of regular - // binding request. In this case |last_ping_received_| will be updated. - // Otherwise we can mark connection to read timeout. No response will be - // sent in this scenario. - case STUN_BINDING_INDICATION: - if (port_->IsStandardIce() && read_state_ == STATE_READABLE) { - ReceivedPing(); - } else { - LOG_J(LS_WARNING, this) << "Received STUN binding indication " - << "from an unreadable connection."; - } - break; - - default: - ASSERT(false); - break; - } - } -} - -void Connection::OnReadyToSend() { - if (write_state_ == STATE_WRITABLE) { - SignalReadyToSend(this); - } -} - -void Connection::Prune() { - if (!pruned_) { - LOG_J(LS_VERBOSE, this) << "Connection pruned"; - pruned_ = true; - requests_.Clear(); - set_write_state(STATE_WRITE_TIMEOUT); - } -} - -void Connection::Destroy() { - LOG_J(LS_VERBOSE, this) << "Connection destroyed"; - set_read_state(STATE_READ_TIMEOUT); - set_write_state(STATE_WRITE_TIMEOUT); -} - -void Connection::UpdateState(uint32 now) { - uint32 rtt = ConservativeRTTEstimate(rtt_); - - std::string pings; - for (size_t i = 0; i < pings_since_last_response_.size(); ++i) { - char buf[32]; - rtc::sprintfn(buf, sizeof(buf), "%u", - pings_since_last_response_[i]); - pings.append(buf).append(" "); - } - LOG_J(LS_VERBOSE, this) << "UpdateState(): pings_since_last_response_=" << - pings << ", rtt=" << rtt << ", now=" << now; - - // Check the readable state. - // - // Since we don't know how many pings the other side has attempted, the best - // test we can do is a simple window. - // If other side has not sent ping after connection has become readable, use - // |last_data_received_| as the indication. - // If remote endpoint is doing RFC 5245, it's not required to send ping - // after connection is established. If this connection is serving a data - // channel, it may not be in a position to send media continuously. Do not - // mark connection timeout if it's in RFC5245 mode. - // Below check will be performed with end point if it's doing google-ice. - if (port_->IsGoogleIce() && (read_state_ == STATE_READABLE) && - (last_ping_received_ + CONNECTION_READ_TIMEOUT <= now) && - (last_data_received_ + CONNECTION_READ_TIMEOUT <= now)) { - LOG_J(LS_INFO, this) << "Unreadable after " - << now - last_ping_received_ - << " ms without a ping," - << " ms since last received response=" - << now - last_ping_response_received_ - << " ms since last received data=" - << now - last_data_received_ - << " rtt=" << rtt; - set_read_state(STATE_READ_TIMEOUT); - } - - // Check the writable state. (The order of these checks is important.) - // - // Before becoming unwritable, we allow for a fixed number of pings to fail - // (i.e., receive no response). We also have to give the response time to - // get back, so we include a conservative estimate of this. - // - // Before timing out writability, we give a fixed amount of time. This is to - // allow for changes in network conditions. - - if ((write_state_ == STATE_WRITABLE) && - TooManyFailures(pings_since_last_response_, - CONNECTION_WRITE_CONNECT_FAILURES, - rtt, - now) && - TooLongWithoutResponse(pings_since_last_response_, - CONNECTION_WRITE_CONNECT_TIMEOUT, - now)) { - uint32 max_pings = CONNECTION_WRITE_CONNECT_FAILURES; - LOG_J(LS_INFO, this) << "Unwritable after " << max_pings - << " ping failures and " - << now - pings_since_last_response_[0] - << " ms without a response," - << " ms since last received ping=" - << now - last_ping_received_ - << " ms since last received data=" - << now - last_data_received_ - << " rtt=" << rtt; - set_write_state(STATE_WRITE_UNRELIABLE); - } - - if ((write_state_ == STATE_WRITE_UNRELIABLE || - write_state_ == STATE_WRITE_INIT) && - TooLongWithoutResponse(pings_since_last_response_, - CONNECTION_WRITE_TIMEOUT, - now)) { - LOG_J(LS_INFO, this) << "Timed out after " - << now - pings_since_last_response_[0] - << " ms without a response, rtt=" << rtt; - set_write_state(STATE_WRITE_TIMEOUT); - } -} - -void Connection::Ping(uint32 now) { - ASSERT(connected_); - last_ping_sent_ = now; - pings_since_last_response_.push_back(now); - ConnectionRequest *req = new ConnectionRequest(this); - LOG_J(LS_VERBOSE, this) << "Sending STUN ping " << req->id() << " at " << now; - requests_.Send(req); - state_ = STATE_INPROGRESS; -} - -void Connection::ReceivedPing() { - last_ping_received_ = rtc::Time(); - set_read_state(STATE_READABLE); -} - -std::string Connection::ToString() const { - const char CONNECT_STATE_ABBREV[2] = { - '-', // not connected (false) - 'C', // connected (true) - }; - const char READ_STATE_ABBREV[3] = { - '-', // STATE_READ_INIT - 'R', // STATE_READABLE - 'x', // STATE_READ_TIMEOUT - }; - const char WRITE_STATE_ABBREV[4] = { - 'W', // STATE_WRITABLE - 'w', // STATE_WRITE_UNRELIABLE - '-', // STATE_WRITE_INIT - 'x', // STATE_WRITE_TIMEOUT - }; - const std::string ICESTATE[4] = { - "W", // STATE_WAITING - "I", // STATE_INPROGRESS - "S", // STATE_SUCCEEDED - "F" // STATE_FAILED - }; - const Candidate& local = local_candidate(); - const Candidate& remote = remote_candidate(); - std::stringstream ss; - ss << "Conn[" << port_->content_name() - << ":" << local.id() << ":" << local.component() - << ":" << local.generation() - << ":" << local.type() << ":" << local.protocol() - << ":" << local.address().ToSensitiveString() - << "->" << remote.id() << ":" << remote.component() - << ":" << remote.priority() - << ":" << remote.type() << ":" - << remote.protocol() << ":" << remote.address().ToSensitiveString() << "|" - << CONNECT_STATE_ABBREV[connected()] - << READ_STATE_ABBREV[read_state()] - << WRITE_STATE_ABBREV[write_state()] - << ICESTATE[state()] << "|" - << priority() << "|"; - if (rtt_ < DEFAULT_RTT) { - ss << rtt_ << "]"; - } else { - ss << "-]"; - } - return ss.str(); -} - -std::string Connection::ToSensitiveString() const { - return ToString(); -} - -void Connection::OnConnectionRequestResponse(ConnectionRequest* request, - StunMessage* response) { - // We've already validated that this is a STUN binding response with - // the correct local and remote username for this connection. - // So if we're not already, become writable. We may be bringing a pruned - // connection back to life, but if we don't really want it, we can always - // prune it again. - uint32 rtt = request->Elapsed(); - set_write_state(STATE_WRITABLE); - set_state(STATE_SUCCEEDED); - - if (remote_ice_mode_ == ICEMODE_LITE) { - // A ice-lite end point never initiates ping requests. This will allow - // us to move to STATE_READABLE. - ReceivedPing(); - } - - std::string pings; - for (size_t i = 0; i < pings_since_last_response_.size(); ++i) { - char buf[32]; - rtc::sprintfn(buf, sizeof(buf), "%u", - pings_since_last_response_[i]); - pings.append(buf).append(" "); - } - - rtc::LoggingSeverity level = - (pings_since_last_response_.size() > CONNECTION_WRITE_CONNECT_FAILURES) ? - rtc::LS_INFO : rtc::LS_VERBOSE; - - LOG_JV(level, this) << "Received STUN ping response " << request->id() - << ", pings_since_last_response_=" << pings - << ", rtt=" << rtt; - - pings_since_last_response_.clear(); - last_ping_response_received_ = rtc::Time(); - rtt_ = (RTT_RATIO * rtt_ + rtt) / (RTT_RATIO + 1); - - // Peer reflexive candidate is only for RFC 5245 ICE. - if (port_->IsStandardIce()) { - MaybeAddPrflxCandidate(request, response); - } -} - -void Connection::OnConnectionRequestErrorResponse(ConnectionRequest* request, - StunMessage* response) { - const StunErrorCodeAttribute* error_attr = response->GetErrorCode(); - int error_code = STUN_ERROR_GLOBAL_FAILURE; - if (error_attr) { - if (port_->IsGoogleIce()) { - // When doing GICE, the error code is written out incorrectly, so we need - // to unmunge it here. - error_code = error_attr->eclass() * 256 + error_attr->number(); - } else { - error_code = error_attr->code(); - } - } - - if (error_code == STUN_ERROR_UNKNOWN_ATTRIBUTE || - error_code == STUN_ERROR_SERVER_ERROR || - error_code == STUN_ERROR_UNAUTHORIZED) { - // Recoverable error, retry - } else if (error_code == STUN_ERROR_STALE_CREDENTIALS) { - // Race failure, retry - } else if (error_code == STUN_ERROR_ROLE_CONFLICT) { - HandleRoleConflictFromPeer(); - } else { - // This is not a valid connection. - LOG_J(LS_ERROR, this) << "Received STUN error response, code=" - << error_code << "; killing connection"; - set_state(STATE_FAILED); - set_write_state(STATE_WRITE_TIMEOUT); - } -} - -void Connection::OnConnectionRequestTimeout(ConnectionRequest* request) { - // Log at LS_INFO if we miss a ping on a writable connection. - rtc::LoggingSeverity sev = (write_state_ == STATE_WRITABLE) ? - rtc::LS_INFO : rtc::LS_VERBOSE; - LOG_JV(sev, this) << "Timing-out STUN ping " << request->id() - << " after " << request->Elapsed() << " ms"; -} - -void Connection::CheckTimeout() { - // If both read and write have timed out or read has never initialized, then - // this connection can contribute no more to p2p socket unless at some later - // date readability were to come back. However, we gave readability a long - // time to timeout, so at this point, it seems fair to get rid of this - // connection. - if ((read_state_ == STATE_READ_TIMEOUT || - read_state_ == STATE_READ_INIT) && - write_state_ == STATE_WRITE_TIMEOUT) { - port_->thread()->Post(this, MSG_DELETE); - } -} - -void Connection::HandleRoleConflictFromPeer() { - port_->SignalRoleConflict(port_); -} - -void Connection::OnMessage(rtc::Message *pmsg) { - ASSERT(pmsg->message_id == MSG_DELETE); - - LOG_J(LS_INFO, this) << "Connection deleted due to read or write timeout"; - SignalDestroyed(this); - delete this; -} - -size_t Connection::recv_bytes_second() { - return recv_rate_tracker_.units_second(); -} - -size_t Connection::recv_total_bytes() { - return recv_rate_tracker_.total_units(); -} - -size_t Connection::sent_bytes_second() { - return send_rate_tracker_.units_second(); -} - -size_t Connection::sent_total_bytes() { - return send_rate_tracker_.total_units(); -} - -void Connection::MaybeAddPrflxCandidate(ConnectionRequest* request, - StunMessage* response) { - // RFC 5245 - // The agent checks the mapped address from the STUN response. If the - // transport address does not match any of the local candidates that the - // agent knows about, the mapped address represents a new candidate -- a - // peer reflexive candidate. - const StunAddressAttribute* addr = - response->GetAddress(STUN_ATTR_XOR_MAPPED_ADDRESS); - if (!addr) { - LOG(LS_WARNING) << "Connection::OnConnectionRequestResponse - " - << "No MAPPED-ADDRESS or XOR-MAPPED-ADDRESS found in the " - << "stun response message"; - return; - } - - bool known_addr = false; - for (size_t i = 0; i < port_->Candidates().size(); ++i) { - if (port_->Candidates()[i].address() == addr->GetAddress()) { - known_addr = true; - break; - } - } - if (known_addr) { - return; - } - - // RFC 5245 - // Its priority is set equal to the value of the PRIORITY attribute - // in the Binding request. - const StunUInt32Attribute* priority_attr = - request->msg()->GetUInt32(STUN_ATTR_PRIORITY); - if (!priority_attr) { - LOG(LS_WARNING) << "Connection::OnConnectionRequestResponse - " - << "No STUN_ATTR_PRIORITY found in the " - << "stun response message"; - return; - } - const uint32 priority = priority_attr->value(); - std::string id = rtc::CreateRandomString(8); - - Candidate new_local_candidate; - new_local_candidate.set_id(id); - new_local_candidate.set_component(local_candidate().component()); - new_local_candidate.set_type(PRFLX_PORT_TYPE); - new_local_candidate.set_protocol(local_candidate().protocol()); - new_local_candidate.set_address(addr->GetAddress()); - new_local_candidate.set_priority(priority); - new_local_candidate.set_username(local_candidate().username()); - new_local_candidate.set_password(local_candidate().password()); - new_local_candidate.set_network_name(local_candidate().network_name()); - new_local_candidate.set_related_address(local_candidate().address()); - new_local_candidate.set_foundation( - ComputeFoundation(PRFLX_PORT_TYPE, local_candidate().protocol(), - local_candidate().address())); - - // Change the local candidate of this Connection to the new prflx candidate. - local_candidate_index_ = port_->AddPrflxCandidate(new_local_candidate); - - // SignalStateChange to force a re-sort in P2PTransportChannel as this - // Connection's local candidate has changed. - SignalStateChange(this); -} - -ProxyConnection::ProxyConnection(Port* port, size_t index, - const Candidate& candidate) - : Connection(port, index, candidate), error_(0) { -} - -int ProxyConnection::Send(const void* data, size_t size, - const rtc::PacketOptions& options) { - if (write_state_ == STATE_WRITE_INIT || write_state_ == STATE_WRITE_TIMEOUT) { - error_ = EWOULDBLOCK; - return SOCKET_ERROR; - } - int sent = port_->SendTo(data, size, remote_candidate_.address(), - options, true); - if (sent <= 0) { - ASSERT(sent < 0); - error_ = port_->GetError(); - } else { - send_rate_tracker_.Update(sent); - } - return sent; -} - -} // namespace cricket diff --git a/talk/p2p/base/port.h b/talk/p2p/base/port.h deleted file mode 100644 index 490aee537..000000000 --- a/talk/p2p/base/port.h +++ /dev/null @@ -1,619 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef WEBRTC_P2P_BASE_PORT_H_ -#define WEBRTC_P2P_BASE_PORT_H_ - -#include <map> -#include <set> -#include <string> -#include <vector> - -#include "webrtc/p2p/base/candidate.h" -#include "webrtc/p2p/base/packetsocketfactory.h" -#include "webrtc/p2p/base/portinterface.h" -#include "webrtc/p2p/base/stun.h" -#include "webrtc/p2p/base/stunrequest.h" -#include "webrtc/p2p/base/transport.h" -#include "webrtc/base/asyncpacketsocket.h" -#include "webrtc/base/network.h" -#include "webrtc/base/proxyinfo.h" -#include "webrtc/base/ratetracker.h" -#include "webrtc/base/sigslot.h" -#include "webrtc/base/socketaddress.h" -#include "webrtc/base/thread.h" - -namespace cricket { - -class Connection; -class ConnectionRequest; - -extern const char LOCAL_PORT_TYPE[]; -extern const char STUN_PORT_TYPE[]; -extern const char PRFLX_PORT_TYPE[]; -extern const char RELAY_PORT_TYPE[]; - -extern const char UDP_PROTOCOL_NAME[]; -extern const char TCP_PROTOCOL_NAME[]; -extern const char SSLTCP_PROTOCOL_NAME[]; - -// RFC 6544, TCP candidate encoding rules. -extern const int DISCARD_PORT; -extern const char TCPTYPE_ACTIVE_STR[]; -extern const char TCPTYPE_PASSIVE_STR[]; -extern const char TCPTYPE_SIMOPEN_STR[]; - -// The length of time we wait before timing out readability on a connection. -const uint32 CONNECTION_READ_TIMEOUT = 30 * 1000; // 30 seconds - -// The length of time we wait before timing out writability on a connection. -const uint32 CONNECTION_WRITE_TIMEOUT = 15 * 1000; // 15 seconds - -// The length of time we wait before we become unwritable. -const uint32 CONNECTION_WRITE_CONNECT_TIMEOUT = 5 * 1000; // 5 seconds - -// The number of pings that must fail to respond before we become unwritable. -const uint32 CONNECTION_WRITE_CONNECT_FAILURES = 5; - -// This is the length of time that we wait for a ping response to come back. -const int CONNECTION_RESPONSE_TIMEOUT = 5 * 1000; // 5 seconds - -enum RelayType { - RELAY_GTURN, // Legacy google relay service. - RELAY_TURN // Standard (TURN) relay service. -}; - -enum IcePriorityValue { - // The reason we are choosing Relay preference 2 is because, we can run - // Relay from client to server on UDP/TCP/TLS. To distinguish the transport - // protocol, we prefer UDP over TCP over TLS. - // For UDP ICE_TYPE_PREFERENCE_RELAY will be 2. - // For TCP ICE_TYPE_PREFERENCE_RELAY will be 1. - // For TLS ICE_TYPE_PREFERENCE_RELAY will be 0. - // Check turnport.cc for setting these values. - ICE_TYPE_PREFERENCE_RELAY = 2, - ICE_TYPE_PREFERENCE_HOST_TCP = 90, - ICE_TYPE_PREFERENCE_SRFLX = 100, - ICE_TYPE_PREFERENCE_PRFLX = 110, - ICE_TYPE_PREFERENCE_HOST = 126 -}; - -const char* ProtoToString(ProtocolType proto); -bool StringToProto(const char* value, ProtocolType* proto); - -struct ProtocolAddress { - rtc::SocketAddress address; - ProtocolType proto; - bool secure; - - ProtocolAddress(const rtc::SocketAddress& a, ProtocolType p) - : address(a), proto(p), secure(false) { } - ProtocolAddress(const rtc::SocketAddress& a, ProtocolType p, bool sec) - : address(a), proto(p), secure(sec) { } -}; - -typedef std::set<rtc::SocketAddress> ServerAddresses; - -// Represents a local communication mechanism that can be used to create -// connections to similar mechanisms of the other client. Subclasses of this -// one add support for specific mechanisms like local UDP ports. -class Port : public PortInterface, public rtc::MessageHandler, - public sigslot::has_slots<> { - public: - Port(rtc::Thread* thread, rtc::PacketSocketFactory* factory, - rtc::Network* network, const rtc::IPAddress& ip, - const std::string& username_fragment, const std::string& password); - Port(rtc::Thread* thread, const std::string& type, - rtc::PacketSocketFactory* factory, - rtc::Network* network, const rtc::IPAddress& ip, - int min_port, int max_port, const std::string& username_fragment, - const std::string& password); - virtual ~Port(); - - virtual const std::string& Type() const { return type_; } - virtual rtc::Network* Network() const { return network_; } - - // This method will set the flag which enables standard ICE/STUN procedures - // in STUN connectivity checks. Currently this method does - // 1. Add / Verify MI attribute in STUN binding requests. - // 2. Username attribute in STUN binding request will be RFRAF:LFRAG, - // as opposed to RFRAGLFRAG. - virtual void SetIceProtocolType(IceProtocolType protocol) { - ice_protocol_ = protocol; - } - virtual IceProtocolType IceProtocol() const { return ice_protocol_; } - - // Methods to set/get ICE role and tiebreaker values. - IceRole GetIceRole() const { return ice_role_; } - void SetIceRole(IceRole role) { ice_role_ = role; } - - void SetIceTiebreaker(uint64 tiebreaker) { tiebreaker_ = tiebreaker; } - uint64 IceTiebreaker() const { return tiebreaker_; } - - virtual bool SharedSocket() const { return shared_socket_; } - void ResetSharedSocket() { shared_socket_ = false; } - - // The thread on which this port performs its I/O. - rtc::Thread* thread() { return thread_; } - - // The factory used to create the sockets of this port. - rtc::PacketSocketFactory* socket_factory() const { return factory_; } - void set_socket_factory(rtc::PacketSocketFactory* factory) { - factory_ = factory; - } - - // For debugging purposes. - const std::string& content_name() const { return content_name_; } - void set_content_name(const std::string& content_name) { - content_name_ = content_name; - } - - int component() const { return component_; } - void set_component(int component) { component_ = component; } - - bool send_retransmit_count_attribute() const { - return send_retransmit_count_attribute_; - } - void set_send_retransmit_count_attribute(bool enable) { - send_retransmit_count_attribute_ = enable; - } - - // Identifies the generation that this port was created in. - uint32 generation() { return generation_; } - void set_generation(uint32 generation) { generation_ = generation; } - - // ICE requires a single username/password per content/media line. So the - // |ice_username_fragment_| of the ports that belongs to the same content will - // be the same. However this causes a small complication with our relay - // server, which expects different username for RTP and RTCP. - // - // To resolve this problem, we implemented the username_fragment(), - // which returns a different username (calculated from - // |ice_username_fragment_|) for RTCP in the case of ICEPROTO_GOOGLE. And the - // username_fragment() simply returns |ice_username_fragment_| when running - // in ICEPROTO_RFC5245. - // - // As a result the ICEPROTO_GOOGLE will use different usernames for RTP and - // RTCP. And the ICEPROTO_RFC5245 will use same username for both RTP and - // RTCP. - const std::string username_fragment() const; - const std::string& password() const { return password_; } - - // Fired when candidates are discovered by the port. When all candidates - // are discovered that belong to port SignalAddressReady is fired. - sigslot::signal2<Port*, const Candidate&> SignalCandidateReady; - - // Provides all of the above information in one handy object. - virtual const std::vector<Candidate>& Candidates() const { - return candidates_; - } - - // SignalPortComplete is sent when port completes the task of candidates - // allocation. - sigslot::signal1<Port*> SignalPortComplete; - // This signal sent when port fails to allocate candidates and this port - // can't be used in establishing the connections. When port is in shared mode - // and port fails to allocate one of the candidates, port shouldn't send - // this signal as other candidates might be usefull in establishing the - // connection. - sigslot::signal1<Port*> SignalPortError; - - // Returns a map containing all of the connections of this port, keyed by the - // remote address. - typedef std::map<rtc::SocketAddress, Connection*> AddressMap; - const AddressMap& connections() { return connections_; } - - // Returns the connection to the given address or NULL if none exists. - virtual Connection* GetConnection( - const rtc::SocketAddress& remote_addr); - - // Called each time a connection is created. - sigslot::signal2<Port*, Connection*> SignalConnectionCreated; - - // In a shared socket mode each port which shares the socket will decide - // to accept the packet based on the |remote_addr|. Currently only UDP - // port implemented this method. - // TODO(mallinath) - Make it pure virtual. - virtual bool HandleIncomingPacket( - rtc::AsyncPacketSocket* socket, const char* data, size_t size, - const rtc::SocketAddress& remote_addr, - const rtc::PacketTime& packet_time) { - ASSERT(false); - return false; - } - - // Sends a response message (normal or error) to the given request. One of - // these methods should be called as a response to SignalUnknownAddress. - // NOTE: You MUST call CreateConnection BEFORE SendBindingResponse. - virtual void SendBindingResponse(StunMessage* request, - const rtc::SocketAddress& addr); - virtual void SendBindingErrorResponse( - StunMessage* request, const rtc::SocketAddress& addr, - int error_code, const std::string& reason); - - void set_proxy(const std::string& user_agent, - const rtc::ProxyInfo& proxy) { - user_agent_ = user_agent; - proxy_ = proxy; - } - const std::string& user_agent() { return user_agent_; } - const rtc::ProxyInfo& proxy() { return proxy_; } - - virtual void EnablePortPackets(); - - // Called if the port has no connections and is no longer useful. - void Destroy(); - - virtual void OnMessage(rtc::Message *pmsg); - - // Debugging description of this port - virtual std::string ToString() const; - rtc::IPAddress& ip() { return ip_; } - int min_port() { return min_port_; } - int max_port() { return max_port_; } - - // Timeout shortening function to speed up unit tests. - void set_timeout_delay(int delay) { timeout_delay_ = delay; } - - // This method will return local and remote username fragements from the - // stun username attribute if present. - bool ParseStunUsername(const StunMessage* stun_msg, - std::string* local_username, - std::string* remote_username, - IceProtocolType* remote_protocol_type) const; - void CreateStunUsername(const std::string& remote_username, - std::string* stun_username_attr_str) const; - - bool MaybeIceRoleConflict(const rtc::SocketAddress& addr, - IceMessage* stun_msg, - const std::string& remote_ufrag); - - // Called when the socket is currently able to send. - void OnReadyToSend(); - - // Called when the Connection discovers a local peer reflexive candidate. - // Returns the index of the new local candidate. - size_t AddPrflxCandidate(const Candidate& local); - - // Returns if RFC 5245 ICE protocol is used. - bool IsStandardIce() const; - - // Returns if Google ICE protocol is used. - bool IsGoogleIce() const; - - // Returns if Hybrid ICE protocol is used. - bool IsHybridIce() const; - - void set_candidate_filter(uint32 candidate_filter) { - candidate_filter_ = candidate_filter; - } - - protected: - enum { - MSG_CHECKTIMEOUT = 0, - MSG_FIRST_AVAILABLE - }; - - void set_type(const std::string& type) { type_ = type; } - - void AddAddress(const rtc::SocketAddress& address, - const rtc::SocketAddress& base_address, - const rtc::SocketAddress& related_address, - const std::string& protocol, const std::string& tcptype, - const std::string& type, uint32 type_preference, - uint32 relay_preference, bool final); - - // Adds the given connection to the list. (Deleting removes them.) - void AddConnection(Connection* conn); - - // Called when a packet is received from an unknown address that is not - // currently a connection. If this is an authenticated STUN binding request, - // then we will signal the client. - void OnReadPacket(const char* data, size_t size, - const rtc::SocketAddress& addr, - ProtocolType proto); - - // If the given data comprises a complete and correct STUN message then the - // return value is true, otherwise false. If the message username corresponds - // with this port's username fragment, msg will contain the parsed STUN - // message. Otherwise, the function may send a STUN response internally. - // remote_username contains the remote fragment of the STUN username. - bool GetStunMessage(const char* data, size_t size, - const rtc::SocketAddress& addr, - IceMessage** out_msg, std::string* out_username); - - // Checks if the address in addr is compatible with the port's ip. - bool IsCompatibleAddress(const rtc::SocketAddress& addr); - - // Returns default DSCP value. - rtc::DiffServCodePoint DefaultDscpValue() const { - // No change from what MediaChannel set. - return rtc::DSCP_NO_CHANGE; - } - - uint32 candidate_filter() { return candidate_filter_; } - - private: - void Construct(); - // Called when one of our connections deletes itself. - void OnConnectionDestroyed(Connection* conn); - - // Checks if this port is useless, and hence, should be destroyed. - void CheckTimeout(); - - rtc::Thread* thread_; - rtc::PacketSocketFactory* factory_; - std::string type_; - bool send_retransmit_count_attribute_; - rtc::Network* network_; - rtc::IPAddress ip_; - int min_port_; - int max_port_; - std::string content_name_; - int component_; - uint32 generation_; - // In order to establish a connection to this Port (so that real data can be - // sent through), the other side must send us a STUN binding request that is - // authenticated with this username_fragment and password. - // PortAllocatorSession will provide these username_fragment and password. - // - // Note: we should always use username_fragment() instead of using - // |ice_username_fragment_| directly. For the details see the comment on - // username_fragment(). - std::string ice_username_fragment_; - std::string password_; - std::vector<Candidate> candidates_; - AddressMap connections_; - int timeout_delay_; - bool enable_port_packets_; - IceProtocolType ice_protocol_; - IceRole ice_role_; - uint64 tiebreaker_; - bool shared_socket_; - // Information to use when going through a proxy. - std::string user_agent_; - rtc::ProxyInfo proxy_; - - // Candidate filter is pushed down to Port such that each Port could - // make its own decision on how to create candidates. For example, - // when IceTransportsType is set to relay, both RelayPort and - // TurnPort will hide raddr to avoid local address leakage. - uint32 candidate_filter_; - - friend class Connection; -}; - -// Represents a communication link between a port on the local client and a -// port on the remote client. -class Connection : public rtc::MessageHandler, - public sigslot::has_slots<> { - public: - // States are from RFC 5245. http://tools.ietf.org/html/rfc5245#section-5.7.4 - enum State { - STATE_WAITING = 0, // Check has not been performed, Waiting pair on CL. - STATE_INPROGRESS, // Check has been sent, transaction is in progress. - STATE_SUCCEEDED, // Check already done, produced a successful result. - STATE_FAILED // Check for this connection failed. - }; - - virtual ~Connection(); - - // The local port where this connection sends and receives packets. - Port* port() { return port_; } - const Port* port() const { return port_; } - - // Returns the description of the local port - virtual const Candidate& local_candidate() const; - - // Returns the description of the remote port to which we communicate. - const Candidate& remote_candidate() const { return remote_candidate_; } - - // Returns the pair priority. - uint64 priority() const; - - enum ReadState { - STATE_READ_INIT = 0, // we have yet to receive a ping - STATE_READABLE = 1, // we have received pings recently - STATE_READ_TIMEOUT = 2, // we haven't received pings in a while - }; - - ReadState read_state() const { return read_state_; } - bool readable() const { return read_state_ == STATE_READABLE; } - - enum WriteState { - STATE_WRITABLE = 0, // we have received ping responses recently - STATE_WRITE_UNRELIABLE = 1, // we have had a few ping failures - STATE_WRITE_INIT = 2, // we have yet to receive a ping response - STATE_WRITE_TIMEOUT = 3, // we have had a large number of ping failures - }; - - WriteState write_state() const { return write_state_; } - bool writable() const { return write_state_ == STATE_WRITABLE; } - - // Determines whether the connection has finished connecting. This can only - // be false for TCP connections. - bool connected() const { return connected_; } - - // Estimate of the round-trip time over this connection. - uint32 rtt() const { return rtt_; } - - size_t sent_total_bytes(); - size_t sent_bytes_second(); - size_t recv_total_bytes(); - size_t recv_bytes_second(); - sigslot::signal1<Connection*> SignalStateChange; - - // Sent when the connection has decided that it is no longer of value. It - // will delete itself immediately after this call. - sigslot::signal1<Connection*> SignalDestroyed; - - // The connection can send and receive packets asynchronously. This matches - // the interface of AsyncPacketSocket, which may use UDP or TCP under the - // covers. - virtual int Send(const void* data, size_t size, - const rtc::PacketOptions& options) = 0; - - // Error if Send() returns < 0 - virtual int GetError() = 0; - - sigslot::signal4<Connection*, const char*, size_t, - const rtc::PacketTime&> SignalReadPacket; - - sigslot::signal1<Connection*> SignalReadyToSend; - - // Called when a packet is received on this connection. - void OnReadPacket(const char* data, size_t size, - const rtc::PacketTime& packet_time); - - // Called when the socket is currently able to send. - void OnReadyToSend(); - - // Called when a connection is determined to be no longer useful to us. We - // still keep it around in case the other side wants to use it. But we can - // safely stop pinging on it and we can allow it to time out if the other - // side stops using it as well. - bool pruned() const { return pruned_; } - void Prune(); - - bool use_candidate_attr() const { return use_candidate_attr_; } - void set_use_candidate_attr(bool enable); - - void set_remote_ice_mode(IceMode mode) { - remote_ice_mode_ = mode; - } - - // Makes the connection go away. - void Destroy(); - - // Checks that the state of this connection is up-to-date. The argument is - // the current time, which is compared against various timeouts. - void UpdateState(uint32 now); - - // Called when this connection should try checking writability again. - uint32 last_ping_sent() const { return last_ping_sent_; } - void Ping(uint32 now); - - // Called whenever a valid ping is received on this connection. This is - // public because the connection intercepts the first ping for us. - uint32 last_ping_received() const { return last_ping_received_; } - void ReceivedPing(); - - // Debugging description of this connection - std::string ToString() const; - std::string ToSensitiveString() const; - - bool reported() const { return reported_; } - void set_reported(bool reported) { reported_ = reported;} - - // This flag will be set if this connection is the chosen one for media - // transmission. This connection will send STUN ping with USE-CANDIDATE - // attribute. - sigslot::signal1<Connection*> SignalUseCandidate; - // Invoked when Connection receives STUN error response with 487 code. - void HandleRoleConflictFromPeer(); - - State state() const { return state_; } - - IceMode remote_ice_mode() const { return remote_ice_mode_; } - - protected: - // Constructs a new connection to the given remote port. - Connection(Port* port, size_t index, const Candidate& candidate); - - // Called back when StunRequestManager has a stun packet to send - void OnSendStunPacket(const void* data, size_t size, StunRequest* req); - - // Callbacks from ConnectionRequest - void OnConnectionRequestResponse(ConnectionRequest* req, - StunMessage* response); - void OnConnectionRequestErrorResponse(ConnectionRequest* req, - StunMessage* response); - void OnConnectionRequestTimeout(ConnectionRequest* req); - - // Changes the state and signals if necessary. - void set_read_state(ReadState value); - void set_write_state(WriteState value); - void set_state(State state); - void set_connected(bool value); - - // Checks if this connection is useless, and hence, should be destroyed. - void CheckTimeout(); - - void OnMessage(rtc::Message *pmsg); - - Port* port_; - size_t local_candidate_index_; - Candidate remote_candidate_; - ReadState read_state_; - WriteState write_state_; - bool connected_; - bool pruned_; - // By default |use_candidate_attr_| flag will be true, - // as we will be using agrressive nomination. - // But when peer is ice-lite, this flag "must" be initialized to false and - // turn on when connection becomes "best connection". - bool use_candidate_attr_; - IceMode remote_ice_mode_; - StunRequestManager requests_; - uint32 rtt_; - uint32 last_ping_sent_; // last time we sent a ping to the other side - uint32 last_ping_received_; // last time we received a ping from the other - // side - uint32 last_data_received_; - uint32 last_ping_response_received_; - std::vector<uint32> pings_since_last_response_; - - rtc::RateTracker recv_rate_tracker_; - rtc::RateTracker send_rate_tracker_; - - private: - void MaybeAddPrflxCandidate(ConnectionRequest* request, - StunMessage* response); - - bool reported_; - State state_; - - friend class Port; - friend class ConnectionRequest; -}; - -// ProxyConnection defers all the interesting work to the port -class ProxyConnection : public Connection { - public: - ProxyConnection(Port* port, size_t index, const Candidate& candidate); - - virtual int Send(const void* data, size_t size, - const rtc::PacketOptions& options); - virtual int GetError() { return error_; } - - private: - int error_; -}; - -} // namespace cricket - -#endif // WEBRTC_P2P_BASE_PORT_H_ diff --git a/talk/p2p/base/port_unittest.cc b/talk/p2p/base/port_unittest.cc deleted file mode 100644 index bd4520f6a..000000000 --- a/talk/p2p/base/port_unittest.cc +++ /dev/null @@ -1,2511 +0,0 @@ -/* - * libjingle - * Copyright 2004 Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "webrtc/p2p/base/basicpacketsocketfactory.h" -#include "webrtc/p2p/base/portproxy.h" -#include "webrtc/p2p/base/relayport.h" -#include "webrtc/p2p/base/stunport.h" -#include "webrtc/p2p/base/tcpport.h" -#include "webrtc/p2p/base/testrelayserver.h" -#include "webrtc/p2p/base/teststunserver.h" -#include "webrtc/p2p/base/testturnserver.h" -#include "webrtc/p2p/base/transport.h" -#include "webrtc/p2p/base/turnport.h" -#include "webrtc/base/crc32.h" -#include "webrtc/base/gunit.h" -#include "webrtc/base/helpers.h" -#include "webrtc/base/logging.h" -#include "webrtc/base/natserver.h" -#include "webrtc/base/natsocketfactory.h" -#include "webrtc/base/physicalsocketserver.h" -#include "webrtc/base/scoped_ptr.h" -#include "webrtc/base/socketaddress.h" -#include "webrtc/base/ssladapter.h" -#include "webrtc/base/stringutils.h" -#include "webrtc/base/thread.h" -#include "webrtc/base/virtualsocketserver.h" - -using rtc::AsyncPacketSocket; -using rtc::ByteBuffer; -using rtc::NATType; -using rtc::NAT_OPEN_CONE; -using rtc::NAT_ADDR_RESTRICTED; -using rtc::NAT_PORT_RESTRICTED; -using rtc::NAT_SYMMETRIC; -using rtc::PacketSocketFactory; -using rtc::scoped_ptr; -using rtc::Socket; -using rtc::SocketAddress; -using namespace cricket; - -static const int kTimeout = 1000; -static const SocketAddress kLocalAddr1("192.168.1.2", 0); -static const SocketAddress kLocalAddr2("192.168.1.3", 0); -static const SocketAddress kNatAddr1("77.77.77.77", rtc::NAT_SERVER_PORT); -static const SocketAddress kNatAddr2("88.88.88.88", rtc::NAT_SERVER_PORT); -static const SocketAddress kStunAddr("99.99.99.1", STUN_SERVER_PORT); -static const SocketAddress kRelayUdpIntAddr("99.99.99.2", 5000); -static const SocketAddress kRelayUdpExtAddr("99.99.99.3", 5001); -static const SocketAddress kRelayTcpIntAddr("99.99.99.2", 5002); -static const SocketAddress kRelayTcpExtAddr("99.99.99.3", 5003); -static const SocketAddress kRelaySslTcpIntAddr("99.99.99.2", 5004); -static const SocketAddress kRelaySslTcpExtAddr("99.99.99.3", 5005); -static const SocketAddress kTurnUdpIntAddr("99.99.99.4", STUN_SERVER_PORT); -static const SocketAddress kTurnUdpExtAddr("99.99.99.5", 0); -static const RelayCredentials kRelayCredentials("test", "test"); - -// TODO: Update these when RFC5245 is completely supported. -// Magic value of 30 is from RFC3484, for IPv4 addresses. -static const uint32 kDefaultPrflxPriority = ICE_TYPE_PREFERENCE_PRFLX << 24 | - 30 << 8 | (256 - ICE_CANDIDATE_COMPONENT_DEFAULT); -static const int STUN_ERROR_BAD_REQUEST_AS_GICE = - STUN_ERROR_BAD_REQUEST / 256 * 100 + STUN_ERROR_BAD_REQUEST % 256; -static const int STUN_ERROR_UNAUTHORIZED_AS_GICE = - STUN_ERROR_UNAUTHORIZED / 256 * 100 + STUN_ERROR_UNAUTHORIZED % 256; -static const int STUN_ERROR_SERVER_ERROR_AS_GICE = - STUN_ERROR_SERVER_ERROR / 256 * 100 + STUN_ERROR_SERVER_ERROR % 256; - -static const int kTiebreaker1 = 11111; -static const int kTiebreaker2 = 22222; - -static Candidate GetCandidate(Port* port) { - assert(port->Candidates().size() == 1); - return port->Candidates()[0]; -} - -static SocketAddress GetAddress(Port* port) { - return GetCandidate(port).address(); -} - -static IceMessage* CopyStunMessage(const IceMessage* src) { - IceMessage* dst = new IceMessage(); - ByteBuffer buf; - src->Write(&buf); - dst->Read(&buf); - return dst; -} - -static bool WriteStunMessage(const StunMessage* msg, ByteBuffer* buf) { - buf->Resize(0); // clear out any existing buffer contents - return msg->Write(buf); -} - -// Stub port class for testing STUN generation and processing. -class TestPort : public Port { - public: - TestPort(rtc::Thread* thread, const std::string& type, - rtc::PacketSocketFactory* factory, rtc::Network* network, - const rtc::IPAddress& ip, int min_port, int max_port, - const std::string& username_fragment, const std::string& password) - : Port(thread, type, factory, network, ip, - min_port, max_port, username_fragment, password) { - } - ~TestPort() {} - - // Expose GetStunMessage so that we can test it. - using cricket::Port::GetStunMessage; - - // The last StunMessage that was sent on this Port. - // TODO: Make these const; requires changes to SendXXXXResponse. - ByteBuffer* last_stun_buf() { return last_stun_buf_.get(); } - IceMessage* last_stun_msg() { return last_stun_msg_.get(); } - int last_stun_error_code() { - int code = 0; - if (last_stun_msg_) { - const StunErrorCodeAttribute* error_attr = last_stun_msg_->GetErrorCode(); - if (error_attr) { - code = error_attr->code(); - } - } - return code; - } - - virtual void PrepareAddress() { - rtc::SocketAddress addr(ip(), min_port()); - AddAddress(addr, addr, rtc::SocketAddress(), "udp", "", Type(), - ICE_TYPE_PREFERENCE_HOST, 0, true); - } - - // Exposed for testing candidate building. - void AddCandidateAddress(const rtc::SocketAddress& addr) { - AddAddress(addr, addr, rtc::SocketAddress(), "udp", "", Type(), - type_preference_, 0, false); - } - void AddCandidateAddress(const rtc::SocketAddress& addr, - const rtc::SocketAddress& base_address, - const std::string& type, - int type_preference, - bool final) { - AddAddress(addr, base_address, rtc::SocketAddress(), "udp", "", type, - type_preference, 0, final); - } - - virtual Connection* CreateConnection(const Candidate& remote_candidate, - CandidateOrigin origin) { - Connection* conn = new ProxyConnection(this, 0, remote_candidate); - AddConnection(conn); - // Set use-candidate attribute flag as this will add USE-CANDIDATE attribute - // in STUN binding requests. - conn->set_use_candidate_attr(true); - return conn; - } - virtual int SendTo( - const void* data, size_t size, const rtc::SocketAddress& addr, - const rtc::PacketOptions& options, bool payload) { - if (!payload) { - IceMessage* msg = new IceMessage; - ByteBuffer* buf = new ByteBuffer(static_cast<const char*>(data), size); - ByteBuffer::ReadPosition pos(buf->GetReadPosition()); - if (!msg->Read(buf)) { - delete msg; - delete buf; - return -1; - } - buf->SetReadPosition(pos); - last_stun_buf_.reset(buf); - last_stun_msg_.reset(msg); - } - return static_cast<int>(size); - } - virtual int SetOption(rtc::Socket::Option opt, int value) { - return 0; - } - virtual int GetOption(rtc::Socket::Option opt, int* value) { - return -1; - } - virtual int GetError() { - return 0; - } - void Reset() { - last_stun_buf_.reset(); - last_stun_msg_.reset(); - } - void set_type_preference(int type_preference) { - type_preference_ = type_preference; - } - - private: - rtc::scoped_ptr<ByteBuffer> last_stun_buf_; - rtc::scoped_ptr<IceMessage> last_stun_msg_; - int type_preference_; -}; - -class TestChannel : public sigslot::has_slots<> { - public: - // Takes ownership of |p1| (but not |p2|). - TestChannel(Port* p1, Port* p2) - : ice_mode_(ICEMODE_FULL), src_(p1), dst_(p2), complete_count_(0), - conn_(NULL), remote_request_(), nominated_(false) { - src_->SignalPortComplete.connect( - this, &TestChannel::OnPortComplete); - src_->SignalUnknownAddress.connect(this, &TestChannel::OnUnknownAddress); - src_->SignalDestroyed.connect(this, &TestChannel::OnSrcPortDestroyed); - } - - int complete_count() { return complete_count_; } - Connection* conn() { return conn_; } - const SocketAddress& remote_address() { return remote_address_; } - const std::string remote_fragment() { return remote_frag_; } - - void Start() { - src_->PrepareAddress(); - } - void CreateConnection() { - conn_ = src_->CreateConnection(GetCandidate(dst_), Port::ORIGIN_MESSAGE); - IceMode remote_ice_mode = - (ice_mode_ == ICEMODE_FULL) ? ICEMODE_LITE : ICEMODE_FULL; - conn_->set_remote_ice_mode(remote_ice_mode); - conn_->set_use_candidate_attr(remote_ice_mode == ICEMODE_FULL); - conn_->SignalStateChange.connect( - this, &TestChannel::OnConnectionStateChange); - } - void OnConnectionStateChange(Connection* conn) { - if (conn->write_state() == Connection::STATE_WRITABLE) { - conn->set_use_candidate_attr(true); - nominated_ = true; - } - } - void AcceptConnection() { - ASSERT_TRUE(remote_request_.get() != NULL); - Candidate c = GetCandidate(dst_); - c.set_address(remote_address_); - conn_ = src_->CreateConnection(c, Port::ORIGIN_MESSAGE); - src_->SendBindingResponse(remote_request_.get(), remote_address_); - remote_request_.reset(); - } - void Ping() { - Ping(0); - } - void Ping(uint32 now) { - conn_->Ping(now); - } - void Stop() { - conn_->SignalDestroyed.connect(this, &TestChannel::OnDestroyed); - conn_->Destroy(); - } - - void OnPortComplete(Port* port) { - complete_count_++; - } - void SetIceMode(IceMode ice_mode) { - ice_mode_ = ice_mode; - } - - void OnUnknownAddress(PortInterface* port, const SocketAddress& addr, - ProtocolType proto, - IceMessage* msg, const std::string& rf, - bool /*port_muxed*/) { - ASSERT_EQ(src_.get(), port); - if (!remote_address_.IsNil()) { - ASSERT_EQ(remote_address_, addr); - } - // MI and PRIORITY attribute should be present in ping requests when port - // is in ICEPROTO_RFC5245 mode. - const cricket::StunUInt32Attribute* priority_attr = - msg->GetUInt32(STUN_ATTR_PRIORITY); - const cricket::StunByteStringAttribute* mi_attr = - msg->GetByteString(STUN_ATTR_MESSAGE_INTEGRITY); - const cricket::StunUInt32Attribute* fingerprint_attr = - msg->GetUInt32(STUN_ATTR_FINGERPRINT); - if (src_->IceProtocol() == cricket::ICEPROTO_RFC5245) { - EXPECT_TRUE(priority_attr != NULL); - EXPECT_TRUE(mi_attr != NULL); - EXPECT_TRUE(fingerprint_attr != NULL); - } else { - EXPECT_TRUE(priority_attr == NULL); - EXPECT_TRUE(mi_attr == NULL); - EXPECT_TRUE(fingerprint_attr == NULL); - } - remote_address_ = addr; - remote_request_.reset(CopyStunMessage(msg)); - remote_frag_ = rf; - } - - void OnDestroyed(Connection* conn) { - ASSERT_EQ(conn_, conn); - conn_ = NULL; - } - - void OnSrcPortDestroyed(PortInterface* port) { - Port* destroyed_src = src_.release(); - ASSERT_EQ(destroyed_src, port); - } - - bool nominated() const { return nominated_; } - - private: - IceMode ice_mode_; - rtc::scoped_ptr<Port> src_; - Port* dst_; - - int complete_count_; - Connection* conn_; - SocketAddress remote_address_; - rtc::scoped_ptr<StunMessage> remote_request_; - std::string remote_frag_; - bool nominated_; -}; - -class PortTest : public testing::Test, public sigslot::has_slots<> { - public: - PortTest() - : main_(rtc::Thread::Current()), - pss_(new rtc::PhysicalSocketServer), - ss_(new rtc::VirtualSocketServer(pss_.get())), - ss_scope_(ss_.get()), - network_("unittest", "unittest", rtc::IPAddress(INADDR_ANY), 32), - socket_factory_(rtc::Thread::Current()), - nat_factory1_(ss_.get(), kNatAddr1), - nat_factory2_(ss_.get(), kNatAddr2), - nat_socket_factory1_(&nat_factory1_), - nat_socket_factory2_(&nat_factory2_), - stun_server_(TestStunServer::Create(main_, kStunAddr)), - turn_server_(main_, kTurnUdpIntAddr, kTurnUdpExtAddr), - relay_server_(main_, kRelayUdpIntAddr, kRelayUdpExtAddr, - kRelayTcpIntAddr, kRelayTcpExtAddr, - kRelaySslTcpIntAddr, kRelaySslTcpExtAddr), - username_(rtc::CreateRandomString(ICE_UFRAG_LENGTH)), - password_(rtc::CreateRandomString(ICE_PWD_LENGTH)), - ice_protocol_(cricket::ICEPROTO_GOOGLE), - role_conflict_(false), - destroyed_(false) { - network_.AddIP(rtc::IPAddress(INADDR_ANY)); - } - - protected: - void TestLocalToLocal() { - Port* port1 = CreateUdpPort(kLocalAddr1); - Port* port2 = CreateUdpPort(kLocalAddr2); - TestConnectivity("udp", port1, "udp", port2, true, true, true, true); - } - void TestLocalToStun(NATType ntype) { - Port* port1 = CreateUdpPort(kLocalAddr1); - nat_server2_.reset(CreateNatServer(kNatAddr2, ntype)); - Port* port2 = CreateStunPort(kLocalAddr2, &nat_socket_factory2_); - TestConnectivity("udp", port1, StunName(ntype), port2, - ntype == NAT_OPEN_CONE, true, - ntype != NAT_SYMMETRIC, true); - } - void TestLocalToRelay(RelayType rtype, ProtocolType proto) { - Port* port1 = CreateUdpPort(kLocalAddr1); - Port* port2 = CreateRelayPort(kLocalAddr2, rtype, proto, PROTO_UDP); - TestConnectivity("udp", port1, RelayName(rtype, proto), port2, - rtype == RELAY_GTURN, true, true, true); - } - void TestStunToLocal(NATType ntype) { - nat_server1_.reset(CreateNatServer(kNatAddr1, ntype)); - Port* port1 = CreateStunPort(kLocalAddr1, &nat_socket_factory1_); - Port* port2 = CreateUdpPort(kLocalAddr2); - TestConnectivity(StunName(ntype), port1, "udp", port2, - true, ntype != NAT_SYMMETRIC, true, true); - } - void TestStunToStun(NATType ntype1, NATType ntype2) { - nat_server1_.reset(CreateNatServer(kNatAddr1, ntype1)); - Port* port1 = CreateStunPort(kLocalAddr1, &nat_socket_factory1_); - nat_server2_.reset(CreateNatServer(kNatAddr2, ntype2)); - Port* port2 = CreateStunPort(kLocalAddr2, &nat_socket_factory2_); - TestConnectivity(StunName(ntype1), port1, StunName(ntype2), port2, - ntype2 == NAT_OPEN_CONE, - ntype1 != NAT_SYMMETRIC, ntype2 != NAT_SYMMETRIC, - ntype1 + ntype2 < (NAT_PORT_RESTRICTED + NAT_SYMMETRIC)); - } - void TestStunToRelay(NATType ntype, RelayType rtype, ProtocolType proto) { - nat_server1_.reset(CreateNatServer(kNatAddr1, ntype)); - Port* port1 = CreateStunPort(kLocalAddr1, &nat_socket_factory1_); - Port* port2 = CreateRelayPort(kLocalAddr2, rtype, proto, PROTO_UDP); - TestConnectivity(StunName(ntype), port1, RelayName(rtype, proto), port2, - rtype == RELAY_GTURN, ntype != NAT_SYMMETRIC, true, true); - } - void TestTcpToTcp() { - Port* port1 = CreateTcpPort(kLocalAddr1); - Port* port2 = CreateTcpPort(kLocalAddr2); - TestConnectivity("tcp", port1, "tcp", port2, true, false, true, true); - } - void TestTcpToRelay(RelayType rtype, ProtocolType proto) { - Port* port1 = CreateTcpPort(kLocalAddr1); - Port* port2 = CreateRelayPort(kLocalAddr2, rtype, proto, PROTO_TCP); - TestConnectivity("tcp", port1, RelayName(rtype, proto), port2, - rtype == RELAY_GTURN, false, true, true); - } - void TestSslTcpToRelay(RelayType rtype, ProtocolType proto) { - Port* port1 = CreateTcpPort(kLocalAddr1); - Port* port2 = CreateRelayPort(kLocalAddr2, rtype, proto, PROTO_SSLTCP); - TestConnectivity("ssltcp", port1, RelayName(rtype, proto), port2, - rtype == RELAY_GTURN, false, true, true); - } - - // helpers for above functions - UDPPort* CreateUdpPort(const SocketAddress& addr) { - return CreateUdpPort(addr, &socket_factory_); - } - UDPPort* CreateUdpPort(const SocketAddress& addr, - PacketSocketFactory* socket_factory) { - UDPPort* port = UDPPort::Create(main_, socket_factory, &network_, - addr.ipaddr(), 0, 0, username_, password_); - port->SetIceProtocolType(ice_protocol_); - return port; - } - TCPPort* CreateTcpPort(const SocketAddress& addr) { - TCPPort* port = CreateTcpPort(addr, &socket_factory_); - port->SetIceProtocolType(ice_protocol_); - return port; - } - TCPPort* CreateTcpPort(const SocketAddress& addr, - PacketSocketFactory* socket_factory) { - TCPPort* port = TCPPort::Create(main_, socket_factory, &network_, - addr.ipaddr(), 0, 0, username_, password_, - true); - port->SetIceProtocolType(ice_protocol_); - return port; - } - StunPort* CreateStunPort(const SocketAddress& addr, - rtc::PacketSocketFactory* factory) { - ServerAddresses stun_servers; - stun_servers.insert(kStunAddr); - StunPort* port = StunPort::Create(main_, factory, &network_, - addr.ipaddr(), 0, 0, - username_, password_, stun_servers); - port->SetIceProtocolType(ice_protocol_); - return port; - } - Port* CreateRelayPort(const SocketAddress& addr, RelayType rtype, - ProtocolType int_proto, ProtocolType ext_proto) { - if (rtype == RELAY_TURN) { - return CreateTurnPort(addr, &socket_factory_, int_proto, ext_proto); - } else { - return CreateGturnPort(addr, int_proto, ext_proto); - } - } - TurnPort* CreateTurnPort(const SocketAddress& addr, - PacketSocketFactory* socket_factory, - ProtocolType int_proto, ProtocolType ext_proto) { - return CreateTurnPort(addr, socket_factory, - int_proto, ext_proto, kTurnUdpIntAddr); - } - TurnPort* CreateTurnPort(const SocketAddress& addr, - PacketSocketFactory* socket_factory, - ProtocolType int_proto, ProtocolType ext_proto, - const rtc::SocketAddress& server_addr) { - TurnPort* port = TurnPort::Create(main_, socket_factory, &network_, - addr.ipaddr(), 0, 0, - username_, password_, ProtocolAddress( - server_addr, PROTO_UDP), - kRelayCredentials, 0); - port->SetIceProtocolType(ice_protocol_); - return port; - } - RelayPort* CreateGturnPort(const SocketAddress& addr, - ProtocolType int_proto, ProtocolType ext_proto) { - RelayPort* port = CreateGturnPort(addr); - SocketAddress addrs[] = - { kRelayUdpIntAddr, kRelayTcpIntAddr, kRelaySslTcpIntAddr }; - port->AddServerAddress(ProtocolAddress(addrs[int_proto], int_proto)); - return port; - } - RelayPort* CreateGturnPort(const SocketAddress& addr) { - RelayPort* port = RelayPort::Create(main_, &socket_factory_, &network_, - addr.ipaddr(), 0, 0, - username_, password_); - // TODO: Add an external address for ext_proto, so that the - // other side can connect to this port using a non-UDP protocol. - port->SetIceProtocolType(ice_protocol_); - return port; - } - rtc::NATServer* CreateNatServer(const SocketAddress& addr, - rtc::NATType type) { - return new rtc::NATServer(type, ss_.get(), addr, ss_.get(), addr); - } - static const char* StunName(NATType type) { - switch (type) { - case NAT_OPEN_CONE: return "stun(open cone)"; - case NAT_ADDR_RESTRICTED: return "stun(addr restricted)"; - case NAT_PORT_RESTRICTED: return "stun(port restricted)"; - case NAT_SYMMETRIC: return "stun(symmetric)"; - default: return "stun(?)"; - } - } - static const char* RelayName(RelayType type, ProtocolType proto) { - if (type == RELAY_TURN) { - switch (proto) { - case PROTO_UDP: return "turn(udp)"; - case PROTO_TCP: return "turn(tcp)"; - case PROTO_SSLTCP: return "turn(ssltcp)"; - default: return "turn(?)"; - } - } else { - switch (proto) { - case PROTO_UDP: return "gturn(udp)"; - case PROTO_TCP: return "gturn(tcp)"; - case PROTO_SSLTCP: return "gturn(ssltcp)"; - default: return "gturn(?)"; - } - } - } - - void TestCrossFamilyPorts(int type); - - // This does all the work and then deletes |port1| and |port2|. - void TestConnectivity(const char* name1, Port* port1, - const char* name2, Port* port2, - bool accept, bool same_addr1, - bool same_addr2, bool possible); - - // This connects and disconnects the provided channels in the same sequence as - // TestConnectivity with all options set to |true|. It does not delete either - // channel. - void ConnectAndDisconnectChannels(TestChannel* ch1, TestChannel* ch2); - - void SetIceProtocolType(cricket::IceProtocolType protocol) { - ice_protocol_ = protocol; - } - - IceMessage* CreateStunMessage(int type) { - IceMessage* msg = new IceMessage(); - msg->SetType(type); - msg->SetTransactionID("TESTTESTTEST"); - return msg; - } - IceMessage* CreateStunMessageWithUsername(int type, - const std::string& username) { - IceMessage* msg = CreateStunMessage(type); - msg->AddAttribute( - new StunByteStringAttribute(STUN_ATTR_USERNAME, username)); - return msg; - } - TestPort* CreateTestPort(const rtc::SocketAddress& addr, - const std::string& username, - const std::string& password) { - TestPort* port = new TestPort(main_, "test", &socket_factory_, &network_, - addr.ipaddr(), 0, 0, username, password); - port->SignalRoleConflict.connect(this, &PortTest::OnRoleConflict); - return port; - } - TestPort* CreateTestPort(const rtc::SocketAddress& addr, - const std::string& username, - const std::string& password, - cricket::IceProtocolType type, - cricket::IceRole role, - int tiebreaker) { - TestPort* port = CreateTestPort(addr, username, password); - port->SetIceProtocolType(type); - port->SetIceRole(role); - port->SetIceTiebreaker(tiebreaker); - return port; - } - - void OnRoleConflict(PortInterface* port) { - role_conflict_ = true; - } - bool role_conflict() const { return role_conflict_; } - - void ConnectToSignalDestroyed(PortInterface* port) { - port->SignalDestroyed.connect(this, &PortTest::OnDestroyed); - } - - void OnDestroyed(PortInterface* port) { - destroyed_ = true; - } - bool destroyed() const { return destroyed_; } - - rtc::BasicPacketSocketFactory* nat_socket_factory1() { - return &nat_socket_factory1_; - } - - private: - rtc::Thread* main_; - rtc::scoped_ptr<rtc::PhysicalSocketServer> pss_; - rtc::scoped_ptr<rtc::VirtualSocketServer> ss_; - rtc::SocketServerScope ss_scope_; - rtc::Network network_; - rtc::BasicPacketSocketFactory socket_factory_; - rtc::scoped_ptr<rtc::NATServer> nat_server1_; - rtc::scoped_ptr<rtc::NATServer> nat_server2_; - rtc::NATSocketFactory nat_factory1_; - rtc::NATSocketFactory nat_factory2_; - rtc::BasicPacketSocketFactory nat_socket_factory1_; - rtc::BasicPacketSocketFactory nat_socket_factory2_; - scoped_ptr<TestStunServer> stun_server_; - TestTurnServer turn_server_; - TestRelayServer relay_server_; - std::string username_; - std::string password_; - cricket::IceProtocolType ice_protocol_; - bool role_conflict_; - bool destroyed_; -}; - -void PortTest::TestConnectivity(const char* name1, Port* port1, - const char* name2, Port* port2, - bool accept, bool same_addr1, - bool same_addr2, bool possible) { - LOG(LS_INFO) << "Test: " << name1 << " to " << name2 << ": "; - port1->set_component(cricket::ICE_CANDIDATE_COMPONENT_DEFAULT); - port2->set_component(cricket::ICE_CANDIDATE_COMPONENT_DEFAULT); - - // Set up channels and ensure both ports will be deleted. - TestChannel ch1(port1, port2); - TestChannel ch2(port2, port1); - EXPECT_EQ(0, ch1.complete_count()); - EXPECT_EQ(0, ch2.complete_count()); - - // Acquire addresses. - ch1.Start(); - ch2.Start(); - ASSERT_EQ_WAIT(1, ch1.complete_count(), kTimeout); - ASSERT_EQ_WAIT(1, ch2.complete_count(), kTimeout); - - // Send a ping from src to dst. This may or may not make it. - ch1.CreateConnection(); - ASSERT_TRUE(ch1.conn() != NULL); - EXPECT_TRUE_WAIT(ch1.conn()->connected(), kTimeout); // for TCP connect - ch1.Ping(); - WAIT(!ch2.remote_address().IsNil(), kTimeout); - - if (accept) { - // We are able to send a ping from src to dst. This is the case when - // sending to UDP ports and cone NATs. - EXPECT_TRUE(ch1.remote_address().IsNil()); - EXPECT_EQ(ch2.remote_fragment(), port1->username_fragment()); - - // Ensure the ping came from the same address used for src. - // This is the case unless the source NAT was symmetric. - if (same_addr1) EXPECT_EQ(ch2.remote_address(), GetAddress(port1)); - EXPECT_TRUE(same_addr2); - - // Send a ping from dst to src. - ch2.AcceptConnection(); - ASSERT_TRUE(ch2.conn() != NULL); - ch2.Ping(); - EXPECT_EQ_WAIT(Connection::STATE_WRITABLE, ch2.conn()->write_state(), - kTimeout); - } else { - // We can't send a ping from src to dst, so flip it around. This will happen - // when the destination NAT is addr/port restricted or symmetric. - EXPECT_TRUE(ch1.remote_address().IsNil()); - EXPECT_TRUE(ch2.remote_address().IsNil()); - - // Send a ping from dst to src. Again, this may or may not make it. - ch2.CreateConnection(); - ASSERT_TRUE(ch2.conn() != NULL); - ch2.Ping(); - WAIT(ch2.conn()->write_state() == Connection::STATE_WRITABLE, kTimeout); - - if (same_addr1 && same_addr2) { - // The new ping got back to the source. - EXPECT_EQ(Connection::STATE_READABLE, ch1.conn()->read_state()); - EXPECT_EQ(Connection::STATE_WRITABLE, ch2.conn()->write_state()); - - // First connection may not be writable if the first ping did not get - // through. So we will have to do another. - if (ch1.conn()->write_state() == Connection::STATE_WRITE_INIT) { - ch1.Ping(); - EXPECT_EQ_WAIT(Connection::STATE_WRITABLE, ch1.conn()->write_state(), - kTimeout); - } - } else if (!same_addr1 && possible) { - // The new ping went to the candidate address, but that address was bad. - // This will happen when the source NAT is symmetric. - EXPECT_TRUE(ch1.remote_address().IsNil()); - EXPECT_TRUE(ch2.remote_address().IsNil()); - - // However, since we have now sent a ping to the source IP, we should be - // able to get a ping from it. This gives us the real source address. - ch1.Ping(); - EXPECT_TRUE_WAIT(!ch2.remote_address().IsNil(), kTimeout); - EXPECT_EQ(Connection::STATE_READ_INIT, ch2.conn()->read_state()); - EXPECT_TRUE(ch1.remote_address().IsNil()); - - // Pick up the actual address and establish the connection. - ch2.AcceptConnection(); - ASSERT_TRUE(ch2.conn() != NULL); - ch2.Ping(); - EXPECT_EQ_WAIT(Connection::STATE_WRITABLE, ch2.conn()->write_state(), - kTimeout); - } else if (!same_addr2 && possible) { - // The new ping came in, but from an unexpected address. This will happen - // when the destination NAT is symmetric. - EXPECT_FALSE(ch1.remote_address().IsNil()); - EXPECT_EQ(Connection::STATE_READ_INIT, ch1.conn()->read_state()); - - // Update our address and complete the connection. - ch1.AcceptConnection(); - ch1.Ping(); - EXPECT_EQ_WAIT(Connection::STATE_WRITABLE, ch1.conn()->write_state(), - kTimeout); - } else { // (!possible) - // There should be s no way for the pings to reach each other. Check it. - EXPECT_TRUE(ch1.remote_address().IsNil()); - EXPECT_TRUE(ch2.remote_address().IsNil()); - ch1.Ping(); - WAIT(!ch2.remote_address().IsNil(), kTimeout); - EXPECT_TRUE(ch1.remote_address().IsNil()); - EXPECT_TRUE(ch2.remote_address().IsNil()); - } - } - - // Everything should be good, unless we know the situation is impossible. - ASSERT_TRUE(ch1.conn() != NULL); - ASSERT_TRUE(ch2.conn() != NULL); - if (possible) { - EXPECT_EQ(Connection::STATE_READABLE, ch1.conn()->read_state()); - EXPECT_EQ(Connection::STATE_WRITABLE, ch1.conn()->write_state()); - EXPECT_EQ(Connection::STATE_READABLE, ch2.conn()->read_state()); - EXPECT_EQ(Connection::STATE_WRITABLE, ch2.conn()->write_state()); - } else { - EXPECT_NE(Connection::STATE_READABLE, ch1.conn()->read_state()); - EXPECT_NE(Connection::STATE_WRITABLE, ch1.conn()->write_state()); - EXPECT_NE(Connection::STATE_READABLE, ch2.conn()->read_state()); - EXPECT_NE(Connection::STATE_WRITABLE, ch2.conn()->write_state()); - } - - // Tear down and ensure that goes smoothly. - ch1.Stop(); - ch2.Stop(); - EXPECT_TRUE_WAIT(ch1.conn() == NULL, kTimeout); - EXPECT_TRUE_WAIT(ch2.conn() == NULL, kTimeout); -} - -void PortTest::ConnectAndDisconnectChannels(TestChannel* ch1, - TestChannel* ch2) { - // Acquire addresses. - ch1->Start(); - ch2->Start(); - - // Send a ping from src to dst. - ch1->CreateConnection(); - EXPECT_TRUE_WAIT(ch1->conn()->connected(), kTimeout); // for TCP connect - ch1->Ping(); - WAIT(!ch2->remote_address().IsNil(), kTimeout); - - // Send a ping from dst to src. - ch2->AcceptConnection(); - ch2->Ping(); - EXPECT_EQ_WAIT(Connection::STATE_WRITABLE, ch2->conn()->write_state(), - kTimeout); - - // Destroy the connections. - ch1->Stop(); - ch2->Stop(); -} - -class FakePacketSocketFactory : public rtc::PacketSocketFactory { - public: - FakePacketSocketFactory() - : next_udp_socket_(NULL), - next_server_tcp_socket_(NULL), - next_client_tcp_socket_(NULL) { - } - virtual ~FakePacketSocketFactory() { } - - virtual AsyncPacketSocket* CreateUdpSocket( - const SocketAddress& address, int min_port, int max_port) { - EXPECT_TRUE(next_udp_socket_ != NULL); - AsyncPacketSocket* result = next_udp_socket_; - next_udp_socket_ = NULL; - return result; - } - - virtual AsyncPacketSocket* CreateServerTcpSocket( - const SocketAddress& local_address, int min_port, int max_port, - int opts) { - EXPECT_TRUE(next_server_tcp_socket_ != NULL); - AsyncPacketSocket* result = next_server_tcp_socket_; - next_server_tcp_socket_ = NULL; - return result; - } - - // TODO: |proxy_info| and |user_agent| should be set - // per-factory and not when socket is created. - virtual AsyncPacketSocket* CreateClientTcpSocket( - const SocketAddress& local_address, const SocketAddress& remote_address, - const rtc::ProxyInfo& proxy_info, - const std::string& user_agent, int opts) { - EXPECT_TRUE(next_client_tcp_socket_ != NULL); - AsyncPacketSocket* result = next_client_tcp_socket_; - next_client_tcp_socket_ = NULL; - return result; - } - - void set_next_udp_socket(AsyncPacketSocket* next_udp_socket) { - next_udp_socket_ = next_udp_socket; - } - void set_next_server_tcp_socket(AsyncPacketSocket* next_server_tcp_socket) { - next_server_tcp_socket_ = next_server_tcp_socket; - } - void set_next_client_tcp_socket(AsyncPacketSocket* next_client_tcp_socket) { - next_client_tcp_socket_ = next_client_tcp_socket; - } - rtc::AsyncResolverInterface* CreateAsyncResolver() { - return NULL; - } - - private: - AsyncPacketSocket* next_udp_socket_; - AsyncPacketSocket* next_server_tcp_socket_; - AsyncPacketSocket* next_client_tcp_socket_; -}; - -class FakeAsyncPacketSocket : public AsyncPacketSocket { - public: - // Returns current local address. Address may be set to NULL if the - // socket is not bound yet (GetState() returns STATE_BINDING). - virtual SocketAddress GetLocalAddress() const { - return SocketAddress(); - } - - // Returns remote address. Returns zeroes if this is not a client TCP socket. - virtual SocketAddress GetRemoteAddress() const { - return SocketAddress(); - } - - // Send a packet. - virtual int Send(const void *pv, size_t cb, - const rtc::PacketOptions& options) { - return static_cast<int>(cb); - } - virtual int SendTo(const void *pv, size_t cb, const SocketAddress& addr, - const rtc::PacketOptions& options) { - return static_cast<int>(cb); - } - virtual int Close() { - return 0; - } - - virtual State GetState() const { return state_; } - virtual int GetOption(Socket::Option opt, int* value) { return 0; } - virtual int SetOption(Socket::Option opt, int value) { return 0; } - virtual int GetError() const { return 0; } - virtual void SetError(int error) { } - - void set_state(State state) { state_ = state; } - - private: - State state_; -}; - -// Local -> XXXX -TEST_F(PortTest, TestLocalToLocal) { - TestLocalToLocal(); -} - -TEST_F(PortTest, TestLocalToConeNat) { - TestLocalToStun(NAT_OPEN_CONE); -} - -TEST_F(PortTest, TestLocalToARNat) { - TestLocalToStun(NAT_ADDR_RESTRICTED); -} - -TEST_F(PortTest, TestLocalToPRNat) { - TestLocalToStun(NAT_PORT_RESTRICTED); -} - -TEST_F(PortTest, TestLocalToSymNat) { - TestLocalToStun(NAT_SYMMETRIC); -} - -// Flaky: https://code.google.com/p/webrtc/issues/detail?id=3316. -TEST_F(PortTest, DISABLED_TestLocalToTurn) { - TestLocalToRelay(RELAY_TURN, PROTO_UDP); -} - -TEST_F(PortTest, TestLocalToGturn) { - TestLocalToRelay(RELAY_GTURN, PROTO_UDP); -} - -TEST_F(PortTest, TestLocalToTcpGturn) { - TestLocalToRelay(RELAY_GTURN, PROTO_TCP); -} - -TEST_F(PortTest, TestLocalToSslTcpGturn) { - TestLocalToRelay(RELAY_GTURN, PROTO_SSLTCP); -} - -// Cone NAT -> XXXX -TEST_F(PortTest, TestConeNatToLocal) { - TestStunToLocal(NAT_OPEN_CONE); -} - -TEST_F(PortTest, TestConeNatToConeNat) { - TestStunToStun(NAT_OPEN_CONE, NAT_OPEN_CONE); -} - -TEST_F(PortTest, TestConeNatToARNat) { - TestStunToStun(NAT_OPEN_CONE, NAT_ADDR_RESTRICTED); -} - -TEST_F(PortTest, TestConeNatToPRNat) { - TestStunToStun(NAT_OPEN_CONE, NAT_PORT_RESTRICTED); -} - -TEST_F(PortTest, TestConeNatToSymNat) { - TestStunToStun(NAT_OPEN_CONE, NAT_SYMMETRIC); -} - -TEST_F(PortTest, TestConeNatToTurn) { - TestStunToRelay(NAT_OPEN_CONE, RELAY_TURN, PROTO_UDP); -} - -TEST_F(PortTest, TestConeNatToGturn) { - TestStunToRelay(NAT_OPEN_CONE, RELAY_GTURN, PROTO_UDP); -} - -TEST_F(PortTest, TestConeNatToTcpGturn) { - TestStunToRelay(NAT_OPEN_CONE, RELAY_GTURN, PROTO_TCP); -} - -// Address-restricted NAT -> XXXX -TEST_F(PortTest, TestARNatToLocal) { - TestStunToLocal(NAT_ADDR_RESTRICTED); -} - -TEST_F(PortTest, TestARNatToConeNat) { - TestStunToStun(NAT_ADDR_RESTRICTED, NAT_OPEN_CONE); -} - -TEST_F(PortTest, TestARNatToARNat) { - TestStunToStun(NAT_ADDR_RESTRICTED, NAT_ADDR_RESTRICTED); -} - -TEST_F(PortTest, TestARNatToPRNat) { - TestStunToStun(NAT_ADDR_RESTRICTED, NAT_PORT_RESTRICTED); -} - -TEST_F(PortTest, TestARNatToSymNat) { - TestStunToStun(NAT_ADDR_RESTRICTED, NAT_SYMMETRIC); -} - -TEST_F(PortTest, TestARNatToTurn) { - TestStunToRelay(NAT_ADDR_RESTRICTED, RELAY_TURN, PROTO_UDP); -} - -TEST_F(PortTest, TestARNatToGturn) { - TestStunToRelay(NAT_ADDR_RESTRICTED, RELAY_GTURN, PROTO_UDP); -} - -TEST_F(PortTest, TestARNATNatToTcpGturn) { - TestStunToRelay(NAT_ADDR_RESTRICTED, RELAY_GTURN, PROTO_TCP); -} - -// Port-restricted NAT -> XXXX -TEST_F(PortTest, TestPRNatToLocal) { - TestStunToLocal(NAT_PORT_RESTRICTED); -} - -TEST_F(PortTest, TestPRNatToConeNat) { - TestStunToStun(NAT_PORT_RESTRICTED, NAT_OPEN_CONE); -} - -TEST_F(PortTest, TestPRNatToARNat) { - TestStunToStun(NAT_PORT_RESTRICTED, NAT_ADDR_RESTRICTED); -} - -TEST_F(PortTest, TestPRNatToPRNat) { - TestStunToStun(NAT_PORT_RESTRICTED, NAT_PORT_RESTRICTED); -} - -TEST_F(PortTest, TestPRNatToSymNat) { - // Will "fail" - TestStunToStun(NAT_PORT_RESTRICTED, NAT_SYMMETRIC); -} - -TEST_F(PortTest, TestPRNatToTurn) { - TestStunToRelay(NAT_PORT_RESTRICTED, RELAY_TURN, PROTO_UDP); -} - -TEST_F(PortTest, TestPRNatToGturn) { - TestStunToRelay(NAT_PORT_RESTRICTED, RELAY_GTURN, PROTO_UDP); -} - -TEST_F(PortTest, TestPRNatToTcpGturn) { - TestStunToRelay(NAT_PORT_RESTRICTED, RELAY_GTURN, PROTO_TCP); -} - -// Symmetric NAT -> XXXX -TEST_F(PortTest, TestSymNatToLocal) { - TestStunToLocal(NAT_SYMMETRIC); -} - -TEST_F(PortTest, TestSymNatToConeNat) { - TestStunToStun(NAT_SYMMETRIC, NAT_OPEN_CONE); -} - -TEST_F(PortTest, TestSymNatToARNat) { - TestStunToStun(NAT_SYMMETRIC, NAT_ADDR_RESTRICTED); -} - -TEST_F(PortTest, TestSymNatToPRNat) { - // Will "fail" - TestStunToStun(NAT_SYMMETRIC, NAT_PORT_RESTRICTED); -} - -TEST_F(PortTest, TestSymNatToSymNat) { - // Will "fail" - TestStunToStun(NAT_SYMMETRIC, NAT_SYMMETRIC); -} - -TEST_F(PortTest, TestSymNatToTurn) { - TestStunToRelay(NAT_SYMMETRIC, RELAY_TURN, PROTO_UDP); -} - -TEST_F(PortTest, TestSymNatToGturn) { - TestStunToRelay(NAT_SYMMETRIC, RELAY_GTURN, PROTO_UDP); -} - -TEST_F(PortTest, TestSymNatToTcpGturn) { - TestStunToRelay(NAT_SYMMETRIC, RELAY_GTURN, PROTO_TCP); -} - -// Outbound TCP -> XXXX -TEST_F(PortTest, TestTcpToTcp) { - TestTcpToTcp(); -} - -/* TODO: Enable these once testrelayserver can accept external TCP. -TEST_F(PortTest, TestTcpToTcpRelay) { - TestTcpToRelay(PROTO_TCP); -} - -TEST_F(PortTest, TestTcpToSslTcpRelay) { - TestTcpToRelay(PROTO_SSLTCP); -} -*/ - -// Outbound SSLTCP -> XXXX -/* TODO: Enable these once testrelayserver can accept external SSL. -TEST_F(PortTest, TestSslTcpToTcpRelay) { - TestSslTcpToRelay(PROTO_TCP); -} - -TEST_F(PortTest, TestSslTcpToSslTcpRelay) { - TestSslTcpToRelay(PROTO_SSLTCP); -} -*/ - -// This test case verifies standard ICE features in STUN messages. Currently it -// verifies Message Integrity attribute in STUN messages and username in STUN -// binding request will have colon (":") between remote and local username. -TEST_F(PortTest, TestLocalToLocalAsIce) { - SetIceProtocolType(cricket::ICEPROTO_RFC5245); - UDPPort* port1 = CreateUdpPort(kLocalAddr1); - port1->SetIceRole(cricket::ICEROLE_CONTROLLING); - port1->SetIceTiebreaker(kTiebreaker1); - ASSERT_EQ(cricket::ICEPROTO_RFC5245, port1->IceProtocol()); - UDPPort* port2 = CreateUdpPort(kLocalAddr2); - port2->SetIceRole(cricket::ICEROLE_CONTROLLED); - port2->SetIceTiebreaker(kTiebreaker2); - ASSERT_EQ(cricket::ICEPROTO_RFC5245, port2->IceProtocol()); - // Same parameters as TestLocalToLocal above. - TestConnectivity("udp", port1, "udp", port2, true, true, true, true); -} - -// This test is trying to validate a successful and failure scenario in a -// loopback test when protocol is RFC5245. For success IceTiebreaker, username -// should remain equal to the request generated by the port and role of port -// must be in controlling. -TEST_F(PortTest, TestLoopbackCallAsIce) { - rtc::scoped_ptr<TestPort> lport( - CreateTestPort(kLocalAddr1, "lfrag", "lpass")); - lport->SetIceProtocolType(ICEPROTO_RFC5245); - lport->SetIceRole(cricket::ICEROLE_CONTROLLING); - lport->SetIceTiebreaker(kTiebreaker1); - lport->PrepareAddress(); - ASSERT_FALSE(lport->Candidates().empty()); - Connection* conn = lport->CreateConnection(lport->Candidates()[0], - Port::ORIGIN_MESSAGE); - conn->Ping(0); - - ASSERT_TRUE_WAIT(lport->last_stun_msg() != NULL, 1000); - IceMessage* msg = lport->last_stun_msg(); - EXPECT_EQ(STUN_BINDING_REQUEST, msg->type()); - conn->OnReadPacket(lport->last_stun_buf()->Data(), - lport->last_stun_buf()->Length(), - rtc::PacketTime()); - ASSERT_TRUE_WAIT(lport->last_stun_msg() != NULL, 1000); - msg = lport->last_stun_msg(); - EXPECT_EQ(STUN_BINDING_RESPONSE, msg->type()); - - // If the tiebreaker value is different from port, we expect a error - // response. - lport->Reset(); - lport->AddCandidateAddress(kLocalAddr2); - // Creating a different connection as |conn| is in STATE_READABLE. - Connection* conn1 = lport->CreateConnection(lport->Candidates()[1], - Port::ORIGIN_MESSAGE); - conn1->Ping(0); - - ASSERT_TRUE_WAIT(lport->last_stun_msg() != NULL, 1000); - msg = lport->last_stun_msg(); - EXPECT_EQ(STUN_BINDING_REQUEST, msg->type()); - rtc::scoped_ptr<IceMessage> modified_req( - CreateStunMessage(STUN_BINDING_REQUEST)); - const StunByteStringAttribute* username_attr = msg->GetByteString( - STUN_ATTR_USERNAME); - modified_req->AddAttribute(new StunByteStringAttribute( - STUN_ATTR_USERNAME, username_attr->GetString())); - // To make sure we receive error response, adding tiebreaker less than - // what's present in request. - modified_req->AddAttribute(new StunUInt64Attribute( - STUN_ATTR_ICE_CONTROLLING, kTiebreaker1 - 1)); - modified_req->AddMessageIntegrity("lpass"); - modified_req->AddFingerprint(); - - lport->Reset(); - rtc::scoped_ptr<ByteBuffer> buf(new ByteBuffer()); - WriteStunMessage(modified_req.get(), buf.get()); - conn1->OnReadPacket(buf->Data(), buf->Length(), rtc::PacketTime()); - ASSERT_TRUE_WAIT(lport->last_stun_msg() != NULL, 1000); - msg = lport->last_stun_msg(); - EXPECT_EQ(STUN_BINDING_ERROR_RESPONSE, msg->type()); -} - -// This test verifies role conflict signal is received when there is -// conflict in the role. In this case both ports are in controlling and -// |rport| has higher tiebreaker value than |lport|. Since |lport| has lower -// value of tiebreaker, when it receives ping request from |rport| it will -// send role conflict signal. -TEST_F(PortTest, TestIceRoleConflict) { - rtc::scoped_ptr<TestPort> lport( - CreateTestPort(kLocalAddr1, "lfrag", "lpass")); - lport->SetIceProtocolType(ICEPROTO_RFC5245); - lport->SetIceRole(cricket::ICEROLE_CONTROLLING); - lport->SetIceTiebreaker(kTiebreaker1); - rtc::scoped_ptr<TestPort> rport( - CreateTestPort(kLocalAddr2, "rfrag", "rpass")); - rport->SetIceProtocolType(ICEPROTO_RFC5245); - rport->SetIceRole(cricket::ICEROLE_CONTROLLING); - rport->SetIceTiebreaker(kTiebreaker2); - - lport->PrepareAddress(); - rport->PrepareAddress(); - ASSERT_FALSE(lport->Candidates().empty()); - ASSERT_FALSE(rport->Candidates().empty()); - Connection* lconn = lport->CreateConnection(rport->Candidates()[0], - Port::ORIGIN_MESSAGE); - Connection* rconn = rport->CreateConnection(lport->Candidates()[0], - Port::ORIGIN_MESSAGE); - rconn->Ping(0); - - ASSERT_TRUE_WAIT(rport->last_stun_msg() != NULL, 1000); - IceMessage* msg = rport->last_stun_msg(); - EXPECT_EQ(STUN_BINDING_REQUEST, msg->type()); - // Send rport binding request to lport. - lconn->OnReadPacket(rport->last_stun_buf()->Data(), - rport->last_stun_buf()->Length(), - rtc::PacketTime()); - - ASSERT_TRUE_WAIT(lport->last_stun_msg() != NULL, 1000); - EXPECT_EQ(STUN_BINDING_RESPONSE, lport->last_stun_msg()->type()); - EXPECT_TRUE(role_conflict()); -} - -TEST_F(PortTest, TestTcpNoDelay) { - TCPPort* port1 = CreateTcpPort(kLocalAddr1); - int option_value = -1; - int success = port1->GetOption(rtc::Socket::OPT_NODELAY, - &option_value); - ASSERT_EQ(0, success); // GetOption() should complete successfully w/ 0 - ASSERT_EQ(1, option_value); - delete port1; -} - -TEST_F(PortTest, TestDelayedBindingUdp) { - FakeAsyncPacketSocket *socket = new FakeAsyncPacketSocket(); - FakePacketSocketFactory socket_factory; - - socket_factory.set_next_udp_socket(socket); - scoped_ptr<UDPPort> port( - CreateUdpPort(kLocalAddr1, &socket_factory)); - - socket->set_state(AsyncPacketSocket::STATE_BINDING); - port->PrepareAddress(); - - EXPECT_EQ(0U, port->Candidates().size()); - socket->SignalAddressReady(socket, kLocalAddr2); - - EXPECT_EQ(1U, port->Candidates().size()); -} - -TEST_F(PortTest, TestDelayedBindingTcp) { - FakeAsyncPacketSocket *socket = new FakeAsyncPacketSocket(); - FakePacketSocketFactory socket_factory; - - socket_factory.set_next_server_tcp_socket(socket); - scoped_ptr<TCPPort> port( - CreateTcpPort(kLocalAddr1, &socket_factory)); - - socket->set_state(AsyncPacketSocket::STATE_BINDING); - port->PrepareAddress(); - - EXPECT_EQ(0U, port->Candidates().size()); - socket->SignalAddressReady(socket, kLocalAddr2); - - EXPECT_EQ(1U, port->Candidates().size()); -} - -void PortTest::TestCrossFamilyPorts(int type) { - FakePacketSocketFactory factory; - scoped_ptr<Port> ports[4]; - SocketAddress addresses[4] = {SocketAddress("192.168.1.3", 0), - SocketAddress("192.168.1.4", 0), - SocketAddress("2001:db8::1", 0), - SocketAddress("2001:db8::2", 0)}; - for (int i = 0; i < 4; i++) { - FakeAsyncPacketSocket *socket = new FakeAsyncPacketSocket(); - if (type == SOCK_DGRAM) { - factory.set_next_udp_socket(socket); - ports[i].reset(CreateUdpPort(addresses[i], &factory)); - } else if (type == SOCK_STREAM) { - factory.set_next_server_tcp_socket(socket); - ports[i].reset(CreateTcpPort(addresses[i], &factory)); - } - socket->set_state(AsyncPacketSocket::STATE_BINDING); - socket->SignalAddressReady(socket, addresses[i]); - ports[i]->PrepareAddress(); - } - - // IPv4 Port, connects to IPv6 candidate and then to IPv4 candidate. - if (type == SOCK_STREAM) { - FakeAsyncPacketSocket* clientsocket = new FakeAsyncPacketSocket(); - factory.set_next_client_tcp_socket(clientsocket); - } - Connection* c = ports[0]->CreateConnection(GetCandidate(ports[2].get()), - Port::ORIGIN_MESSAGE); - EXPECT_TRUE(NULL == c); - EXPECT_EQ(0U, ports[0]->connections().size()); - c = ports[0]->CreateConnection(GetCandidate(ports[1].get()), - Port::ORIGIN_MESSAGE); - EXPECT_FALSE(NULL == c); - EXPECT_EQ(1U, ports[0]->connections().size()); - - // IPv6 Port, connects to IPv4 candidate and to IPv6 candidate. - if (type == SOCK_STREAM) { - FakeAsyncPacketSocket* clientsocket = new FakeAsyncPacketSocket(); - factory.set_next_client_tcp_socket(clientsocket); - } - c = ports[2]->CreateConnection(GetCandidate(ports[0].get()), - Port::ORIGIN_MESSAGE); - EXPECT_TRUE(NULL == c); - EXPECT_EQ(0U, ports[2]->connections().size()); - c = ports[2]->CreateConnection(GetCandidate(ports[3].get()), - Port::ORIGIN_MESSAGE); - EXPECT_FALSE(NULL == c); - EXPECT_EQ(1U, ports[2]->connections().size()); -} - -TEST_F(PortTest, TestSkipCrossFamilyTcp) { - TestCrossFamilyPorts(SOCK_STREAM); -} - -TEST_F(PortTest, TestSkipCrossFamilyUdp) { - TestCrossFamilyPorts(SOCK_DGRAM); -} - -// This test verifies DSCP value set through SetOption interface can be -// get through DefaultDscpValue. -TEST_F(PortTest, TestDefaultDscpValue) { - int dscp; - rtc::scoped_ptr<UDPPort> udpport(CreateUdpPort(kLocalAddr1)); - EXPECT_EQ(0, udpport->SetOption(rtc::Socket::OPT_DSCP, - rtc::DSCP_CS6)); - EXPECT_EQ(0, udpport->GetOption(rtc::Socket::OPT_DSCP, &dscp)); - rtc::scoped_ptr<TCPPort> tcpport(CreateTcpPort(kLocalAddr1)); - EXPECT_EQ(0, tcpport->SetOption(rtc::Socket::OPT_DSCP, - rtc::DSCP_AF31)); - EXPECT_EQ(0, tcpport->GetOption(rtc::Socket::OPT_DSCP, &dscp)); - EXPECT_EQ(rtc::DSCP_AF31, dscp); - rtc::scoped_ptr<StunPort> stunport( - CreateStunPort(kLocalAddr1, nat_socket_factory1())); - EXPECT_EQ(0, stunport->SetOption(rtc::Socket::OPT_DSCP, - rtc::DSCP_AF41)); - EXPECT_EQ(0, stunport->GetOption(rtc::Socket::OPT_DSCP, &dscp)); - EXPECT_EQ(rtc::DSCP_AF41, dscp); - rtc::scoped_ptr<TurnPort> turnport1(CreateTurnPort( - kLocalAddr1, nat_socket_factory1(), PROTO_UDP, PROTO_UDP)); - // Socket is created in PrepareAddress. - turnport1->PrepareAddress(); - EXPECT_EQ(0, turnport1->SetOption(rtc::Socket::OPT_DSCP, - rtc::DSCP_CS7)); - EXPECT_EQ(0, turnport1->GetOption(rtc::Socket::OPT_DSCP, &dscp)); - EXPECT_EQ(rtc::DSCP_CS7, dscp); - // This will verify correct value returned without the socket. - rtc::scoped_ptr<TurnPort> turnport2(CreateTurnPort( - kLocalAddr1, nat_socket_factory1(), PROTO_UDP, PROTO_UDP)); - EXPECT_EQ(0, turnport2->SetOption(rtc::Socket::OPT_DSCP, - rtc::DSCP_CS6)); - EXPECT_EQ(0, turnport2->GetOption(rtc::Socket::OPT_DSCP, &dscp)); - EXPECT_EQ(rtc::DSCP_CS6, dscp); -} - -// Test sending STUN messages in GICE format. -TEST_F(PortTest, TestSendStunMessageAsGice) { - rtc::scoped_ptr<TestPort> lport( - CreateTestPort(kLocalAddr1, "lfrag", "lpass")); - rtc::scoped_ptr<TestPort> rport( - CreateTestPort(kLocalAddr2, "rfrag", "rpass")); - lport->SetIceProtocolType(ICEPROTO_GOOGLE); - rport->SetIceProtocolType(ICEPROTO_GOOGLE); - - // Send a fake ping from lport to rport. - lport->PrepareAddress(); - rport->PrepareAddress(); - ASSERT_FALSE(rport->Candidates().empty()); - Connection* conn = lport->CreateConnection(rport->Candidates()[0], - Port::ORIGIN_MESSAGE); - rport->CreateConnection(lport->Candidates()[0], Port::ORIGIN_MESSAGE); - conn->Ping(0); - - // Check that it's a proper BINDING-REQUEST. - ASSERT_TRUE_WAIT(lport->last_stun_msg() != NULL, 1000); - IceMessage* msg = lport->last_stun_msg(); - EXPECT_EQ(STUN_BINDING_REQUEST, msg->type()); - EXPECT_FALSE(msg->IsLegacy()); - const StunByteStringAttribute* username_attr = msg->GetByteString( - STUN_ATTR_USERNAME); - ASSERT_TRUE(username_attr != NULL); - EXPECT_EQ("rfraglfrag", username_attr->GetString()); - EXPECT_TRUE(msg->GetByteString(STUN_ATTR_MESSAGE_INTEGRITY) == NULL); - EXPECT_TRUE(msg->GetByteString(STUN_ATTR_PRIORITY) == NULL); - EXPECT_TRUE(msg->GetByteString(STUN_ATTR_FINGERPRINT) == NULL); - - // Save a copy of the BINDING-REQUEST for use below. - rtc::scoped_ptr<IceMessage> request(CopyStunMessage(msg)); - - // Respond with a BINDING-RESPONSE. - rport->SendBindingResponse(request.get(), lport->Candidates()[0].address()); - msg = rport->last_stun_msg(); - ASSERT_TRUE(msg != NULL); - EXPECT_EQ(STUN_BINDING_RESPONSE, msg->type()); - EXPECT_FALSE(msg->IsLegacy()); - username_attr = msg->GetByteString(STUN_ATTR_USERNAME); - ASSERT_TRUE(username_attr != NULL); // GICE has a username in the response. - EXPECT_EQ("rfraglfrag", username_attr->GetString()); - const StunAddressAttribute* addr_attr = msg->GetAddress( - STUN_ATTR_MAPPED_ADDRESS); - ASSERT_TRUE(addr_attr != NULL); - EXPECT_EQ(lport->Candidates()[0].address(), addr_attr->GetAddress()); - EXPECT_TRUE(msg->GetByteString(STUN_ATTR_XOR_MAPPED_ADDRESS) == NULL); - EXPECT_TRUE(msg->GetByteString(STUN_ATTR_MESSAGE_INTEGRITY) == NULL); - EXPECT_TRUE(msg->GetByteString(STUN_ATTR_PRIORITY) == NULL); - EXPECT_TRUE(msg->GetByteString(STUN_ATTR_FINGERPRINT) == NULL); - - // Respond with a BINDING-ERROR-RESPONSE. This wouldn't happen in real life, - // but we can do it here. - rport->SendBindingErrorResponse(request.get(), - rport->Candidates()[0].address(), - STUN_ERROR_SERVER_ERROR, - STUN_ERROR_REASON_SERVER_ERROR); - msg = rport->last_stun_msg(); - ASSERT_TRUE(msg != NULL); - EXPECT_EQ(STUN_BINDING_ERROR_RESPONSE, msg->type()); - EXPECT_FALSE(msg->IsLegacy()); - username_attr = msg->GetByteString(STUN_ATTR_USERNAME); - ASSERT_TRUE(username_attr != NULL); // GICE has a username in the response. - EXPECT_EQ("rfraglfrag", username_attr->GetString()); - const StunErrorCodeAttribute* error_attr = msg->GetErrorCode(); - ASSERT_TRUE(error_attr != NULL); - // The GICE wire format for error codes is incorrect. - EXPECT_EQ(STUN_ERROR_SERVER_ERROR_AS_GICE, error_attr->code()); - EXPECT_EQ(STUN_ERROR_SERVER_ERROR / 256, error_attr->eclass()); - EXPECT_EQ(STUN_ERROR_SERVER_ERROR % 256, error_attr->number()); - EXPECT_EQ(std::string(STUN_ERROR_REASON_SERVER_ERROR), error_attr->reason()); - EXPECT_TRUE(msg->GetByteString(STUN_ATTR_PRIORITY) == NULL); - EXPECT_TRUE(msg->GetByteString(STUN_ATTR_MESSAGE_INTEGRITY) == NULL); - EXPECT_TRUE(msg->GetByteString(STUN_ATTR_FINGERPRINT) == NULL); -} - -// Test sending STUN messages in ICE format. -TEST_F(PortTest, TestSendStunMessageAsIce) { - rtc::scoped_ptr<TestPort> lport( - CreateTestPort(kLocalAddr1, "lfrag", "lpass")); - rtc::scoped_ptr<TestPort> rport( - CreateTestPort(kLocalAddr2, "rfrag", "rpass")); - lport->SetIceProtocolType(ICEPROTO_RFC5245); - lport->SetIceRole(cricket::ICEROLE_CONTROLLING); - lport->SetIceTiebreaker(kTiebreaker1); - rport->SetIceProtocolType(ICEPROTO_RFC5245); - rport->SetIceRole(cricket::ICEROLE_CONTROLLED); - rport->SetIceTiebreaker(kTiebreaker2); - - // Send a fake ping from lport to rport. - lport->PrepareAddress(); - rport->PrepareAddress(); - ASSERT_FALSE(rport->Candidates().empty()); - Connection* lconn = lport->CreateConnection( - rport->Candidates()[0], Port::ORIGIN_MESSAGE); - Connection* rconn = rport->CreateConnection( - lport->Candidates()[0], Port::ORIGIN_MESSAGE); - lconn->Ping(0); - - // Check that it's a proper BINDING-REQUEST. - ASSERT_TRUE_WAIT(lport->last_stun_msg() != NULL, 1000); - IceMessage* msg = lport->last_stun_msg(); - EXPECT_EQ(STUN_BINDING_REQUEST, msg->type()); - EXPECT_FALSE(msg->IsLegacy()); - const StunByteStringAttribute* username_attr = - msg->GetByteString(STUN_ATTR_USERNAME); - ASSERT_TRUE(username_attr != NULL); - const StunUInt32Attribute* priority_attr = msg->GetUInt32(STUN_ATTR_PRIORITY); - ASSERT_TRUE(priority_attr != NULL); - EXPECT_EQ(kDefaultPrflxPriority, priority_attr->value()); - EXPECT_EQ("rfrag:lfrag", username_attr->GetString()); - EXPECT_TRUE(msg->GetByteString(STUN_ATTR_MESSAGE_INTEGRITY) != NULL); - EXPECT_TRUE(StunMessage::ValidateMessageIntegrity( - lport->last_stun_buf()->Data(), lport->last_stun_buf()->Length(), - "rpass")); - const StunUInt64Attribute* ice_controlling_attr = - msg->GetUInt64(STUN_ATTR_ICE_CONTROLLING); - ASSERT_TRUE(ice_controlling_attr != NULL); - EXPECT_EQ(lport->IceTiebreaker(), ice_controlling_attr->value()); - EXPECT_TRUE(msg->GetByteString(STUN_ATTR_ICE_CONTROLLED) == NULL); - EXPECT_TRUE(msg->GetByteString(STUN_ATTR_USE_CANDIDATE) != NULL); - EXPECT_TRUE(msg->GetUInt32(STUN_ATTR_FINGERPRINT) != NULL); - EXPECT_TRUE(StunMessage::ValidateFingerprint( - lport->last_stun_buf()->Data(), lport->last_stun_buf()->Length())); - - // Request should not include ping count. - ASSERT_TRUE(msg->GetUInt32(STUN_ATTR_RETRANSMIT_COUNT) == NULL); - - // Save a copy of the BINDING-REQUEST for use below. - rtc::scoped_ptr<IceMessage> request(CopyStunMessage(msg)); - - // Respond with a BINDING-RESPONSE. - rport->SendBindingResponse(request.get(), lport->Candidates()[0].address()); - msg = rport->last_stun_msg(); - ASSERT_TRUE(msg != NULL); - EXPECT_EQ(STUN_BINDING_RESPONSE, msg->type()); - - - EXPECT_FALSE(msg->IsLegacy()); - const StunAddressAttribute* addr_attr = msg->GetAddress( - STUN_ATTR_XOR_MAPPED_ADDRESS); - ASSERT_TRUE(addr_attr != NULL); - EXPECT_EQ(lport->Candidates()[0].address(), addr_attr->GetAddress()); - EXPECT_TRUE(msg->GetByteString(STUN_ATTR_MESSAGE_INTEGRITY) != NULL); - EXPECT_TRUE(StunMessage::ValidateMessageIntegrity( - rport->last_stun_buf()->Data(), rport->last_stun_buf()->Length(), - "rpass")); - EXPECT_TRUE(msg->GetUInt32(STUN_ATTR_FINGERPRINT) != NULL); - EXPECT_TRUE(StunMessage::ValidateFingerprint( - lport->last_stun_buf()->Data(), lport->last_stun_buf()->Length())); - // No USERNAME or PRIORITY in ICE responses. - EXPECT_TRUE(msg->GetByteString(STUN_ATTR_USERNAME) == NULL); - EXPECT_TRUE(msg->GetByteString(STUN_ATTR_PRIORITY) == NULL); - EXPECT_TRUE(msg->GetByteString(STUN_ATTR_MAPPED_ADDRESS) == NULL); - EXPECT_TRUE(msg->GetByteString(STUN_ATTR_ICE_CONTROLLING) == NULL); - EXPECT_TRUE(msg->GetByteString(STUN_ATTR_ICE_CONTROLLED) == NULL); - EXPECT_TRUE(msg->GetByteString(STUN_ATTR_USE_CANDIDATE) == NULL); - - // Response should not include ping count. - ASSERT_TRUE(msg->GetUInt32(STUN_ATTR_RETRANSMIT_COUNT) == NULL); - - // Respond with a BINDING-ERROR-RESPONSE. This wouldn't happen in real life, - // but we can do it here. - rport->SendBindingErrorResponse(request.get(), - lport->Candidates()[0].address(), - STUN_ERROR_SERVER_ERROR, - STUN_ERROR_REASON_SERVER_ERROR); - msg = rport->last_stun_msg(); - ASSERT_TRUE(msg != NULL); - EXPECT_EQ(STUN_BINDING_ERROR_RESPONSE, msg->type()); - EXPECT_FALSE(msg->IsLegacy()); - const StunErrorCodeAttribute* error_attr = msg->GetErrorCode(); - ASSERT_TRUE(error_attr != NULL); - EXPECT_EQ(STUN_ERROR_SERVER_ERROR, error_attr->code()); - EXPECT_EQ(std::string(STUN_ERROR_REASON_SERVER_ERROR), error_attr->reason()); - EXPECT_TRUE(msg->GetByteString(STUN_ATTR_MESSAGE_INTEGRITY) != NULL); - EXPECT_TRUE(StunMessage::ValidateMessageIntegrity( - rport->last_stun_buf()->Data(), rport->last_stun_buf()->Length(), - "rpass")); - EXPECT_TRUE(msg->GetUInt32(STUN_ATTR_FINGERPRINT) != NULL); - EXPECT_TRUE(StunMessage::ValidateFingerprint( - lport->last_stun_buf()->Data(), lport->last_stun_buf()->Length())); - // No USERNAME with ICE. - EXPECT_TRUE(msg->GetByteString(STUN_ATTR_USERNAME) == NULL); - EXPECT_TRUE(msg->GetByteString(STUN_ATTR_PRIORITY) == NULL); - - // Testing STUN binding requests from rport --> lport, having ICE_CONTROLLED - // and (incremented) RETRANSMIT_COUNT attributes. - rport->Reset(); - rport->set_send_retransmit_count_attribute(true); - rconn->Ping(0); - rconn->Ping(0); - rconn->Ping(0); - ASSERT_TRUE_WAIT(rport->last_stun_msg() != NULL, 1000); - msg = rport->last_stun_msg(); - EXPECT_EQ(STUN_BINDING_REQUEST, msg->type()); - const StunUInt64Attribute* ice_controlled_attr = - msg->GetUInt64(STUN_ATTR_ICE_CONTROLLED); - ASSERT_TRUE(ice_controlled_attr != NULL); - EXPECT_EQ(rport->IceTiebreaker(), ice_controlled_attr->value()); - EXPECT_TRUE(msg->GetByteString(STUN_ATTR_USE_CANDIDATE) == NULL); - - // Request should include ping count. - const StunUInt32Attribute* retransmit_attr = - msg->GetUInt32(STUN_ATTR_RETRANSMIT_COUNT); - ASSERT_TRUE(retransmit_attr != NULL); - EXPECT_EQ(2U, retransmit_attr->value()); - - // Respond with a BINDING-RESPONSE. - request.reset(CopyStunMessage(msg)); - lport->SendBindingResponse(request.get(), rport->Candidates()[0].address()); - msg = lport->last_stun_msg(); - - // Response should include same ping count. - retransmit_attr = msg->GetUInt32(STUN_ATTR_RETRANSMIT_COUNT); - ASSERT_TRUE(retransmit_attr != NULL); - EXPECT_EQ(2U, retransmit_attr->value()); -} - -TEST_F(PortTest, TestUseCandidateAttribute) { - rtc::scoped_ptr<TestPort> lport( - CreateTestPort(kLocalAddr1, "lfrag", "lpass")); - rtc::scoped_ptr<TestPort> rport( - CreateTestPort(kLocalAddr2, "rfrag", "rpass")); - lport->SetIceProtocolType(ICEPROTO_RFC5245); - lport->SetIceRole(cricket::ICEROLE_CONTROLLING); - lport->SetIceTiebreaker(kTiebreaker1); - rport->SetIceProtocolType(ICEPROTO_RFC5245); - rport->SetIceRole(cricket::ICEROLE_CONTROLLED); - rport->SetIceTiebreaker(kTiebreaker2); - - // Send a fake ping from lport to rport. - lport->PrepareAddress(); - rport->PrepareAddress(); - ASSERT_FALSE(rport->Candidates().empty()); - Connection* lconn = lport->CreateConnection( - rport->Candidates()[0], Port::ORIGIN_MESSAGE); - lconn->Ping(0); - ASSERT_TRUE_WAIT(lport->last_stun_msg() != NULL, 1000); - IceMessage* msg = lport->last_stun_msg(); - const StunUInt64Attribute* ice_controlling_attr = - msg->GetUInt64(STUN_ATTR_ICE_CONTROLLING); - ASSERT_TRUE(ice_controlling_attr != NULL); - const StunByteStringAttribute* use_candidate_attr = msg->GetByteString( - STUN_ATTR_USE_CANDIDATE); - ASSERT_TRUE(use_candidate_attr != NULL); -} - -// Test handling STUN messages in GICE format. -TEST_F(PortTest, TestHandleStunMessageAsGice) { - // Our port will act as the "remote" port. - rtc::scoped_ptr<TestPort> port( - CreateTestPort(kLocalAddr2, "rfrag", "rpass")); - port->SetIceProtocolType(ICEPROTO_GOOGLE); - - rtc::scoped_ptr<IceMessage> in_msg, out_msg; - rtc::scoped_ptr<ByteBuffer> buf(new ByteBuffer()); - rtc::SocketAddress addr(kLocalAddr1); - std::string username; - - // BINDING-REQUEST from local to remote with valid GICE username and no M-I. - in_msg.reset(CreateStunMessageWithUsername(STUN_BINDING_REQUEST, - "rfraglfrag")); - WriteStunMessage(in_msg.get(), buf.get()); - EXPECT_TRUE(port->GetStunMessage(buf->Data(), buf->Length(), addr, - out_msg.accept(), &username)); - EXPECT_TRUE(out_msg.get() != NULL); // Succeeds, since this is GICE. - EXPECT_EQ("lfrag", username); - - // Add M-I; should be ignored and rest of message parsed normally. - in_msg->AddMessageIntegrity("password"); - WriteStunMessage(in_msg.get(), buf.get()); - EXPECT_TRUE(port->GetStunMessage(buf->Data(), buf->Length(), addr, - out_msg.accept(), &username)); - EXPECT_TRUE(out_msg.get() != NULL); - EXPECT_EQ("lfrag", username); - - // BINDING-RESPONSE with username, as done in GICE. Should succeed. - in_msg.reset(CreateStunMessageWithUsername(STUN_BINDING_RESPONSE, - "rfraglfrag")); - in_msg->AddAttribute( - new StunAddressAttribute(STUN_ATTR_MAPPED_ADDRESS, kLocalAddr2)); - WriteStunMessage(in_msg.get(), buf.get()); - EXPECT_TRUE(port->GetStunMessage(buf->Data(), buf->Length(), addr, - out_msg.accept(), &username)); - EXPECT_TRUE(out_msg.get() != NULL); - EXPECT_EQ("", username); - - // BINDING-RESPONSE without username. Should be tolerated as well. - in_msg.reset(CreateStunMessage(STUN_BINDING_RESPONSE)); - in_msg->AddAttribute( - new StunAddressAttribute(STUN_ATTR_MAPPED_ADDRESS, kLocalAddr2)); - WriteStunMessage(in_msg.get(), buf.get()); - EXPECT_TRUE(port->GetStunMessage(buf->Data(), buf->Length(), addr, - out_msg.accept(), &username)); - EXPECT_TRUE(out_msg.get() != NULL); - EXPECT_EQ("", username); - - // BINDING-ERROR-RESPONSE with username and error code. - in_msg.reset(CreateStunMessageWithUsername(STUN_BINDING_ERROR_RESPONSE, - "rfraglfrag")); - in_msg->AddAttribute(new StunErrorCodeAttribute(STUN_ATTR_ERROR_CODE, - STUN_ERROR_SERVER_ERROR_AS_GICE, STUN_ERROR_REASON_SERVER_ERROR)); - WriteStunMessage(in_msg.get(), buf.get()); - EXPECT_TRUE(port->GetStunMessage(buf->Data(), buf->Length(), addr, - out_msg.accept(), &username)); - ASSERT_TRUE(out_msg.get() != NULL); - EXPECT_EQ("", username); - ASSERT_TRUE(out_msg->GetErrorCode() != NULL); - // GetStunMessage doesn't unmunge the GICE error code (happens downstream). - EXPECT_EQ(STUN_ERROR_SERVER_ERROR_AS_GICE, out_msg->GetErrorCode()->code()); - EXPECT_EQ(std::string(STUN_ERROR_REASON_SERVER_ERROR), - out_msg->GetErrorCode()->reason()); -} - -// Test handling STUN messages in ICE format. -TEST_F(PortTest, TestHandleStunMessageAsIce) { - // Our port will act as the "remote" port. - rtc::scoped_ptr<TestPort> port( - CreateTestPort(kLocalAddr2, "rfrag", "rpass")); - port->SetIceProtocolType(ICEPROTO_RFC5245); - - rtc::scoped_ptr<IceMessage> in_msg, out_msg; - rtc::scoped_ptr<ByteBuffer> buf(new ByteBuffer()); - rtc::SocketAddress addr(kLocalAddr1); - std::string username; - - // BINDING-REQUEST from local to remote with valid ICE username, - // MESSAGE-INTEGRITY, and FINGERPRINT. - in_msg.reset(CreateStunMessageWithUsername(STUN_BINDING_REQUEST, - "rfrag:lfrag")); - in_msg->AddMessageIntegrity("rpass"); - in_msg->AddFingerprint(); - WriteStunMessage(in_msg.get(), buf.get()); - EXPECT_TRUE(port->GetStunMessage(buf->Data(), buf->Length(), addr, - out_msg.accept(), &username)); - EXPECT_TRUE(out_msg.get() != NULL); - EXPECT_EQ("lfrag", username); - - // BINDING-RESPONSE without username, with MESSAGE-INTEGRITY and FINGERPRINT. - in_msg.reset(CreateStunMessage(STUN_BINDING_RESPONSE)); - in_msg->AddAttribute( - new StunXorAddressAttribute(STUN_ATTR_XOR_MAPPED_ADDRESS, kLocalAddr2)); - in_msg->AddMessageIntegrity("rpass"); - in_msg->AddFingerprint(); - WriteStunMessage(in_msg.get(), buf.get()); - EXPECT_TRUE(port->GetStunMessage(buf->Data(), buf->Length(), addr, - out_msg.accept(), &username)); - EXPECT_TRUE(out_msg.get() != NULL); - EXPECT_EQ("", username); - - // BINDING-ERROR-RESPONSE without username, with error, M-I, and FINGERPRINT. - in_msg.reset(CreateStunMessage(STUN_BINDING_ERROR_RESPONSE)); - in_msg->AddAttribute(new StunErrorCodeAttribute(STUN_ATTR_ERROR_CODE, - STUN_ERROR_SERVER_ERROR, STUN_ERROR_REASON_SERVER_ERROR)); - in_msg->AddFingerprint(); - WriteStunMessage(in_msg.get(), buf.get()); - EXPECT_TRUE(port->GetStunMessage(buf->Data(), buf->Length(), addr, - out_msg.accept(), &username)); - EXPECT_TRUE(out_msg.get() != NULL); - EXPECT_EQ("", username); - ASSERT_TRUE(out_msg->GetErrorCode() != NULL); - EXPECT_EQ(STUN_ERROR_SERVER_ERROR, out_msg->GetErrorCode()->code()); - EXPECT_EQ(std::string(STUN_ERROR_REASON_SERVER_ERROR), - out_msg->GetErrorCode()->reason()); -} - -// This test verifies port can handle ICE messages in Hybrid mode and switches -// ICEPROTO_RFC5245 mode after successfully handling the message. -TEST_F(PortTest, TestHandleStunMessageAsIceInHybridMode) { - // Our port will act as the "remote" port. - rtc::scoped_ptr<TestPort> port( - CreateTestPort(kLocalAddr2, "rfrag", "rpass")); - port->SetIceProtocolType(ICEPROTO_HYBRID); - - rtc::scoped_ptr<IceMessage> in_msg, out_msg; - rtc::scoped_ptr<ByteBuffer> buf(new ByteBuffer()); - rtc::SocketAddress addr(kLocalAddr1); - std::string username; - - // BINDING-REQUEST from local to remote with valid ICE username, - // MESSAGE-INTEGRITY, and FINGERPRINT. - in_msg.reset(CreateStunMessageWithUsername(STUN_BINDING_REQUEST, - "rfrag:lfrag")); - in_msg->AddMessageIntegrity("rpass"); - in_msg->AddFingerprint(); - WriteStunMessage(in_msg.get(), buf.get()); - EXPECT_TRUE(port->GetStunMessage(buf->Data(), buf->Length(), addr, - out_msg.accept(), &username)); - EXPECT_TRUE(out_msg.get() != NULL); - EXPECT_EQ("lfrag", username); - EXPECT_EQ(ICEPROTO_RFC5245, port->IceProtocol()); -} - -// This test verifies port can handle GICE messages in Hybrid mode and switches -// ICEPROTO_GOOGLE mode after successfully handling the message. -TEST_F(PortTest, TestHandleStunMessageAsGiceInHybridMode) { - // Our port will act as the "remote" port. - rtc::scoped_ptr<TestPort> port( - CreateTestPort(kLocalAddr2, "rfrag", "rpass")); - port->SetIceProtocolType(ICEPROTO_HYBRID); - - rtc::scoped_ptr<IceMessage> in_msg, out_msg; - rtc::scoped_ptr<ByteBuffer> buf(new ByteBuffer()); - rtc::SocketAddress addr(kLocalAddr1); - std::string username; - - // BINDING-REQUEST from local to remote with valid GICE username and no M-I. - in_msg.reset(CreateStunMessageWithUsername(STUN_BINDING_REQUEST, - "rfraglfrag")); - WriteStunMessage(in_msg.get(), buf.get()); - EXPECT_TRUE(port->GetStunMessage(buf->Data(), buf->Length(), addr, - out_msg.accept(), &username)); - EXPECT_TRUE(out_msg.get() != NULL); // Succeeds, since this is GICE. - EXPECT_EQ("lfrag", username); - EXPECT_EQ(ICEPROTO_GOOGLE, port->IceProtocol()); -} - -// Verify port is not switched out of RFC5245 mode if GICE message is received -// in that mode. -TEST_F(PortTest, TestHandleStunMessageAsGiceInIceMode) { - // Our port will act as the "remote" port. - rtc::scoped_ptr<TestPort> port( - CreateTestPort(kLocalAddr2, "rfrag", "rpass")); - port->SetIceProtocolType(ICEPROTO_RFC5245); - - rtc::scoped_ptr<IceMessage> in_msg, out_msg; - rtc::scoped_ptr<ByteBuffer> buf(new ByteBuffer()); - rtc::SocketAddress addr(kLocalAddr1); - std::string username; - - // BINDING-REQUEST from local to remote with valid GICE username and no M-I. - in_msg.reset(CreateStunMessageWithUsername(STUN_BINDING_REQUEST, - "rfraglfrag")); - WriteStunMessage(in_msg.get(), buf.get()); - // Should fail as there is no MI and fingerprint. - EXPECT_FALSE(port->GetStunMessage(buf->Data(), buf->Length(), addr, - out_msg.accept(), &username)); - EXPECT_EQ(ICEPROTO_RFC5245, port->IceProtocol()); -} - - -// Tests handling of GICE binding requests with missing or incorrect usernames. -TEST_F(PortTest, TestHandleStunMessageAsGiceBadUsername) { - rtc::scoped_ptr<TestPort> port( - CreateTestPort(kLocalAddr2, "rfrag", "rpass")); - port->SetIceProtocolType(ICEPROTO_GOOGLE); - - rtc::scoped_ptr<IceMessage> in_msg, out_msg; - rtc::scoped_ptr<ByteBuffer> buf(new ByteBuffer()); - rtc::SocketAddress addr(kLocalAddr1); - std::string username; - - // BINDING-REQUEST with no username. - in_msg.reset(CreateStunMessage(STUN_BINDING_REQUEST)); - WriteStunMessage(in_msg.get(), buf.get()); - EXPECT_TRUE(port->GetStunMessage(buf->Data(), buf->Length(), addr, - out_msg.accept(), &username)); - EXPECT_TRUE(out_msg.get() == NULL); - EXPECT_EQ("", username); - EXPECT_EQ(STUN_ERROR_BAD_REQUEST_AS_GICE, port->last_stun_error_code()); - - // BINDING-REQUEST with empty username. - in_msg.reset(CreateStunMessageWithUsername(STUN_BINDING_REQUEST, "")); - WriteStunMessage(in_msg.get(), buf.get()); - EXPECT_TRUE(port->GetStunMessage(buf->Data(), buf->Length(), addr, - out_msg.accept(), &username)); - EXPECT_TRUE(out_msg.get() == NULL); - EXPECT_EQ("", username); - EXPECT_EQ(STUN_ERROR_UNAUTHORIZED_AS_GICE, port->last_stun_error_code()); - - // BINDING-REQUEST with too-short username. - in_msg.reset(CreateStunMessageWithUsername(STUN_BINDING_REQUEST, "lfra")); - WriteStunMessage(in_msg.get(), buf.get()); - EXPECT_TRUE(port->GetStunMessage(buf->Data(), buf->Length(), addr, - out_msg.accept(), &username)); - EXPECT_TRUE(out_msg.get() == NULL); - EXPECT_EQ("", username); - EXPECT_EQ(STUN_ERROR_UNAUTHORIZED_AS_GICE, port->last_stun_error_code()); - - // BINDING-REQUEST with reversed username. - in_msg.reset(CreateStunMessageWithUsername(STUN_BINDING_REQUEST, - "lfragrfrag")); - WriteStunMessage(in_msg.get(), buf.get()); - EXPECT_TRUE(port->GetStunMessage(buf->Data(), buf->Length(), addr, - out_msg.accept(), &username)); - EXPECT_TRUE(out_msg.get() == NULL); - EXPECT_EQ("", username); - EXPECT_EQ(STUN_ERROR_UNAUTHORIZED_AS_GICE, port->last_stun_error_code()); - - // BINDING-REQUEST with garbage username. - in_msg.reset(CreateStunMessageWithUsername(STUN_BINDING_REQUEST, - "abcdefgh")); - WriteStunMessage(in_msg.get(), buf.get()); - EXPECT_TRUE(port->GetStunMessage(buf->Data(), buf->Length(), addr, - out_msg.accept(), &username)); - EXPECT_TRUE(out_msg.get() == NULL); - EXPECT_EQ("", username); - EXPECT_EQ(STUN_ERROR_UNAUTHORIZED_AS_GICE, port->last_stun_error_code()); -} - -// Tests handling of ICE binding requests with missing or incorrect usernames. -TEST_F(PortTest, TestHandleStunMessageAsIceBadUsername) { - rtc::scoped_ptr<TestPort> port( - CreateTestPort(kLocalAddr2, "rfrag", "rpass")); - port->SetIceProtocolType(ICEPROTO_RFC5245); - - rtc::scoped_ptr<IceMessage> in_msg, out_msg; - rtc::scoped_ptr<ByteBuffer> buf(new ByteBuffer()); - rtc::SocketAddress addr(kLocalAddr1); - std::string username; - - // BINDING-REQUEST with no username. - in_msg.reset(CreateStunMessage(STUN_BINDING_REQUEST)); - in_msg->AddMessageIntegrity("rpass"); - in_msg->AddFingerprint(); - WriteStunMessage(in_msg.get(), buf.get()); - EXPECT_TRUE(port->GetStunMessage(buf->Data(), buf->Length(), addr, - out_msg.accept(), &username)); - EXPECT_TRUE(out_msg.get() == NULL); - EXPECT_EQ("", username); - EXPECT_EQ(STUN_ERROR_BAD_REQUEST, port->last_stun_error_code()); - - // BINDING-REQUEST with empty username. - in_msg.reset(CreateStunMessageWithUsername(STUN_BINDING_REQUEST, "")); - in_msg->AddMessageIntegrity("rpass"); - in_msg->AddFingerprint(); - WriteStunMessage(in_msg.get(), buf.get()); - EXPECT_TRUE(port->GetStunMessage(buf->Data(), buf->Length(), addr, - out_msg.accept(), &username)); - EXPECT_TRUE(out_msg.get() == NULL); - EXPECT_EQ("", username); - EXPECT_EQ(STUN_ERROR_UNAUTHORIZED, port->last_stun_error_code()); - - // BINDING-REQUEST with too-short username. - in_msg.reset(CreateStunMessageWithUsername(STUN_BINDING_REQUEST, "rfra")); - in_msg->AddMessageIntegrity("rpass"); - in_msg->AddFingerprint(); - WriteStunMessage(in_msg.get(), buf.get()); - EXPECT_TRUE(port->GetStunMessage(buf->Data(), buf->Length(), addr, - out_msg.accept(), &username)); - EXPECT_TRUE(out_msg.get() == NULL); - EXPECT_EQ("", username); - EXPECT_EQ(STUN_ERROR_UNAUTHORIZED, port->last_stun_error_code()); - - // BINDING-REQUEST with reversed username. - in_msg.reset(CreateStunMessageWithUsername(STUN_BINDING_REQUEST, - "lfrag:rfrag")); - in_msg->AddMessageIntegrity("rpass"); - in_msg->AddFingerprint(); - WriteStunMessage(in_msg.get(), buf.get()); - EXPECT_TRUE(port->GetStunMessage(buf->Data(), buf->Length(), addr, - out_msg.accept(), &username)); - EXPECT_TRUE(out_msg.get() == NULL); - EXPECT_EQ("", username); - EXPECT_EQ(STUN_ERROR_UNAUTHORIZED, port->last_stun_error_code()); - - // BINDING-REQUEST with garbage username. - in_msg.reset(CreateStunMessageWithUsername(STUN_BINDING_REQUEST, - "abcd:efgh")); - in_msg->AddMessageIntegrity("rpass"); - in_msg->AddFingerprint(); - WriteStunMessage(in_msg.get(), buf.get()); - EXPECT_TRUE(port->GetStunMessage(buf->Data(), buf->Length(), addr, - out_msg.accept(), &username)); - EXPECT_TRUE(out_msg.get() == NULL); - EXPECT_EQ("", username); - EXPECT_EQ(STUN_ERROR_UNAUTHORIZED, port->last_stun_error_code()); -} - -// Test handling STUN messages (as ICE) with missing or malformed M-I. -TEST_F(PortTest, TestHandleStunMessageAsIceBadMessageIntegrity) { - // Our port will act as the "remote" port. - rtc::scoped_ptr<TestPort> port( - CreateTestPort(kLocalAddr2, "rfrag", "rpass")); - port->SetIceProtocolType(ICEPROTO_RFC5245); - - rtc::scoped_ptr<IceMessage> in_msg, out_msg; - rtc::scoped_ptr<ByteBuffer> buf(new ByteBuffer()); - rtc::SocketAddress addr(kLocalAddr1); - std::string username; - - // BINDING-REQUEST from local to remote with valid ICE username and - // FINGERPRINT, but no MESSAGE-INTEGRITY. - in_msg.reset(CreateStunMessageWithUsername(STUN_BINDING_REQUEST, - "rfrag:lfrag")); - in_msg->AddFingerprint(); - WriteStunMessage(in_msg.get(), buf.get()); - EXPECT_TRUE(port->GetStunMessage(buf->Data(), buf->Length(), addr, - out_msg.accept(), &username)); - EXPECT_TRUE(out_msg.get() == NULL); - EXPECT_EQ("", username); - EXPECT_EQ(STUN_ERROR_BAD_REQUEST, port->last_stun_error_code()); - - // BINDING-REQUEST from local to remote with valid ICE username and - // FINGERPRINT, but invalid MESSAGE-INTEGRITY. - in_msg.reset(CreateStunMessageWithUsername(STUN_BINDING_REQUEST, - "rfrag:lfrag")); - in_msg->AddMessageIntegrity("invalid"); - in_msg->AddFingerprint(); - WriteStunMessage(in_msg.get(), buf.get()); - EXPECT_TRUE(port->GetStunMessage(buf->Data(), buf->Length(), addr, - out_msg.accept(), &username)); - EXPECT_TRUE(out_msg.get() == NULL); - EXPECT_EQ("", username); - EXPECT_EQ(STUN_ERROR_UNAUTHORIZED, port->last_stun_error_code()); - - // TODO: BINDING-RESPONSES and BINDING-ERROR-RESPONSES are checked - // by the Connection, not the Port, since they require the remote username. - // Change this test to pass in data via Connection::OnReadPacket instead. -} - -// Test handling STUN messages (as ICE) with missing or malformed FINGERPRINT. -TEST_F(PortTest, TestHandleStunMessageAsIceBadFingerprint) { - // Our port will act as the "remote" port. - rtc::scoped_ptr<TestPort> port( - CreateTestPort(kLocalAddr2, "rfrag", "rpass")); - port->SetIceProtocolType(ICEPROTO_RFC5245); - - rtc::scoped_ptr<IceMessage> in_msg, out_msg; - rtc::scoped_ptr<ByteBuffer> buf(new ByteBuffer()); - rtc::SocketAddress addr(kLocalAddr1); - std::string username; - - // BINDING-REQUEST from local to remote with valid ICE username and - // MESSAGE-INTEGRITY, but no FINGERPRINT; GetStunMessage should fail. - in_msg.reset(CreateStunMessageWithUsername(STUN_BINDING_REQUEST, - "rfrag:lfrag")); - in_msg->AddMessageIntegrity("rpass"); - WriteStunMessage(in_msg.get(), buf.get()); - EXPECT_FALSE(port->GetStunMessage(buf->Data(), buf->Length(), addr, - out_msg.accept(), &username)); - EXPECT_EQ(0, port->last_stun_error_code()); - - // Now, add a fingerprint, but munge the message so it's not valid. - in_msg->AddFingerprint(); - in_msg->SetTransactionID("TESTTESTBADD"); - WriteStunMessage(in_msg.get(), buf.get()); - EXPECT_FALSE(port->GetStunMessage(buf->Data(), buf->Length(), addr, - out_msg.accept(), &username)); - EXPECT_EQ(0, port->last_stun_error_code()); - - // Valid BINDING-RESPONSE, except no FINGERPRINT. - in_msg.reset(CreateStunMessage(STUN_BINDING_RESPONSE)); - in_msg->AddAttribute( - new StunXorAddressAttribute(STUN_ATTR_XOR_MAPPED_ADDRESS, kLocalAddr2)); - in_msg->AddMessageIntegrity("rpass"); - WriteStunMessage(in_msg.get(), buf.get()); - EXPECT_FALSE(port->GetStunMessage(buf->Data(), buf->Length(), addr, - out_msg.accept(), &username)); - EXPECT_EQ(0, port->last_stun_error_code()); - - // Now, add a fingerprint, but munge the message so it's not valid. - in_msg->AddFingerprint(); - in_msg->SetTransactionID("TESTTESTBADD"); - WriteStunMessage(in_msg.get(), buf.get()); - EXPECT_FALSE(port->GetStunMessage(buf->Data(), buf->Length(), addr, - out_msg.accept(), &username)); - EXPECT_EQ(0, port->last_stun_error_code()); - - // Valid BINDING-ERROR-RESPONSE, except no FINGERPRINT. - in_msg.reset(CreateStunMessage(STUN_BINDING_ERROR_RESPONSE)); - in_msg->AddAttribute(new StunErrorCodeAttribute(STUN_ATTR_ERROR_CODE, - STUN_ERROR_SERVER_ERROR, STUN_ERROR_REASON_SERVER_ERROR)); - in_msg->AddMessageIntegrity("rpass"); - WriteStunMessage(in_msg.get(), buf.get()); - EXPECT_FALSE(port->GetStunMessage(buf->Data(), buf->Length(), addr, - out_msg.accept(), &username)); - EXPECT_EQ(0, port->last_stun_error_code()); - - // Now, add a fingerprint, but munge the message so it's not valid. - in_msg->AddFingerprint(); - in_msg->SetTransactionID("TESTTESTBADD"); - WriteStunMessage(in_msg.get(), buf.get()); - EXPECT_FALSE(port->GetStunMessage(buf->Data(), buf->Length(), addr, - out_msg.accept(), &username)); - EXPECT_EQ(0, port->last_stun_error_code()); -} - -// Test handling of STUN binding indication messages (as ICE). STUN binding -// indications are allowed only to the connection which is in read mode. -TEST_F(PortTest, TestHandleStunBindingIndication) { - rtc::scoped_ptr<TestPort> lport( - CreateTestPort(kLocalAddr2, "lfrag", "lpass")); - lport->SetIceProtocolType(ICEPROTO_RFC5245); - lport->SetIceRole(cricket::ICEROLE_CONTROLLING); - lport->SetIceTiebreaker(kTiebreaker1); - - // Verifying encoding and decoding STUN indication message. - rtc::scoped_ptr<IceMessage> in_msg, out_msg; - rtc::scoped_ptr<ByteBuffer> buf(new ByteBuffer()); - rtc::SocketAddress addr(kLocalAddr1); - std::string username; - - in_msg.reset(CreateStunMessage(STUN_BINDING_INDICATION)); - in_msg->AddFingerprint(); - WriteStunMessage(in_msg.get(), buf.get()); - EXPECT_TRUE(lport->GetStunMessage(buf->Data(), buf->Length(), addr, - out_msg.accept(), &username)); - EXPECT_TRUE(out_msg.get() != NULL); - EXPECT_EQ(out_msg->type(), STUN_BINDING_INDICATION); - EXPECT_EQ("", username); - - // Verify connection can handle STUN indication and updates - // last_ping_received. - rtc::scoped_ptr<TestPort> rport( - CreateTestPort(kLocalAddr2, "rfrag", "rpass")); - rport->SetIceProtocolType(ICEPROTO_RFC5245); - rport->SetIceRole(cricket::ICEROLE_CONTROLLED); - rport->SetIceTiebreaker(kTiebreaker2); - - lport->PrepareAddress(); - rport->PrepareAddress(); - ASSERT_FALSE(lport->Candidates().empty()); - ASSERT_FALSE(rport->Candidates().empty()); - - Connection* lconn = lport->CreateConnection(rport->Candidates()[0], - Port::ORIGIN_MESSAGE); - Connection* rconn = rport->CreateConnection(lport->Candidates()[0], - Port::ORIGIN_MESSAGE); - rconn->Ping(0); - - ASSERT_TRUE_WAIT(rport->last_stun_msg() != NULL, 1000); - IceMessage* msg = rport->last_stun_msg(); - EXPECT_EQ(STUN_BINDING_REQUEST, msg->type()); - // Send rport binding request to lport. - lconn->OnReadPacket(rport->last_stun_buf()->Data(), - rport->last_stun_buf()->Length(), - rtc::PacketTime()); - ASSERT_TRUE_WAIT(lport->last_stun_msg() != NULL, 1000); - EXPECT_EQ(STUN_BINDING_RESPONSE, lport->last_stun_msg()->type()); - uint32 last_ping_received1 = lconn->last_ping_received(); - - // Adding a delay of 100ms. - rtc::Thread::Current()->ProcessMessages(100); - // Pinging lconn using stun indication message. - lconn->OnReadPacket(buf->Data(), buf->Length(), rtc::PacketTime()); - uint32 last_ping_received2 = lconn->last_ping_received(); - EXPECT_GT(last_ping_received2, last_ping_received1); -} - -TEST_F(PortTest, TestComputeCandidatePriority) { - rtc::scoped_ptr<TestPort> port( - CreateTestPort(kLocalAddr1, "name", "pass")); - port->set_type_preference(90); - port->set_component(177); - port->AddCandidateAddress(SocketAddress("192.168.1.4", 1234)); - port->AddCandidateAddress(SocketAddress("2001:db8::1234", 1234)); - port->AddCandidateAddress(SocketAddress("fc12:3456::1234", 1234)); - port->AddCandidateAddress(SocketAddress("::ffff:192.168.1.4", 1234)); - port->AddCandidateAddress(SocketAddress("::192.168.1.4", 1234)); - port->AddCandidateAddress(SocketAddress("2002::1234:5678", 1234)); - port->AddCandidateAddress(SocketAddress("2001::1234:5678", 1234)); - port->AddCandidateAddress(SocketAddress("fecf::1234:5678", 1234)); - port->AddCandidateAddress(SocketAddress("3ffe::1234:5678", 1234)); - // These should all be: - // (90 << 24) | ([rfc3484 pref value] << 8) | (256 - 177) - uint32 expected_priority_v4 = 1509957199U; - uint32 expected_priority_v6 = 1509959759U; - uint32 expected_priority_ula = 1509962319U; - uint32 expected_priority_v4mapped = expected_priority_v4; - uint32 expected_priority_v4compat = 1509949775U; - uint32 expected_priority_6to4 = 1509954639U; - uint32 expected_priority_teredo = 1509952079U; - uint32 expected_priority_sitelocal = 1509949775U; - uint32 expected_priority_6bone = 1509949775U; - ASSERT_EQ(expected_priority_v4, port->Candidates()[0].priority()); - ASSERT_EQ(expected_priority_v6, port->Candidates()[1].priority()); - ASSERT_EQ(expected_priority_ula, port->Candidates()[2].priority()); - ASSERT_EQ(expected_priority_v4mapped, port->Candidates()[3].priority()); - ASSERT_EQ(expected_priority_v4compat, port->Candidates()[4].priority()); - ASSERT_EQ(expected_priority_6to4, port->Candidates()[5].priority()); - ASSERT_EQ(expected_priority_teredo, port->Candidates()[6].priority()); - ASSERT_EQ(expected_priority_sitelocal, port->Candidates()[7].priority()); - ASSERT_EQ(expected_priority_6bone, port->Candidates()[8].priority()); -} - -TEST_F(PortTest, TestPortProxyProperties) { - rtc::scoped_ptr<TestPort> port( - CreateTestPort(kLocalAddr1, "name", "pass")); - port->SetIceRole(cricket::ICEROLE_CONTROLLING); - port->SetIceTiebreaker(kTiebreaker1); - - // Create a proxy port. - rtc::scoped_ptr<PortProxy> proxy(new PortProxy()); - proxy->set_impl(port.get()); - EXPECT_EQ(port->Type(), proxy->Type()); - EXPECT_EQ(port->Network(), proxy->Network()); - EXPECT_EQ(port->GetIceRole(), proxy->GetIceRole()); - EXPECT_EQ(port->IceTiebreaker(), proxy->IceTiebreaker()); -} - -// In the case of shared socket, one port may be shared by local and stun. -// Test that candidates with different types will have different foundation. -TEST_F(PortTest, TestFoundation) { - rtc::scoped_ptr<TestPort> testport( - CreateTestPort(kLocalAddr1, "name", "pass")); - testport->AddCandidateAddress(kLocalAddr1, kLocalAddr1, - LOCAL_PORT_TYPE, - cricket::ICE_TYPE_PREFERENCE_HOST, false); - testport->AddCandidateAddress(kLocalAddr2, kLocalAddr1, - STUN_PORT_TYPE, - cricket::ICE_TYPE_PREFERENCE_SRFLX, true); - EXPECT_NE(testport->Candidates()[0].foundation(), - testport->Candidates()[1].foundation()); -} - -// This test verifies the foundation of different types of ICE candidates. -TEST_F(PortTest, TestCandidateFoundation) { - rtc::scoped_ptr<rtc::NATServer> nat_server( - CreateNatServer(kNatAddr1, NAT_OPEN_CONE)); - rtc::scoped_ptr<UDPPort> udpport1(CreateUdpPort(kLocalAddr1)); - udpport1->PrepareAddress(); - rtc::scoped_ptr<UDPPort> udpport2(CreateUdpPort(kLocalAddr1)); - udpport2->PrepareAddress(); - EXPECT_EQ(udpport1->Candidates()[0].foundation(), - udpport2->Candidates()[0].foundation()); - rtc::scoped_ptr<TCPPort> tcpport1(CreateTcpPort(kLocalAddr1)); - tcpport1->PrepareAddress(); - rtc::scoped_ptr<TCPPort> tcpport2(CreateTcpPort(kLocalAddr1)); - tcpport2->PrepareAddress(); - EXPECT_EQ(tcpport1->Candidates()[0].foundation(), - tcpport2->Candidates()[0].foundation()); - rtc::scoped_ptr<Port> stunport( - CreateStunPort(kLocalAddr1, nat_socket_factory1())); - stunport->PrepareAddress(); - ASSERT_EQ_WAIT(1U, stunport->Candidates().size(), kTimeout); - EXPECT_NE(tcpport1->Candidates()[0].foundation(), - stunport->Candidates()[0].foundation()); - EXPECT_NE(tcpport2->Candidates()[0].foundation(), - stunport->Candidates()[0].foundation()); - EXPECT_NE(udpport1->Candidates()[0].foundation(), - stunport->Candidates()[0].foundation()); - EXPECT_NE(udpport2->Candidates()[0].foundation(), - stunport->Candidates()[0].foundation()); - // Verify GTURN candidate foundation. - rtc::scoped_ptr<RelayPort> relayport( - CreateGturnPort(kLocalAddr1)); - relayport->AddServerAddress( - cricket::ProtocolAddress(kRelayUdpIntAddr, cricket::PROTO_UDP)); - relayport->PrepareAddress(); - ASSERT_EQ_WAIT(1U, relayport->Candidates().size(), kTimeout); - EXPECT_NE(udpport1->Candidates()[0].foundation(), - relayport->Candidates()[0].foundation()); - EXPECT_NE(udpport2->Candidates()[0].foundation(), - relayport->Candidates()[0].foundation()); - // Verifying TURN candidate foundation. - rtc::scoped_ptr<Port> turnport1(CreateTurnPort( - kLocalAddr1, nat_socket_factory1(), PROTO_UDP, PROTO_UDP)); - turnport1->PrepareAddress(); - ASSERT_EQ_WAIT(1U, turnport1->Candidates().size(), kTimeout); - EXPECT_NE(udpport1->Candidates()[0].foundation(), - turnport1->Candidates()[0].foundation()); - EXPECT_NE(udpport2->Candidates()[0].foundation(), - turnport1->Candidates()[0].foundation()); - EXPECT_NE(stunport->Candidates()[0].foundation(), - turnport1->Candidates()[0].foundation()); - rtc::scoped_ptr<Port> turnport2(CreateTurnPort( - kLocalAddr1, nat_socket_factory1(), PROTO_UDP, PROTO_UDP)); - turnport2->PrepareAddress(); - ASSERT_EQ_WAIT(1U, turnport2->Candidates().size(), kTimeout); - EXPECT_EQ(turnport1->Candidates()[0].foundation(), - turnport2->Candidates()[0].foundation()); - - // Running a second turn server, to get different base IP address. - SocketAddress kTurnUdpIntAddr2("99.99.98.4", STUN_SERVER_PORT); - SocketAddress kTurnUdpExtAddr2("99.99.98.5", 0); - TestTurnServer turn_server2( - rtc::Thread::Current(), kTurnUdpIntAddr2, kTurnUdpExtAddr2); - rtc::scoped_ptr<Port> turnport3(CreateTurnPort( - kLocalAddr1, nat_socket_factory1(), PROTO_UDP, PROTO_UDP, - kTurnUdpIntAddr2)); - turnport3->PrepareAddress(); - ASSERT_EQ_WAIT(1U, turnport3->Candidates().size(), kTimeout); - EXPECT_NE(turnport3->Candidates()[0].foundation(), - turnport2->Candidates()[0].foundation()); -} - -// This test verifies the related addresses of different types of -// ICE candiates. -TEST_F(PortTest, TestCandidateRelatedAddress) { - rtc::scoped_ptr<rtc::NATServer> nat_server( - CreateNatServer(kNatAddr1, NAT_OPEN_CONE)); - rtc::scoped_ptr<UDPPort> udpport(CreateUdpPort(kLocalAddr1)); - udpport->PrepareAddress(); - // For UDPPort, related address will be empty. - EXPECT_TRUE(udpport->Candidates()[0].related_address().IsNil()); - // Testing related address for stun candidates. - // For stun candidate related address must be equal to the base - // socket address. - rtc::scoped_ptr<StunPort> stunport( - CreateStunPort(kLocalAddr1, nat_socket_factory1())); - stunport->PrepareAddress(); - ASSERT_EQ_WAIT(1U, stunport->Candidates().size(), kTimeout); - // Check STUN candidate address. - EXPECT_EQ(stunport->Candidates()[0].address().ipaddr(), - kNatAddr1.ipaddr()); - // Check STUN candidate related address. - EXPECT_EQ(stunport->Candidates()[0].related_address(), - stunport->GetLocalAddress()); - // Verifying the related address for the GTURN candidates. - // NOTE: In case of GTURN related address will be equal to the mapped - // address, but address(mapped) will not be XOR. - rtc::scoped_ptr<RelayPort> relayport( - CreateGturnPort(kLocalAddr1)); - relayport->AddServerAddress( - cricket::ProtocolAddress(kRelayUdpIntAddr, cricket::PROTO_UDP)); - relayport->PrepareAddress(); - ASSERT_EQ_WAIT(1U, relayport->Candidates().size(), kTimeout); - // For Gturn related address is set to "0.0.0.0:0" - EXPECT_EQ(rtc::SocketAddress(), - relayport->Candidates()[0].related_address()); - // Verifying the related address for TURN candidate. - // For TURN related address must be equal to the mapped address. - rtc::scoped_ptr<Port> turnport(CreateTurnPort( - kLocalAddr1, nat_socket_factory1(), PROTO_UDP, PROTO_UDP)); - turnport->PrepareAddress(); - ASSERT_EQ_WAIT(1U, turnport->Candidates().size(), kTimeout); - EXPECT_EQ(kTurnUdpExtAddr.ipaddr(), - turnport->Candidates()[0].address().ipaddr()); - EXPECT_EQ(kNatAddr1.ipaddr(), - turnport->Candidates()[0].related_address().ipaddr()); -} - -// Test priority value overflow handling when preference is set to 3. -TEST_F(PortTest, TestCandidatePreference) { - cricket::Candidate cand1; - cand1.set_preference(3); - cricket::Candidate cand2; - cand2.set_preference(1); - EXPECT_TRUE(cand1.preference() > cand2.preference()); -} - -// Test the Connection priority is calculated correctly. -TEST_F(PortTest, TestConnectionPriority) { - rtc::scoped_ptr<TestPort> lport( - CreateTestPort(kLocalAddr1, "lfrag", "lpass")); - lport->set_type_preference(cricket::ICE_TYPE_PREFERENCE_HOST); - rtc::scoped_ptr<TestPort> rport( - CreateTestPort(kLocalAddr2, "rfrag", "rpass")); - rport->set_type_preference(cricket::ICE_TYPE_PREFERENCE_RELAY); - lport->set_component(123); - lport->AddCandidateAddress(SocketAddress("192.168.1.4", 1234)); - rport->set_component(23); - rport->AddCandidateAddress(SocketAddress("10.1.1.100", 1234)); - - EXPECT_EQ(0x7E001E85U, lport->Candidates()[0].priority()); - EXPECT_EQ(0x2001EE9U, rport->Candidates()[0].priority()); - - // RFC 5245 - // pair priority = 2^32*MIN(G,D) + 2*MAX(G,D) + (G>D?1:0) - lport->SetIceRole(cricket::ICEROLE_CONTROLLING); - rport->SetIceRole(cricket::ICEROLE_CONTROLLED); - Connection* lconn = lport->CreateConnection( - rport->Candidates()[0], Port::ORIGIN_MESSAGE); -#if defined(WIN32) - EXPECT_EQ(0x2001EE9FC003D0BU, lconn->priority()); -#else - EXPECT_EQ(0x2001EE9FC003D0BLLU, lconn->priority()); -#endif - - lport->SetIceRole(cricket::ICEROLE_CONTROLLED); - rport->SetIceRole(cricket::ICEROLE_CONTROLLING); - Connection* rconn = rport->CreateConnection( - lport->Candidates()[0], Port::ORIGIN_MESSAGE); -#if defined(WIN32) - EXPECT_EQ(0x2001EE9FC003D0AU, rconn->priority()); -#else - EXPECT_EQ(0x2001EE9FC003D0ALLU, rconn->priority()); -#endif -} - -TEST_F(PortTest, TestWritableState) { - UDPPort* port1 = CreateUdpPort(kLocalAddr1); - UDPPort* port2 = CreateUdpPort(kLocalAddr2); - - // Set up channels. - TestChannel ch1(port1, port2); - TestChannel ch2(port2, port1); - - // Acquire addresses. - ch1.Start(); - ch2.Start(); - ASSERT_EQ_WAIT(1, ch1.complete_count(), kTimeout); - ASSERT_EQ_WAIT(1, ch2.complete_count(), kTimeout); - - // Send a ping from src to dst. - ch1.CreateConnection(); - ASSERT_TRUE(ch1.conn() != NULL); - EXPECT_EQ(Connection::STATE_WRITE_INIT, ch1.conn()->write_state()); - EXPECT_TRUE_WAIT(ch1.conn()->connected(), kTimeout); // for TCP connect - ch1.Ping(); - WAIT(!ch2.remote_address().IsNil(), kTimeout); - - // Data should be unsendable until the connection is accepted. - char data[] = "abcd"; - int data_size = ARRAY_SIZE(data); - rtc::PacketOptions options; - EXPECT_EQ(SOCKET_ERROR, ch1.conn()->Send(data, data_size, options)); - - // Accept the connection to return the binding response, transition to - // writable, and allow data to be sent. - ch2.AcceptConnection(); - EXPECT_EQ_WAIT(Connection::STATE_WRITABLE, ch1.conn()->write_state(), - kTimeout); - EXPECT_EQ(data_size, ch1.conn()->Send(data, data_size, options)); - - // Ask the connection to update state as if enough time has passed to lose - // full writability and 5 pings went unresponded to. We'll accomplish the - // latter by sending pings but not pumping messages. - for (uint32 i = 1; i <= CONNECTION_WRITE_CONNECT_FAILURES; ++i) { - ch1.Ping(i); - } - uint32 unreliable_timeout_delay = CONNECTION_WRITE_CONNECT_TIMEOUT + 500u; - ch1.conn()->UpdateState(unreliable_timeout_delay); - EXPECT_EQ(Connection::STATE_WRITE_UNRELIABLE, ch1.conn()->write_state()); - - // Data should be able to be sent in this state. - EXPECT_EQ(data_size, ch1.conn()->Send(data, data_size, options)); - - // And now allow the other side to process the pings and send binding - // responses. - EXPECT_EQ_WAIT(Connection::STATE_WRITABLE, ch1.conn()->write_state(), - kTimeout); - - // Wait long enough for a full timeout (past however long we've already - // waited). - for (uint32 i = 1; i <= CONNECTION_WRITE_CONNECT_FAILURES; ++i) { - ch1.Ping(unreliable_timeout_delay + i); - } - ch1.conn()->UpdateState(unreliable_timeout_delay + CONNECTION_WRITE_TIMEOUT + - 500u); - EXPECT_EQ(Connection::STATE_WRITE_TIMEOUT, ch1.conn()->write_state()); - - // Now that the connection has completely timed out, data send should fail. - EXPECT_EQ(SOCKET_ERROR, ch1.conn()->Send(data, data_size, options)); - - ch1.Stop(); - ch2.Stop(); -} - -TEST_F(PortTest, TestTimeoutForNeverWritable) { - UDPPort* port1 = CreateUdpPort(kLocalAddr1); - UDPPort* port2 = CreateUdpPort(kLocalAddr2); - - // Set up channels. - TestChannel ch1(port1, port2); - TestChannel ch2(port2, port1); - - // Acquire addresses. - ch1.Start(); - ch2.Start(); - - ch1.CreateConnection(); - ASSERT_TRUE(ch1.conn() != NULL); - EXPECT_EQ(Connection::STATE_WRITE_INIT, ch1.conn()->write_state()); - - // Attempt to go directly to write timeout. - for (uint32 i = 1; i <= CONNECTION_WRITE_CONNECT_FAILURES; ++i) { - ch1.Ping(i); - } - ch1.conn()->UpdateState(CONNECTION_WRITE_TIMEOUT + 500u); - EXPECT_EQ(Connection::STATE_WRITE_TIMEOUT, ch1.conn()->write_state()); -} - -// This test verifies the connection setup between ICEMODE_FULL -// and ICEMODE_LITE. -// In this test |ch1| behaves like FULL mode client and we have created -// port which responds to the ping message just like LITE client. -TEST_F(PortTest, TestIceLiteConnectivity) { - TestPort* ice_full_port = CreateTestPort( - kLocalAddr1, "lfrag", "lpass", cricket::ICEPROTO_RFC5245, - cricket::ICEROLE_CONTROLLING, kTiebreaker1); - - rtc::scoped_ptr<TestPort> ice_lite_port(CreateTestPort( - kLocalAddr2, "rfrag", "rpass", cricket::ICEPROTO_RFC5245, - cricket::ICEROLE_CONTROLLED, kTiebreaker2)); - // Setup TestChannel. This behaves like FULL mode client. - TestChannel ch1(ice_full_port, ice_lite_port.get()); - ch1.SetIceMode(ICEMODE_FULL); - - // Start gathering candidates. - ch1.Start(); - ice_lite_port->PrepareAddress(); - - ASSERT_EQ_WAIT(1, ch1.complete_count(), kTimeout); - ASSERT_FALSE(ice_lite_port->Candidates().empty()); - - ch1.CreateConnection(); - ASSERT_TRUE(ch1.conn() != NULL); - EXPECT_EQ(Connection::STATE_WRITE_INIT, ch1.conn()->write_state()); - - // Send ping from full mode client. - // This ping must not have USE_CANDIDATE_ATTR. - ch1.Ping(); - - // Verify stun ping is without USE_CANDIDATE_ATTR. Getting message directly - // from port. - ASSERT_TRUE_WAIT(ice_full_port->last_stun_msg() != NULL, 1000); - IceMessage* msg = ice_full_port->last_stun_msg(); - EXPECT_TRUE(msg->GetByteString(STUN_ATTR_USE_CANDIDATE) == NULL); - - // Respond with a BINDING-RESPONSE from litemode client. - // NOTE: Ideally we should't create connection at this stage from lite - // port, as it should be done only after receiving ping with USE_CANDIDATE. - // But we need a connection to send a response message. - ice_lite_port->CreateConnection( - ice_full_port->Candidates()[0], cricket::Port::ORIGIN_MESSAGE); - rtc::scoped_ptr<IceMessage> request(CopyStunMessage(msg)); - ice_lite_port->SendBindingResponse( - request.get(), ice_full_port->Candidates()[0].address()); - - // Feeding the respone message from litemode to the full mode connection. - ch1.conn()->OnReadPacket(ice_lite_port->last_stun_buf()->Data(), - ice_lite_port->last_stun_buf()->Length(), - rtc::PacketTime()); - // Verifying full mode connection becomes writable from the response. - EXPECT_EQ_WAIT(Connection::STATE_WRITABLE, ch1.conn()->write_state(), - kTimeout); - EXPECT_TRUE_WAIT(ch1.nominated(), kTimeout); - - // Clear existing stun messsages. Otherwise we will process old stun - // message right after we send ping. - ice_full_port->Reset(); - // Send ping. This must have USE_CANDIDATE_ATTR. - ch1.Ping(); - ASSERT_TRUE_WAIT(ice_full_port->last_stun_msg() != NULL, 1000); - msg = ice_full_port->last_stun_msg(); - EXPECT_TRUE(msg->GetByteString(STUN_ATTR_USE_CANDIDATE) != NULL); - ch1.Stop(); -} - -// This test case verifies that the CONTROLLING port does not time out. -TEST_F(PortTest, TestControllingNoTimeout) { - SetIceProtocolType(cricket::ICEPROTO_RFC5245); - UDPPort* port1 = CreateUdpPort(kLocalAddr1); - ConnectToSignalDestroyed(port1); - port1->set_timeout_delay(10); // milliseconds - port1->SetIceRole(cricket::ICEROLE_CONTROLLING); - port1->SetIceTiebreaker(kTiebreaker1); - - UDPPort* port2 = CreateUdpPort(kLocalAddr2); - port2->SetIceRole(cricket::ICEROLE_CONTROLLED); - port2->SetIceTiebreaker(kTiebreaker2); - - // Set up channels and ensure both ports will be deleted. - TestChannel ch1(port1, port2); - TestChannel ch2(port2, port1); - - // Simulate a connection that succeeds, and then is destroyed. - ConnectAndDisconnectChannels(&ch1, &ch2); - - // After the connection is destroyed, the port should not be destroyed. - rtc::Thread::Current()->ProcessMessages(kTimeout); - EXPECT_FALSE(destroyed()); -} - -// This test case verifies that the CONTROLLED port does time out, but only -// after connectivity is lost. -TEST_F(PortTest, TestControlledTimeout) { - SetIceProtocolType(cricket::ICEPROTO_RFC5245); - UDPPort* port1 = CreateUdpPort(kLocalAddr1); - port1->SetIceRole(cricket::ICEROLE_CONTROLLING); - port1->SetIceTiebreaker(kTiebreaker1); - - UDPPort* port2 = CreateUdpPort(kLocalAddr2); - ConnectToSignalDestroyed(port2); - port2->set_timeout_delay(10); // milliseconds - port2->SetIceRole(cricket::ICEROLE_CONTROLLED); - port2->SetIceTiebreaker(kTiebreaker2); - - // The connection must not be destroyed before a connection is attempted. - EXPECT_FALSE(destroyed()); - - port1->set_component(cricket::ICE_CANDIDATE_COMPONENT_DEFAULT); - port2->set_component(cricket::ICE_CANDIDATE_COMPONENT_DEFAULT); - - // Set up channels and ensure both ports will be deleted. - TestChannel ch1(port1, port2); - TestChannel ch2(port2, port1); - - // Simulate a connection that succeeds, and then is destroyed. - ConnectAndDisconnectChannels(&ch1, &ch2); - - // The controlled port should be destroyed after 10 milliseconds. - EXPECT_TRUE_WAIT(destroyed(), kTimeout); -} diff --git a/talk/p2p/base/portallocator.cc b/talk/p2p/base/portallocator.cc deleted file mode 100644 index 84fb34480..000000000 --- a/talk/p2p/base/portallocator.cc +++ /dev/null @@ -1,109 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "webrtc/p2p/base/portallocator.h" - -#include "webrtc/p2p/base/portallocatorsessionproxy.h" - -namespace cricket { - -PortAllocatorSession::PortAllocatorSession(const std::string& content_name, - int component, - const std::string& ice_ufrag, - const std::string& ice_pwd, - uint32 flags) - : content_name_(content_name), - component_(component), - flags_(flags), - generation_(0), - // If PORTALLOCATOR_ENABLE_SHARED_UFRAG flag is not enabled, ignore the - // incoming ufrag and pwd, which will cause each Port to generate one - // by itself. - username_(flags_ & PORTALLOCATOR_ENABLE_SHARED_UFRAG ? ice_ufrag : ""), - password_(flags_ & PORTALLOCATOR_ENABLE_SHARED_UFRAG ? ice_pwd : "") { -} - -PortAllocator::~PortAllocator() { - for (SessionMuxerMap::iterator iter = muxers_.begin(); - iter != muxers_.end(); ++iter) { - delete iter->second; - } -} - -PortAllocatorSession* PortAllocator::CreateSession( - const std::string& sid, - const std::string& content_name, - int component, - const std::string& ice_ufrag, - const std::string& ice_pwd) { - if (flags_ & PORTALLOCATOR_ENABLE_BUNDLE) { - // If we just use |sid| as key in identifying PortAllocatorSessionMuxer, - // ICE restart will not result in different candidates, as |sid| will - // be same. To yield different candiates we are using combination of - // |ice_ufrag| and |ice_pwd|. - // Ideally |ice_ufrag| and |ice_pwd| should change together, but - // there can be instances where only ice_pwd will be changed. - std::string key_str = ice_ufrag + ":" + ice_pwd; - PortAllocatorSessionMuxer* muxer = GetSessionMuxer(key_str); - if (!muxer) { - PortAllocatorSession* session_impl = CreateSessionInternal( - content_name, component, ice_ufrag, ice_pwd); - // Create PortAllocatorSessionMuxer object for |session_impl|. - muxer = new PortAllocatorSessionMuxer(session_impl); - muxer->SignalDestroyed.connect( - this, &PortAllocator::OnSessionMuxerDestroyed); - // Add PortAllocatorSession to the map. - muxers_[key_str] = muxer; - } - PortAllocatorSessionProxy* proxy = - new PortAllocatorSessionProxy(content_name, component, flags_); - muxer->RegisterSessionProxy(proxy); - return proxy; - } - return CreateSessionInternal(content_name, component, ice_ufrag, ice_pwd); -} - -PortAllocatorSessionMuxer* PortAllocator::GetSessionMuxer( - const std::string& key) const { - SessionMuxerMap::const_iterator iter = muxers_.find(key); - if (iter != muxers_.end()) - return iter->second; - return NULL; -} - -void PortAllocator::OnSessionMuxerDestroyed( - PortAllocatorSessionMuxer* session) { - SessionMuxerMap::iterator iter; - for (iter = muxers_.begin(); iter != muxers_.end(); ++iter) { - if (iter->second == session) - break; - } - if (iter != muxers_.end()) - muxers_.erase(iter); -} - -} // namespace cricket diff --git a/talk/p2p/base/portallocator.h b/talk/p2p/base/portallocator.h deleted file mode 100644 index 29a1b0e09..000000000 --- a/talk/p2p/base/portallocator.h +++ /dev/null @@ -1,209 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef WEBRTC_P2P_BASE_PORTALLOCATOR_H_ -#define WEBRTC_P2P_BASE_PORTALLOCATOR_H_ - -#include <string> -#include <vector> - -#include "webrtc/p2p/base/portinterface.h" -#include "webrtc/base/helpers.h" -#include "webrtc/base/proxyinfo.h" -#include "webrtc/base/sigslot.h" - -namespace cricket { - -// PortAllocator is responsible for allocating Port types for a given -// P2PSocket. It also handles port freeing. -// -// Clients can override this class to control port allocation, including -// what kinds of ports are allocated. - -enum { - PORTALLOCATOR_DISABLE_UDP = 0x01, - PORTALLOCATOR_DISABLE_STUN = 0x02, - PORTALLOCATOR_DISABLE_RELAY = 0x04, - PORTALLOCATOR_DISABLE_TCP = 0x08, - PORTALLOCATOR_ENABLE_SHAKER = 0x10, - PORTALLOCATOR_ENABLE_BUNDLE = 0x20, - PORTALLOCATOR_ENABLE_IPV6 = 0x40, - PORTALLOCATOR_ENABLE_SHARED_UFRAG = 0x80, - PORTALLOCATOR_ENABLE_SHARED_SOCKET = 0x100, - PORTALLOCATOR_ENABLE_STUN_RETRANSMIT_ATTRIBUTE = 0x200, -}; - -const uint32 kDefaultPortAllocatorFlags = 0; - -const uint32 kDefaultStepDelay = 1000; // 1 sec step delay. -// As per RFC 5245 Appendix B.1, STUN transactions need to be paced at certain -// internal. Less than 20ms is not acceptable. We choose 50ms as our default. -const uint32 kMinimumStepDelay = 50; - -// CF = CANDIDATE FILTER -enum { - CF_NONE = 0x0, - CF_HOST = 0x1, - CF_REFLEXIVE = 0x2, - CF_RELAY = 0x4, - CF_ALL = 0x7, -}; - -class PortAllocatorSessionMuxer; - -class PortAllocatorSession : public sigslot::has_slots<> { - public: - // Content name passed in mostly for logging and debugging. - // TODO(mallinath) - Change username and password to ice_ufrag and ice_pwd. - PortAllocatorSession(const std::string& content_name, - int component, - const std::string& username, - const std::string& password, - uint32 flags); - - // Subclasses should clean up any ports created. - virtual ~PortAllocatorSession() {} - - uint32 flags() const { return flags_; } - void set_flags(uint32 flags) { flags_ = flags; } - std::string content_name() const { return content_name_; } - int component() const { return component_; } - - // Starts gathering STUN and Relay configurations. - virtual void StartGettingPorts() = 0; - virtual void StopGettingPorts() = 0; - virtual bool IsGettingPorts() = 0; - - sigslot::signal2<PortAllocatorSession*, PortInterface*> SignalPortReady; - sigslot::signal2<PortAllocatorSession*, - const std::vector<Candidate>&> SignalCandidatesReady; - sigslot::signal1<PortAllocatorSession*> SignalCandidatesAllocationDone; - - virtual uint32 generation() { return generation_; } - virtual void set_generation(uint32 generation) { generation_ = generation; } - sigslot::signal1<PortAllocatorSession*> SignalDestroyed; - - protected: - const std::string& username() const { return username_; } - const std::string& password() const { return password_; } - - std::string content_name_; - int component_; - - private: - uint32 flags_; - uint32 generation_; - std::string username_; - std::string password_; -}; - -class PortAllocator : public sigslot::has_slots<> { - public: - PortAllocator() : - flags_(kDefaultPortAllocatorFlags), - min_port_(0), - max_port_(0), - step_delay_(kDefaultStepDelay), - allow_tcp_listen_(true), - candidate_filter_(CF_ALL) { - // This will allow us to have old behavior on non webrtc clients. - } - virtual ~PortAllocator(); - - PortAllocatorSession* CreateSession( - const std::string& sid, - const std::string& content_name, - int component, - const std::string& ice_ufrag, - const std::string& ice_pwd); - - PortAllocatorSessionMuxer* GetSessionMuxer(const std::string& key) const; - void OnSessionMuxerDestroyed(PortAllocatorSessionMuxer* session); - - uint32 flags() const { return flags_; } - void set_flags(uint32 flags) { flags_ = flags; } - - const std::string& user_agent() const { return agent_; } - const rtc::ProxyInfo& proxy() const { return proxy_; } - void set_proxy(const std::string& agent, const rtc::ProxyInfo& proxy) { - agent_ = agent; - proxy_ = proxy; - } - - // Gets/Sets the port range to use when choosing client ports. - int min_port() const { return min_port_; } - int max_port() const { return max_port_; } - bool SetPortRange(int min_port, int max_port) { - if (min_port > max_port) { - return false; - } - - min_port_ = min_port; - max_port_ = max_port; - return true; - } - - uint32 step_delay() const { return step_delay_; } - void set_step_delay(uint32 delay) { - step_delay_ = delay; - } - - bool allow_tcp_listen() const { return allow_tcp_listen_; } - void set_allow_tcp_listen(bool allow_tcp_listen) { - allow_tcp_listen_ = allow_tcp_listen; - } - - uint32 candidate_filter() { return candidate_filter_; } - bool set_candidate_filter(uint32 filter) { - // TODO(mallinath) - Do transition check? - candidate_filter_ = filter; - return true; - } - - protected: - virtual PortAllocatorSession* CreateSessionInternal( - const std::string& content_name, - int component, - const std::string& ice_ufrag, - const std::string& ice_pwd) = 0; - - typedef std::map<std::string, PortAllocatorSessionMuxer*> SessionMuxerMap; - - uint32 flags_; - std::string agent_; - rtc::ProxyInfo proxy_; - int min_port_; - int max_port_; - uint32 step_delay_; - SessionMuxerMap muxers_; - bool allow_tcp_listen_; - uint32 candidate_filter_; -}; - -} // namespace cricket - -#endif // WEBRTC_P2P_BASE_PORTALLOCATOR_H_ diff --git a/talk/p2p/base/portallocatorsessionproxy.cc b/talk/p2p/base/portallocatorsessionproxy.cc deleted file mode 100644 index 2801f26f0..000000000 --- a/talk/p2p/base/portallocatorsessionproxy.cc +++ /dev/null @@ -1,239 +0,0 @@ -/* - * libjingle - * Copyright 2004--2011, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "webrtc/p2p/base/portallocatorsessionproxy.h" - -#include "webrtc/p2p/base/portallocator.h" -#include "webrtc/p2p/base/portproxy.h" -#include "webrtc/base/thread.h" - -namespace cricket { - -enum { - MSG_SEND_ALLOCATION_DONE = 1, - MSG_SEND_ALLOCATED_PORTS, -}; - -typedef rtc::TypedMessageData<PortAllocatorSessionProxy*> ProxyObjData; - -PortAllocatorSessionMuxer::PortAllocatorSessionMuxer( - PortAllocatorSession* session) - : worker_thread_(rtc::Thread::Current()), - session_(session), - candidate_done_signal_received_(false) { - session_->SignalPortReady.connect( - this, &PortAllocatorSessionMuxer::OnPortReady); - session_->SignalCandidatesAllocationDone.connect( - this, &PortAllocatorSessionMuxer::OnCandidatesAllocationDone); -} - -PortAllocatorSessionMuxer::~PortAllocatorSessionMuxer() { - for (size_t i = 0; i < session_proxies_.size(); ++i) - delete session_proxies_[i]; - - SignalDestroyed(this); -} - -void PortAllocatorSessionMuxer::RegisterSessionProxy( - PortAllocatorSessionProxy* session_proxy) { - session_proxies_.push_back(session_proxy); - session_proxy->SignalDestroyed.connect( - this, &PortAllocatorSessionMuxer::OnSessionProxyDestroyed); - session_proxy->set_impl(session_.get()); - - // Populate new proxy session with the information available in the actual - // implementation. - if (!ports_.empty()) { - worker_thread_->Post( - this, MSG_SEND_ALLOCATED_PORTS, new ProxyObjData(session_proxy)); - } - - if (candidate_done_signal_received_) { - worker_thread_->Post( - this, MSG_SEND_ALLOCATION_DONE, new ProxyObjData(session_proxy)); - } -} - -void PortAllocatorSessionMuxer::OnCandidatesAllocationDone( - PortAllocatorSession* session) { - candidate_done_signal_received_ = true; -} - -void PortAllocatorSessionMuxer::OnPortReady(PortAllocatorSession* session, - PortInterface* port) { - ASSERT(session == session_.get()); - ports_.push_back(port); - port->SignalDestroyed.connect( - this, &PortAllocatorSessionMuxer::OnPortDestroyed); -} - -void PortAllocatorSessionMuxer::OnPortDestroyed(PortInterface* port) { - std::vector<PortInterface*>::iterator it = - std::find(ports_.begin(), ports_.end(), port); - if (it != ports_.end()) - ports_.erase(it); -} - -void PortAllocatorSessionMuxer::OnSessionProxyDestroyed( - PortAllocatorSession* proxy) { - - std::vector<PortAllocatorSessionProxy*>::iterator it = - std::find(session_proxies_.begin(), session_proxies_.end(), proxy); - if (it != session_proxies_.end()) { - session_proxies_.erase(it); - } - - if (session_proxies_.empty()) { - // Destroy PortAllocatorSession and its associated muxer object if all - // proxies belonging to this session are already destroyed. - delete this; - } -} - -void PortAllocatorSessionMuxer::OnMessage(rtc::Message *pmsg) { - ProxyObjData* proxy = static_cast<ProxyObjData*>(pmsg->pdata); - switch (pmsg->message_id) { - case MSG_SEND_ALLOCATION_DONE: - SendAllocationDone_w(proxy->data()); - delete proxy; - break; - case MSG_SEND_ALLOCATED_PORTS: - SendAllocatedPorts_w(proxy->data()); - delete proxy; - break; - default: - ASSERT(false); - break; - } -} - -void PortAllocatorSessionMuxer::SendAllocationDone_w( - PortAllocatorSessionProxy* proxy) { - std::vector<PortAllocatorSessionProxy*>::iterator iter = - std::find(session_proxies_.begin(), session_proxies_.end(), proxy); - if (iter != session_proxies_.end()) { - proxy->OnCandidatesAllocationDone(session_.get()); - } -} - -void PortAllocatorSessionMuxer::SendAllocatedPorts_w( - PortAllocatorSessionProxy* proxy) { - std::vector<PortAllocatorSessionProxy*>::iterator iter = - std::find(session_proxies_.begin(), session_proxies_.end(), proxy); - if (iter != session_proxies_.end()) { - for (size_t i = 0; i < ports_.size(); ++i) { - PortInterface* port = ports_[i]; - proxy->OnPortReady(session_.get(), port); - // If port already has candidates, send this to the clients of proxy - // session. This can happen if proxy is created later than the actual - // implementation. - if (!port->Candidates().empty()) { - proxy->OnCandidatesReady(session_.get(), port->Candidates()); - } - } - } -} - -PortAllocatorSessionProxy::~PortAllocatorSessionProxy() { - std::map<PortInterface*, PortProxy*>::iterator it; - for (it = proxy_ports_.begin(); it != proxy_ports_.end(); it++) - delete it->second; - - SignalDestroyed(this); -} - -void PortAllocatorSessionProxy::set_impl( - PortAllocatorSession* session) { - impl_ = session; - - impl_->SignalCandidatesReady.connect( - this, &PortAllocatorSessionProxy::OnCandidatesReady); - impl_->SignalPortReady.connect( - this, &PortAllocatorSessionProxy::OnPortReady); - impl_->SignalCandidatesAllocationDone.connect( - this, &PortAllocatorSessionProxy::OnCandidatesAllocationDone); -} - -void PortAllocatorSessionProxy::StartGettingPorts() { - ASSERT(impl_ != NULL); - // Since all proxies share a common PortAllocatorSession, this check will - // prohibit sending multiple STUN ping messages to the stun server, which - // is a problem on Chrome. GetInitialPorts() and StartGetAllPorts() called - // from the worker thread and are called together from TransportChannel, - // checking for IsGettingAllPorts() for GetInitialPorts() will not be a - // problem. - if (!impl_->IsGettingPorts()) { - impl_->StartGettingPorts(); - } -} - -void PortAllocatorSessionProxy::StopGettingPorts() { - ASSERT(impl_ != NULL); - if (impl_->IsGettingPorts()) { - impl_->StopGettingPorts(); - } -} - -bool PortAllocatorSessionProxy::IsGettingPorts() { - ASSERT(impl_ != NULL); - return impl_->IsGettingPorts(); -} - -void PortAllocatorSessionProxy::OnPortReady(PortAllocatorSession* session, - PortInterface* port) { - ASSERT(session == impl_); - - PortProxy* proxy_port = new PortProxy(); - proxy_port->set_impl(port); - proxy_ports_[port] = proxy_port; - SignalPortReady(this, proxy_port); -} - -void PortAllocatorSessionProxy::OnCandidatesReady( - PortAllocatorSession* session, - const std::vector<Candidate>& candidates) { - ASSERT(session == impl_); - - // Since all proxy sessions share a common PortAllocatorSession, - // all Candidates will have name associated with the common PAS. - // Change Candidate name with the PortAllocatorSessionProxy name. - std::vector<Candidate> our_candidates; - for (size_t i = 0; i < candidates.size(); ++i) { - Candidate new_local_candidate = candidates[i]; - new_local_candidate.set_component(component_); - our_candidates.push_back(new_local_candidate); - } - SignalCandidatesReady(this, our_candidates); -} - -void PortAllocatorSessionProxy::OnCandidatesAllocationDone( - PortAllocatorSession* session) { - ASSERT(session == impl_); - SignalCandidatesAllocationDone(this); -} - -} // namespace cricket diff --git a/talk/p2p/base/portallocatorsessionproxy.h b/talk/p2p/base/portallocatorsessionproxy.h deleted file mode 100644 index fdd5d02b6..000000000 --- a/talk/p2p/base/portallocatorsessionproxy.h +++ /dev/null @@ -1,123 +0,0 @@ -/* - * libjingle - * Copyright 2004--2011, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef WEBRTC_P2P_BASE_PORTALLOCATORSESSIONPROXY_H_ -#define WEBRTC_P2P_BASE_PORTALLOCATORSESSIONPROXY_H_ - -#include <string> - -#include "webrtc/p2p/base/candidate.h" -#include "webrtc/p2p/base/portallocator.h" - -namespace cricket { -class PortAllocator; -class PortAllocatorSessionProxy; -class PortProxy; - -// This class maintains the list of cricket::Port* objects. Ports will be -// deleted upon receiving SignalDestroyed signal. This class is used when -// PORTALLOCATOR_ENABLE_BUNDLE flag is set. - -class PortAllocatorSessionMuxer : public rtc::MessageHandler, - public sigslot::has_slots<> { - public: - explicit PortAllocatorSessionMuxer(PortAllocatorSession* session); - virtual ~PortAllocatorSessionMuxer(); - - void RegisterSessionProxy(PortAllocatorSessionProxy* session_proxy); - - void OnPortReady(PortAllocatorSession* session, PortInterface* port); - void OnPortDestroyed(PortInterface* port); - void OnCandidatesAllocationDone(PortAllocatorSession* session); - - const std::vector<PortInterface*>& ports() { return ports_; } - - sigslot::signal1<PortAllocatorSessionMuxer*> SignalDestroyed; - - private: - virtual void OnMessage(rtc::Message *pmsg); - void OnSessionProxyDestroyed(PortAllocatorSession* proxy); - void SendAllocationDone_w(PortAllocatorSessionProxy* proxy); - void SendAllocatedPorts_w(PortAllocatorSessionProxy* proxy); - - // Port will be deleted when SignalDestroyed received, otherwise delete - // happens when PortAllocatorSession dtor is called. - rtc::Thread* worker_thread_; - std::vector<PortInterface*> ports_; - rtc::scoped_ptr<PortAllocatorSession> session_; - std::vector<PortAllocatorSessionProxy*> session_proxies_; - bool candidate_done_signal_received_; -}; - -class PortAllocatorSessionProxy : public PortAllocatorSession { - public: - PortAllocatorSessionProxy(const std::string& content_name, - int component, - uint32 flags) - // Use empty string as the ufrag and pwd because the proxy always uses - // the ufrag and pwd from the underlying implementation. - : PortAllocatorSession(content_name, component, "", "", flags), - impl_(NULL) { - } - - virtual ~PortAllocatorSessionProxy(); - - PortAllocatorSession* impl() { return impl_; } - void set_impl(PortAllocatorSession* session); - - // Forwards call to the actual PortAllocatorSession. - virtual void StartGettingPorts(); - virtual void StopGettingPorts(); - virtual bool IsGettingPorts(); - - virtual void set_generation(uint32 generation) { - ASSERT(impl_ != NULL); - impl_->set_generation(generation); - } - - virtual uint32 generation() { - ASSERT(impl_ != NULL); - return impl_->generation(); - } - - private: - void OnPortReady(PortAllocatorSession* session, PortInterface* port); - void OnCandidatesReady(PortAllocatorSession* session, - const std::vector<Candidate>& candidates); - void OnPortDestroyed(PortInterface* port); - void OnCandidatesAllocationDone(PortAllocatorSession* session); - - // This is the actual PortAllocatorSession, owned by PortAllocator. - PortAllocatorSession* impl_; - std::map<PortInterface*, PortProxy*> proxy_ports_; - - friend class PortAllocatorSessionMuxer; -}; - -} // namespace cricket - -#endif // WEBRTC_P2P_BASE_PORTALLOCATORSESSIONPROXY_H_ diff --git a/talk/p2p/base/portallocatorsessionproxy_unittest.cc b/talk/p2p/base/portallocatorsessionproxy_unittest.cc deleted file mode 100644 index 30353ee70..000000000 --- a/talk/p2p/base/portallocatorsessionproxy_unittest.cc +++ /dev/null @@ -1,163 +0,0 @@ -/* - * libjingle - * Copyright 2012 Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <vector> - -#include "webrtc/p2p/base/basicpacketsocketfactory.h" -#include "webrtc/p2p/base/portallocatorsessionproxy.h" -#include "webrtc/p2p/client/basicportallocator.h" -#include "webrtc/p2p/client/fakeportallocator.h" -#include "webrtc/base/fakenetwork.h" -#include "webrtc/base/gunit.h" -#include "webrtc/base/thread.h" - -using cricket::Candidate; -using cricket::PortAllocatorSession; -using cricket::PortAllocatorSessionMuxer; -using cricket::PortAllocatorSessionProxy; - -// Based on ICE_UFRAG_LENGTH -static const char kIceUfrag0[] = "TESTICEUFRAG0000"; -// Based on ICE_PWD_LENGTH -static const char kIcePwd0[] = "TESTICEPWD00000000000000"; - -class TestSessionChannel : public sigslot::has_slots<> { - public: - explicit TestSessionChannel(PortAllocatorSessionProxy* proxy) - : proxy_session_(proxy), - candidates_count_(0), - allocation_complete_(false), - ports_count_(0) { - proxy_session_->SignalCandidatesAllocationDone.connect( - this, &TestSessionChannel::OnCandidatesAllocationDone); - proxy_session_->SignalCandidatesReady.connect( - this, &TestSessionChannel::OnCandidatesReady); - proxy_session_->SignalPortReady.connect( - this, &TestSessionChannel::OnPortReady); - } - virtual ~TestSessionChannel() { - delete proxy_session_; - } - void OnCandidatesReady(PortAllocatorSession* session, - const std::vector<Candidate>& candidates) { - EXPECT_EQ(proxy_session_, session); - candidates_count_ += static_cast<int>(candidates.size()); - } - void OnCandidatesAllocationDone(PortAllocatorSession* session) { - EXPECT_EQ(proxy_session_, session); - allocation_complete_ = true; - } - void OnPortReady(PortAllocatorSession* session, - cricket::PortInterface* port) { - EXPECT_EQ(proxy_session_, session); - ++ports_count_; - } - int candidates_count() { return candidates_count_; } - bool allocation_complete() { return allocation_complete_; } - int ports_count() { return ports_count_; } - - void StartGettingPorts() { - proxy_session_->StartGettingPorts(); - } - - void StopGettingPorts() { - proxy_session_->StopGettingPorts(); - } - - bool IsGettingPorts() { - return proxy_session_->IsGettingPorts(); - } - - private: - PortAllocatorSessionProxy* proxy_session_; - int candidates_count_; - bool allocation_complete_; - int ports_count_; -}; - -class PortAllocatorSessionProxyTest : public testing::Test { - public: - PortAllocatorSessionProxyTest() - : socket_factory_(rtc::Thread::Current()), - allocator_(rtc::Thread::Current(), NULL), - session_(new cricket::FakePortAllocatorSession( - rtc::Thread::Current(), &socket_factory_, - "test content", 1, - kIceUfrag0, kIcePwd0)), - session_muxer_(new PortAllocatorSessionMuxer(session_)) { - } - virtual ~PortAllocatorSessionProxyTest() {} - void RegisterSessionProxy(PortAllocatorSessionProxy* proxy) { - session_muxer_->RegisterSessionProxy(proxy); - } - - TestSessionChannel* CreateChannel() { - PortAllocatorSessionProxy* proxy = - new PortAllocatorSessionProxy("test content", 1, 0); - TestSessionChannel* channel = new TestSessionChannel(proxy); - session_muxer_->RegisterSessionProxy(proxy); - channel->StartGettingPorts(); - return channel; - } - - protected: - rtc::BasicPacketSocketFactory socket_factory_; - cricket::FakePortAllocator allocator_; - cricket::FakePortAllocatorSession* session_; - // Muxer object will be delete itself after all registered session proxies - // are deleted. - PortAllocatorSessionMuxer* session_muxer_; -}; - -TEST_F(PortAllocatorSessionProxyTest, TestBasic) { - TestSessionChannel* channel = CreateChannel(); - EXPECT_EQ_WAIT(1, channel->candidates_count(), 1000); - EXPECT_EQ(1, channel->ports_count()); - EXPECT_TRUE(channel->allocation_complete()); - delete channel; -} - -TEST_F(PortAllocatorSessionProxyTest, TestLateBinding) { - TestSessionChannel* channel1 = CreateChannel(); - EXPECT_EQ_WAIT(1, channel1->candidates_count(), 1000); - EXPECT_EQ(1, channel1->ports_count()); - EXPECT_TRUE(channel1->allocation_complete()); - EXPECT_EQ(1, session_->port_config_count()); - // Creating another PortAllocatorSessionProxy and it also should receive - // already happened events. - PortAllocatorSessionProxy* proxy = - new PortAllocatorSessionProxy("test content", 2, 0); - TestSessionChannel* channel2 = new TestSessionChannel(proxy); - session_muxer_->RegisterSessionProxy(proxy); - EXPECT_TRUE(channel2->IsGettingPorts()); - EXPECT_EQ_WAIT(1, channel2->candidates_count(), 1000); - EXPECT_EQ(1, channel2->ports_count()); - EXPECT_TRUE_WAIT(channel2->allocation_complete(), 1000); - EXPECT_EQ(1, session_->port_config_count()); - delete channel1; - delete channel2; -} diff --git a/talk/p2p/base/portinterface.h b/talk/p2p/base/portinterface.h deleted file mode 100644 index d53dc2e8e..000000000 --- a/talk/p2p/base/portinterface.h +++ /dev/null @@ -1,143 +0,0 @@ -/* - * libjingle - * Copyright 2012, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef WEBRTC_P2P_BASE_PORTINTERFACE_H_ -#define WEBRTC_P2P_BASE_PORTINTERFACE_H_ - -#include <string> - -#include "webrtc/p2p/base/transport.h" -#include "webrtc/base/socketaddress.h" - -namespace rtc { -class Network; -struct PacketOptions; -} - -namespace cricket { -class Connection; -class IceMessage; -class StunMessage; - -enum ProtocolType { - PROTO_UDP, - PROTO_TCP, - PROTO_SSLTCP, - PROTO_LAST = PROTO_SSLTCP -}; - -// Defines the interface for a port, which represents a local communication -// mechanism that can be used to create connections to similar mechanisms of -// the other client. Various types of ports will implement this interface. -class PortInterface { - public: - virtual ~PortInterface() {} - - virtual const std::string& Type() const = 0; - virtual rtc::Network* Network() const = 0; - - virtual void SetIceProtocolType(IceProtocolType protocol) = 0; - virtual IceProtocolType IceProtocol() const = 0; - - // Methods to set/get ICE role and tiebreaker values. - virtual void SetIceRole(IceRole role) = 0; - virtual IceRole GetIceRole() const = 0; - - virtual void SetIceTiebreaker(uint64 tiebreaker) = 0; - virtual uint64 IceTiebreaker() const = 0; - - virtual bool SharedSocket() const = 0; - - // PrepareAddress will attempt to get an address for this port that other - // clients can send to. It may take some time before the address is ready. - // Once it is ready, we will send SignalAddressReady. If errors are - // preventing the port from getting an address, it may send - // SignalAddressError. - virtual void PrepareAddress() = 0; - - // Returns the connection to the given address or NULL if none exists. - virtual Connection* GetConnection( - const rtc::SocketAddress& remote_addr) = 0; - - // Creates a new connection to the given address. - enum CandidateOrigin { ORIGIN_THIS_PORT, ORIGIN_OTHER_PORT, ORIGIN_MESSAGE }; - virtual Connection* CreateConnection( - const Candidate& remote_candidate, CandidateOrigin origin) = 0; - - // Functions on the underlying socket(s). - virtual int SetOption(rtc::Socket::Option opt, int value) = 0; - virtual int GetOption(rtc::Socket::Option opt, int* value) = 0; - virtual int GetError() = 0; - - virtual const std::vector<Candidate>& Candidates() const = 0; - - // Sends the given packet to the given address, provided that the address is - // that of a connection or an address that has sent to us already. - virtual int SendTo(const void* data, size_t size, - const rtc::SocketAddress& addr, - const rtc::PacketOptions& options, bool payload) = 0; - - // Indicates that we received a successful STUN binding request from an - // address that doesn't correspond to any current connection. To turn this - // into a real connection, call CreateConnection. - sigslot::signal6<PortInterface*, const rtc::SocketAddress&, - ProtocolType, IceMessage*, const std::string&, - bool> SignalUnknownAddress; - - // Sends a response message (normal or error) to the given request. One of - // these methods should be called as a response to SignalUnknownAddress. - // NOTE: You MUST call CreateConnection BEFORE SendBindingResponse. - virtual void SendBindingResponse(StunMessage* request, - const rtc::SocketAddress& addr) = 0; - virtual void SendBindingErrorResponse( - StunMessage* request, const rtc::SocketAddress& addr, - int error_code, const std::string& reason) = 0; - - // Signaled when this port decides to delete itself because it no longer has - // any usefulness. - sigslot::signal1<PortInterface*> SignalDestroyed; - - // Signaled when Port discovers ice role conflict with the peer. - sigslot::signal1<PortInterface*> SignalRoleConflict; - - // Normally, packets arrive through a connection (or they result signaling of - // unknown address). Calling this method turns off delivery of packets - // through their respective connection and instead delivers every packet - // through this port. - virtual void EnablePortPackets() = 0; - sigslot::signal4<PortInterface*, const char*, size_t, - const rtc::SocketAddress&> SignalReadPacket; - - virtual std::string ToString() const = 0; - - protected: - PortInterface() {} -}; - -} // namespace cricket - -#endif // WEBRTC_P2P_BASE_PORTINTERFACE_H_ diff --git a/talk/p2p/base/portproxy.cc b/talk/p2p/base/portproxy.cc deleted file mode 100644 index 5a5d1ff8a..000000000 --- a/talk/p2p/base/portproxy.cc +++ /dev/null @@ -1,180 +0,0 @@ -/* - * libjingle - * Copyright 2004--2011, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "webrtc/p2p/base/portproxy.h" - -namespace cricket { - -void PortProxy::set_impl(PortInterface* port) { - impl_ = port; - impl_->SignalUnknownAddress.connect( - this, &PortProxy::OnUnknownAddress); - impl_->SignalDestroyed.connect(this, &PortProxy::OnPortDestroyed); - impl_->SignalRoleConflict.connect(this, &PortProxy::OnRoleConflict); -} - -const std::string& PortProxy::Type() const { - ASSERT(impl_ != NULL); - return impl_->Type(); -} - -rtc::Network* PortProxy::Network() const { - ASSERT(impl_ != NULL); - return impl_->Network(); -} - -void PortProxy::SetIceProtocolType(IceProtocolType protocol) { - ASSERT(impl_ != NULL); - impl_->SetIceProtocolType(protocol); -} - -IceProtocolType PortProxy::IceProtocol() const { - ASSERT(impl_ != NULL); - return impl_->IceProtocol(); -} - -// Methods to set/get ICE role and tiebreaker values. -void PortProxy::SetIceRole(IceRole role) { - ASSERT(impl_ != NULL); - impl_->SetIceRole(role); -} - -IceRole PortProxy::GetIceRole() const { - ASSERT(impl_ != NULL); - return impl_->GetIceRole(); -} - -void PortProxy::SetIceTiebreaker(uint64 tiebreaker) { - ASSERT(impl_ != NULL); - impl_->SetIceTiebreaker(tiebreaker); -} - -uint64 PortProxy::IceTiebreaker() const { - ASSERT(impl_ != NULL); - return impl_->IceTiebreaker(); -} - -bool PortProxy::SharedSocket() const { - ASSERT(impl_ != NULL); - return impl_->SharedSocket(); -} - -void PortProxy::PrepareAddress() { - ASSERT(impl_ != NULL); - impl_->PrepareAddress(); -} - -Connection* PortProxy::CreateConnection(const Candidate& remote_candidate, - CandidateOrigin origin) { - ASSERT(impl_ != NULL); - return impl_->CreateConnection(remote_candidate, origin); -} - -int PortProxy::SendTo(const void* data, - size_t size, - const rtc::SocketAddress& addr, - const rtc::PacketOptions& options, - bool payload) { - ASSERT(impl_ != NULL); - return impl_->SendTo(data, size, addr, options, payload); -} - -int PortProxy::SetOption(rtc::Socket::Option opt, - int value) { - ASSERT(impl_ != NULL); - return impl_->SetOption(opt, value); -} - -int PortProxy::GetOption(rtc::Socket::Option opt, - int* value) { - ASSERT(impl_ != NULL); - return impl_->GetOption(opt, value); -} - -int PortProxy::GetError() { - ASSERT(impl_ != NULL); - return impl_->GetError(); -} - -const std::vector<Candidate>& PortProxy::Candidates() const { - ASSERT(impl_ != NULL); - return impl_->Candidates(); -} - -void PortProxy::SendBindingResponse( - StunMessage* request, const rtc::SocketAddress& addr) { - ASSERT(impl_ != NULL); - impl_->SendBindingResponse(request, addr); -} - -Connection* PortProxy::GetConnection( - const rtc::SocketAddress& remote_addr) { - ASSERT(impl_ != NULL); - return impl_->GetConnection(remote_addr); -} - -void PortProxy::SendBindingErrorResponse( - StunMessage* request, const rtc::SocketAddress& addr, - int error_code, const std::string& reason) { - ASSERT(impl_ != NULL); - impl_->SendBindingErrorResponse(request, addr, error_code, reason); -} - -void PortProxy::EnablePortPackets() { - ASSERT(impl_ != NULL); - impl_->EnablePortPackets(); -} - -std::string PortProxy::ToString() const { - ASSERT(impl_ != NULL); - return impl_->ToString(); -} - -void PortProxy::OnUnknownAddress( - PortInterface *port, - const rtc::SocketAddress &addr, - ProtocolType proto, - IceMessage *stun_msg, - const std::string &remote_username, - bool port_muxed) { - ASSERT(port == impl_); - ASSERT(!port_muxed); - SignalUnknownAddress(this, addr, proto, stun_msg, remote_username, true); -} - -void PortProxy::OnRoleConflict(PortInterface* port) { - ASSERT(port == impl_); - SignalRoleConflict(this); -} - -void PortProxy::OnPortDestroyed(PortInterface* port) { - ASSERT(port == impl_); - // |port| will be destroyed in PortAllocatorSessionMuxer. - SignalDestroyed(this); -} - -} // namespace cricket diff --git a/talk/p2p/base/portproxy.h b/talk/p2p/base/portproxy.h deleted file mode 100644 index 6f79318f1..000000000 --- a/talk/p2p/base/portproxy.h +++ /dev/null @@ -1,104 +0,0 @@ -/* - * libjingle - * Copyright 2004--2011, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef WEBRTC_P2P_BASE_PORTPROXY_H_ -#define WEBRTC_P2P_BASE_PORTPROXY_H_ - -#include "webrtc/p2p/base/portinterface.h" -#include "webrtc/base/sigslot.h" - -namespace rtc { -class Network; -} - -namespace cricket { - -class PortProxy : public PortInterface, public sigslot::has_slots<> { - public: - PortProxy() {} - virtual ~PortProxy() {} - - PortInterface* impl() { return impl_; } - void set_impl(PortInterface* port); - - virtual const std::string& Type() const; - virtual rtc::Network* Network() const; - - virtual void SetIceProtocolType(IceProtocolType protocol); - virtual IceProtocolType IceProtocol() const; - - // Methods to set/get ICE role and tiebreaker values. - virtual void SetIceRole(IceRole role); - virtual IceRole GetIceRole() const; - - virtual void SetIceTiebreaker(uint64 tiebreaker); - virtual uint64 IceTiebreaker() const; - - virtual bool SharedSocket() const; - - // Forwards call to the actual Port. - virtual void PrepareAddress(); - virtual Connection* CreateConnection(const Candidate& remote_candidate, - CandidateOrigin origin); - virtual Connection* GetConnection( - const rtc::SocketAddress& remote_addr); - - virtual int SendTo(const void* data, size_t size, - const rtc::SocketAddress& addr, - const rtc::PacketOptions& options, - bool payload); - virtual int SetOption(rtc::Socket::Option opt, int value); - virtual int GetOption(rtc::Socket::Option opt, int* value); - virtual int GetError(); - - virtual const std::vector<Candidate>& Candidates() const; - - virtual void SendBindingResponse(StunMessage* request, - const rtc::SocketAddress& addr); - virtual void SendBindingErrorResponse( - StunMessage* request, const rtc::SocketAddress& addr, - int error_code, const std::string& reason); - - virtual void EnablePortPackets(); - virtual std::string ToString() const; - - private: - void OnUnknownAddress(PortInterface *port, - const rtc::SocketAddress &addr, - ProtocolType proto, - IceMessage *stun_msg, - const std::string &remote_username, - bool port_muxed); - void OnRoleConflict(PortInterface* port); - void OnPortDestroyed(PortInterface* port); - - PortInterface* impl_; -}; - -} // namespace cricket - -#endif // WEBRTC_P2P_BASE_PORTPROXY_H_ diff --git a/talk/p2p/base/pseudotcp.cc b/talk/p2p/base/pseudotcp.cc deleted file mode 100644 index a82cd677d..000000000 --- a/talk/p2p/base/pseudotcp.cc +++ /dev/null @@ -1,1291 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "webrtc/p2p/base/pseudotcp.h" - -#include <stdio.h> -#include <stdlib.h> - -#include <set> - -#include "webrtc/base/basictypes.h" -#include "webrtc/base/bytebuffer.h" -#include "webrtc/base/byteorder.h" -#include "webrtc/base/common.h" -#include "webrtc/base/logging.h" -#include "webrtc/base/scoped_ptr.h" -#include "webrtc/base/socket.h" -#include "webrtc/base/stringutils.h" -#include "webrtc/base/timeutils.h" - -// The following logging is for detailed (packet-level) analysis only. -#define _DBG_NONE 0 -#define _DBG_NORMAL 1 -#define _DBG_VERBOSE 2 -#define _DEBUGMSG _DBG_NONE - -namespace cricket { - -////////////////////////////////////////////////////////////////////// -// Network Constants -////////////////////////////////////////////////////////////////////// - -// Standard MTUs -const uint16 PACKET_MAXIMUMS[] = { - 65535, // Theoretical maximum, Hyperchannel - 32000, // Nothing - 17914, // 16Mb IBM Token Ring - 8166, // IEEE 802.4 - //4464, // IEEE 802.5 (4Mb max) - 4352, // FDDI - //2048, // Wideband Network - 2002, // IEEE 802.5 (4Mb recommended) - //1536, // Expermental Ethernet Networks - //1500, // Ethernet, Point-to-Point (default) - 1492, // IEEE 802.3 - 1006, // SLIP, ARPANET - //576, // X.25 Networks - //544, // DEC IP Portal - //512, // NETBIOS - 508, // IEEE 802/Source-Rt Bridge, ARCNET - 296, // Point-to-Point (low delay) - //68, // Official minimum - 0, // End of list marker -}; - -const uint32 MAX_PACKET = 65535; -// Note: we removed lowest level because packet overhead was larger! -const uint32 MIN_PACKET = 296; - -const uint32 IP_HEADER_SIZE = 20; // (+ up to 40 bytes of options?) -const uint32 UDP_HEADER_SIZE = 8; -// TODO: Make JINGLE_HEADER_SIZE transparent to this code? -const uint32 JINGLE_HEADER_SIZE = 64; // when relay framing is in use - -// Default size for receive and send buffer. -const uint32 DEFAULT_RCV_BUF_SIZE = 60 * 1024; -const uint32 DEFAULT_SND_BUF_SIZE = 90 * 1024; - -////////////////////////////////////////////////////////////////////// -// Global Constants and Functions -////////////////////////////////////////////////////////////////////// -// -// 0 1 2 3 -// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// 0 | Conversation Number | -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// 4 | Sequence Number | -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// 8 | Acknowledgment Number | -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// | | |U|A|P|R|S|F| | -// 12 | Control | |R|C|S|S|Y|I| Window | -// | | |G|K|H|T|N|N| | -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// 16 | Timestamp sending | -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// 20 | Timestamp receiving | -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// 24 | data | -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// -////////////////////////////////////////////////////////////////////// - -#define PSEUDO_KEEPALIVE 0 - -const uint32 HEADER_SIZE = 24; -const uint32 PACKET_OVERHEAD = HEADER_SIZE + UDP_HEADER_SIZE + IP_HEADER_SIZE + JINGLE_HEADER_SIZE; - -const uint32 MIN_RTO = 250; // 250 ms (RFC1122, Sec 4.2.3.1 "fractions of a second") -const uint32 DEF_RTO = 3000; // 3 seconds (RFC1122, Sec 4.2.3.1) -const uint32 MAX_RTO = 60000; // 60 seconds -const uint32 DEF_ACK_DELAY = 100; // 100 milliseconds - -const uint8 FLAG_CTL = 0x02; -const uint8 FLAG_RST = 0x04; - -const uint8 CTL_CONNECT = 0; - -// TCP options. -const uint8 TCP_OPT_EOL = 0; // End of list. -const uint8 TCP_OPT_NOOP = 1; // No-op. -const uint8 TCP_OPT_MSS = 2; // Maximum segment size. -const uint8 TCP_OPT_WND_SCALE = 3; // Window scale factor. - -const long DEFAULT_TIMEOUT = 4000; // If there are no pending clocks, wake up every 4 seconds -const long CLOSED_TIMEOUT = 60 * 1000; // If the connection is closed, once per minute - -#if PSEUDO_KEEPALIVE -// !?! Rethink these times -const uint32 IDLE_PING = 20 * 1000; // 20 seconds (note: WinXP SP2 firewall udp timeout is 90 seconds) -const uint32 IDLE_TIMEOUT = 90 * 1000; // 90 seconds; -#endif // PSEUDO_KEEPALIVE - -////////////////////////////////////////////////////////////////////// -// Helper Functions -////////////////////////////////////////////////////////////////////// - -inline void long_to_bytes(uint32 val, void* buf) { - *static_cast<uint32*>(buf) = rtc::HostToNetwork32(val); -} - -inline void short_to_bytes(uint16 val, void* buf) { - *static_cast<uint16*>(buf) = rtc::HostToNetwork16(val); -} - -inline uint32 bytes_to_long(const void* buf) { - return rtc::NetworkToHost32(*static_cast<const uint32*>(buf)); -} - -inline uint16 bytes_to_short(const void* buf) { - return rtc::NetworkToHost16(*static_cast<const uint16*>(buf)); -} - -uint32 bound(uint32 lower, uint32 middle, uint32 upper) { - return rtc::_min(rtc::_max(lower, middle), upper); -} - -////////////////////////////////////////////////////////////////////// -// Debugging Statistics -////////////////////////////////////////////////////////////////////// - -#if 0 // Not used yet - -enum Stat { - S_SENT_PACKET, // All packet sends - S_RESENT_PACKET, // All packet sends that are retransmits - S_RECV_PACKET, // All packet receives - S_RECV_NEW, // All packet receives that are too new - S_RECV_OLD, // All packet receives that are too old - S_NUM_STATS -}; - -const char* const STAT_NAMES[S_NUM_STATS] = { - "snt", - "snt-r", - "rcv" - "rcv-n", - "rcv-o" -}; - -int g_stats[S_NUM_STATS]; -inline void Incr(Stat s) { ++g_stats[s]; } -void ReportStats() { - char buffer[256]; - size_t len = 0; - for (int i = 0; i < S_NUM_STATS; ++i) { - len += rtc::sprintfn(buffer, ARRAY_SIZE(buffer), "%s%s:%d", - (i == 0) ? "" : ",", STAT_NAMES[i], g_stats[i]); - g_stats[i] = 0; - } - LOG(LS_INFO) << "Stats[" << buffer << "]"; -} - -#endif - -////////////////////////////////////////////////////////////////////// -// PseudoTcp -////////////////////////////////////////////////////////////////////// - -uint32 PseudoTcp::Now() { -#if 0 // Use this to synchronize timers with logging timestamps (easier debug) - return rtc::TimeSince(StartTime()); -#else - return rtc::Time(); -#endif -} - -PseudoTcp::PseudoTcp(IPseudoTcpNotify* notify, uint32 conv) - : m_notify(notify), - m_shutdown(SD_NONE), - m_error(0), - m_rbuf_len(DEFAULT_RCV_BUF_SIZE), - m_rbuf(m_rbuf_len), - m_sbuf_len(DEFAULT_SND_BUF_SIZE), - m_sbuf(m_sbuf_len) { - - // Sanity check on buffer sizes (needed for OnTcpWriteable notification logic) - ASSERT(m_rbuf_len + MIN_PACKET < m_sbuf_len); - - uint32 now = Now(); - - m_state = TCP_LISTEN; - m_conv = conv; - m_rcv_wnd = m_rbuf_len; - m_rwnd_scale = m_swnd_scale = 0; - m_snd_nxt = 0; - m_snd_wnd = 1; - m_snd_una = m_rcv_nxt = 0; - m_bReadEnable = true; - m_bWriteEnable = false; - m_t_ack = 0; - - m_msslevel = 0; - m_largest = 0; - ASSERT(MIN_PACKET > PACKET_OVERHEAD); - m_mss = MIN_PACKET - PACKET_OVERHEAD; - m_mtu_advise = MAX_PACKET; - - m_rto_base = 0; - - m_cwnd = 2 * m_mss; - m_ssthresh = m_rbuf_len; - m_lastrecv = m_lastsend = m_lasttraffic = now; - m_bOutgoing = false; - - m_dup_acks = 0; - m_recover = 0; - - m_ts_recent = m_ts_lastack = 0; - - m_rx_rto = DEF_RTO; - m_rx_srtt = m_rx_rttvar = 0; - - m_use_nagling = true; - m_ack_delay = DEF_ACK_DELAY; - m_support_wnd_scale = true; -} - -PseudoTcp::~PseudoTcp() { -} - -int PseudoTcp::Connect() { - if (m_state != TCP_LISTEN) { - m_error = EINVAL; - return -1; - } - - m_state = TCP_SYN_SENT; - LOG(LS_INFO) << "State: TCP_SYN_SENT"; - - queueConnectMessage(); - attemptSend(); - - return 0; -} - -void PseudoTcp::NotifyMTU(uint16 mtu) { - m_mtu_advise = mtu; - if (m_state == TCP_ESTABLISHED) { - adjustMTU(); - } -} - -void PseudoTcp::NotifyClock(uint32 now) { - if (m_state == TCP_CLOSED) - return; - - // Check if it's time to retransmit a segment - if (m_rto_base && (rtc::TimeDiff(m_rto_base + m_rx_rto, now) <= 0)) { - if (m_slist.empty()) { - ASSERT(false); - } else { - // Note: (m_slist.front().xmit == 0)) { - // retransmit segments -#if _DEBUGMSG >= _DBG_NORMAL - LOG(LS_INFO) << "timeout retransmit (rto: " << m_rx_rto - << ") (rto_base: " << m_rto_base - << ") (now: " << now - << ") (dup_acks: " << static_cast<unsigned>(m_dup_acks) - << ")"; -#endif // _DEBUGMSG - if (!transmit(m_slist.begin(), now)) { - closedown(ECONNABORTED); - return; - } - - uint32 nInFlight = m_snd_nxt - m_snd_una; - m_ssthresh = rtc::_max(nInFlight / 2, 2 * m_mss); - //LOG(LS_INFO) << "m_ssthresh: " << m_ssthresh << " nInFlight: " << nInFlight << " m_mss: " << m_mss; - m_cwnd = m_mss; - - // Back off retransmit timer. Note: the limit is lower when connecting. - uint32 rto_limit = (m_state < TCP_ESTABLISHED) ? DEF_RTO : MAX_RTO; - m_rx_rto = rtc::_min(rto_limit, m_rx_rto * 2); - m_rto_base = now; - } - } - - // Check if it's time to probe closed windows - if ((m_snd_wnd == 0) - && (rtc::TimeDiff(m_lastsend + m_rx_rto, now) <= 0)) { - if (rtc::TimeDiff(now, m_lastrecv) >= 15000) { - closedown(ECONNABORTED); - return; - } - - // probe the window - packet(m_snd_nxt - 1, 0, 0, 0); - m_lastsend = now; - - // back off retransmit timer - m_rx_rto = rtc::_min(MAX_RTO, m_rx_rto * 2); - } - - // Check if it's time to send delayed acks - if (m_t_ack && (rtc::TimeDiff(m_t_ack + m_ack_delay, now) <= 0)) { - packet(m_snd_nxt, 0, 0, 0); - } - -#if PSEUDO_KEEPALIVE - // Check for idle timeout - if ((m_state == TCP_ESTABLISHED) && (TimeDiff(m_lastrecv + IDLE_TIMEOUT, now) <= 0)) { - closedown(ECONNABORTED); - return; - } - - // Check for ping timeout (to keep udp mapping open) - if ((m_state == TCP_ESTABLISHED) && (TimeDiff(m_lasttraffic + (m_bOutgoing ? IDLE_PING * 3/2 : IDLE_PING), now) <= 0)) { - packet(m_snd_nxt, 0, 0, 0); - } -#endif // PSEUDO_KEEPALIVE -} - -bool PseudoTcp::NotifyPacket(const char* buffer, size_t len) { - if (len > MAX_PACKET) { - LOG_F(WARNING) << "packet too large"; - return false; - } - return parse(reinterpret_cast<const uint8 *>(buffer), uint32(len)); -} - -bool PseudoTcp::GetNextClock(uint32 now, long& timeout) { - return clock_check(now, timeout); -} - -void PseudoTcp::GetOption(Option opt, int* value) { - if (opt == OPT_NODELAY) { - *value = m_use_nagling ? 0 : 1; - } else if (opt == OPT_ACKDELAY) { - *value = m_ack_delay; - } else if (opt == OPT_SNDBUF) { - *value = m_sbuf_len; - } else if (opt == OPT_RCVBUF) { - *value = m_rbuf_len; - } else { - ASSERT(false); - } -} -void PseudoTcp::SetOption(Option opt, int value) { - if (opt == OPT_NODELAY) { - m_use_nagling = value == 0; - } else if (opt == OPT_ACKDELAY) { - m_ack_delay = value; - } else if (opt == OPT_SNDBUF) { - ASSERT(m_state == TCP_LISTEN); - resizeSendBuffer(value); - } else if (opt == OPT_RCVBUF) { - ASSERT(m_state == TCP_LISTEN); - resizeReceiveBuffer(value); - } else { - ASSERT(false); - } -} - -uint32 PseudoTcp::GetCongestionWindow() const { - return m_cwnd; -} - -uint32 PseudoTcp::GetBytesInFlight() const { - return m_snd_nxt - m_snd_una; -} - -uint32 PseudoTcp::GetBytesBufferedNotSent() const { - size_t buffered_bytes = 0; - m_sbuf.GetBuffered(&buffered_bytes); - return static_cast<uint32>(m_snd_una + buffered_bytes - m_snd_nxt); -} - -uint32 PseudoTcp::GetRoundTripTimeEstimateMs() const { - return m_rx_srtt; -} - -// -// IPStream Implementation -// - -int PseudoTcp::Recv(char* buffer, size_t len) { - if (m_state != TCP_ESTABLISHED) { - m_error = ENOTCONN; - return SOCKET_ERROR; - } - - size_t read = 0; - rtc::StreamResult result = m_rbuf.Read(buffer, len, &read, NULL); - - // If there's no data in |m_rbuf|. - if (result == rtc::SR_BLOCK) { - m_bReadEnable = true; - m_error = EWOULDBLOCK; - return SOCKET_ERROR; - } - ASSERT(result == rtc::SR_SUCCESS); - - size_t available_space = 0; - m_rbuf.GetWriteRemaining(&available_space); - - if (uint32(available_space) - m_rcv_wnd >= - rtc::_min<uint32>(m_rbuf_len / 2, m_mss)) { - // TODO(jbeda): !?! Not sure about this was closed business - bool bWasClosed = (m_rcv_wnd == 0); - m_rcv_wnd = static_cast<uint32>(available_space); - - if (bWasClosed) { - attemptSend(sfImmediateAck); - } - } - - return static_cast<int>(read); -} - -int PseudoTcp::Send(const char* buffer, size_t len) { - if (m_state != TCP_ESTABLISHED) { - m_error = ENOTCONN; - return SOCKET_ERROR; - } - - size_t available_space = 0; - m_sbuf.GetWriteRemaining(&available_space); - - if (!available_space) { - m_bWriteEnable = true; - m_error = EWOULDBLOCK; - return SOCKET_ERROR; - } - - int written = queue(buffer, uint32(len), false); - attemptSend(); - return written; -} - -void PseudoTcp::Close(bool force) { - LOG_F(LS_VERBOSE) << "(" << (force ? "true" : "false") << ")"; - m_shutdown = force ? SD_FORCEFUL : SD_GRACEFUL; -} - -int PseudoTcp::GetError() { - return m_error; -} - -// -// Internal Implementation -// - -uint32 PseudoTcp::queue(const char* data, uint32 len, bool bCtrl) { - size_t available_space = 0; - m_sbuf.GetWriteRemaining(&available_space); - - if (len > static_cast<uint32>(available_space)) { - ASSERT(!bCtrl); - len = static_cast<uint32>(available_space); - } - - // We can concatenate data if the last segment is the same type - // (control v. regular data), and has not been transmitted yet - if (!m_slist.empty() && (m_slist.back().bCtrl == bCtrl) && - (m_slist.back().xmit == 0)) { - m_slist.back().len += len; - } else { - size_t snd_buffered = 0; - m_sbuf.GetBuffered(&snd_buffered); - SSegment sseg(static_cast<uint32>(m_snd_una + snd_buffered), len, bCtrl); - m_slist.push_back(sseg); - } - - size_t written = 0; - m_sbuf.Write(data, len, &written, NULL); - return static_cast<uint32>(written); -} - -IPseudoTcpNotify::WriteResult PseudoTcp::packet(uint32 seq, uint8 flags, - uint32 offset, uint32 len) { - ASSERT(HEADER_SIZE + len <= MAX_PACKET); - - uint32 now = Now(); - - rtc::scoped_ptr<uint8[]> buffer(new uint8[MAX_PACKET]); - long_to_bytes(m_conv, buffer.get()); - long_to_bytes(seq, buffer.get() + 4); - long_to_bytes(m_rcv_nxt, buffer.get() + 8); - buffer[12] = 0; - buffer[13] = flags; - short_to_bytes( - static_cast<uint16>(m_rcv_wnd >> m_rwnd_scale), buffer.get() + 14); - - // Timestamp computations - long_to_bytes(now, buffer.get() + 16); - long_to_bytes(m_ts_recent, buffer.get() + 20); - m_ts_lastack = m_rcv_nxt; - - if (len) { - size_t bytes_read = 0; - rtc::StreamResult result = m_sbuf.ReadOffset( - buffer.get() + HEADER_SIZE, len, offset, &bytes_read); - RTC_UNUSED(result); - ASSERT(result == rtc::SR_SUCCESS); - ASSERT(static_cast<uint32>(bytes_read) == len); - } - -#if _DEBUGMSG >= _DBG_VERBOSE - LOG(LS_INFO) << "<-- <CONV=" << m_conv - << "><FLG=" << static_cast<unsigned>(flags) - << "><SEQ=" << seq << ":" << seq + len - << "><ACK=" << m_rcv_nxt - << "><WND=" << m_rcv_wnd - << "><TS=" << (now % 10000) - << "><TSR=" << (m_ts_recent % 10000) - << "><LEN=" << len << ">"; -#endif // _DEBUGMSG - - IPseudoTcpNotify::WriteResult wres = m_notify->TcpWritePacket( - this, reinterpret_cast<char *>(buffer.get()), len + HEADER_SIZE); - // Note: When len is 0, this is an ACK packet. We don't read the return value for those, - // and thus we won't retry. So go ahead and treat the packet as a success (basically simulate - // as if it were dropped), which will prevent our timers from being messed up. - if ((wres != IPseudoTcpNotify::WR_SUCCESS) && (0 != len)) - return wres; - - m_t_ack = 0; - if (len > 0) { - m_lastsend = now; - } - m_lasttraffic = now; - m_bOutgoing = true; - - return IPseudoTcpNotify::WR_SUCCESS; -} - -bool PseudoTcp::parse(const uint8* buffer, uint32 size) { - if (size < 12) - return false; - - Segment seg; - seg.conv = bytes_to_long(buffer); - seg.seq = bytes_to_long(buffer + 4); - seg.ack = bytes_to_long(buffer + 8); - seg.flags = buffer[13]; - seg.wnd = bytes_to_short(buffer + 14); - - seg.tsval = bytes_to_long(buffer + 16); - seg.tsecr = bytes_to_long(buffer + 20); - - seg.data = reinterpret_cast<const char *>(buffer) + HEADER_SIZE; - seg.len = size - HEADER_SIZE; - -#if _DEBUGMSG >= _DBG_VERBOSE - LOG(LS_INFO) << "--> <CONV=" << seg.conv - << "><FLG=" << static_cast<unsigned>(seg.flags) - << "><SEQ=" << seg.seq << ":" << seg.seq + seg.len - << "><ACK=" << seg.ack - << "><WND=" << seg.wnd - << "><TS=" << (seg.tsval % 10000) - << "><TSR=" << (seg.tsecr % 10000) - << "><LEN=" << seg.len << ">"; -#endif // _DEBUGMSG - - return process(seg); -} - -bool PseudoTcp::clock_check(uint32 now, long& nTimeout) { - if (m_shutdown == SD_FORCEFUL) - return false; - - size_t snd_buffered = 0; - m_sbuf.GetBuffered(&snd_buffered); - if ((m_shutdown == SD_GRACEFUL) - && ((m_state != TCP_ESTABLISHED) - || ((snd_buffered == 0) && (m_t_ack == 0)))) { - return false; - } - - if (m_state == TCP_CLOSED) { - nTimeout = CLOSED_TIMEOUT; - return true; - } - - nTimeout = DEFAULT_TIMEOUT; - - if (m_t_ack) { - nTimeout = rtc::_min<int32>(nTimeout, - rtc::TimeDiff(m_t_ack + m_ack_delay, now)); - } - if (m_rto_base) { - nTimeout = rtc::_min<int32>(nTimeout, - rtc::TimeDiff(m_rto_base + m_rx_rto, now)); - } - if (m_snd_wnd == 0) { - nTimeout = rtc::_min<int32>(nTimeout, rtc::TimeDiff(m_lastsend + m_rx_rto, now)); - } -#if PSEUDO_KEEPALIVE - if (m_state == TCP_ESTABLISHED) { - nTimeout = rtc::_min<int32>(nTimeout, - rtc::TimeDiff(m_lasttraffic + (m_bOutgoing ? IDLE_PING * 3/2 : IDLE_PING), now)); - } -#endif // PSEUDO_KEEPALIVE - return true; -} - -bool PseudoTcp::process(Segment& seg) { - // If this is the wrong conversation, send a reset!?! (with the correct conversation?) - if (seg.conv != m_conv) { - //if ((seg.flags & FLAG_RST) == 0) { - // packet(tcb, seg.ack, 0, FLAG_RST, 0, 0); - //} - LOG_F(LS_ERROR) << "wrong conversation"; - return false; - } - - uint32 now = Now(); - m_lasttraffic = m_lastrecv = now; - m_bOutgoing = false; - - if (m_state == TCP_CLOSED) { - // !?! send reset? - LOG_F(LS_ERROR) << "closed"; - return false; - } - - // Check if this is a reset segment - if (seg.flags & FLAG_RST) { - closedown(ECONNRESET); - return false; - } - - // Check for control data - bool bConnect = false; - if (seg.flags & FLAG_CTL) { - if (seg.len == 0) { - LOG_F(LS_ERROR) << "Missing control code"; - return false; - } else if (seg.data[0] == CTL_CONNECT) { - bConnect = true; - - // TCP options are in the remainder of the payload after CTL_CONNECT. - parseOptions(&seg.data[1], seg.len - 1); - - if (m_state == TCP_LISTEN) { - m_state = TCP_SYN_RECEIVED; - LOG(LS_INFO) << "State: TCP_SYN_RECEIVED"; - //m_notify->associate(addr); - queueConnectMessage(); - } else if (m_state == TCP_SYN_SENT) { - m_state = TCP_ESTABLISHED; - LOG(LS_INFO) << "State: TCP_ESTABLISHED"; - adjustMTU(); - if (m_notify) { - m_notify->OnTcpOpen(this); - } - //notify(evOpen); - } - } else { - LOG_F(LS_WARNING) << "Unknown control code: " << seg.data[0]; - return false; - } - } - - // Update timestamp - if ((seg.seq <= m_ts_lastack) && (m_ts_lastack < seg.seq + seg.len)) { - m_ts_recent = seg.tsval; - } - - // Check if this is a valuable ack - if ((seg.ack > m_snd_una) && (seg.ack <= m_snd_nxt)) { - // Calculate round-trip time - if (seg.tsecr) { - int32 rtt = rtc::TimeDiff(now, seg.tsecr); - if (rtt >= 0) { - if (m_rx_srtt == 0) { - m_rx_srtt = rtt; - m_rx_rttvar = rtt / 2; - } else { - uint32 unsigned_rtt = static_cast<uint32>(rtt); - uint32 abs_err = unsigned_rtt > m_rx_srtt ? unsigned_rtt - m_rx_srtt - : m_rx_srtt - unsigned_rtt; - m_rx_rttvar = (3 * m_rx_rttvar + abs_err) / 4; - m_rx_srtt = (7 * m_rx_srtt + rtt) / 8; - } - m_rx_rto = bound(MIN_RTO, m_rx_srtt + - rtc::_max<uint32>(1, 4 * m_rx_rttvar), MAX_RTO); -#if _DEBUGMSG >= _DBG_VERBOSE - LOG(LS_INFO) << "rtt: " << rtt - << " srtt: " << m_rx_srtt - << " rto: " << m_rx_rto; -#endif // _DEBUGMSG - } else { - ASSERT(false); - } - } - - m_snd_wnd = static_cast<uint32>(seg.wnd) << m_swnd_scale; - - uint32 nAcked = seg.ack - m_snd_una; - m_snd_una = seg.ack; - - m_rto_base = (m_snd_una == m_snd_nxt) ? 0 : now; - - m_sbuf.ConsumeReadData(nAcked); - - for (uint32 nFree = nAcked; nFree > 0; ) { - ASSERT(!m_slist.empty()); - if (nFree < m_slist.front().len) { - m_slist.front().len -= nFree; - nFree = 0; - } else { - if (m_slist.front().len > m_largest) { - m_largest = m_slist.front().len; - } - nFree -= m_slist.front().len; - m_slist.pop_front(); - } - } - - if (m_dup_acks >= 3) { - if (m_snd_una >= m_recover) { // NewReno - uint32 nInFlight = m_snd_nxt - m_snd_una; - m_cwnd = rtc::_min(m_ssthresh, nInFlight + m_mss); // (Fast Retransmit) -#if _DEBUGMSG >= _DBG_NORMAL - LOG(LS_INFO) << "exit recovery"; -#endif // _DEBUGMSG - m_dup_acks = 0; - } else { -#if _DEBUGMSG >= _DBG_NORMAL - LOG(LS_INFO) << "recovery retransmit"; -#endif // _DEBUGMSG - if (!transmit(m_slist.begin(), now)) { - closedown(ECONNABORTED); - return false; - } - m_cwnd += m_mss - rtc::_min(nAcked, m_cwnd); - } - } else { - m_dup_acks = 0; - // Slow start, congestion avoidance - if (m_cwnd < m_ssthresh) { - m_cwnd += m_mss; - } else { - m_cwnd += rtc::_max<uint32>(1, m_mss * m_mss / m_cwnd); - } - } - } else if (seg.ack == m_snd_una) { - // !?! Note, tcp says don't do this... but otherwise how does a closed window become open? - m_snd_wnd = static_cast<uint32>(seg.wnd) << m_swnd_scale; - - // Check duplicate acks - if (seg.len > 0) { - // it's a dup ack, but with a data payload, so don't modify m_dup_acks - } else if (m_snd_una != m_snd_nxt) { - m_dup_acks += 1; - if (m_dup_acks == 3) { // (Fast Retransmit) -#if _DEBUGMSG >= _DBG_NORMAL - LOG(LS_INFO) << "enter recovery"; - LOG(LS_INFO) << "recovery retransmit"; -#endif // _DEBUGMSG - if (!transmit(m_slist.begin(), now)) { - closedown(ECONNABORTED); - return false; - } - m_recover = m_snd_nxt; - uint32 nInFlight = m_snd_nxt - m_snd_una; - m_ssthresh = rtc::_max(nInFlight / 2, 2 * m_mss); - //LOG(LS_INFO) << "m_ssthresh: " << m_ssthresh << " nInFlight: " << nInFlight << " m_mss: " << m_mss; - m_cwnd = m_ssthresh + 3 * m_mss; - } else if (m_dup_acks > 3) { - m_cwnd += m_mss; - } - } else { - m_dup_acks = 0; - } - } - - // !?! A bit hacky - if ((m_state == TCP_SYN_RECEIVED) && !bConnect) { - m_state = TCP_ESTABLISHED; - LOG(LS_INFO) << "State: TCP_ESTABLISHED"; - adjustMTU(); - if (m_notify) { - m_notify->OnTcpOpen(this); - } - //notify(evOpen); - } - - // If we make room in the send queue, notify the user - // The goal it to make sure we always have at least enough data to fill the - // window. We'd like to notify the app when we are halfway to that point. - const uint32 kIdealRefillSize = (m_sbuf_len + m_rbuf_len) / 2; - size_t snd_buffered = 0; - m_sbuf.GetBuffered(&snd_buffered); - if (m_bWriteEnable && static_cast<uint32>(snd_buffered) < kIdealRefillSize) { - m_bWriteEnable = false; - if (m_notify) { - m_notify->OnTcpWriteable(this); - } - //notify(evWrite); - } - - // Conditions were acks must be sent: - // 1) Segment is too old (they missed an ACK) (immediately) - // 2) Segment is too new (we missed a segment) (immediately) - // 3) Segment has data (so we need to ACK!) (delayed) - // ... so the only time we don't need to ACK, is an empty segment that points to rcv_nxt! - - SendFlags sflags = sfNone; - if (seg.seq != m_rcv_nxt) { - sflags = sfImmediateAck; // (Fast Recovery) - } else if (seg.len != 0) { - if (m_ack_delay == 0) { - sflags = sfImmediateAck; - } else { - sflags = sfDelayedAck; - } - } -#if _DEBUGMSG >= _DBG_NORMAL - if (sflags == sfImmediateAck) { - if (seg.seq > m_rcv_nxt) { - LOG_F(LS_INFO) << "too new"; - } else if (seg.seq + seg.len <= m_rcv_nxt) { - LOG_F(LS_INFO) << "too old"; - } - } -#endif // _DEBUGMSG - - // Adjust the incoming segment to fit our receive buffer - if (seg.seq < m_rcv_nxt) { - uint32 nAdjust = m_rcv_nxt - seg.seq; - if (nAdjust < seg.len) { - seg.seq += nAdjust; - seg.data += nAdjust; - seg.len -= nAdjust; - } else { - seg.len = 0; - } - } - - size_t available_space = 0; - m_rbuf.GetWriteRemaining(&available_space); - - if ((seg.seq + seg.len - m_rcv_nxt) > static_cast<uint32>(available_space)) { - uint32 nAdjust = seg.seq + seg.len - m_rcv_nxt - static_cast<uint32>(available_space); - if (nAdjust < seg.len) { - seg.len -= nAdjust; - } else { - seg.len = 0; - } - } - - bool bIgnoreData = (seg.flags & FLAG_CTL) || (m_shutdown != SD_NONE); - bool bNewData = false; - - if (seg.len > 0) { - if (bIgnoreData) { - if (seg.seq == m_rcv_nxt) { - m_rcv_nxt += seg.len; - } - } else { - uint32 nOffset = seg.seq - m_rcv_nxt; - - rtc::StreamResult result = m_rbuf.WriteOffset(seg.data, seg.len, - nOffset, NULL); - ASSERT(result == rtc::SR_SUCCESS); - RTC_UNUSED(result); - - if (seg.seq == m_rcv_nxt) { - m_rbuf.ConsumeWriteBuffer(seg.len); - m_rcv_nxt += seg.len; - m_rcv_wnd -= seg.len; - bNewData = true; - - RList::iterator it = m_rlist.begin(); - while ((it != m_rlist.end()) && (it->seq <= m_rcv_nxt)) { - if (it->seq + it->len > m_rcv_nxt) { - sflags = sfImmediateAck; // (Fast Recovery) - uint32 nAdjust = (it->seq + it->len) - m_rcv_nxt; -#if _DEBUGMSG >= _DBG_NORMAL - LOG(LS_INFO) << "Recovered " << nAdjust << " bytes (" << m_rcv_nxt << " -> " << m_rcv_nxt + nAdjust << ")"; -#endif // _DEBUGMSG - m_rbuf.ConsumeWriteBuffer(nAdjust); - m_rcv_nxt += nAdjust; - m_rcv_wnd -= nAdjust; - } - it = m_rlist.erase(it); - } - } else { -#if _DEBUGMSG >= _DBG_NORMAL - LOG(LS_INFO) << "Saving " << seg.len << " bytes (" << seg.seq << " -> " << seg.seq + seg.len << ")"; -#endif // _DEBUGMSG - RSegment rseg; - rseg.seq = seg.seq; - rseg.len = seg.len; - RList::iterator it = m_rlist.begin(); - while ((it != m_rlist.end()) && (it->seq < rseg.seq)) { - ++it; - } - m_rlist.insert(it, rseg); - } - } - } - - attemptSend(sflags); - - // If we have new data, notify the user - if (bNewData && m_bReadEnable) { - m_bReadEnable = false; - if (m_notify) { - m_notify->OnTcpReadable(this); - } - //notify(evRead); - } - - return true; -} - -bool PseudoTcp::transmit(const SList::iterator& seg, uint32 now) { - if (seg->xmit >= ((m_state == TCP_ESTABLISHED) ? 15 : 30)) { - LOG_F(LS_VERBOSE) << "too many retransmits"; - return false; - } - - uint32 nTransmit = rtc::_min(seg->len, m_mss); - - while (true) { - uint32 seq = seg->seq; - uint8 flags = (seg->bCtrl ? FLAG_CTL : 0); - IPseudoTcpNotify::WriteResult wres = packet(seq, - flags, - seg->seq - m_snd_una, - nTransmit); - - if (wres == IPseudoTcpNotify::WR_SUCCESS) - break; - - if (wres == IPseudoTcpNotify::WR_FAIL) { - LOG_F(LS_VERBOSE) << "packet failed"; - return false; - } - - ASSERT(wres == IPseudoTcpNotify::WR_TOO_LARGE); - - while (true) { - if (PACKET_MAXIMUMS[m_msslevel + 1] == 0) { - LOG_F(LS_VERBOSE) << "MTU too small"; - return false; - } - // !?! We need to break up all outstanding and pending packets and then retransmit!?! - - m_mss = PACKET_MAXIMUMS[++m_msslevel] - PACKET_OVERHEAD; - m_cwnd = 2 * m_mss; // I added this... haven't researched actual formula - if (m_mss < nTransmit) { - nTransmit = m_mss; - break; - } - } -#if _DEBUGMSG >= _DBG_NORMAL - LOG(LS_INFO) << "Adjusting mss to " << m_mss << " bytes"; -#endif // _DEBUGMSG - } - - if (nTransmit < seg->len) { - LOG_F(LS_VERBOSE) << "mss reduced to " << m_mss; - - SSegment subseg(seg->seq + nTransmit, seg->len - nTransmit, seg->bCtrl); - //subseg.tstamp = seg->tstamp; - subseg.xmit = seg->xmit; - seg->len = nTransmit; - - SList::iterator next = seg; - m_slist.insert(++next, subseg); - } - - if (seg->xmit == 0) { - m_snd_nxt += seg->len; - } - seg->xmit += 1; - //seg->tstamp = now; - if (m_rto_base == 0) { - m_rto_base = now; - } - - return true; -} - -void PseudoTcp::attemptSend(SendFlags sflags) { - uint32 now = Now(); - - if (rtc::TimeDiff(now, m_lastsend) > static_cast<long>(m_rx_rto)) { - m_cwnd = m_mss; - } - -#if _DEBUGMSG - bool bFirst = true; - RTC_UNUSED(bFirst); -#endif // _DEBUGMSG - - while (true) { - uint32 cwnd = m_cwnd; - if ((m_dup_acks == 1) || (m_dup_acks == 2)) { // Limited Transmit - cwnd += m_dup_acks * m_mss; - } - uint32 nWindow = rtc::_min(m_snd_wnd, cwnd); - uint32 nInFlight = m_snd_nxt - m_snd_una; - uint32 nUseable = (nInFlight < nWindow) ? (nWindow - nInFlight) : 0; - - size_t snd_buffered = 0; - m_sbuf.GetBuffered(&snd_buffered); - uint32 nAvailable = - rtc::_min(static_cast<uint32>(snd_buffered) - nInFlight, m_mss); - - if (nAvailable > nUseable) { - if (nUseable * 4 < nWindow) { - // RFC 813 - avoid SWS - nAvailable = 0; - } else { - nAvailable = nUseable; - } - } - -#if _DEBUGMSG >= _DBG_VERBOSE - if (bFirst) { - size_t available_space = 0; - m_sbuf.GetWriteRemaining(&available_space); - - bFirst = false; - LOG(LS_INFO) << "[cwnd: " << m_cwnd - << " nWindow: " << nWindow - << " nInFlight: " << nInFlight - << " nAvailable: " << nAvailable - << " nQueued: " << snd_buffered - << " nEmpty: " << available_space - << " ssthresh: " << m_ssthresh << "]"; - } -#endif // _DEBUGMSG - - if (nAvailable == 0) { - if (sflags == sfNone) - return; - - // If this is an immediate ack, or the second delayed ack - if ((sflags == sfImmediateAck) || m_t_ack) { - packet(m_snd_nxt, 0, 0, 0); - } else { - m_t_ack = Now(); - } - return; - } - - // Nagle's algorithm. - // If there is data already in-flight, and we haven't a full segment of - // data ready to send then hold off until we get more to send, or the - // in-flight data is acknowledged. - if (m_use_nagling && (m_snd_nxt > m_snd_una) && (nAvailable < m_mss)) { - return; - } - - // Find the next segment to transmit - SList::iterator it = m_slist.begin(); - while (it->xmit > 0) { - ++it; - ASSERT(it != m_slist.end()); - } - SList::iterator seg = it; - - // If the segment is too large, break it into two - if (seg->len > nAvailable) { - SSegment subseg(seg->seq + nAvailable, seg->len - nAvailable, seg->bCtrl); - seg->len = nAvailable; - m_slist.insert(++it, subseg); - } - - if (!transmit(seg, now)) { - LOG_F(LS_VERBOSE) << "transmit failed"; - // TODO: consider closing socket - return; - } - - sflags = sfNone; - } -} - -void -PseudoTcp::closedown(uint32 err) { - LOG(LS_INFO) << "State: TCP_CLOSED"; - m_state = TCP_CLOSED; - if (m_notify) { - m_notify->OnTcpClosed(this, err); - } - //notify(evClose, err); -} - -void -PseudoTcp::adjustMTU() { - // Determine our current mss level, so that we can adjust appropriately later - for (m_msslevel = 0; PACKET_MAXIMUMS[m_msslevel + 1] > 0; ++m_msslevel) { - if (static_cast<uint16>(PACKET_MAXIMUMS[m_msslevel]) <= m_mtu_advise) { - break; - } - } - m_mss = m_mtu_advise - PACKET_OVERHEAD; - // !?! Should we reset m_largest here? -#if _DEBUGMSG >= _DBG_NORMAL - LOG(LS_INFO) << "Adjusting mss to " << m_mss << " bytes"; -#endif // _DEBUGMSG - // Enforce minimums on ssthresh and cwnd - m_ssthresh = rtc::_max(m_ssthresh, 2 * m_mss); - m_cwnd = rtc::_max(m_cwnd, m_mss); -} - -bool -PseudoTcp::isReceiveBufferFull() const { - size_t available_space = 0; - m_rbuf.GetWriteRemaining(&available_space); - return !available_space; -} - -void -PseudoTcp::disableWindowScale() { - m_support_wnd_scale = false; -} - -void -PseudoTcp::queueConnectMessage() { - rtc::ByteBuffer buf(rtc::ByteBuffer::ORDER_NETWORK); - - buf.WriteUInt8(CTL_CONNECT); - if (m_support_wnd_scale) { - buf.WriteUInt8(TCP_OPT_WND_SCALE); - buf.WriteUInt8(1); - buf.WriteUInt8(m_rwnd_scale); - } - m_snd_wnd = static_cast<uint32>(buf.Length()); - queue(buf.Data(), static_cast<uint32>(buf.Length()), true); -} - -void -PseudoTcp::parseOptions(const char* data, uint32 len) { - std::set<uint8> options_specified; - - // See http://www.freesoft.org/CIE/Course/Section4/8.htm for - // parsing the options list. - rtc::ByteBuffer buf(data, len); - while (buf.Length()) { - uint8 kind = TCP_OPT_EOL; - buf.ReadUInt8(&kind); - - if (kind == TCP_OPT_EOL) { - // End of option list. - break; - } else if (kind == TCP_OPT_NOOP) { - // No op. - continue; - } - - // Length of this option. - ASSERT(len != 0); - RTC_UNUSED(len); - uint8 opt_len = 0; - buf.ReadUInt8(&opt_len); - - // Content of this option. - if (opt_len <= buf.Length()) { - applyOption(kind, buf.Data(), opt_len); - buf.Consume(opt_len); - } else { - LOG(LS_ERROR) << "Invalid option length received."; - return; - } - options_specified.insert(kind); - } - - if (options_specified.find(TCP_OPT_WND_SCALE) == options_specified.end()) { - LOG(LS_WARNING) << "Peer doesn't support window scaling"; - - if (m_rwnd_scale > 0) { - // Peer doesn't support TCP options and window scaling. - // Revert receive buffer size to default value. - resizeReceiveBuffer(DEFAULT_RCV_BUF_SIZE); - m_swnd_scale = 0; - } - } -} - -void -PseudoTcp::applyOption(char kind, const char* data, uint32 len) { - if (kind == TCP_OPT_MSS) { - LOG(LS_WARNING) << "Peer specified MSS option which is not supported."; - // TODO: Implement. - } else if (kind == TCP_OPT_WND_SCALE) { - // Window scale factor. - // http://www.ietf.org/rfc/rfc1323.txt - if (len != 1) { - LOG_F(WARNING) << "Invalid window scale option received."; - return; - } - applyWindowScaleOption(data[0]); - } -} - -void -PseudoTcp::applyWindowScaleOption(uint8 scale_factor) { - m_swnd_scale = scale_factor; -} - -void -PseudoTcp::resizeSendBuffer(uint32 new_size) { - m_sbuf_len = new_size; - m_sbuf.SetCapacity(new_size); -} - -void -PseudoTcp::resizeReceiveBuffer(uint32 new_size) { - uint8 scale_factor = 0; - - // Determine the scale factor such that the scaled window size can fit - // in a 16-bit unsigned integer. - while (new_size > 0xFFFF) { - ++scale_factor; - new_size >>= 1; - } - - // Determine the proper size of the buffer. - new_size <<= scale_factor; - bool result = m_rbuf.SetCapacity(new_size); - - // Make sure the new buffer is large enough to contain data in the old - // buffer. This should always be true because this method is called either - // before connection is established or when peers are exchanging connect - // messages. - ASSERT(result); - RTC_UNUSED(result); - m_rbuf_len = new_size; - m_rwnd_scale = scale_factor; - m_ssthresh = new_size; - - size_t available_space = 0; - m_rbuf.GetWriteRemaining(&available_space); - m_rcv_wnd = static_cast<uint32>(available_space); -} - -} // namespace cricket diff --git a/talk/p2p/base/pseudotcp.h b/talk/p2p/base/pseudotcp.h deleted file mode 100644 index e3455de71..000000000 --- a/talk/p2p/base/pseudotcp.h +++ /dev/null @@ -1,258 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef WEBRTC_P2P_BASE_PSEUDOTCP_H_ -#define WEBRTC_P2P_BASE_PSEUDOTCP_H_ - -#include <list> - -#include "webrtc/base/basictypes.h" -#include "webrtc/base/stream.h" - -namespace cricket { - -////////////////////////////////////////////////////////////////////// -// IPseudoTcpNotify -////////////////////////////////////////////////////////////////////// - -class PseudoTcp; - -class IPseudoTcpNotify { - public: - // Notification of tcp events - virtual void OnTcpOpen(PseudoTcp* tcp) = 0; - virtual void OnTcpReadable(PseudoTcp* tcp) = 0; - virtual void OnTcpWriteable(PseudoTcp* tcp) = 0; - virtual void OnTcpClosed(PseudoTcp* tcp, uint32 error) = 0; - - // Write the packet onto the network - enum WriteResult { WR_SUCCESS, WR_TOO_LARGE, WR_FAIL }; - virtual WriteResult TcpWritePacket(PseudoTcp* tcp, - const char* buffer, size_t len) = 0; - - protected: - virtual ~IPseudoTcpNotify() {} -}; - -////////////////////////////////////////////////////////////////////// -// PseudoTcp -////////////////////////////////////////////////////////////////////// - -class PseudoTcp { - public: - static uint32 Now(); - - PseudoTcp(IPseudoTcpNotify* notify, uint32 conv); - virtual ~PseudoTcp(); - - int Connect(); - int Recv(char* buffer, size_t len); - int Send(const char* buffer, size_t len); - void Close(bool force); - int GetError(); - - enum TcpState { - TCP_LISTEN, TCP_SYN_SENT, TCP_SYN_RECEIVED, TCP_ESTABLISHED, TCP_CLOSED - }; - TcpState State() const { return m_state; } - - // Call this when the PMTU changes. - void NotifyMTU(uint16 mtu); - - // Call this based on timeout value returned from GetNextClock. - // It's ok to call this too frequently. - void NotifyClock(uint32 now); - - // Call this whenever a packet arrives. - // Returns true if the packet was processed successfully. - bool NotifyPacket(const char * buffer, size_t len); - - // Call this to determine the next time NotifyClock should be called. - // Returns false if the socket is ready to be destroyed. - bool GetNextClock(uint32 now, long& timeout); - - // Call these to get/set option values to tailor this PseudoTcp - // instance's behaviour for the kind of data it will carry. - // If an unrecognized option is set or got, an assertion will fire. - // - // Setting options for OPT_RCVBUF or OPT_SNDBUF after Connect() is called - // will result in an assertion. - enum Option { - OPT_NODELAY, // Whether to enable Nagle's algorithm (0 == off) - OPT_ACKDELAY, // The Delayed ACK timeout (0 == off). - OPT_RCVBUF, // Set the receive buffer size, in bytes. - OPT_SNDBUF, // Set the send buffer size, in bytes. - }; - void GetOption(Option opt, int* value); - void SetOption(Option opt, int value); - - // Returns current congestion window in bytes. - uint32 GetCongestionWindow() const; - - // Returns amount of data in bytes that has been sent, but haven't - // been acknowledged. - uint32 GetBytesInFlight() const; - - // Returns number of bytes that were written in buffer and haven't - // been sent. - uint32 GetBytesBufferedNotSent() const; - - // Returns current round-trip time estimate in milliseconds. - uint32 GetRoundTripTimeEstimateMs() const; - - protected: - enum SendFlags { sfNone, sfDelayedAck, sfImmediateAck }; - - struct Segment { - uint32 conv, seq, ack; - uint8 flags; - uint16 wnd; - const char * data; - uint32 len; - uint32 tsval, tsecr; - }; - - struct SSegment { - SSegment(uint32 s, uint32 l, bool c) - : seq(s), len(l), /*tstamp(0),*/ xmit(0), bCtrl(c) { - } - uint32 seq, len; - //uint32 tstamp; - uint8 xmit; - bool bCtrl; - }; - typedef std::list<SSegment> SList; - - struct RSegment { - uint32 seq, len; - }; - - uint32 queue(const char* data, uint32 len, bool bCtrl); - - // Creates a packet and submits it to the network. This method can either - // send payload or just an ACK packet. - // - // |seq| is the sequence number of this packet. - // |flags| is the flags for sending this packet. - // |offset| is the offset to read from |m_sbuf|. - // |len| is the number of bytes to read from |m_sbuf| as payload. If this - // value is 0 then this is an ACK packet, otherwise this packet has payload. - IPseudoTcpNotify::WriteResult packet(uint32 seq, uint8 flags, - uint32 offset, uint32 len); - bool parse(const uint8* buffer, uint32 size); - - void attemptSend(SendFlags sflags = sfNone); - - void closedown(uint32 err = 0); - - bool clock_check(uint32 now, long& nTimeout); - - bool process(Segment& seg); - bool transmit(const SList::iterator& seg, uint32 now); - - void adjustMTU(); - - protected: - // This method is used in test only to query receive buffer state. - bool isReceiveBufferFull() const; - - // This method is only used in tests, to disable window scaling - // support for testing backward compatibility. - void disableWindowScale(); - - private: - // Queue the connect message with TCP options. - void queueConnectMessage(); - - // Parse TCP options in the header. - void parseOptions(const char* data, uint32 len); - - // Apply a TCP option that has been read from the header. - void applyOption(char kind, const char* data, uint32 len); - - // Apply window scale option. - void applyWindowScaleOption(uint8 scale_factor); - - // Resize the send buffer with |new_size| in bytes. - void resizeSendBuffer(uint32 new_size); - - // Resize the receive buffer with |new_size| in bytes. This call adjusts - // window scale factor |m_swnd_scale| accordingly. - void resizeReceiveBuffer(uint32 new_size); - - IPseudoTcpNotify* m_notify; - enum Shutdown { SD_NONE, SD_GRACEFUL, SD_FORCEFUL } m_shutdown; - int m_error; - - // TCB data - TcpState m_state; - uint32 m_conv; - bool m_bReadEnable, m_bWriteEnable, m_bOutgoing; - uint32 m_lasttraffic; - - // Incoming data - typedef std::list<RSegment> RList; - RList m_rlist; - uint32 m_rbuf_len, m_rcv_nxt, m_rcv_wnd, m_lastrecv; - uint8 m_rwnd_scale; // Window scale factor. - rtc::FifoBuffer m_rbuf; - - // Outgoing data - SList m_slist; - uint32 m_sbuf_len, m_snd_nxt, m_snd_wnd, m_lastsend, m_snd_una; - uint8 m_swnd_scale; // Window scale factor. - rtc::FifoBuffer m_sbuf; - - // Maximum segment size, estimated protocol level, largest segment sent - uint32 m_mss, m_msslevel, m_largest, m_mtu_advise; - // Retransmit timer - uint32 m_rto_base; - - // Timestamp tracking - uint32 m_ts_recent, m_ts_lastack; - - // Round-trip calculation - uint32 m_rx_rttvar, m_rx_srtt, m_rx_rto; - - // Congestion avoidance, Fast retransmit/recovery, Delayed ACKs - uint32 m_ssthresh, m_cwnd; - uint8 m_dup_acks; - uint32 m_recover; - uint32 m_t_ack; - - // Configuration options - bool m_use_nagling; - uint32 m_ack_delay; - - // This is used by unit tests to test backward compatibility of - // PseudoTcp implementations that don't support window scaling. - bool m_support_wnd_scale; -}; - -} // namespace cricket - -#endif // WEBRTC_P2P_BASE_PSEUDOTCP_H_ diff --git a/talk/p2p/base/pseudotcp_unittest.cc b/talk/p2p/base/pseudotcp_unittest.cc deleted file mode 100644 index 522eb1889..000000000 --- a/talk/p2p/base/pseudotcp_unittest.cc +++ /dev/null @@ -1,858 +0,0 @@ -/* - * libjingle - * Copyright 2011 Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <vector> - -#include "webrtc/p2p/base/pseudotcp.h" -#include "webrtc/base/gunit.h" -#include "webrtc/base/helpers.h" -#include "webrtc/base/messagehandler.h" -#include "webrtc/base/stream.h" -#include "webrtc/base/thread.h" -#include "webrtc/base/timeutils.h" - -using cricket::PseudoTcp; - -static const int kConnectTimeoutMs = 10000; // ~3 * default RTO of 3000ms -static const int kTransferTimeoutMs = 15000; -static const int kBlockSize = 4096; - -class PseudoTcpForTest : public cricket::PseudoTcp { - public: - PseudoTcpForTest(cricket::IPseudoTcpNotify* notify, uint32 conv) - : PseudoTcp(notify, conv) { - } - - bool isReceiveBufferFull() const { - return PseudoTcp::isReceiveBufferFull(); - } - - void disableWindowScale() { - PseudoTcp::disableWindowScale(); - } -}; - -class PseudoTcpTestBase : public testing::Test, - public rtc::MessageHandler, - public cricket::IPseudoTcpNotify { - public: - PseudoTcpTestBase() - : local_(this, 1), - remote_(this, 1), - have_connected_(false), - have_disconnected_(false), - local_mtu_(65535), - remote_mtu_(65535), - delay_(0), - loss_(0) { - // Set use of the test RNG to get predictable loss patterns. - rtc::SetRandomTestMode(true); - } - ~PseudoTcpTestBase() { - // Put it back for the next test. - rtc::SetRandomTestMode(false); - } - void SetLocalMtu(int mtu) { - local_.NotifyMTU(mtu); - local_mtu_ = mtu; - } - void SetRemoteMtu(int mtu) { - remote_.NotifyMTU(mtu); - remote_mtu_ = mtu; - } - void SetDelay(int delay) { - delay_ = delay; - } - void SetLoss(int percent) { - loss_ = percent; - } - void SetOptNagling(bool enable_nagles) { - local_.SetOption(PseudoTcp::OPT_NODELAY, !enable_nagles); - remote_.SetOption(PseudoTcp::OPT_NODELAY, !enable_nagles); - } - void SetOptAckDelay(int ack_delay) { - local_.SetOption(PseudoTcp::OPT_ACKDELAY, ack_delay); - remote_.SetOption(PseudoTcp::OPT_ACKDELAY, ack_delay); - } - void SetOptSndBuf(int size) { - local_.SetOption(PseudoTcp::OPT_SNDBUF, size); - remote_.SetOption(PseudoTcp::OPT_SNDBUF, size); - } - void SetRemoteOptRcvBuf(int size) { - remote_.SetOption(PseudoTcp::OPT_RCVBUF, size); - } - void SetLocalOptRcvBuf(int size) { - local_.SetOption(PseudoTcp::OPT_RCVBUF, size); - } - void DisableRemoteWindowScale() { - remote_.disableWindowScale(); - } - void DisableLocalWindowScale() { - local_.disableWindowScale(); - } - - protected: - int Connect() { - int ret = local_.Connect(); - if (ret == 0) { - UpdateLocalClock(); - } - return ret; - } - void Close() { - local_.Close(false); - UpdateLocalClock(); - } - - enum { MSG_LPACKET, MSG_RPACKET, MSG_LCLOCK, MSG_RCLOCK, MSG_IOCOMPLETE, - MSG_WRITE}; - virtual void OnTcpOpen(PseudoTcp* tcp) { - // Consider ourselves connected when the local side gets OnTcpOpen. - // OnTcpWriteable isn't fired at open, so we trigger it now. - LOG(LS_VERBOSE) << "Opened"; - if (tcp == &local_) { - have_connected_ = true; - OnTcpWriteable(tcp); - } - } - // Test derived from the base should override - // virtual void OnTcpReadable(PseudoTcp* tcp) - // and - // virtual void OnTcpWritable(PseudoTcp* tcp) - virtual void OnTcpClosed(PseudoTcp* tcp, uint32 error) { - // Consider ourselves closed when the remote side gets OnTcpClosed. - // TODO: OnTcpClosed is only ever notified in case of error in - // the current implementation. Solicited close is not (yet) supported. - LOG(LS_VERBOSE) << "Closed"; - EXPECT_EQ(0U, error); - if (tcp == &remote_) { - have_disconnected_ = true; - } - } - virtual WriteResult TcpWritePacket(PseudoTcp* tcp, - const char* buffer, size_t len) { - // Randomly drop the desired percentage of packets. - // Also drop packets that are larger than the configured MTU. - if (rtc::CreateRandomId() % 100 < static_cast<uint32>(loss_)) { - LOG(LS_VERBOSE) << "Randomly dropping packet, size=" << len; - } else if (len > static_cast<size_t>( - rtc::_min(local_mtu_, remote_mtu_))) { - LOG(LS_VERBOSE) << "Dropping packet that exceeds path MTU, size=" << len; - } else { - int id = (tcp == &local_) ? MSG_RPACKET : MSG_LPACKET; - std::string packet(buffer, len); - rtc::Thread::Current()->PostDelayed(delay_, this, id, - rtc::WrapMessageData(packet)); - } - return WR_SUCCESS; - } - - void UpdateLocalClock() { UpdateClock(&local_, MSG_LCLOCK); } - void UpdateRemoteClock() { UpdateClock(&remote_, MSG_RCLOCK); } - void UpdateClock(PseudoTcp* tcp, uint32 message) { - long interval = 0; // NOLINT - tcp->GetNextClock(PseudoTcp::Now(), interval); - interval = rtc::_max<int>(interval, 0L); // sometimes interval is < 0 - rtc::Thread::Current()->Clear(this, message); - rtc::Thread::Current()->PostDelayed(interval, this, message); - } - - virtual void OnMessage(rtc::Message* message) { - switch (message->message_id) { - case MSG_LPACKET: { - const std::string& s( - rtc::UseMessageData<std::string>(message->pdata)); - local_.NotifyPacket(s.c_str(), s.size()); - UpdateLocalClock(); - break; - } - case MSG_RPACKET: { - const std::string& s( - rtc::UseMessageData<std::string>(message->pdata)); - remote_.NotifyPacket(s.c_str(), s.size()); - UpdateRemoteClock(); - break; - } - case MSG_LCLOCK: - local_.NotifyClock(PseudoTcp::Now()); - UpdateLocalClock(); - break; - case MSG_RCLOCK: - remote_.NotifyClock(PseudoTcp::Now()); - UpdateRemoteClock(); - break; - default: - break; - } - delete message->pdata; - } - - PseudoTcpForTest local_; - PseudoTcpForTest remote_; - rtc::MemoryStream send_stream_; - rtc::MemoryStream recv_stream_; - bool have_connected_; - bool have_disconnected_; - int local_mtu_; - int remote_mtu_; - int delay_; - int loss_; -}; - -class PseudoTcpTest : public PseudoTcpTestBase { - public: - void TestTransfer(int size) { - uint32 start, elapsed; - size_t received; - // Create some dummy data to send. - send_stream_.ReserveSize(size); - for (int i = 0; i < size; ++i) { - char ch = static_cast<char>(i); - send_stream_.Write(&ch, 1, NULL, NULL); - } - send_stream_.Rewind(); - // Prepare the receive stream. - recv_stream_.ReserveSize(size); - // Connect and wait until connected. - start = rtc::Time(); - EXPECT_EQ(0, Connect()); - EXPECT_TRUE_WAIT(have_connected_, kConnectTimeoutMs); - // Sending will start from OnTcpWriteable and complete when all data has - // been received. - EXPECT_TRUE_WAIT(have_disconnected_, kTransferTimeoutMs); - elapsed = rtc::TimeSince(start); - recv_stream_.GetSize(&received); - // Ensure we closed down OK and we got the right data. - // TODO: Ensure the errors are cleared properly. - //EXPECT_EQ(0, local_.GetError()); - //EXPECT_EQ(0, remote_.GetError()); - EXPECT_EQ(static_cast<size_t>(size), received); - EXPECT_EQ(0, memcmp(send_stream_.GetBuffer(), - recv_stream_.GetBuffer(), size)); - LOG(LS_INFO) << "Transferred " << received << " bytes in " << elapsed - << " ms (" << size * 8 / elapsed << " Kbps)"; - } - - private: - // IPseudoTcpNotify interface - - virtual void OnTcpReadable(PseudoTcp* tcp) { - // Stream bytes to the recv stream as they arrive. - if (tcp == &remote_) { - ReadData(); - - // TODO: OnTcpClosed() is currently only notified on error - - // there is no on-the-wire equivalent of TCP FIN. - // So we fake the notification when all the data has been read. - size_t received, required; - recv_stream_.GetPosition(&received); - send_stream_.GetSize(&required); - if (received == required) - OnTcpClosed(&remote_, 0); - } - } - virtual void OnTcpWriteable(PseudoTcp* tcp) { - // Write bytes from the send stream when we can. - // Shut down when we've sent everything. - if (tcp == &local_) { - LOG(LS_VERBOSE) << "Flow Control Lifted"; - bool done; - WriteData(&done); - if (done) { - Close(); - } - } - } - - void ReadData() { - char block[kBlockSize]; - size_t position; - int rcvd; - do { - rcvd = remote_.Recv(block, sizeof(block)); - if (rcvd != -1) { - recv_stream_.Write(block, rcvd, NULL, NULL); - recv_stream_.GetPosition(&position); - LOG(LS_VERBOSE) << "Received: " << position; - } - } while (rcvd > 0); - } - void WriteData(bool* done) { - size_t position, tosend; - int sent; - char block[kBlockSize]; - do { - send_stream_.GetPosition(&position); - if (send_stream_.Read(block, sizeof(block), &tosend, NULL) != - rtc::SR_EOS) { - sent = local_.Send(block, tosend); - UpdateLocalClock(); - if (sent != -1) { - send_stream_.SetPosition(position + sent); - LOG(LS_VERBOSE) << "Sent: " << position + sent; - } else { - send_stream_.SetPosition(position); - LOG(LS_VERBOSE) << "Flow Controlled"; - } - } else { - sent = static_cast<int>(tosend = 0); - } - } while (sent > 0); - *done = (tosend == 0); - } - - private: - rtc::MemoryStream send_stream_; - rtc::MemoryStream recv_stream_; -}; - - -class PseudoTcpTestPingPong : public PseudoTcpTestBase { - public: - PseudoTcpTestPingPong() - : iterations_remaining_(0), - sender_(NULL), - receiver_(NULL), - bytes_per_send_(0) { - } - void SetBytesPerSend(int bytes) { - bytes_per_send_ = bytes; - } - void TestPingPong(int size, int iterations) { - uint32 start, elapsed; - iterations_remaining_ = iterations; - receiver_ = &remote_; - sender_ = &local_; - // Create some dummy data to send. - send_stream_.ReserveSize(size); - for (int i = 0; i < size; ++i) { - char ch = static_cast<char>(i); - send_stream_.Write(&ch, 1, NULL, NULL); - } - send_stream_.Rewind(); - // Prepare the receive stream. - recv_stream_.ReserveSize(size); - // Connect and wait until connected. - start = rtc::Time(); - EXPECT_EQ(0, Connect()); - EXPECT_TRUE_WAIT(have_connected_, kConnectTimeoutMs); - // Sending will start from OnTcpWriteable and stop when the required - // number of iterations have completed. - EXPECT_TRUE_WAIT(have_disconnected_, kTransferTimeoutMs); - elapsed = rtc::TimeSince(start); - LOG(LS_INFO) << "Performed " << iterations << " pings in " - << elapsed << " ms"; - } - - private: - // IPseudoTcpNotify interface - - virtual void OnTcpReadable(PseudoTcp* tcp) { - if (tcp != receiver_) { - LOG_F(LS_ERROR) << "unexpected OnTcpReadable"; - return; - } - // Stream bytes to the recv stream as they arrive. - ReadData(); - // If we've received the desired amount of data, rewind things - // and send it back the other way! - size_t position, desired; - recv_stream_.GetPosition(&position); - send_stream_.GetSize(&desired); - if (position == desired) { - if (receiver_ == &local_ && --iterations_remaining_ == 0) { - Close(); - // TODO: Fake OnTcpClosed() on the receiver for now. - OnTcpClosed(&remote_, 0); - return; - } - PseudoTcp* tmp = receiver_; - receiver_ = sender_; - sender_ = tmp; - recv_stream_.Rewind(); - send_stream_.Rewind(); - OnTcpWriteable(sender_); - } - } - virtual void OnTcpWriteable(PseudoTcp* tcp) { - if (tcp != sender_) - return; - // Write bytes from the send stream when we can. - // Shut down when we've sent everything. - LOG(LS_VERBOSE) << "Flow Control Lifted"; - WriteData(); - } - - void ReadData() { - char block[kBlockSize]; - size_t position; - int rcvd; - do { - rcvd = receiver_->Recv(block, sizeof(block)); - if (rcvd != -1) { - recv_stream_.Write(block, rcvd, NULL, NULL); - recv_stream_.GetPosition(&position); - LOG(LS_VERBOSE) << "Received: " << position; - } - } while (rcvd > 0); - } - void WriteData() { - size_t position, tosend; - int sent; - char block[kBlockSize]; - do { - send_stream_.GetPosition(&position); - tosend = bytes_per_send_ ? bytes_per_send_ : sizeof(block); - if (send_stream_.Read(block, tosend, &tosend, NULL) != - rtc::SR_EOS) { - sent = sender_->Send(block, tosend); - UpdateLocalClock(); - if (sent != -1) { - send_stream_.SetPosition(position + sent); - LOG(LS_VERBOSE) << "Sent: " << position + sent; - } else { - send_stream_.SetPosition(position); - LOG(LS_VERBOSE) << "Flow Controlled"; - } - } else { - sent = static_cast<int>(tosend = 0); - } - } while (sent > 0); - } - - private: - int iterations_remaining_; - PseudoTcp* sender_; - PseudoTcp* receiver_; - int bytes_per_send_; -}; - -// Fill the receiver window until it is full, drain it and then -// fill it with the same amount. This is to test that receiver window -// contracts and enlarges correctly. -class PseudoTcpTestReceiveWindow : public PseudoTcpTestBase { - public: - // Not all the data are transfered, |size| just need to be big enough - // to fill up the receiver window twice. - void TestTransfer(int size) { - // Create some dummy data to send. - send_stream_.ReserveSize(size); - for (int i = 0; i < size; ++i) { - char ch = static_cast<char>(i); - send_stream_.Write(&ch, 1, NULL, NULL); - } - send_stream_.Rewind(); - - // Prepare the receive stream. - recv_stream_.ReserveSize(size); - - // Connect and wait until connected. - EXPECT_EQ(0, Connect()); - EXPECT_TRUE_WAIT(have_connected_, kConnectTimeoutMs); - - rtc::Thread::Current()->Post(this, MSG_WRITE); - EXPECT_TRUE_WAIT(have_disconnected_, kTransferTimeoutMs); - - ASSERT_EQ(2u, send_position_.size()); - ASSERT_EQ(2u, recv_position_.size()); - - const size_t estimated_recv_window = EstimateReceiveWindowSize(); - - // The difference in consecutive send positions should equal the - // receive window size or match very closely. This verifies that receive - // window is open after receiver drained all the data. - const size_t send_position_diff = send_position_[1] - send_position_[0]; - EXPECT_GE(1024u, estimated_recv_window - send_position_diff); - - // Receiver drained the receive window twice. - EXPECT_EQ(2 * estimated_recv_window, recv_position_[1]); - } - - virtual void OnMessage(rtc::Message* message) { - int message_id = message->message_id; - PseudoTcpTestBase::OnMessage(message); - - switch (message_id) { - case MSG_WRITE: { - WriteData(); - break; - } - default: - break; - } - } - - uint32 EstimateReceiveWindowSize() const { - return static_cast<uint32>(recv_position_[0]); - } - - uint32 EstimateSendWindowSize() const { - return static_cast<uint32>(send_position_[0] - recv_position_[0]); - } - - private: - // IPseudoTcpNotify interface - virtual void OnTcpReadable(PseudoTcp* tcp) { - } - - virtual void OnTcpWriteable(PseudoTcp* tcp) { - } - - void ReadUntilIOPending() { - char block[kBlockSize]; - size_t position; - int rcvd; - - do { - rcvd = remote_.Recv(block, sizeof(block)); - if (rcvd != -1) { - recv_stream_.Write(block, rcvd, NULL, NULL); - recv_stream_.GetPosition(&position); - LOG(LS_VERBOSE) << "Received: " << position; - } - } while (rcvd > 0); - - recv_stream_.GetPosition(&position); - recv_position_.push_back(position); - - // Disconnect if we have done two transfers. - if (recv_position_.size() == 2u) { - Close(); - OnTcpClosed(&remote_, 0); - } else { - WriteData(); - } - } - - void WriteData() { - size_t position, tosend; - int sent; - char block[kBlockSize]; - do { - send_stream_.GetPosition(&position); - if (send_stream_.Read(block, sizeof(block), &tosend, NULL) != - rtc::SR_EOS) { - sent = local_.Send(block, tosend); - UpdateLocalClock(); - if (sent != -1) { - send_stream_.SetPosition(position + sent); - LOG(LS_VERBOSE) << "Sent: " << position + sent; - } else { - send_stream_.SetPosition(position); - LOG(LS_VERBOSE) << "Flow Controlled"; - } - } else { - sent = static_cast<int>(tosend = 0); - } - } while (sent > 0); - // At this point, we've filled up the available space in the send queue. - - int message_queue_size = - static_cast<int>(rtc::Thread::Current()->size()); - // The message queue will always have at least 2 messages, an RCLOCK and - // an LCLOCK, since they are added back on the delay queue at the same time - // they are pulled off and therefore are never really removed. - if (message_queue_size > 2) { - // If there are non-clock messages remaining, attempt to continue sending - // after giving those messages time to process, which should free up the - // send buffer. - rtc::Thread::Current()->PostDelayed(10, this, MSG_WRITE); - } else { - if (!remote_.isReceiveBufferFull()) { - LOG(LS_ERROR) << "This shouldn't happen - the send buffer is full, " - << "the receive buffer is not, and there are no " - << "remaining messages to process."; - } - send_stream_.GetPosition(&position); - send_position_.push_back(position); - - // Drain the receiver buffer. - ReadUntilIOPending(); - } - } - - private: - rtc::MemoryStream send_stream_; - rtc::MemoryStream recv_stream_; - - std::vector<size_t> send_position_; - std::vector<size_t> recv_position_; -}; - -// Basic end-to-end data transfer tests - -// Test the normal case of sending data from one side to the other. -TEST_F(PseudoTcpTest, TestSend) { - SetLocalMtu(1500); - SetRemoteMtu(1500); - TestTransfer(1000000); -} - -// Test sending data with a 50 ms RTT. Transmission should take longer due -// to a slower ramp-up in send rate. -TEST_F(PseudoTcpTest, TestSendWithDelay) { - SetLocalMtu(1500); - SetRemoteMtu(1500); - SetDelay(50); - TestTransfer(1000000); -} - -// Test sending data with packet loss. Transmission should take much longer due -// to send back-off when loss occurs. -TEST_F(PseudoTcpTest, TestSendWithLoss) { - SetLocalMtu(1500); - SetRemoteMtu(1500); - SetLoss(10); - TestTransfer(100000); // less data so test runs faster -} - -// Test sending data with a 50 ms RTT and 10% packet loss. Transmission should -// take much longer due to send back-off and slower detection of loss. -TEST_F(PseudoTcpTest, TestSendWithDelayAndLoss) { - SetLocalMtu(1500); - SetRemoteMtu(1500); - SetDelay(50); - SetLoss(10); - TestTransfer(100000); // less data so test runs faster -} - -// Test sending data with 10% packet loss and Nagling disabled. Transmission -// should take about the same time as with Nagling enabled. -TEST_F(PseudoTcpTest, TestSendWithLossAndOptNaglingOff) { - SetLocalMtu(1500); - SetRemoteMtu(1500); - SetLoss(10); - SetOptNagling(false); - TestTransfer(100000); // less data so test runs faster -} - -// Test sending data with 10% packet loss and Delayed ACK disabled. -// Transmission should be slightly faster than with it enabled. -TEST_F(PseudoTcpTest, TestSendWithLossAndOptAckDelayOff) { - SetLocalMtu(1500); - SetRemoteMtu(1500); - SetLoss(10); - SetOptAckDelay(0); - TestTransfer(100000); -} - -// Test sending data with 50ms delay and Nagling disabled. -TEST_F(PseudoTcpTest, TestSendWithDelayAndOptNaglingOff) { - SetLocalMtu(1500); - SetRemoteMtu(1500); - SetDelay(50); - SetOptNagling(false); - TestTransfer(100000); // less data so test runs faster -} - -// Test sending data with 50ms delay and Delayed ACK disabled. -TEST_F(PseudoTcpTest, TestSendWithDelayAndOptAckDelayOff) { - SetLocalMtu(1500); - SetRemoteMtu(1500); - SetDelay(50); - SetOptAckDelay(0); - TestTransfer(100000); // less data so test runs faster -} - -// Test a large receive buffer with a sender that doesn't support scaling. -TEST_F(PseudoTcpTest, TestSendRemoteNoWindowScale) { - SetLocalMtu(1500); - SetRemoteMtu(1500); - SetLocalOptRcvBuf(100000); - DisableRemoteWindowScale(); - TestTransfer(1000000); -} - -// Test a large sender-side receive buffer with a receiver that doesn't support -// scaling. -TEST_F(PseudoTcpTest, TestSendLocalNoWindowScale) { - SetLocalMtu(1500); - SetRemoteMtu(1500); - SetRemoteOptRcvBuf(100000); - DisableLocalWindowScale(); - TestTransfer(1000000); -} - -// Test when both sides use window scaling. -TEST_F(PseudoTcpTest, TestSendBothUseWindowScale) { - SetLocalMtu(1500); - SetRemoteMtu(1500); - SetRemoteOptRcvBuf(100000); - SetLocalOptRcvBuf(100000); - TestTransfer(1000000); -} - -// Test using a large window scale value. -TEST_F(PseudoTcpTest, TestSendLargeInFlight) { - SetLocalMtu(1500); - SetRemoteMtu(1500); - SetRemoteOptRcvBuf(100000); - SetLocalOptRcvBuf(100000); - SetOptSndBuf(150000); - TestTransfer(1000000); -} - -TEST_F(PseudoTcpTest, TestSendBothUseLargeWindowScale) { - SetLocalMtu(1500); - SetRemoteMtu(1500); - SetRemoteOptRcvBuf(1000000); - SetLocalOptRcvBuf(1000000); - TestTransfer(10000000); -} - -// Test using a small receive buffer. -TEST_F(PseudoTcpTest, TestSendSmallReceiveBuffer) { - SetLocalMtu(1500); - SetRemoteMtu(1500); - SetRemoteOptRcvBuf(10000); - SetLocalOptRcvBuf(10000); - TestTransfer(1000000); -} - -// Test using a very small receive buffer. -TEST_F(PseudoTcpTest, TestSendVerySmallReceiveBuffer) { - SetLocalMtu(1500); - SetRemoteMtu(1500); - SetRemoteOptRcvBuf(100); - SetLocalOptRcvBuf(100); - TestTransfer(100000); -} - -// Ping-pong (request/response) tests - -// Test sending <= 1x MTU of data in each ping/pong. Should take <10ms. -TEST_F(PseudoTcpTestPingPong, TestPingPong1xMtu) { - SetLocalMtu(1500); - SetRemoteMtu(1500); - TestPingPong(100, 100); -} - -// Test sending 2x-3x MTU of data in each ping/pong. Should take <10ms. -TEST_F(PseudoTcpTestPingPong, TestPingPong3xMtu) { - SetLocalMtu(1500); - SetRemoteMtu(1500); - TestPingPong(400, 100); -} - -// Test sending 1x-2x MTU of data in each ping/pong. -// Should take ~1s, due to interaction between Nagling and Delayed ACK. -TEST_F(PseudoTcpTestPingPong, TestPingPong2xMtu) { - SetLocalMtu(1500); - SetRemoteMtu(1500); - TestPingPong(2000, 5); -} - -// Test sending 1x-2x MTU of data in each ping/pong with Delayed ACK off. -// Should take <10ms. -TEST_F(PseudoTcpTestPingPong, TestPingPong2xMtuWithAckDelayOff) { - SetLocalMtu(1500); - SetRemoteMtu(1500); - SetOptAckDelay(0); - TestPingPong(2000, 100); -} - -// Test sending 1x-2x MTU of data in each ping/pong with Nagling off. -// Should take <10ms. -TEST_F(PseudoTcpTestPingPong, TestPingPong2xMtuWithNaglingOff) { - SetLocalMtu(1500); - SetRemoteMtu(1500); - SetOptNagling(false); - TestPingPong(2000, 5); -} - -// Test sending a ping as pair of short (non-full) segments. -// Should take ~1s, due to Delayed ACK interaction with Nagling. -TEST_F(PseudoTcpTestPingPong, TestPingPongShortSegments) { - SetLocalMtu(1500); - SetRemoteMtu(1500); - SetOptAckDelay(5000); - SetBytesPerSend(50); // i.e. two Send calls per payload - TestPingPong(100, 5); -} - -// Test sending ping as a pair of short (non-full) segments, with Nagling off. -// Should take <10ms. -TEST_F(PseudoTcpTestPingPong, TestPingPongShortSegmentsWithNaglingOff) { - SetLocalMtu(1500); - SetRemoteMtu(1500); - SetOptNagling(false); - SetBytesPerSend(50); // i.e. two Send calls per payload - TestPingPong(100, 5); -} - -// Test sending <= 1x MTU of data ping/pong, in two segments, no Delayed ACK. -// Should take ~1s. -TEST_F(PseudoTcpTestPingPong, TestPingPongShortSegmentsWithAckDelayOff) { - SetLocalMtu(1500); - SetRemoteMtu(1500); - SetBytesPerSend(50); // i.e. two Send calls per payload - SetOptAckDelay(0); - TestPingPong(100, 5); -} - -// Test that receive window expands and contract correctly. -TEST_F(PseudoTcpTestReceiveWindow, TestReceiveWindow) { - SetLocalMtu(1500); - SetRemoteMtu(1500); - SetOptNagling(false); - SetOptAckDelay(0); - TestTransfer(1024 * 1000); -} - -// Test setting send window size to a very small value. -TEST_F(PseudoTcpTestReceiveWindow, TestSetVerySmallSendWindowSize) { - SetLocalMtu(1500); - SetRemoteMtu(1500); - SetOptNagling(false); - SetOptAckDelay(0); - SetOptSndBuf(900); - TestTransfer(1024 * 1000); - EXPECT_EQ(900u, EstimateSendWindowSize()); -} - -// Test setting receive window size to a value other than default. -TEST_F(PseudoTcpTestReceiveWindow, TestSetReceiveWindowSize) { - SetLocalMtu(1500); - SetRemoteMtu(1500); - SetOptNagling(false); - SetOptAckDelay(0); - SetRemoteOptRcvBuf(100000); - SetLocalOptRcvBuf(100000); - TestTransfer(1024 * 1000); - EXPECT_EQ(100000u, EstimateReceiveWindowSize()); -} - -/* Test sending data with mismatched MTUs. We should detect this and reduce -// our packet size accordingly. -// TODO: This doesn't actually work right now. The current code -// doesn't detect if the MTU is set too high on either side. -TEST_F(PseudoTcpTest, TestSendWithMismatchedMtus) { - SetLocalMtu(1500); - SetRemoteMtu(1280); - TestTransfer(1000000); -} -*/ diff --git a/talk/p2p/base/rawtransport.cc b/talk/p2p/base/rawtransport.cc deleted file mode 100644 index f363dd104..000000000 --- a/talk/p2p/base/rawtransport.cc +++ /dev/null @@ -1,132 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <string> -#include <vector> -#include "webrtc/p2p/base/constants.h" -#include "webrtc/p2p/base/parsing.h" -#include "webrtc/p2p/base/rawtransport.h" -#include "webrtc/p2p/base/rawtransportchannel.h" -#include "webrtc/p2p/base/sessionmanager.h" -#include "webrtc/libjingle/xmllite/qname.h" -#include "webrtc/libjingle/xmllite/xmlelement.h" -#include "webrtc/libjingle/xmpp/constants.h" -#include "webrtc/base/common.h" - -#if defined(FEATURE_ENABLE_PSTN) -namespace cricket { - -RawTransport::RawTransport(rtc::Thread* signaling_thread, - rtc::Thread* worker_thread, - const std::string& content_name, - PortAllocator* allocator) - : Transport(signaling_thread, worker_thread, - content_name, NS_GINGLE_RAW, allocator) { -} - -RawTransport::~RawTransport() { - DestroyAllChannels(); -} - -bool RawTransport::ParseCandidates(SignalingProtocol protocol, - const buzz::XmlElement* elem, - const CandidateTranslator* translator, - Candidates* candidates, - ParseError* error) { - for (const buzz::XmlElement* cand_elem = elem->FirstElement(); - cand_elem != NULL; - cand_elem = cand_elem->NextElement()) { - if (cand_elem->Name() == QN_GINGLE_RAW_CHANNEL) { - if (!cand_elem->HasAttr(buzz::QN_NAME)) { - return BadParse("no channel name given", error); - } - if (type() != cand_elem->Attr(buzz::QN_NAME)) { - return BadParse("channel named does not exist", error); - } - rtc::SocketAddress addr; - if (!ParseRawAddress(cand_elem, &addr, error)) - return false; - - Candidate candidate; - candidate.set_component(1); - candidate.set_address(addr); - candidates->push_back(candidate); - } - } - return true; -} - -bool RawTransport::WriteCandidates(SignalingProtocol protocol, - const Candidates& candidates, - const CandidateTranslator* translator, - XmlElements* candidate_elems, - WriteError* error) { - for (std::vector<Candidate>::const_iterator - cand = candidates.begin(); - cand != candidates.end(); - ++cand) { - ASSERT(cand->component() == 1); - ASSERT(cand->protocol() == "udp"); - rtc::SocketAddress addr = cand->address(); - - buzz::XmlElement* elem = new buzz::XmlElement(QN_GINGLE_RAW_CHANNEL); - elem->SetAttr(buzz::QN_NAME, type()); - elem->SetAttr(QN_ADDRESS, addr.ipaddr().ToString()); - elem->SetAttr(QN_PORT, addr.PortAsString()); - candidate_elems->push_back(elem); - } - return true; -} - -bool RawTransport::ParseRawAddress(const buzz::XmlElement* elem, - rtc::SocketAddress* addr, - ParseError* error) { - // Make sure the required attributes exist - if (!elem->HasAttr(QN_ADDRESS) || - !elem->HasAttr(QN_PORT)) { - return BadParse("channel missing required attribute", error); - } - - // Parse the address. - if (!ParseAddress(elem, QN_ADDRESS, QN_PORT, addr, error)) - return false; - - return true; -} - -TransportChannelImpl* RawTransport::CreateTransportChannel(int component) { - return new RawTransportChannel(content_name(), component, this, - worker_thread(), - port_allocator()); -} - -void RawTransport::DestroyTransportChannel(TransportChannelImpl* channel) { - delete channel; -} - -} // namespace cricket -#endif // defined(FEATURE_ENABLE_PSTN) diff --git a/talk/p2p/base/rawtransport.h b/talk/p2p/base/rawtransport.h deleted file mode 100644 index 7458191b6..000000000 --- a/talk/p2p/base/rawtransport.h +++ /dev/null @@ -1,81 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef WEBRTC_P2P_BASE_RAWTRANSPORT_H_ -#define WEBRTC_P2P_BASE_RAWTRANSPORT_H_ - -#include <string> -#include "webrtc/p2p/base/transport.h" - -#if defined(FEATURE_ENABLE_PSTN) -namespace cricket { - -// Implements a transport that only sends raw packets, no STUN. As a result, -// it cannot do pings to determine connectivity, so it only uses a single port -// that it thinks will work. -class RawTransport : public Transport, public TransportParser { - public: - RawTransport(rtc::Thread* signaling_thread, - rtc::Thread* worker_thread, - const std::string& content_name, - PortAllocator* allocator); - virtual ~RawTransport(); - - virtual bool ParseCandidates(SignalingProtocol protocol, - const buzz::XmlElement* elem, - const CandidateTranslator* translator, - Candidates* candidates, - ParseError* error); - virtual bool WriteCandidates(SignalingProtocol protocol, - const Candidates& candidates, - const CandidateTranslator* translator, - XmlElements* candidate_elems, - WriteError* error); - - protected: - // Creates and destroys raw channels. - virtual TransportChannelImpl* CreateTransportChannel(int component); - virtual void DestroyTransportChannel(TransportChannelImpl* channel); - - private: - // Parses the given element, which should describe the address to use for a - // given channel. This will return false and signal an error if the address - // or channel name is bad. - bool ParseRawAddress(const buzz::XmlElement* elem, - rtc::SocketAddress* addr, - ParseError* error); - - friend class RawTransportChannel; // For ParseAddress. - - DISALLOW_EVIL_CONSTRUCTORS(RawTransport); -}; - -} // namespace cricket - -#endif // defined(FEATURE_ENABLE_PSTN) - -#endif // WEBRTC_P2P_BASE_RAWTRANSPORT_H_ diff --git a/talk/p2p/base/rawtransportchannel.cc b/talk/p2p/base/rawtransportchannel.cc deleted file mode 100644 index ef2286b6a..000000000 --- a/talk/p2p/base/rawtransportchannel.cc +++ /dev/null @@ -1,277 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "webrtc/p2p/base/rawtransportchannel.h" - -#include <string> -#include <vector> -#include "webrtc/p2p/base/constants.h" -#include "webrtc/p2p/base/portallocator.h" -#include "webrtc/p2p/base/portinterface.h" -#include "webrtc/p2p/base/rawtransport.h" -#include "webrtc/p2p/base/relayport.h" -#include "webrtc/p2p/base/sessionmanager.h" -#include "webrtc/p2p/base/stunport.h" -#include "webrtc/libjingle/xmllite/qname.h" -#include "webrtc/libjingle/xmllite/xmlelement.h" -#include "webrtc/libjingle/xmpp/constants.h" -#include "webrtc/base/common.h" - -#if defined(FEATURE_ENABLE_PSTN) - -namespace { - -const uint32 MSG_DESTROY_RTC_UNUSED_PORTS = 1; - -} // namespace - -namespace cricket { - -RawTransportChannel::RawTransportChannel(const std::string& content_name, - int component, - RawTransport* transport, - rtc::Thread *worker_thread, - PortAllocator *allocator) - : TransportChannelImpl(content_name, component), - raw_transport_(transport), - allocator_(allocator), - allocator_session_(NULL), - stun_port_(NULL), - relay_port_(NULL), - port_(NULL), - use_relay_(false) { - if (worker_thread == NULL) - worker_thread_ = raw_transport_->worker_thread(); - else - worker_thread_ = worker_thread; -} - -RawTransportChannel::~RawTransportChannel() { - delete allocator_session_; -} - -int RawTransportChannel::SendPacket(const char *data, size_t size, - const rtc::PacketOptions& options, - int flags) { - if (port_ == NULL) - return -1; - if (remote_address_.IsNil()) - return -1; - if (flags != 0) - return -1; - return port_->SendTo(data, size, remote_address_, options, true); -} - -int RawTransportChannel::SetOption(rtc::Socket::Option opt, int value) { - // TODO: allow these to be set before we have a port - if (port_ == NULL) - return -1; - return port_->SetOption(opt, value); -} - -int RawTransportChannel::GetError() { - return (port_ != NULL) ? port_->GetError() : 0; -} - -void RawTransportChannel::Connect() { - // Create an allocator that only returns stun and relay ports. - // Use empty string for ufrag and pwd here. There won't be any STUN or relay - // interactions when using RawTC. - // TODO: Change raw to only use local udp ports. - allocator_session_ = allocator_->CreateSession( - SessionId(), content_name(), component(), "", ""); - - uint32 flags = PORTALLOCATOR_DISABLE_UDP | PORTALLOCATOR_DISABLE_TCP; - -#if !defined(FEATURE_ENABLE_STUN_CLASSIFICATION) - flags |= PORTALLOCATOR_DISABLE_RELAY; -#endif - allocator_session_->set_flags(flags); - allocator_session_->SignalPortReady.connect( - this, &RawTransportChannel::OnPortReady); - allocator_session_->SignalCandidatesReady.connect( - this, &RawTransportChannel::OnCandidatesReady); - - // The initial ports will include stun. - allocator_session_->StartGettingPorts(); -} - -void RawTransportChannel::Reset() { - set_readable(false); - set_writable(false); - - delete allocator_session_; - - allocator_session_ = NULL; - stun_port_ = NULL; - relay_port_ = NULL; - port_ = NULL; - remote_address_ = rtc::SocketAddress(); -} - -void RawTransportChannel::OnCandidate(const Candidate& candidate) { - remote_address_ = candidate.address(); - ASSERT(!remote_address_.IsNil()); - set_readable(true); - - // We can write once we have a port and a remote address. - if (port_ != NULL) - SetWritable(); -} - -void RawTransportChannel::OnRemoteAddress( - const rtc::SocketAddress& remote_address) { - remote_address_ = remote_address; - set_readable(true); - - if (port_ != NULL) - SetWritable(); -} - -// Note about stun classification -// Code to classify our NAT type and use the relay port if we are behind an -// asymmetric NAT is under a FEATURE_ENABLE_STUN_CLASSIFICATION #define. -// To turn this one we will have to enable a second stun address and make sure -// that the relay server works for raw UDP. -// -// Another option is to classify the NAT type early and not offer the raw -// transport type at all if we can't support it. - -void RawTransportChannel::OnPortReady( - PortAllocatorSession* session, PortInterface* port) { - ASSERT(session == allocator_session_); - - if (port->Type() == STUN_PORT_TYPE) { - stun_port_ = static_cast<StunPort*>(port); - } else if (port->Type() == RELAY_PORT_TYPE) { - relay_port_ = static_cast<RelayPort*>(port); - } else { - ASSERT(false); - } -} - -void RawTransportChannel::OnCandidatesReady( - PortAllocatorSession *session, const std::vector<Candidate>& candidates) { - ASSERT(session == allocator_session_); - ASSERT(candidates.size() >= 1); - - // The most recent candidate is the one we haven't seen yet. - Candidate c = candidates[candidates.size() - 1]; - - if (c.type() == STUN_PORT_TYPE) { - ASSERT(stun_port_ != NULL); - -#if defined(FEATURE_ENABLE_STUN_CLASSIFICATION) - // We need to wait until we have two addresses. - if (stun_port_->candidates().size() < 2) - return; - - // This is the second address. If these addresses are the same, then we - // are not behind a symmetric NAT. Hence, a stun port should be sufficient. - if (stun_port_->candidates()[0].address() == - stun_port_->candidates()[1].address()) { - SetPort(stun_port_); - return; - } - - // We will need to use relay. - use_relay_ = true; - - // If we already have a relay address, we're good. Otherwise, we will need - // to wait until one arrives. - if (relay_port_->candidates().size() > 0) - SetPort(relay_port_); -#else // defined(FEATURE_ENABLE_STUN_CLASSIFICATION) - // Always use the stun port. We don't classify right now so just assume it - // will work fine. - SetPort(stun_port_); -#endif - } else if (c.type() == RELAY_PORT_TYPE) { - if (use_relay_) - SetPort(relay_port_); - } else { - ASSERT(false); - } -} - -void RawTransportChannel::SetPort(PortInterface* port) { - ASSERT(port_ == NULL); - port_ = port; - - // We don't need any ports other than the one we picked. - allocator_session_->StopGettingPorts(); - worker_thread_->Post( - this, MSG_DESTROY_RTC_UNUSED_PORTS, NULL); - - // Send a message to the other client containing our address. - - ASSERT(port_->Candidates().size() >= 1); - ASSERT(port_->Candidates()[0].protocol() == "udp"); - SignalCandidateReady(this, port_->Candidates()[0]); - - // Read all packets from this port. - port_->EnablePortPackets(); - port_->SignalReadPacket.connect(this, &RawTransportChannel::OnReadPacket); - - // We can write once we have a port and a remote address. - if (!remote_address_.IsAny()) - SetWritable(); -} - -void RawTransportChannel::SetWritable() { - ASSERT(port_ != NULL); - ASSERT(!remote_address_.IsAny()); - - set_writable(true); - - Candidate remote_candidate; - remote_candidate.set_address(remote_address_); - SignalRouteChange(this, remote_candidate); -} - -void RawTransportChannel::OnReadPacket( - PortInterface* port, const char* data, size_t size, - const rtc::SocketAddress& addr) { - ASSERT(port_ == port); - SignalReadPacket(this, data, size, rtc::CreatePacketTime(0), 0); -} - -void RawTransportChannel::OnMessage(rtc::Message* msg) { - ASSERT(msg->message_id == MSG_DESTROY_RTC_UNUSED_PORTS); - ASSERT(port_ != NULL); - if (port_ != stun_port_) { - stun_port_->Destroy(); - stun_port_ = NULL; - } - if (port_ != relay_port_ && relay_port_ != NULL) { - relay_port_->Destroy(); - relay_port_ = NULL; - } -} - -} // namespace cricket -#endif // defined(FEATURE_ENABLE_PSTN) diff --git a/talk/p2p/base/rawtransportchannel.h b/talk/p2p/base/rawtransportchannel.h deleted file mode 100644 index 25f6e4f3d..000000000 --- a/talk/p2p/base/rawtransportchannel.h +++ /dev/null @@ -1,206 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef WEBRTC_P2P_BASE_RAWTRANSPORTCHANNEL_H_ -#define WEBRTC_P2P_BASE_RAWTRANSPORTCHANNEL_H_ - -#include <string> -#include <vector> -#include "webrtc/p2p/base/candidate.h" -#include "webrtc/p2p/base/rawtransport.h" -#include "webrtc/p2p/base/transportchannelimpl.h" -#include "webrtc/base/messagequeue.h" - -#if defined(FEATURE_ENABLE_PSTN) - -namespace rtc { -class Thread; -} - -namespace cricket { - -class Connection; -class PortAllocator; -class PortAllocatorSession; -class PortInterface; -class RelayPort; -class StunPort; - -// Implements a channel that just sends bare packets once we have received the -// address of the other side. We pick a single address to send them based on -// a simple investigation of NAT type. -class RawTransportChannel : public TransportChannelImpl, - public rtc::MessageHandler { - public: - RawTransportChannel(const std::string& content_name, - int component, - RawTransport* transport, - rtc::Thread *worker_thread, - PortAllocator *allocator); - virtual ~RawTransportChannel(); - - // Implementation of normal channel packet sending. - virtual int SendPacket(const char *data, size_t len, - const rtc::PacketOptions& options, int flags); - virtual int SetOption(rtc::Socket::Option opt, int value); - virtual int GetError(); - - // Implements TransportChannelImpl. - virtual Transport* GetTransport() { return raw_transport_; } - virtual void SetIceCredentials(const std::string& ice_ufrag, - const std::string& ice_pwd) {} - virtual void SetRemoteIceCredentials(const std::string& ice_ufrag, - const std::string& ice_pwd) {} - - // Creates an allocator session to start figuring out which type of - // port we should send to the other client. This will send - // SignalAvailableCandidate once we have decided. - virtual void Connect(); - - // Resets state back to unconnected. - virtual void Reset(); - - // We don't actually worry about signaling since we can't send new candidates. - virtual void OnSignalingReady() {} - - // Handles a message setting the remote address. We are writable once we - // have this since we now know where to send. - virtual void OnCandidate(const Candidate& candidate); - - void OnRemoteAddress(const rtc::SocketAddress& remote_address); - - // Below ICE specific virtual methods not implemented. - virtual IceRole GetIceRole() const { return ICEROLE_UNKNOWN; } - virtual void SetIceRole(IceRole role) {} - virtual void SetIceTiebreaker(uint64 tiebreaker) {} - - virtual bool GetIceProtocolType(IceProtocolType* type) const { return false; } - virtual void SetIceProtocolType(IceProtocolType type) {} - - virtual void SetIceUfrag(const std::string& ice_ufrag) {} - virtual void SetIcePwd(const std::string& ice_pwd) {} - virtual void SetRemoteIceMode(IceMode mode) {} - virtual size_t GetConnectionCount() const { return 1; } - - virtual bool GetStats(ConnectionInfos* infos) { - return false; - } - - // DTLS methods. - virtual bool IsDtlsActive() const { return false; } - - // Default implementation. - virtual bool GetSslRole(rtc::SSLRole* role) const { - return false; - } - - virtual bool SetSslRole(rtc::SSLRole role) { - return false; - } - - // Set up the ciphers to use for DTLS-SRTP. - virtual bool SetSrtpCiphers(const std::vector<std::string>& ciphers) { - return false; - } - - // Find out which DTLS-SRTP cipher was negotiated - virtual bool GetSrtpCipher(std::string* cipher) { - return false; - } - - // Returns false because the channel is not DTLS. - virtual bool GetLocalIdentity(rtc::SSLIdentity** identity) const { - return false; - } - - virtual bool GetRemoteCertificate(rtc::SSLCertificate** cert) const { - return false; - } - - // Allows key material to be extracted for external encryption. - virtual bool ExportKeyingMaterial( - const std::string& label, - const uint8* context, - size_t context_len, - bool use_context, - uint8* result, - size_t result_len) { - return false; - } - - virtual bool SetLocalIdentity(rtc::SSLIdentity* identity) { - return false; - } - - // Set DTLS Remote fingerprint. Must be after local identity set. - virtual bool SetRemoteFingerprint( - const std::string& digest_alg, - const uint8* digest, - size_t digest_len) { - return false; - } - - private: - RawTransport* raw_transport_; - rtc::Thread *worker_thread_; - PortAllocator* allocator_; - PortAllocatorSession* allocator_session_; - StunPort* stun_port_; - RelayPort* relay_port_; - PortInterface* port_; - bool use_relay_; - rtc::SocketAddress remote_address_; - - // Called when the allocator creates another port. - void OnPortReady(PortAllocatorSession* session, PortInterface* port); - - // Called when one of the ports we are using has determined its address. - void OnCandidatesReady(PortAllocatorSession *session, - const std::vector<Candidate>& candidates); - - // Called once we have chosen the port to use for communication with the - // other client. This will send its address and prepare the port for use. - void SetPort(PortInterface* port); - - // Called once we have a port and a remote address. This will set mark the - // channel as writable and signal the route to the client. - void SetWritable(); - - // Called when we receive a packet from the other client. - void OnReadPacket(PortInterface* port, const char* data, size_t size, - const rtc::SocketAddress& addr); - - // Handles a message to destroy unused ports. - virtual void OnMessage(rtc::Message *msg); - - DISALLOW_EVIL_CONSTRUCTORS(RawTransportChannel); -}; - -} // namespace cricket - -#endif // defined(FEATURE_ENABLE_PSTN) -#endif // WEBRTC_P2P_BASE_RAWTRANSPORTCHANNEL_H_ diff --git a/talk/p2p/base/relayport.cc b/talk/p2p/base/relayport.cc deleted file mode 100644 index 2db42c97e..000000000 --- a/talk/p2p/base/relayport.cc +++ /dev/null @@ -1,835 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "webrtc/p2p/base/relayport.h" -#include "webrtc/base/asyncpacketsocket.h" -#include "webrtc/base/helpers.h" -#include "webrtc/base/logging.h" - -namespace cricket { - -static const uint32 kMessageConnectTimeout = 1; -static const int kKeepAliveDelay = 10 * 60 * 1000; -static const int kRetryTimeout = 50 * 1000; // ICE says 50 secs -// How long to wait for a socket to connect to remote host in milliseconds -// before trying another connection. -static const int kSoftConnectTimeoutMs = 3 * 1000; - -// Handles a connection to one address/port/protocol combination for a -// particular RelayEntry. -class RelayConnection : public sigslot::has_slots<> { - public: - RelayConnection(const ProtocolAddress* protocol_address, - rtc::AsyncPacketSocket* socket, - rtc::Thread* thread); - ~RelayConnection(); - rtc::AsyncPacketSocket* socket() const { return socket_; } - - const ProtocolAddress* protocol_address() { - return protocol_address_; - } - - rtc::SocketAddress GetAddress() const { - return protocol_address_->address; - } - - ProtocolType GetProtocol() const { - return protocol_address_->proto; - } - - int SetSocketOption(rtc::Socket::Option opt, int value); - - // Validates a response to a STUN allocate request. - bool CheckResponse(StunMessage* msg); - - // Sends data to the relay server. - int Send(const void* pv, size_t cb, const rtc::PacketOptions& options); - - // Sends a STUN allocate request message to the relay server. - void SendAllocateRequest(RelayEntry* entry, int delay); - - // Return the latest error generated by the socket. - int GetError() { return socket_->GetError(); } - - // Called on behalf of a StunRequest to write data to the socket. This is - // already STUN intended for the server, so no wrapping is necessary. - void OnSendPacket(const void* data, size_t size, StunRequest* req); - - private: - rtc::AsyncPacketSocket* socket_; - const ProtocolAddress* protocol_address_; - StunRequestManager *request_manager_; -}; - -// Manages a number of connections to the relayserver, one for each -// available protocol. We aim to use each connection for only a -// specific destination address so that we can avoid wrapping every -// packet in a STUN send / data indication. -class RelayEntry : public rtc::MessageHandler, - public sigslot::has_slots<> { - public: - RelayEntry(RelayPort* port, const rtc::SocketAddress& ext_addr); - ~RelayEntry(); - - RelayPort* port() { return port_; } - - const rtc::SocketAddress& address() const { return ext_addr_; } - void set_address(const rtc::SocketAddress& addr) { ext_addr_ = addr; } - - bool connected() const { return connected_; } - bool locked() const { return locked_; } - - // Returns the last error on the socket of this entry. - int GetError(); - - // Returns the most preferred connection of the given - // ones. Connections are rated based on protocol in the order of: - // UDP, TCP and SSLTCP, where UDP is the most preferred protocol - static RelayConnection* GetBestConnection(RelayConnection* conn1, - RelayConnection* conn2); - - // Sends the STUN requests to the server to initiate this connection. - void Connect(); - - // Called when this entry becomes connected. The address given is the one - // exposed to the outside world on the relay server. - void OnConnect(const rtc::SocketAddress& mapped_addr, - RelayConnection* socket); - - // Sends a packet to the given destination address using the socket of this - // entry. This will wrap the packet in STUN if necessary. - int SendTo(const void* data, size_t size, - const rtc::SocketAddress& addr, - const rtc::PacketOptions& options); - - // Schedules a keep-alive allocate request. - void ScheduleKeepAlive(); - - void SetServerIndex(size_t sindex) { server_index_ = sindex; } - - // Sets this option on the socket of each connection. - int SetSocketOption(rtc::Socket::Option opt, int value); - - size_t ServerIndex() const { return server_index_; } - - // Try a different server address - void HandleConnectFailure(rtc::AsyncPacketSocket* socket); - - // Implementation of the MessageHandler Interface. - virtual void OnMessage(rtc::Message *pmsg); - - private: - RelayPort* port_; - rtc::SocketAddress ext_addr_; - size_t server_index_; - bool connected_; - bool locked_; - RelayConnection* current_connection_; - - // Called when a TCP connection is established or fails - void OnSocketConnect(rtc::AsyncPacketSocket* socket); - void OnSocketClose(rtc::AsyncPacketSocket* socket, int error); - - // Called when a packet is received on this socket. - void OnReadPacket( - rtc::AsyncPacketSocket* socket, - const char* data, size_t size, - const rtc::SocketAddress& remote_addr, - const rtc::PacketTime& packet_time); - // Called when the socket is currently able to send. - void OnReadyToSend(rtc::AsyncPacketSocket* socket); - - // Sends the given data on the socket to the server with no wrapping. This - // returns the number of bytes written or -1 if an error occurred. - int SendPacket(const void* data, size_t size, - const rtc::PacketOptions& options); -}; - -// Handles an allocate request for a particular RelayEntry. -class AllocateRequest : public StunRequest { - public: - AllocateRequest(RelayEntry* entry, RelayConnection* connection); - virtual ~AllocateRequest() {} - - virtual void Prepare(StunMessage* request); - - virtual int GetNextDelay(); - - virtual void OnResponse(StunMessage* response); - virtual void OnErrorResponse(StunMessage* response); - virtual void OnTimeout(); - - private: - RelayEntry* entry_; - RelayConnection* connection_; - uint32 start_time_; -}; - -RelayPort::RelayPort( - rtc::Thread* thread, rtc::PacketSocketFactory* factory, - rtc::Network* network, const rtc::IPAddress& ip, - int min_port, int max_port, const std::string& username, - const std::string& password) - : Port(thread, RELAY_PORT_TYPE, factory, network, ip, min_port, max_port, - username, password), - ready_(false), - error_(0) { - entries_.push_back( - new RelayEntry(this, rtc::SocketAddress())); - // TODO: set local preference value for TCP based candidates. -} - -RelayPort::~RelayPort() { - for (size_t i = 0; i < entries_.size(); ++i) - delete entries_[i]; - thread()->Clear(this); -} - -void RelayPort::AddServerAddress(const ProtocolAddress& addr) { - // Since HTTP proxies usually only allow 443, - // let's up the priority on PROTO_SSLTCP - if (addr.proto == PROTO_SSLTCP && - (proxy().type == rtc::PROXY_HTTPS || - proxy().type == rtc::PROXY_UNKNOWN)) { - server_addr_.push_front(addr); - } else { - server_addr_.push_back(addr); - } -} - -void RelayPort::AddExternalAddress(const ProtocolAddress& addr) { - std::string proto_name = ProtoToString(addr.proto); - for (std::vector<ProtocolAddress>::iterator it = external_addr_.begin(); - it != external_addr_.end(); ++it) { - if ((it->address == addr.address) && (it->proto == addr.proto)) { - LOG(INFO) << "Redundant relay address: " << proto_name - << " @ " << addr.address.ToSensitiveString(); - return; - } - } - external_addr_.push_back(addr); -} - -void RelayPort::SetReady() { - if (!ready_) { - std::vector<ProtocolAddress>::iterator iter; - for (iter = external_addr_.begin(); - iter != external_addr_.end(); ++iter) { - std::string proto_name = ProtoToString(iter->proto); - // In case of Gturn, related address is set to null socket address. - // This is due to as mapped address stun attribute is used for allocated - // address. - AddAddress(iter->address, iter->address, rtc::SocketAddress(), - proto_name, "", RELAY_PORT_TYPE, - ICE_TYPE_PREFERENCE_RELAY, 0, false); - } - ready_ = true; - SignalPortComplete(this); - } -} - -const ProtocolAddress * RelayPort::ServerAddress(size_t index) const { - if (index < server_addr_.size()) - return &server_addr_[index]; - return NULL; -} - -bool RelayPort::HasMagicCookie(const char* data, size_t size) { - if (size < 24 + sizeof(TURN_MAGIC_COOKIE_VALUE)) { - return false; - } else { - return memcmp(data + 24, - TURN_MAGIC_COOKIE_VALUE, - sizeof(TURN_MAGIC_COOKIE_VALUE)) == 0; - } -} - -void RelayPort::PrepareAddress() { - // We initiate a connect on the first entry. If this completes, it will fill - // in the server address as the address of this port. - ASSERT(entries_.size() == 1); - entries_[0]->Connect(); - ready_ = false; -} - -Connection* RelayPort::CreateConnection(const Candidate& address, - CandidateOrigin origin) { - // We only create conns to non-udp sockets if they are incoming on this port - if ((address.protocol() != UDP_PROTOCOL_NAME) && - (origin != ORIGIN_THIS_PORT)) { - return 0; - } - - // We don't support loopback on relays - if (address.type() == Type()) { - return 0; - } - - if (!IsCompatibleAddress(address.address())) { - return 0; - } - - size_t index = 0; - for (size_t i = 0; i < Candidates().size(); ++i) { - const Candidate& local = Candidates()[i]; - if (local.protocol() == address.protocol()) { - index = i; - break; - } - } - - Connection * conn = new ProxyConnection(this, index, address); - AddConnection(conn); - return conn; -} - -int RelayPort::SendTo(const void* data, size_t size, - const rtc::SocketAddress& addr, - const rtc::PacketOptions& options, - bool payload) { - // Try to find an entry for this specific address. Note that the first entry - // created was not given an address initially, so it can be set to the first - // address that comes along. - RelayEntry* entry = 0; - - for (size_t i = 0; i < entries_.size(); ++i) { - if (entries_[i]->address().IsNil() && payload) { - entry = entries_[i]; - entry->set_address(addr); - break; - } else if (entries_[i]->address() == addr) { - entry = entries_[i]; - break; - } - } - - // If we did not find one, then we make a new one. This will not be useable - // until it becomes connected, however. - if (!entry && payload) { - entry = new RelayEntry(this, addr); - if (!entries_.empty()) { - entry->SetServerIndex(entries_[0]->ServerIndex()); - } - entry->Connect(); - entries_.push_back(entry); - } - - // If the entry is connected, then we can send on it (though wrapping may - // still be necessary). Otherwise, we can't yet use this connection, so we - // default to the first one. - if (!entry || !entry->connected()) { - ASSERT(!entries_.empty()); - entry = entries_[0]; - if (!entry->connected()) { - error_ = EWOULDBLOCK; - return SOCKET_ERROR; - } - } - - // Send the actual contents to the server using the usual mechanism. - int sent = entry->SendTo(data, size, addr, options); - if (sent <= 0) { - ASSERT(sent < 0); - error_ = entry->GetError(); - return SOCKET_ERROR; - } - // The caller of the function is expecting the number of user data bytes, - // rather than the size of the packet. - return static_cast<int>(size); -} - -int RelayPort::SetOption(rtc::Socket::Option opt, int value) { - int result = 0; - for (size_t i = 0; i < entries_.size(); ++i) { - if (entries_[i]->SetSocketOption(opt, value) < 0) { - result = -1; - error_ = entries_[i]->GetError(); - } - } - options_.push_back(OptionValue(opt, value)); - return result; -} - -int RelayPort::GetOption(rtc::Socket::Option opt, int* value) { - std::vector<OptionValue>::iterator it; - for (it = options_.begin(); it < options_.end(); ++it) { - if (it->first == opt) { - *value = it->second; - return 0; - } - } - return SOCKET_ERROR; -} - -int RelayPort::GetError() { - return error_; -} - -void RelayPort::OnReadPacket( - const char* data, size_t size, - const rtc::SocketAddress& remote_addr, - ProtocolType proto, - const rtc::PacketTime& packet_time) { - if (Connection* conn = GetConnection(remote_addr)) { - conn->OnReadPacket(data, size, packet_time); - } else { - Port::OnReadPacket(data, size, remote_addr, proto); - } -} - -RelayConnection::RelayConnection(const ProtocolAddress* protocol_address, - rtc::AsyncPacketSocket* socket, - rtc::Thread* thread) - : socket_(socket), - protocol_address_(protocol_address) { - request_manager_ = new StunRequestManager(thread); - request_manager_->SignalSendPacket.connect(this, - &RelayConnection::OnSendPacket); -} - -RelayConnection::~RelayConnection() { - delete request_manager_; - delete socket_; -} - -int RelayConnection::SetSocketOption(rtc::Socket::Option opt, - int value) { - if (socket_) { - return socket_->SetOption(opt, value); - } - return 0; -} - -bool RelayConnection::CheckResponse(StunMessage* msg) { - return request_manager_->CheckResponse(msg); -} - -void RelayConnection::OnSendPacket(const void* data, size_t size, - StunRequest* req) { - // TODO(mallinath) Find a way to get DSCP value from Port. - rtc::PacketOptions options; // Default dscp set to NO_CHANGE. - int sent = socket_->SendTo(data, size, GetAddress(), options); - if (sent <= 0) { - LOG(LS_VERBOSE) << "OnSendPacket: failed sending to " << GetAddress() << - strerror(socket_->GetError()); - ASSERT(sent < 0); - } -} - -int RelayConnection::Send(const void* pv, size_t cb, - const rtc::PacketOptions& options) { - return socket_->SendTo(pv, cb, GetAddress(), options); -} - -void RelayConnection::SendAllocateRequest(RelayEntry* entry, int delay) { - request_manager_->SendDelayed(new AllocateRequest(entry, this), delay); -} - -RelayEntry::RelayEntry(RelayPort* port, - const rtc::SocketAddress& ext_addr) - : port_(port), ext_addr_(ext_addr), - server_index_(0), connected_(false), locked_(false), - current_connection_(NULL) { -} - -RelayEntry::~RelayEntry() { - // Remove all RelayConnections and dispose sockets. - delete current_connection_; - current_connection_ = NULL; -} - -void RelayEntry::Connect() { - // If we're already connected, return. - if (connected_) - return; - - // If we've exhausted all options, bail out. - const ProtocolAddress* ra = port()->ServerAddress(server_index_); - if (!ra) { - LOG(LS_WARNING) << "No more relay addresses left to try"; - return; - } - - // Remove any previous connection. - if (current_connection_) { - port()->thread()->Dispose(current_connection_); - current_connection_ = NULL; - } - - // Try to set up our new socket. - LOG(LS_INFO) << "Connecting to relay via " << ProtoToString(ra->proto) << - " @ " << ra->address.ToSensitiveString(); - - rtc::AsyncPacketSocket* socket = NULL; - - if (ra->proto == PROTO_UDP) { - // UDP sockets are simple. - socket = port_->socket_factory()->CreateUdpSocket( - rtc::SocketAddress(port_->ip(), 0), - port_->min_port(), port_->max_port()); - } else if (ra->proto == PROTO_TCP || ra->proto == PROTO_SSLTCP) { - int opts = (ra->proto == PROTO_SSLTCP) ? - rtc::PacketSocketFactory::OPT_SSLTCP : 0; - socket = port_->socket_factory()->CreateClientTcpSocket( - rtc::SocketAddress(port_->ip(), 0), ra->address, - port_->proxy(), port_->user_agent(), opts); - } else { - LOG(LS_WARNING) << "Unknown protocol (" << ra->proto << ")"; - } - - if (!socket) { - LOG(LS_WARNING) << "Socket creation failed"; - } - - // If we failed to get a socket, move on to the next protocol. - if (!socket) { - port()->thread()->Post(this, kMessageConnectTimeout); - return; - } - - // Otherwise, create the new connection and configure any socket options. - socket->SignalReadPacket.connect(this, &RelayEntry::OnReadPacket); - socket->SignalReadyToSend.connect(this, &RelayEntry::OnReadyToSend); - current_connection_ = new RelayConnection(ra, socket, port()->thread()); - for (size_t i = 0; i < port_->options().size(); ++i) { - current_connection_->SetSocketOption(port_->options()[i].first, - port_->options()[i].second); - } - - // If we're trying UDP, start binding requests. - // If we're trying TCP, wait for connection with a fixed timeout. - if ((ra->proto == PROTO_TCP) || (ra->proto == PROTO_SSLTCP)) { - socket->SignalClose.connect(this, &RelayEntry::OnSocketClose); - socket->SignalConnect.connect(this, &RelayEntry::OnSocketConnect); - port()->thread()->PostDelayed(kSoftConnectTimeoutMs, this, - kMessageConnectTimeout); - } else { - current_connection_->SendAllocateRequest(this, 0); - } -} - -int RelayEntry::GetError() { - if (current_connection_ != NULL) { - return current_connection_->GetError(); - } - return 0; -} - -RelayConnection* RelayEntry::GetBestConnection(RelayConnection* conn1, - RelayConnection* conn2) { - return conn1->GetProtocol() <= conn2->GetProtocol() ? conn1 : conn2; -} - -void RelayEntry::OnConnect(const rtc::SocketAddress& mapped_addr, - RelayConnection* connection) { - // We are connected, notify our parent. - ProtocolType proto = PROTO_UDP; - LOG(INFO) << "Relay allocate succeeded: " << ProtoToString(proto) - << " @ " << mapped_addr.ToSensitiveString(); - connected_ = true; - - port_->AddExternalAddress(ProtocolAddress(mapped_addr, proto)); - port_->SetReady(); -} - -int RelayEntry::SendTo(const void* data, size_t size, - const rtc::SocketAddress& addr, - const rtc::PacketOptions& options) { - // If this connection is locked to the address given, then we can send the - // packet with no wrapper. - if (locked_ && (ext_addr_ == addr)) - return SendPacket(data, size, options); - - // Otherwise, we must wrap the given data in a STUN SEND request so that we - // can communicate the destination address to the server. - // - // Note that we do not use a StunRequest here. This is because there is - // likely no reason to resend this packet. If it is late, we just drop it. - // The next send to this address will try again. - - RelayMessage request; - request.SetType(STUN_SEND_REQUEST); - - StunByteStringAttribute* magic_cookie_attr = - StunAttribute::CreateByteString(STUN_ATTR_MAGIC_COOKIE); - magic_cookie_attr->CopyBytes(TURN_MAGIC_COOKIE_VALUE, - sizeof(TURN_MAGIC_COOKIE_VALUE)); - VERIFY(request.AddAttribute(magic_cookie_attr)); - - StunByteStringAttribute* username_attr = - StunAttribute::CreateByteString(STUN_ATTR_USERNAME); - username_attr->CopyBytes(port_->username_fragment().c_str(), - port_->username_fragment().size()); - VERIFY(request.AddAttribute(username_attr)); - - StunAddressAttribute* addr_attr = - StunAttribute::CreateAddress(STUN_ATTR_DESTINATION_ADDRESS); - addr_attr->SetIP(addr.ipaddr()); - addr_attr->SetPort(addr.port()); - VERIFY(request.AddAttribute(addr_attr)); - - // Attempt to lock - if (ext_addr_ == addr) { - StunUInt32Attribute* options_attr = - StunAttribute::CreateUInt32(STUN_ATTR_OPTIONS); - options_attr->SetValue(0x1); - VERIFY(request.AddAttribute(options_attr)); - } - - StunByteStringAttribute* data_attr = - StunAttribute::CreateByteString(STUN_ATTR_DATA); - data_attr->CopyBytes(data, size); - VERIFY(request.AddAttribute(data_attr)); - - // TODO: compute the HMAC. - - rtc::ByteBuffer buf; - request.Write(&buf); - - return SendPacket(buf.Data(), buf.Length(), options); -} - -void RelayEntry::ScheduleKeepAlive() { - if (current_connection_) { - current_connection_->SendAllocateRequest(this, kKeepAliveDelay); - } -} - -int RelayEntry::SetSocketOption(rtc::Socket::Option opt, int value) { - // Set the option on all available sockets. - int socket_error = 0; - if (current_connection_) { - socket_error = current_connection_->SetSocketOption(opt, value); - } - return socket_error; -} - -void RelayEntry::HandleConnectFailure( - rtc::AsyncPacketSocket* socket) { - // Make sure it's the current connection that has failed, it might - // be an old socked that has not yet been disposed. - if (!socket || - (current_connection_ && socket == current_connection_->socket())) { - if (current_connection_) - port()->SignalConnectFailure(current_connection_->protocol_address()); - - // Try to connect to the next server address. - server_index_ += 1; - Connect(); - } -} - -void RelayEntry::OnMessage(rtc::Message *pmsg) { - ASSERT(pmsg->message_id == kMessageConnectTimeout); - if (current_connection_) { - const ProtocolAddress* ra = current_connection_->protocol_address(); - LOG(LS_WARNING) << "Relay " << ra->proto << " connection to " << - ra->address << " timed out"; - - // Currently we connect to each server address in sequence. If we - // have more addresses to try, treat this is an error and move on to - // the next address, otherwise give this connection more time and - // await the real timeout. - // - // TODO: Connect to servers in parallel to speed up connect time - // and to avoid giving up too early. - port_->SignalSoftTimeout(ra); - HandleConnectFailure(current_connection_->socket()); - } else { - HandleConnectFailure(NULL); - } -} - -void RelayEntry::OnSocketConnect(rtc::AsyncPacketSocket* socket) { - LOG(INFO) << "relay tcp connected to " << - socket->GetRemoteAddress().ToSensitiveString(); - if (current_connection_ != NULL) { - current_connection_->SendAllocateRequest(this, 0); - } -} - -void RelayEntry::OnSocketClose(rtc::AsyncPacketSocket* socket, - int error) { - PLOG(LERROR, error) << "Relay connection failed: socket closed"; - HandleConnectFailure(socket); -} - -void RelayEntry::OnReadPacket( - rtc::AsyncPacketSocket* socket, - const char* data, size_t size, - const rtc::SocketAddress& remote_addr, - const rtc::PacketTime& packet_time) { - // ASSERT(remote_addr == port_->server_addr()); - // TODO: are we worried about this? - - if (current_connection_ == NULL || socket != current_connection_->socket()) { - // This packet comes from an unknown address. - LOG(WARNING) << "Dropping packet: unknown address"; - return; - } - - // If the magic cookie is not present, then this is an unwrapped packet sent - // by the server, The actual remote address is the one we recorded. - if (!port_->HasMagicCookie(data, size)) { - if (locked_) { - port_->OnReadPacket(data, size, ext_addr_, PROTO_UDP, packet_time); - } else { - LOG(WARNING) << "Dropping packet: entry not locked"; - } - return; - } - - rtc::ByteBuffer buf(data, size); - RelayMessage msg; - if (!msg.Read(&buf)) { - LOG(INFO) << "Incoming packet was not STUN"; - return; - } - - // The incoming packet should be a STUN ALLOCATE response, SEND response, or - // DATA indication. - if (current_connection_->CheckResponse(&msg)) { - return; - } else if (msg.type() == STUN_SEND_RESPONSE) { - if (const StunUInt32Attribute* options_attr = - msg.GetUInt32(STUN_ATTR_OPTIONS)) { - if (options_attr->value() & 0x1) { - locked_ = true; - } - } - return; - } else if (msg.type() != STUN_DATA_INDICATION) { - LOG(INFO) << "Received BAD stun type from server: " << msg.type(); - return; - } - - // This must be a data indication. - - const StunAddressAttribute* addr_attr = - msg.GetAddress(STUN_ATTR_SOURCE_ADDRESS2); - if (!addr_attr) { - LOG(INFO) << "Data indication has no source address"; - return; - } else if (addr_attr->family() != 1) { - LOG(INFO) << "Source address has bad family"; - return; - } - - rtc::SocketAddress remote_addr2(addr_attr->ipaddr(), addr_attr->port()); - - const StunByteStringAttribute* data_attr = msg.GetByteString(STUN_ATTR_DATA); - if (!data_attr) { - LOG(INFO) << "Data indication has no data"; - return; - } - - // Process the actual data and remote address in the normal manner. - port_->OnReadPacket(data_attr->bytes(), data_attr->length(), remote_addr2, - PROTO_UDP, packet_time); -} - -void RelayEntry::OnReadyToSend(rtc::AsyncPacketSocket* socket) { - if (connected()) { - port_->OnReadyToSend(); - } -} - -int RelayEntry::SendPacket(const void* data, size_t size, - const rtc::PacketOptions& options) { - int sent = 0; - if (current_connection_) { - // We are connected, no need to send packets anywere else than to - // the current connection. - sent = current_connection_->Send(data, size, options); - } - return sent; -} - -AllocateRequest::AllocateRequest(RelayEntry* entry, - RelayConnection* connection) - : StunRequest(new RelayMessage()), - entry_(entry), - connection_(connection) { - start_time_ = rtc::Time(); -} - -void AllocateRequest::Prepare(StunMessage* request) { - request->SetType(STUN_ALLOCATE_REQUEST); - - StunByteStringAttribute* username_attr = - StunAttribute::CreateByteString(STUN_ATTR_USERNAME); - username_attr->CopyBytes( - entry_->port()->username_fragment().c_str(), - entry_->port()->username_fragment().size()); - VERIFY(request->AddAttribute(username_attr)); -} - -int AllocateRequest::GetNextDelay() { - int delay = 100 * rtc::_max(1 << count_, 2); - count_ += 1; - if (count_ == 5) - timeout_ = true; - return delay; -} - -void AllocateRequest::OnResponse(StunMessage* response) { - const StunAddressAttribute* addr_attr = - response->GetAddress(STUN_ATTR_MAPPED_ADDRESS); - if (!addr_attr) { - LOG(INFO) << "Allocate response missing mapped address."; - } else if (addr_attr->family() != 1) { - LOG(INFO) << "Mapped address has bad family"; - } else { - rtc::SocketAddress addr(addr_attr->ipaddr(), addr_attr->port()); - entry_->OnConnect(addr, connection_); - } - - // We will do a keep-alive regardless of whether this request suceeds. - // This should have almost no impact on network usage. - entry_->ScheduleKeepAlive(); -} - -void AllocateRequest::OnErrorResponse(StunMessage* response) { - const StunErrorCodeAttribute* attr = response->GetErrorCode(); - if (!attr) { - LOG(INFO) << "Bad allocate response error code"; - } else { - LOG(INFO) << "Allocate error response:" - << " code=" << attr->code() - << " reason='" << attr->reason() << "'"; - } - - if (rtc::TimeSince(start_time_) <= kRetryTimeout) - entry_->ScheduleKeepAlive(); -} - -void AllocateRequest::OnTimeout() { - LOG(INFO) << "Allocate request timed out"; - entry_->HandleConnectFailure(connection_->socket()); -} - -} // namespace cricket diff --git a/talk/p2p/base/relayport.h b/talk/p2p/base/relayport.h deleted file mode 100644 index bc0c5d98c..000000000 --- a/talk/p2p/base/relayport.h +++ /dev/null @@ -1,118 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef WEBRTC_P2P_BASE_RELAYPORT_H_ -#define WEBRTC_P2P_BASE_RELAYPORT_H_ - -#include <deque> -#include <string> -#include <utility> -#include <vector> - -#include "webrtc/p2p/base/port.h" -#include "webrtc/p2p/base/stunrequest.h" - -namespace cricket { - -class RelayEntry; -class RelayConnection; - -// Communicates using an allocated port on the relay server. For each -// remote candidate that we try to send data to a RelayEntry instance -// is created. The RelayEntry will try to reach the remote destination -// by connecting to all available server addresses in a pre defined -// order with a small delay in between. When a connection is -// successful all other connection attemts are aborted. -class RelayPort : public Port { - public: - typedef std::pair<rtc::Socket::Option, int> OptionValue; - - // RelayPort doesn't yet do anything fancy in the ctor. - static RelayPort* Create( - rtc::Thread* thread, rtc::PacketSocketFactory* factory, - rtc::Network* network, const rtc::IPAddress& ip, - int min_port, int max_port, const std::string& username, - const std::string& password) { - return new RelayPort(thread, factory, network, ip, min_port, max_port, - username, password); - } - virtual ~RelayPort(); - - void AddServerAddress(const ProtocolAddress& addr); - void AddExternalAddress(const ProtocolAddress& addr); - - const std::vector<OptionValue>& options() const { return options_; } - bool HasMagicCookie(const char* data, size_t size); - - virtual void PrepareAddress(); - virtual Connection* CreateConnection(const Candidate& address, - CandidateOrigin origin); - virtual int SetOption(rtc::Socket::Option opt, int value); - virtual int GetOption(rtc::Socket::Option opt, int* value); - virtual int GetError(); - - const ProtocolAddress * ServerAddress(size_t index) const; - bool IsReady() { return ready_; } - - // Used for testing. - sigslot::signal1<const ProtocolAddress*> SignalConnectFailure; - sigslot::signal1<const ProtocolAddress*> SignalSoftTimeout; - - protected: - RelayPort(rtc::Thread* thread, rtc::PacketSocketFactory* factory, - rtc::Network*, const rtc::IPAddress& ip, - int min_port, int max_port, const std::string& username, - const std::string& password); - bool Init(); - - void SetReady(); - - virtual int SendTo(const void* data, size_t size, - const rtc::SocketAddress& addr, - const rtc::PacketOptions& options, - bool payload); - - // Dispatches the given packet to the port or connection as appropriate. - void OnReadPacket(const char* data, size_t size, - const rtc::SocketAddress& remote_addr, - ProtocolType proto, - const rtc::PacketTime& packet_time); - - private: - friend class RelayEntry; - - std::deque<ProtocolAddress> server_addr_; - std::vector<ProtocolAddress> external_addr_; - bool ready_; - std::vector<RelayEntry*> entries_; - std::vector<OptionValue> options_; - int error_; -}; - -} // namespace cricket - -#endif // WEBRTC_P2P_BASE_RELAYPORT_H_ diff --git a/talk/p2p/base/relayport_unittest.cc b/talk/p2p/base/relayport_unittest.cc deleted file mode 100644 index 2f4515e44..000000000 --- a/talk/p2p/base/relayport_unittest.cc +++ /dev/null @@ -1,289 +0,0 @@ -/* - * libjingle - * Copyright 2009 Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "webrtc/p2p/base/basicpacketsocketfactory.h" -#include "webrtc/p2p/base/relayport.h" -#include "webrtc/p2p/base/relayserver.h" -#include "webrtc/base/gunit.h" -#include "webrtc/base/helpers.h" -#include "webrtc/base/logging.h" -#include "webrtc/base/physicalsocketserver.h" -#include "webrtc/base/scoped_ptr.h" -#include "webrtc/base/socketadapters.h" -#include "webrtc/base/socketaddress.h" -#include "webrtc/base/ssladapter.h" -#include "webrtc/base/thread.h" -#include "webrtc/base/virtualsocketserver.h" - -using rtc::SocketAddress; - -static const SocketAddress kLocalAddress = SocketAddress("192.168.1.2", 0); -static const SocketAddress kRelayUdpAddr = SocketAddress("99.99.99.1", 5000); -static const SocketAddress kRelayTcpAddr = SocketAddress("99.99.99.2", 5001); -static const SocketAddress kRelaySslAddr = SocketAddress("99.99.99.3", 443); -static const SocketAddress kRelayExtAddr = SocketAddress("99.99.99.3", 5002); - -static const int kTimeoutMs = 1000; -static const int kMaxTimeoutMs = 5000; - -// Tests connecting a RelayPort to a fake relay server -// (cricket::RelayServer) using all currently available protocols. The -// network layer is faked out by using a VirtualSocketServer for -// creating sockets. The test will monitor the current state of the -// RelayPort and created sockets by listening for signals such as, -// SignalConnectFailure, SignalConnectTimeout, SignalSocketClosed and -// SignalReadPacket. -class RelayPortTest : public testing::Test, - public sigslot::has_slots<> { - public: - RelayPortTest() - : main_(rtc::Thread::Current()), - physical_socket_server_(new rtc::PhysicalSocketServer), - virtual_socket_server_(new rtc::VirtualSocketServer( - physical_socket_server_.get())), - ss_scope_(virtual_socket_server_.get()), - network_("unittest", "unittest", rtc::IPAddress(INADDR_ANY), 32), - socket_factory_(rtc::Thread::Current()), - username_(rtc::CreateRandomString(16)), - password_(rtc::CreateRandomString(16)), - relay_port_(cricket::RelayPort::Create(main_, &socket_factory_, - &network_, - kLocalAddress.ipaddr(), - 0, 0, username_, password_)), - relay_server_(new cricket::RelayServer(main_)) { - } - - void OnReadPacket(rtc::AsyncPacketSocket* socket, - const char* data, size_t size, - const rtc::SocketAddress& remote_addr, - const rtc::PacketTime& packet_time) { - received_packet_count_[socket]++; - } - - void OnConnectFailure(const cricket::ProtocolAddress* addr) { - failed_connections_.push_back(*addr); - } - - void OnSoftTimeout(const cricket::ProtocolAddress* addr) { - soft_timedout_connections_.push_back(*addr); - } - - protected: - virtual void SetUp() { - // The relay server needs an external socket to work properly. - rtc::AsyncUDPSocket* ext_socket = - CreateAsyncUdpSocket(kRelayExtAddr); - relay_server_->AddExternalSocket(ext_socket); - - // Listen for failures. - relay_port_->SignalConnectFailure. - connect(this, &RelayPortTest::OnConnectFailure); - - // Listen for soft timeouts. - relay_port_->SignalSoftTimeout. - connect(this, &RelayPortTest::OnSoftTimeout); - } - - // Udp has the highest 'goodness' value of the three different - // protocols used for connecting to the relay server. As soon as - // PrepareAddress is called, the RelayPort will start trying to - // connect to the given UDP address. As soon as a response to the - // sent STUN allocate request message has been received, the - // RelayPort will consider the connection to be complete and will - // abort any other connection attempts. - void TestConnectUdp() { - // Add a UDP socket to the relay server. - rtc::AsyncUDPSocket* internal_udp_socket = - CreateAsyncUdpSocket(kRelayUdpAddr); - rtc::AsyncSocket* server_socket = CreateServerSocket(kRelayTcpAddr); - - relay_server_->AddInternalSocket(internal_udp_socket); - relay_server_->AddInternalServerSocket(server_socket, cricket::PROTO_TCP); - - // Now add our relay addresses to the relay port and let it start. - relay_port_->AddServerAddress( - cricket::ProtocolAddress(kRelayUdpAddr, cricket::PROTO_UDP)); - relay_port_->AddServerAddress( - cricket::ProtocolAddress(kRelayTcpAddr, cricket::PROTO_TCP)); - relay_port_->PrepareAddress(); - - // Should be connected. - EXPECT_TRUE_WAIT(relay_port_->IsReady(), kTimeoutMs); - - // Make sure that we are happy with UDP, ie. not continuing with - // TCP, SSLTCP, etc. - WAIT(relay_server_->HasConnection(kRelayTcpAddr), kTimeoutMs); - - // Should have only one connection. - EXPECT_EQ(1, relay_server_->GetConnectionCount()); - - // Should be the UDP address. - EXPECT_TRUE(relay_server_->HasConnection(kRelayUdpAddr)); - } - - // TCP has the second best 'goodness' value, and as soon as UDP - // connection has failed, the RelayPort will attempt to connect via - // TCP. Here we add a fake UDP address together with a real TCP - // address to simulate an UDP failure. As soon as UDP has failed the - // RelayPort will try the TCP adress and succed. - void TestConnectTcp() { - // Create a fake UDP address for relay port to simulate a failure. - cricket::ProtocolAddress fake_protocol_address = - cricket::ProtocolAddress(kRelayUdpAddr, cricket::PROTO_UDP); - - // Create a server socket for the RelayServer. - rtc::AsyncSocket* server_socket = CreateServerSocket(kRelayTcpAddr); - relay_server_->AddInternalServerSocket(server_socket, cricket::PROTO_TCP); - - // Add server addresses to the relay port and let it start. - relay_port_->AddServerAddress( - cricket::ProtocolAddress(fake_protocol_address)); - relay_port_->AddServerAddress( - cricket::ProtocolAddress(kRelayTcpAddr, cricket::PROTO_TCP)); - relay_port_->PrepareAddress(); - - EXPECT_FALSE(relay_port_->IsReady()); - - // Should have timed out in 200 + 200 + 400 + 800 + 1600 ms. - EXPECT_TRUE_WAIT(HasFailed(&fake_protocol_address), 3600); - - // Wait until relayport is ready. - EXPECT_TRUE_WAIT(relay_port_->IsReady(), kMaxTimeoutMs); - - // Should have only one connection. - EXPECT_EQ(1, relay_server_->GetConnectionCount()); - - // Should be the TCP address. - EXPECT_TRUE(relay_server_->HasConnection(kRelayTcpAddr)); - } - - void TestConnectSslTcp() { - // Create a fake TCP address for relay port to simulate a failure. - // We skip UDP here since transition from UDP to TCP has been - // tested above. - cricket::ProtocolAddress fake_protocol_address = - cricket::ProtocolAddress(kRelayTcpAddr, cricket::PROTO_TCP); - - // Create a ssl server socket for the RelayServer. - rtc::AsyncSocket* ssl_server_socket = - CreateServerSocket(kRelaySslAddr); - relay_server_->AddInternalServerSocket(ssl_server_socket, - cricket::PROTO_SSLTCP); - - // Create a tcp server socket that listens on the fake address so - // the relay port can attempt to connect to it. - rtc::scoped_ptr<rtc::AsyncSocket> tcp_server_socket( - CreateServerSocket(kRelayTcpAddr)); - - // Add server addresses to the relay port and let it start. - relay_port_->AddServerAddress(fake_protocol_address); - relay_port_->AddServerAddress( - cricket::ProtocolAddress(kRelaySslAddr, cricket::PROTO_SSLTCP)); - relay_port_->PrepareAddress(); - EXPECT_FALSE(relay_port_->IsReady()); - - // Should have timed out in 3000 ms(relayport.cc, kSoftConnectTimeoutMs). - EXPECT_TRUE_WAIT_MARGIN(HasTimedOut(&fake_protocol_address), 3000, 100); - - // Wait until relayport is ready. - EXPECT_TRUE_WAIT(relay_port_->IsReady(), kMaxTimeoutMs); - - // Should have only one connection. - EXPECT_EQ(1, relay_server_->GetConnectionCount()); - - // Should be the SSLTCP address. - EXPECT_TRUE(relay_server_->HasConnection(kRelaySslAddr)); - } - - private: - rtc::AsyncUDPSocket* CreateAsyncUdpSocket(const SocketAddress addr) { - rtc::AsyncSocket* socket = - virtual_socket_server_->CreateAsyncSocket(SOCK_DGRAM); - rtc::AsyncUDPSocket* packet_socket = - rtc::AsyncUDPSocket::Create(socket, addr); - EXPECT_TRUE(packet_socket != NULL); - packet_socket->SignalReadPacket.connect(this, &RelayPortTest::OnReadPacket); - return packet_socket; - } - - rtc::AsyncSocket* CreateServerSocket(const SocketAddress addr) { - rtc::AsyncSocket* socket = - virtual_socket_server_->CreateAsyncSocket(SOCK_STREAM); - EXPECT_GE(socket->Bind(addr), 0); - EXPECT_GE(socket->Listen(5), 0); - return socket; - } - - bool HasFailed(cricket::ProtocolAddress* addr) { - for (size_t i = 0; i < failed_connections_.size(); i++) { - if (failed_connections_[i].address == addr->address && - failed_connections_[i].proto == addr->proto) { - return true; - } - } - return false; - } - - bool HasTimedOut(cricket::ProtocolAddress* addr) { - for (size_t i = 0; i < soft_timedout_connections_.size(); i++) { - if (soft_timedout_connections_[i].address == addr->address && - soft_timedout_connections_[i].proto == addr->proto) { - return true; - } - } - return false; - } - - typedef std::map<rtc::AsyncPacketSocket*, int> PacketMap; - - rtc::Thread* main_; - rtc::scoped_ptr<rtc::PhysicalSocketServer> - physical_socket_server_; - rtc::scoped_ptr<rtc::VirtualSocketServer> virtual_socket_server_; - rtc::SocketServerScope ss_scope_; - rtc::Network network_; - rtc::BasicPacketSocketFactory socket_factory_; - std::string username_; - std::string password_; - rtc::scoped_ptr<cricket::RelayPort> relay_port_; - rtc::scoped_ptr<cricket::RelayServer> relay_server_; - std::vector<cricket::ProtocolAddress> failed_connections_; - std::vector<cricket::ProtocolAddress> soft_timedout_connections_; - PacketMap received_packet_count_; -}; - -TEST_F(RelayPortTest, ConnectUdp) { - TestConnectUdp(); -} - -TEST_F(RelayPortTest, ConnectTcp) { - TestConnectTcp(); -} - -TEST_F(RelayPortTest, ConnectSslTcp) { - TestConnectSslTcp(); -} diff --git a/talk/p2p/base/relayserver.cc b/talk/p2p/base/relayserver.cc deleted file mode 100644 index ebf165bff..000000000 --- a/talk/p2p/base/relayserver.cc +++ /dev/null @@ -1,763 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "webrtc/p2p/base/relayserver.h" - -#ifdef POSIX -#include <errno.h> -#endif // POSIX - -#include <algorithm> - -#include "webrtc/base/asynctcpsocket.h" -#include "webrtc/base/helpers.h" -#include "webrtc/base/logging.h" -#include "webrtc/base/socketadapters.h" - -namespace cricket { - -// By default, we require a ping every 90 seconds. -const int MAX_LIFETIME = 15 * 60 * 1000; - -// The number of bytes in each of the usernames we use. -const uint32 USERNAME_LENGTH = 16; - -// Calls SendTo on the given socket and logs any bad results. -void Send(rtc::AsyncPacketSocket* socket, const char* bytes, size_t size, - const rtc::SocketAddress& addr) { - rtc::PacketOptions options; - int result = socket->SendTo(bytes, size, addr, options); - if (result < static_cast<int>(size)) { - LOG(LS_ERROR) << "SendTo wrote only " << result << " of " << size - << " bytes"; - } else if (result < 0) { - LOG_ERR(LS_ERROR) << "SendTo"; - } -} - -// Sends the given STUN message on the given socket. -void SendStun(const StunMessage& msg, - rtc::AsyncPacketSocket* socket, - const rtc::SocketAddress& addr) { - rtc::ByteBuffer buf; - msg.Write(&buf); - Send(socket, buf.Data(), buf.Length(), addr); -} - -// Constructs a STUN error response and sends it on the given socket. -void SendStunError(const StunMessage& msg, rtc::AsyncPacketSocket* socket, - const rtc::SocketAddress& remote_addr, int error_code, - const char* error_desc, const std::string& magic_cookie) { - RelayMessage err_msg; - err_msg.SetType(GetStunErrorResponseType(msg.type())); - err_msg.SetTransactionID(msg.transaction_id()); - - StunByteStringAttribute* magic_cookie_attr = - StunAttribute::CreateByteString(cricket::STUN_ATTR_MAGIC_COOKIE); - if (magic_cookie.size() == 0) { - magic_cookie_attr->CopyBytes(cricket::TURN_MAGIC_COOKIE_VALUE, - sizeof(cricket::TURN_MAGIC_COOKIE_VALUE)); - } else { - magic_cookie_attr->CopyBytes(magic_cookie.c_str(), magic_cookie.size()); - } - err_msg.AddAttribute(magic_cookie_attr); - - StunErrorCodeAttribute* err_code = StunAttribute::CreateErrorCode(); - err_code->SetClass(error_code / 100); - err_code->SetNumber(error_code % 100); - err_code->SetReason(error_desc); - err_msg.AddAttribute(err_code); - - SendStun(err_msg, socket, remote_addr); -} - -RelayServer::RelayServer(rtc::Thread* thread) - : thread_(thread), log_bindings_(true) { -} - -RelayServer::~RelayServer() { - // Deleting the binding will cause it to be removed from the map. - while (!bindings_.empty()) - delete bindings_.begin()->second; - for (size_t i = 0; i < internal_sockets_.size(); ++i) - delete internal_sockets_[i]; - for (size_t i = 0; i < external_sockets_.size(); ++i) - delete external_sockets_[i]; - for (size_t i = 0; i < removed_sockets_.size(); ++i) - delete removed_sockets_[i]; - while (!server_sockets_.empty()) { - rtc::AsyncSocket* socket = server_sockets_.begin()->first; - server_sockets_.erase(server_sockets_.begin()->first); - delete socket; - } -} - -void RelayServer::AddInternalSocket(rtc::AsyncPacketSocket* socket) { - ASSERT(internal_sockets_.end() == - std::find(internal_sockets_.begin(), internal_sockets_.end(), socket)); - internal_sockets_.push_back(socket); - socket->SignalReadPacket.connect(this, &RelayServer::OnInternalPacket); -} - -void RelayServer::RemoveInternalSocket(rtc::AsyncPacketSocket* socket) { - SocketList::iterator iter = - std::find(internal_sockets_.begin(), internal_sockets_.end(), socket); - ASSERT(iter != internal_sockets_.end()); - internal_sockets_.erase(iter); - removed_sockets_.push_back(socket); - socket->SignalReadPacket.disconnect(this); -} - -void RelayServer::AddExternalSocket(rtc::AsyncPacketSocket* socket) { - ASSERT(external_sockets_.end() == - std::find(external_sockets_.begin(), external_sockets_.end(), socket)); - external_sockets_.push_back(socket); - socket->SignalReadPacket.connect(this, &RelayServer::OnExternalPacket); -} - -void RelayServer::RemoveExternalSocket(rtc::AsyncPacketSocket* socket) { - SocketList::iterator iter = - std::find(external_sockets_.begin(), external_sockets_.end(), socket); - ASSERT(iter != external_sockets_.end()); - external_sockets_.erase(iter); - removed_sockets_.push_back(socket); - socket->SignalReadPacket.disconnect(this); -} - -void RelayServer::AddInternalServerSocket(rtc::AsyncSocket* socket, - cricket::ProtocolType proto) { - ASSERT(server_sockets_.end() == - server_sockets_.find(socket)); - server_sockets_[socket] = proto; - socket->SignalReadEvent.connect(this, &RelayServer::OnReadEvent); -} - -void RelayServer::RemoveInternalServerSocket( - rtc::AsyncSocket* socket) { - ServerSocketMap::iterator iter = server_sockets_.find(socket); - ASSERT(iter != server_sockets_.end()); - server_sockets_.erase(iter); - socket->SignalReadEvent.disconnect(this); -} - -int RelayServer::GetConnectionCount() const { - return static_cast<int>(connections_.size()); -} - -rtc::SocketAddressPair RelayServer::GetConnection(int connection) const { - int i = 0; - for (ConnectionMap::const_iterator it = connections_.begin(); - it != connections_.end(); ++it) { - if (i == connection) { - return it->second->addr_pair(); - } - ++i; - } - return rtc::SocketAddressPair(); -} - -bool RelayServer::HasConnection(const rtc::SocketAddress& address) const { - for (ConnectionMap::const_iterator it = connections_.begin(); - it != connections_.end(); ++it) { - if (it->second->addr_pair().destination() == address) { - return true; - } - } - return false; -} - -void RelayServer::OnReadEvent(rtc::AsyncSocket* socket) { - ASSERT(server_sockets_.find(socket) != server_sockets_.end()); - AcceptConnection(socket); -} - -void RelayServer::OnInternalPacket( - rtc::AsyncPacketSocket* socket, const char* bytes, size_t size, - const rtc::SocketAddress& remote_addr, - const rtc::PacketTime& packet_time) { - - // Get the address of the connection we just received on. - rtc::SocketAddressPair ap(remote_addr, socket->GetLocalAddress()); - ASSERT(!ap.destination().IsNil()); - - // If this did not come from an existing connection, it should be a STUN - // allocate request. - ConnectionMap::iterator piter = connections_.find(ap); - if (piter == connections_.end()) { - HandleStunAllocate(bytes, size, ap, socket); - return; - } - - RelayServerConnection* int_conn = piter->second; - - // Handle STUN requests to the server itself. - if (int_conn->binding()->HasMagicCookie(bytes, size)) { - HandleStun(int_conn, bytes, size); - return; - } - - // Otherwise, this is a non-wrapped packet that we are to forward. Make sure - // that this connection has been locked. (Otherwise, we would not know what - // address to forward to.) - if (!int_conn->locked()) { - LOG(LS_WARNING) << "Dropping packet: connection not locked"; - return; - } - - // Forward this to the destination address into the connection. - RelayServerConnection* ext_conn = int_conn->binding()->GetExternalConnection( - int_conn->default_destination()); - if (ext_conn && ext_conn->locked()) { - // TODO: Check the HMAC. - ext_conn->Send(bytes, size); - } else { - // This happens very often and is not an error. - LOG(LS_INFO) << "Dropping packet: no external connection"; - } -} - -void RelayServer::OnExternalPacket( - rtc::AsyncPacketSocket* socket, const char* bytes, size_t size, - const rtc::SocketAddress& remote_addr, - const rtc::PacketTime& packet_time) { - - // Get the address of the connection we just received on. - rtc::SocketAddressPair ap(remote_addr, socket->GetLocalAddress()); - ASSERT(!ap.destination().IsNil()); - - // If this connection already exists, then forward the traffic. - ConnectionMap::iterator piter = connections_.find(ap); - if (piter != connections_.end()) { - // TODO: Check the HMAC. - RelayServerConnection* ext_conn = piter->second; - RelayServerConnection* int_conn = - ext_conn->binding()->GetInternalConnection( - ext_conn->addr_pair().source()); - ASSERT(int_conn != NULL); - int_conn->Send(bytes, size, ext_conn->addr_pair().source()); - ext_conn->Lock(); // allow outgoing packets - return; - } - - // The first packet should always be a STUN / TURN packet. If it isn't, then - // we should just ignore this packet. - RelayMessage msg; - rtc::ByteBuffer buf(bytes, size); - if (!msg.Read(&buf)) { - LOG(LS_WARNING) << "Dropping packet: first packet not STUN"; - return; - } - - // The initial packet should have a username (which identifies the binding). - const StunByteStringAttribute* username_attr = - msg.GetByteString(STUN_ATTR_USERNAME); - if (!username_attr) { - LOG(LS_WARNING) << "Dropping packet: no username"; - return; - } - - uint32 length = rtc::_min(static_cast<uint32>(username_attr->length()), - USERNAME_LENGTH); - std::string username(username_attr->bytes(), length); - // TODO: Check the HMAC. - - // The binding should already be present. - BindingMap::iterator biter = bindings_.find(username); - if (biter == bindings_.end()) { - LOG(LS_WARNING) << "Dropping packet: no binding with username"; - return; - } - - // Add this authenticted connection to the binding. - RelayServerConnection* ext_conn = - new RelayServerConnection(biter->second, ap, socket); - ext_conn->binding()->AddExternalConnection(ext_conn); - AddConnection(ext_conn); - - // We always know where external packets should be forwarded, so we can lock - // them from the beginning. - ext_conn->Lock(); - - // Send this message on the appropriate internal connection. - RelayServerConnection* int_conn = ext_conn->binding()->GetInternalConnection( - ext_conn->addr_pair().source()); - ASSERT(int_conn != NULL); - int_conn->Send(bytes, size, ext_conn->addr_pair().source()); -} - -bool RelayServer::HandleStun( - const char* bytes, size_t size, const rtc::SocketAddress& remote_addr, - rtc::AsyncPacketSocket* socket, std::string* username, - StunMessage* msg) { - - // Parse this into a stun message. Eat the message if this fails. - rtc::ByteBuffer buf(bytes, size); - if (!msg->Read(&buf)) { - return false; - } - - // The initial packet should have a username (which identifies the binding). - const StunByteStringAttribute* username_attr = - msg->GetByteString(STUN_ATTR_USERNAME); - if (!username_attr) { - SendStunError(*msg, socket, remote_addr, 432, "Missing Username", ""); - return false; - } - - // Record the username if requested. - if (username) - username->append(username_attr->bytes(), username_attr->length()); - - // TODO: Check for unknown attributes (<= 0x7fff) - - return true; -} - -void RelayServer::HandleStunAllocate( - const char* bytes, size_t size, const rtc::SocketAddressPair& ap, - rtc::AsyncPacketSocket* socket) { - - // Make sure this is a valid STUN request. - RelayMessage request; - std::string username; - if (!HandleStun(bytes, size, ap.source(), socket, &username, &request)) - return; - - // Make sure this is a an allocate request. - if (request.type() != STUN_ALLOCATE_REQUEST) { - SendStunError(request, - socket, - ap.source(), - 600, - "Operation Not Supported", - ""); - return; - } - - // TODO: Check the HMAC. - - // Find or create the binding for this username. - - RelayServerBinding* binding; - - BindingMap::iterator biter = bindings_.find(username); - if (biter != bindings_.end()) { - binding = biter->second; - } else { - // NOTE: In the future, bindings will be created by the bot only. This - // else-branch will then disappear. - - // Compute the appropriate lifetime for this binding. - uint32 lifetime = MAX_LIFETIME; - const StunUInt32Attribute* lifetime_attr = - request.GetUInt32(STUN_ATTR_LIFETIME); - if (lifetime_attr) - lifetime = rtc::_min(lifetime, lifetime_attr->value() * 1000); - - binding = new RelayServerBinding(this, username, "0", lifetime); - binding->SignalTimeout.connect(this, &RelayServer::OnTimeout); - bindings_[username] = binding; - - if (log_bindings_) { - LOG(LS_INFO) << "Added new binding " << username << ", " - << bindings_.size() << " total"; - } - } - - // Add this connection to the binding. It starts out unlocked. - RelayServerConnection* int_conn = - new RelayServerConnection(binding, ap, socket); - binding->AddInternalConnection(int_conn); - AddConnection(int_conn); - - // Now that we have a connection, this other method takes over. - HandleStunAllocate(int_conn, request); -} - -void RelayServer::HandleStun( - RelayServerConnection* int_conn, const char* bytes, size_t size) { - - // Make sure this is a valid STUN request. - RelayMessage request; - std::string username; - if (!HandleStun(bytes, size, int_conn->addr_pair().source(), - int_conn->socket(), &username, &request)) - return; - - // Make sure the username is the one were were expecting. - if (username != int_conn->binding()->username()) { - int_conn->SendStunError(request, 430, "Stale Credentials"); - return; - } - - // TODO: Check the HMAC. - - // Send this request to the appropriate handler. - if (request.type() == STUN_SEND_REQUEST) - HandleStunSend(int_conn, request); - else if (request.type() == STUN_ALLOCATE_REQUEST) - HandleStunAllocate(int_conn, request); - else - int_conn->SendStunError(request, 600, "Operation Not Supported"); -} - -void RelayServer::HandleStunAllocate( - RelayServerConnection* int_conn, const StunMessage& request) { - - // Create a response message that includes an address with which external - // clients can communicate. - - RelayMessage response; - response.SetType(STUN_ALLOCATE_RESPONSE); - response.SetTransactionID(request.transaction_id()); - - StunByteStringAttribute* magic_cookie_attr = - StunAttribute::CreateByteString(cricket::STUN_ATTR_MAGIC_COOKIE); - magic_cookie_attr->CopyBytes(int_conn->binding()->magic_cookie().c_str(), - int_conn->binding()->magic_cookie().size()); - response.AddAttribute(magic_cookie_attr); - - size_t index = rand() % external_sockets_.size(); - rtc::SocketAddress ext_addr = - external_sockets_[index]->GetLocalAddress(); - - StunAddressAttribute* addr_attr = - StunAttribute::CreateAddress(STUN_ATTR_MAPPED_ADDRESS); - addr_attr->SetIP(ext_addr.ipaddr()); - addr_attr->SetPort(ext_addr.port()); - response.AddAttribute(addr_attr); - - StunUInt32Attribute* res_lifetime_attr = - StunAttribute::CreateUInt32(STUN_ATTR_LIFETIME); - res_lifetime_attr->SetValue(int_conn->binding()->lifetime() / 1000); - response.AddAttribute(res_lifetime_attr); - - // TODO: Support transport-prefs (preallocate RTCP port). - // TODO: Support bandwidth restrictions. - // TODO: Add message integrity check. - - // Send a response to the caller. - int_conn->SendStun(response); -} - -void RelayServer::HandleStunSend( - RelayServerConnection* int_conn, const StunMessage& request) { - - const StunAddressAttribute* addr_attr = - request.GetAddress(STUN_ATTR_DESTINATION_ADDRESS); - if (!addr_attr) { - int_conn->SendStunError(request, 400, "Bad Request"); - return; - } - - const StunByteStringAttribute* data_attr = - request.GetByteString(STUN_ATTR_DATA); - if (!data_attr) { - int_conn->SendStunError(request, 400, "Bad Request"); - return; - } - - rtc::SocketAddress ext_addr(addr_attr->ipaddr(), addr_attr->port()); - RelayServerConnection* ext_conn = - int_conn->binding()->GetExternalConnection(ext_addr); - if (!ext_conn) { - // Create a new connection to establish the relationship with this binding. - ASSERT(external_sockets_.size() == 1); - rtc::AsyncPacketSocket* socket = external_sockets_[0]; - rtc::SocketAddressPair ap(ext_addr, socket->GetLocalAddress()); - ext_conn = new RelayServerConnection(int_conn->binding(), ap, socket); - ext_conn->binding()->AddExternalConnection(ext_conn); - AddConnection(ext_conn); - } - - // If this connection has pinged us, then allow outgoing traffic. - if (ext_conn->locked()) - ext_conn->Send(data_attr->bytes(), data_attr->length()); - - const StunUInt32Attribute* options_attr = - request.GetUInt32(STUN_ATTR_OPTIONS); - if (options_attr && (options_attr->value() & 0x01)) { - int_conn->set_default_destination(ext_addr); - int_conn->Lock(); - - RelayMessage response; - response.SetType(STUN_SEND_RESPONSE); - response.SetTransactionID(request.transaction_id()); - - StunByteStringAttribute* magic_cookie_attr = - StunAttribute::CreateByteString(cricket::STUN_ATTR_MAGIC_COOKIE); - magic_cookie_attr->CopyBytes(int_conn->binding()->magic_cookie().c_str(), - int_conn->binding()->magic_cookie().size()); - response.AddAttribute(magic_cookie_attr); - - StunUInt32Attribute* options2_attr = - StunAttribute::CreateUInt32(cricket::STUN_ATTR_OPTIONS); - options2_attr->SetValue(0x01); - response.AddAttribute(options2_attr); - - int_conn->SendStun(response); - } -} - -void RelayServer::AddConnection(RelayServerConnection* conn) { - ASSERT(connections_.find(conn->addr_pair()) == connections_.end()); - connections_[conn->addr_pair()] = conn; -} - -void RelayServer::RemoveConnection(RelayServerConnection* conn) { - ConnectionMap::iterator iter = connections_.find(conn->addr_pair()); - ASSERT(iter != connections_.end()); - connections_.erase(iter); -} - -void RelayServer::RemoveBinding(RelayServerBinding* binding) { - BindingMap::iterator iter = bindings_.find(binding->username()); - ASSERT(iter != bindings_.end()); - bindings_.erase(iter); - - if (log_bindings_) { - LOG(LS_INFO) << "Removed binding " << binding->username() << ", " - << bindings_.size() << " remaining"; - } -} - -void RelayServer::OnMessage(rtc::Message *pmsg) { -#if ENABLE_DEBUG - static const uint32 kMessageAcceptConnection = 1; - ASSERT(pmsg->message_id == kMessageAcceptConnection); -#endif - rtc::MessageData* data = pmsg->pdata; - rtc::AsyncSocket* socket = - static_cast <rtc::TypedMessageData<rtc::AsyncSocket*>*> - (data)->data(); - AcceptConnection(socket); - delete data; -} - -void RelayServer::OnTimeout(RelayServerBinding* binding) { - // This call will result in all of the necessary clean-up. We can't call - // delete here, because you can't delete an object that is signaling you. - thread_->Dispose(binding); -} - -void RelayServer::AcceptConnection(rtc::AsyncSocket* server_socket) { - // Check if someone is trying to connect to us. - rtc::SocketAddress accept_addr; - rtc::AsyncSocket* accepted_socket = - server_socket->Accept(&accept_addr); - if (accepted_socket != NULL) { - // We had someone trying to connect, now check which protocol to - // use and create a packet socket. - ASSERT(server_sockets_[server_socket] == cricket::PROTO_TCP || - server_sockets_[server_socket] == cricket::PROTO_SSLTCP); - if (server_sockets_[server_socket] == cricket::PROTO_SSLTCP) { - accepted_socket = new rtc::AsyncSSLServerSocket(accepted_socket); - } - rtc::AsyncTCPSocket* tcp_socket = - new rtc::AsyncTCPSocket(accepted_socket, false); - - // Finally add the socket so it can start communicating with the client. - AddInternalSocket(tcp_socket); - } -} - -RelayServerConnection::RelayServerConnection( - RelayServerBinding* binding, const rtc::SocketAddressPair& addrs, - rtc::AsyncPacketSocket* socket) - : binding_(binding), addr_pair_(addrs), socket_(socket), locked_(false) { - // The creation of a new connection constitutes a use of the binding. - binding_->NoteUsed(); -} - -RelayServerConnection::~RelayServerConnection() { - // Remove this connection from the server's map (if it exists there). - binding_->server()->RemoveConnection(this); -} - -void RelayServerConnection::Send(const char* data, size_t size) { - // Note that the binding has been used again. - binding_->NoteUsed(); - - cricket::Send(socket_, data, size, addr_pair_.source()); -} - -void RelayServerConnection::Send( - const char* data, size_t size, const rtc::SocketAddress& from_addr) { - // If the from address is known to the client, we don't need to send it. - if (locked() && (from_addr == default_dest_)) { - Send(data, size); - return; - } - - // Wrap the given data in a data-indication packet. - - RelayMessage msg; - msg.SetType(STUN_DATA_INDICATION); - - StunByteStringAttribute* magic_cookie_attr = - StunAttribute::CreateByteString(cricket::STUN_ATTR_MAGIC_COOKIE); - magic_cookie_attr->CopyBytes(binding_->magic_cookie().c_str(), - binding_->magic_cookie().size()); - msg.AddAttribute(magic_cookie_attr); - - StunAddressAttribute* addr_attr = - StunAttribute::CreateAddress(STUN_ATTR_SOURCE_ADDRESS2); - addr_attr->SetIP(from_addr.ipaddr()); - addr_attr->SetPort(from_addr.port()); - msg.AddAttribute(addr_attr); - - StunByteStringAttribute* data_attr = - StunAttribute::CreateByteString(STUN_ATTR_DATA); - ASSERT(size <= 65536); - data_attr->CopyBytes(data, uint16(size)); - msg.AddAttribute(data_attr); - - SendStun(msg); -} - -void RelayServerConnection::SendStun(const StunMessage& msg) { - // Note that the binding has been used again. - binding_->NoteUsed(); - - cricket::SendStun(msg, socket_, addr_pair_.source()); -} - -void RelayServerConnection::SendStunError( - const StunMessage& request, int error_code, const char* error_desc) { - // An error does not indicate use. If no legitimate use off the binding - // occurs, we want it to be cleaned up even if errors are still occuring. - - cricket::SendStunError( - request, socket_, addr_pair_.source(), error_code, error_desc, - binding_->magic_cookie()); -} - -void RelayServerConnection::Lock() { - locked_ = true; -} - -void RelayServerConnection::Unlock() { - locked_ = false; -} - -// IDs used for posted messages: -const uint32 MSG_LIFETIME_TIMER = 1; - -RelayServerBinding::RelayServerBinding( - RelayServer* server, const std::string& username, - const std::string& password, uint32 lifetime) - : server_(server), username_(username), password_(password), - lifetime_(lifetime) { - // For now, every connection uses the standard magic cookie value. - magic_cookie_.append( - reinterpret_cast<const char*>(TURN_MAGIC_COOKIE_VALUE), - sizeof(TURN_MAGIC_COOKIE_VALUE)); - - // Initialize the last-used time to now. - NoteUsed(); - - // Set the first timeout check. - server_->thread()->PostDelayed(lifetime_, this, MSG_LIFETIME_TIMER); -} - -RelayServerBinding::~RelayServerBinding() { - // Clear the outstanding timeout check. - server_->thread()->Clear(this); - - // Clean up all of the connections. - for (size_t i = 0; i < internal_connections_.size(); ++i) - delete internal_connections_[i]; - for (size_t i = 0; i < external_connections_.size(); ++i) - delete external_connections_[i]; - - // Remove this binding from the server's map. - server_->RemoveBinding(this); -} - -void RelayServerBinding::AddInternalConnection(RelayServerConnection* conn) { - internal_connections_.push_back(conn); -} - -void RelayServerBinding::AddExternalConnection(RelayServerConnection* conn) { - external_connections_.push_back(conn); -} - -void RelayServerBinding::NoteUsed() { - last_used_ = rtc::Time(); -} - -bool RelayServerBinding::HasMagicCookie(const char* bytes, size_t size) const { - if (size < 24 + magic_cookie_.size()) { - return false; - } else { - return memcmp(bytes + 24, magic_cookie_.c_str(), magic_cookie_.size()) == 0; - } -} - -RelayServerConnection* RelayServerBinding::GetInternalConnection( - const rtc::SocketAddress& ext_addr) { - - // Look for an internal connection that is locked to this address. - for (size_t i = 0; i < internal_connections_.size(); ++i) { - if (internal_connections_[i]->locked() && - (ext_addr == internal_connections_[i]->default_destination())) - return internal_connections_[i]; - } - - // If one was not found, we send to the first connection. - ASSERT(internal_connections_.size() > 0); - return internal_connections_[0]; -} - -RelayServerConnection* RelayServerBinding::GetExternalConnection( - const rtc::SocketAddress& ext_addr) { - for (size_t i = 0; i < external_connections_.size(); ++i) { - if (ext_addr == external_connections_[i]->addr_pair().source()) - return external_connections_[i]; - } - return 0; -} - -void RelayServerBinding::OnMessage(rtc::Message *pmsg) { - if (pmsg->message_id == MSG_LIFETIME_TIMER) { - ASSERT(!pmsg->pdata); - - // If the lifetime timeout has been exceeded, then send a signal. - // Otherwise, just keep waiting. - if (rtc::Time() >= last_used_ + lifetime_) { - LOG(LS_INFO) << "Expiring binding " << username_; - SignalTimeout(this); - } else { - server_->thread()->PostDelayed(lifetime_, this, MSG_LIFETIME_TIMER); - } - - } else { - ASSERT(false); - } -} - -} // namespace cricket diff --git a/talk/p2p/base/relayserver.h b/talk/p2p/base/relayserver.h deleted file mode 100644 index 8065174ac..000000000 --- a/talk/p2p/base/relayserver.h +++ /dev/null @@ -1,252 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef WEBRTC_P2P_BASE_RELAYSERVER_H_ -#define WEBRTC_P2P_BASE_RELAYSERVER_H_ - -#include <map> -#include <string> -#include <vector> - -#include "webrtc/p2p/base/port.h" -#include "webrtc/p2p/base/stun.h" -#include "webrtc/base/asyncudpsocket.h" -#include "webrtc/base/socketaddresspair.h" -#include "webrtc/base/thread.h" -#include "webrtc/base/timeutils.h" - -namespace cricket { - -class RelayServerBinding; -class RelayServerConnection; - -// Relays traffic between connections to the server that are "bound" together. -// All connections created with the same username/password are bound together. -class RelayServer : public rtc::MessageHandler, - public sigslot::has_slots<> { - public: - // Creates a server, which will use this thread to post messages to itself. - explicit RelayServer(rtc::Thread* thread); - ~RelayServer(); - - rtc::Thread* thread() { return thread_; } - - // Indicates whether we will print updates of the number of bindings. - bool log_bindings() const { return log_bindings_; } - void set_log_bindings(bool log_bindings) { log_bindings_ = log_bindings; } - - // Updates the set of sockets that the server uses to talk to "internal" - // clients. These are clients that do the "port allocations". - void AddInternalSocket(rtc::AsyncPacketSocket* socket); - void RemoveInternalSocket(rtc::AsyncPacketSocket* socket); - - // Updates the set of sockets that the server uses to talk to "external" - // clients. These are the clients that do not do allocations. They do not - // know that these addresses represent a relay server. - void AddExternalSocket(rtc::AsyncPacketSocket* socket); - void RemoveExternalSocket(rtc::AsyncPacketSocket* socket); - - // Starts listening for connections on this sockets. When someone - // tries to connect, the connection will be accepted and a new - // internal socket will be added. - void AddInternalServerSocket(rtc::AsyncSocket* socket, - cricket::ProtocolType proto); - - // Removes this server socket from the list. - void RemoveInternalServerSocket(rtc::AsyncSocket* socket); - - // Methods for testing and debuging. - int GetConnectionCount() const; - rtc::SocketAddressPair GetConnection(int connection) const; - bool HasConnection(const rtc::SocketAddress& address) const; - - private: - typedef std::vector<rtc::AsyncPacketSocket*> SocketList; - typedef std::map<rtc::AsyncSocket*, - cricket::ProtocolType> ServerSocketMap; - typedef std::map<std::string, RelayServerBinding*> BindingMap; - typedef std::map<rtc::SocketAddressPair, - RelayServerConnection*> ConnectionMap; - - rtc::Thread* thread_; - bool log_bindings_; - SocketList internal_sockets_; - SocketList external_sockets_; - SocketList removed_sockets_; - ServerSocketMap server_sockets_; - BindingMap bindings_; - ConnectionMap connections_; - - // Called when a packet is received by the server on one of its sockets. - void OnInternalPacket(rtc::AsyncPacketSocket* socket, - const char* bytes, size_t size, - const rtc::SocketAddress& remote_addr, - const rtc::PacketTime& packet_time); - void OnExternalPacket(rtc::AsyncPacketSocket* socket, - const char* bytes, size_t size, - const rtc::SocketAddress& remote_addr, - const rtc::PacketTime& packet_time); - - void OnReadEvent(rtc::AsyncSocket* socket); - - // Processes the relevant STUN request types from the client. - bool HandleStun(const char* bytes, size_t size, - const rtc::SocketAddress& remote_addr, - rtc::AsyncPacketSocket* socket, - std::string* username, StunMessage* msg); - void HandleStunAllocate(const char* bytes, size_t size, - const rtc::SocketAddressPair& ap, - rtc::AsyncPacketSocket* socket); - void HandleStun(RelayServerConnection* int_conn, const char* bytes, - size_t size); - void HandleStunAllocate(RelayServerConnection* int_conn, - const StunMessage& msg); - void HandleStunSend(RelayServerConnection* int_conn, const StunMessage& msg); - - // Adds/Removes the a connection or binding. - void AddConnection(RelayServerConnection* conn); - void RemoveConnection(RelayServerConnection* conn); - void RemoveBinding(RelayServerBinding* binding); - - // Handle messages in our worker thread. - void OnMessage(rtc::Message *pmsg); - - // Called when the timer for checking lifetime times out. - void OnTimeout(RelayServerBinding* binding); - - // Accept connections on this server socket. - void AcceptConnection(rtc::AsyncSocket* server_socket); - - friend class RelayServerConnection; - friend class RelayServerBinding; -}; - -// Maintains information about a connection to the server. Each connection is -// part of one and only one binding. -class RelayServerConnection { - public: - RelayServerConnection(RelayServerBinding* binding, - const rtc::SocketAddressPair& addrs, - rtc::AsyncPacketSocket* socket); - ~RelayServerConnection(); - - RelayServerBinding* binding() { return binding_; } - rtc::AsyncPacketSocket* socket() { return socket_; } - - // Returns a pair where the source is the remote address and the destination - // is the local address. - const rtc::SocketAddressPair& addr_pair() { return addr_pair_; } - - // Sends a packet to the connected client. If an address is provided, then - // we make sure the internal client receives it, wrapping if necessary. - void Send(const char* data, size_t size); - void Send(const char* data, size_t size, - const rtc::SocketAddress& ext_addr); - - // Sends a STUN message to the connected client with no wrapping. - void SendStun(const StunMessage& msg); - void SendStunError(const StunMessage& request, int code, const char* desc); - - // A locked connection is one for which we know the intended destination of - // any raw packet received. - bool locked() const { return locked_; } - void Lock(); - void Unlock(); - - // Records the address that raw packets should be forwarded to (for internal - // packets only; for external, we already know where they go). - const rtc::SocketAddress& default_destination() const { - return default_dest_; - } - void set_default_destination(const rtc::SocketAddress& addr) { - default_dest_ = addr; - } - - private: - RelayServerBinding* binding_; - rtc::SocketAddressPair addr_pair_; - rtc::AsyncPacketSocket* socket_; - bool locked_; - rtc::SocketAddress default_dest_; -}; - -// Records a set of internal and external connections that we relay between, -// or in other words, that are "bound" together. -class RelayServerBinding : public rtc::MessageHandler { - public: - RelayServerBinding( - RelayServer* server, const std::string& username, - const std::string& password, uint32 lifetime); - virtual ~RelayServerBinding(); - - RelayServer* server() { return server_; } - uint32 lifetime() { return lifetime_; } - const std::string& username() { return username_; } - const std::string& password() { return password_; } - const std::string& magic_cookie() { return magic_cookie_; } - - // Adds/Removes a connection into the binding. - void AddInternalConnection(RelayServerConnection* conn); - void AddExternalConnection(RelayServerConnection* conn); - - // We keep track of the use of each binding. If we detect that it was not - // used for longer than the lifetime, then we send a signal. - void NoteUsed(); - sigslot::signal1<RelayServerBinding*> SignalTimeout; - - // Determines whether the given packet has the magic cookie present (in the - // right place). - bool HasMagicCookie(const char* bytes, size_t size) const; - - // Determines the connection to use to send packets to or from the given - // external address. - RelayServerConnection* GetInternalConnection( - const rtc::SocketAddress& ext_addr); - RelayServerConnection* GetExternalConnection( - const rtc::SocketAddress& ext_addr); - - // MessageHandler: - void OnMessage(rtc::Message *pmsg); - - private: - RelayServer* server_; - - std::string username_; - std::string password_; - std::string magic_cookie_; - - std::vector<RelayServerConnection*> internal_connections_; - std::vector<RelayServerConnection*> external_connections_; - - uint32 lifetime_; - uint32 last_used_; - // TODO: bandwidth -}; - -} // namespace cricket - -#endif // WEBRTC_P2P_BASE_RELAYSERVER_H_ diff --git a/talk/p2p/base/relayserver_unittest.cc b/talk/p2p/base/relayserver_unittest.cc deleted file mode 100644 index 5ea5e100c..000000000 --- a/talk/p2p/base/relayserver_unittest.cc +++ /dev/null @@ -1,536 +0,0 @@ -/* - * libjingle - * Copyright 2004 Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <string> - -#include "webrtc/p2p/base/relayserver.h" -#include "webrtc/base/gunit.h" -#include "webrtc/base/helpers.h" -#include "webrtc/base/logging.h" -#include "webrtc/base/physicalsocketserver.h" -#include "webrtc/base/socketaddress.h" -#include "webrtc/base/ssladapter.h" -#include "webrtc/base/testclient.h" -#include "webrtc/base/thread.h" - -using rtc::SocketAddress; -using namespace cricket; - -static const uint32 LIFETIME = 4; // seconds -static const SocketAddress server_int_addr("127.0.0.1", 5000); -static const SocketAddress server_ext_addr("127.0.0.1", 5001); -static const SocketAddress client1_addr("127.0.0.1", 6000 + (rand() % 1000)); -static const SocketAddress client2_addr("127.0.0.1", 7000 + (rand() % 1000)); -static const char* bad = "this is a completely nonsensical message whose only " - "purpose is to make the parser go 'ack'. it doesn't " - "look anything like a normal stun message"; -static const char* msg1 = "spamspamspamspamspamspamspambakedbeansspam"; -static const char* msg2 = "Lobster Thermidor a Crevette with a mornay sauce..."; - -class RelayServerTest : public testing::Test { - public: - RelayServerTest() - : main_(rtc::Thread::Current()), ss_(main_->socketserver()), - username_(rtc::CreateRandomString(12)), - password_(rtc::CreateRandomString(12)) { - } - protected: - virtual void SetUp() { - server_.reset(new RelayServer(main_)); - - server_->AddInternalSocket( - rtc::AsyncUDPSocket::Create(ss_, server_int_addr)); - server_->AddExternalSocket( - rtc::AsyncUDPSocket::Create(ss_, server_ext_addr)); - - client1_.reset(new rtc::TestClient( - rtc::AsyncUDPSocket::Create(ss_, client1_addr))); - client2_.reset(new rtc::TestClient( - rtc::AsyncUDPSocket::Create(ss_, client2_addr))); - } - - void Allocate() { - rtc::scoped_ptr<StunMessage> req( - CreateStunMessage(STUN_ALLOCATE_REQUEST)); - AddUsernameAttr(req.get(), username_); - AddLifetimeAttr(req.get(), LIFETIME); - Send1(req.get()); - delete Receive1(); - } - void Bind() { - rtc::scoped_ptr<StunMessage> req( - CreateStunMessage(STUN_BINDING_REQUEST)); - AddUsernameAttr(req.get(), username_); - Send2(req.get()); - delete Receive1(); - } - - void Send1(const StunMessage* msg) { - rtc::ByteBuffer buf; - msg->Write(&buf); - SendRaw1(buf.Data(), static_cast<int>(buf.Length())); - } - void Send2(const StunMessage* msg) { - rtc::ByteBuffer buf; - msg->Write(&buf); - SendRaw2(buf.Data(), static_cast<int>(buf.Length())); - } - void SendRaw1(const char* data, int len) { - return Send(client1_.get(), data, len, server_int_addr); - } - void SendRaw2(const char* data, int len) { - return Send(client2_.get(), data, len, server_ext_addr); - } - void Send(rtc::TestClient* client, const char* data, - int len, const SocketAddress& addr) { - client->SendTo(data, len, addr); - } - - StunMessage* Receive1() { - return Receive(client1_.get()); - } - StunMessage* Receive2() { - return Receive(client2_.get()); - } - std::string ReceiveRaw1() { - return ReceiveRaw(client1_.get()); - } - std::string ReceiveRaw2() { - return ReceiveRaw(client2_.get()); - } - StunMessage* Receive(rtc::TestClient* client) { - StunMessage* msg = NULL; - rtc::TestClient::Packet* packet = client->NextPacket(); - if (packet) { - rtc::ByteBuffer buf(packet->buf, packet->size); - msg = new RelayMessage(); - msg->Read(&buf); - delete packet; - } - return msg; - } - std::string ReceiveRaw(rtc::TestClient* client) { - std::string raw; - rtc::TestClient::Packet* packet = client->NextPacket(); - if (packet) { - raw = std::string(packet->buf, packet->size); - delete packet; - } - return raw; - } - - static StunMessage* CreateStunMessage(int type) { - StunMessage* msg = new RelayMessage(); - msg->SetType(type); - msg->SetTransactionID( - rtc::CreateRandomString(kStunTransactionIdLength)); - return msg; - } - static void AddMagicCookieAttr(StunMessage* msg) { - StunByteStringAttribute* attr = - StunAttribute::CreateByteString(STUN_ATTR_MAGIC_COOKIE); - attr->CopyBytes(TURN_MAGIC_COOKIE_VALUE, sizeof(TURN_MAGIC_COOKIE_VALUE)); - msg->AddAttribute(attr); - } - static void AddUsernameAttr(StunMessage* msg, const std::string& val) { - StunByteStringAttribute* attr = - StunAttribute::CreateByteString(STUN_ATTR_USERNAME); - attr->CopyBytes(val.c_str(), val.size()); - msg->AddAttribute(attr); - } - static void AddLifetimeAttr(StunMessage* msg, int val) { - StunUInt32Attribute* attr = - StunAttribute::CreateUInt32(STUN_ATTR_LIFETIME); - attr->SetValue(val); - msg->AddAttribute(attr); - } - static void AddDestinationAttr(StunMessage* msg, const SocketAddress& addr) { - StunAddressAttribute* attr = - StunAttribute::CreateAddress(STUN_ATTR_DESTINATION_ADDRESS); - attr->SetIP(addr.ipaddr()); - attr->SetPort(addr.port()); - msg->AddAttribute(attr); - } - - rtc::Thread* main_; - rtc::SocketServer* ss_; - rtc::scoped_ptr<RelayServer> server_; - rtc::scoped_ptr<rtc::TestClient> client1_; - rtc::scoped_ptr<rtc::TestClient> client2_; - std::string username_; - std::string password_; -}; - -// Send a complete nonsense message and verify that it is eaten. -TEST_F(RelayServerTest, TestBadRequest) { - rtc::scoped_ptr<StunMessage> res; - - SendRaw1(bad, static_cast<int>(strlen(bad))); - res.reset(Receive1()); - - ASSERT_TRUE(!res); -} - -// Send an allocate request without a username and verify it is rejected. -TEST_F(RelayServerTest, TestAllocateNoUsername) { - rtc::scoped_ptr<StunMessage> req( - CreateStunMessage(STUN_ALLOCATE_REQUEST)), res; - - Send1(req.get()); - res.reset(Receive1()); - - ASSERT_TRUE(res); - EXPECT_EQ(STUN_ALLOCATE_ERROR_RESPONSE, res->type()); - EXPECT_EQ(req->transaction_id(), res->transaction_id()); - - const StunErrorCodeAttribute* err = res->GetErrorCode(); - ASSERT_TRUE(err != NULL); - EXPECT_EQ(4, err->eclass()); - EXPECT_EQ(32, err->number()); - EXPECT_EQ("Missing Username", err->reason()); -} - -// Send a binding request and verify that it is rejected. -TEST_F(RelayServerTest, TestBindingRequest) { - rtc::scoped_ptr<StunMessage> req( - CreateStunMessage(STUN_BINDING_REQUEST)), res; - AddUsernameAttr(req.get(), username_); - - Send1(req.get()); - res.reset(Receive1()); - - ASSERT_TRUE(res); - EXPECT_EQ(STUN_BINDING_ERROR_RESPONSE, res->type()); - EXPECT_EQ(req->transaction_id(), res->transaction_id()); - - const StunErrorCodeAttribute* err = res->GetErrorCode(); - ASSERT_TRUE(err != NULL); - EXPECT_EQ(6, err->eclass()); - EXPECT_EQ(0, err->number()); - EXPECT_EQ("Operation Not Supported", err->reason()); -} - -// Send an allocate request and verify that it is accepted. -TEST_F(RelayServerTest, TestAllocate) { - rtc::scoped_ptr<StunMessage> req( - CreateStunMessage(STUN_ALLOCATE_REQUEST)), res; - AddUsernameAttr(req.get(), username_); - AddLifetimeAttr(req.get(), LIFETIME); - - Send1(req.get()); - res.reset(Receive1()); - - ASSERT_TRUE(res); - EXPECT_EQ(STUN_ALLOCATE_RESPONSE, res->type()); - EXPECT_EQ(req->transaction_id(), res->transaction_id()); - - const StunAddressAttribute* mapped_addr = - res->GetAddress(STUN_ATTR_MAPPED_ADDRESS); - ASSERT_TRUE(mapped_addr != NULL); - EXPECT_EQ(1, mapped_addr->family()); - EXPECT_EQ(server_ext_addr.port(), mapped_addr->port()); - EXPECT_EQ(server_ext_addr.ipaddr(), mapped_addr->ipaddr()); - - const StunUInt32Attribute* res_lifetime_attr = - res->GetUInt32(STUN_ATTR_LIFETIME); - ASSERT_TRUE(res_lifetime_attr != NULL); - EXPECT_EQ(LIFETIME, res_lifetime_attr->value()); -} - -// Send a second allocate request and verify that it is also accepted, though -// the lifetime should be ignored. -TEST_F(RelayServerTest, TestReallocate) { - Allocate(); - - rtc::scoped_ptr<StunMessage> req( - CreateStunMessage(STUN_ALLOCATE_REQUEST)), res; - AddMagicCookieAttr(req.get()); - AddUsernameAttr(req.get(), username_); - - Send1(req.get()); - res.reset(Receive1()); - - ASSERT_TRUE(res); - EXPECT_EQ(STUN_ALLOCATE_RESPONSE, res->type()); - EXPECT_EQ(req->transaction_id(), res->transaction_id()); - - const StunAddressAttribute* mapped_addr = - res->GetAddress(STUN_ATTR_MAPPED_ADDRESS); - ASSERT_TRUE(mapped_addr != NULL); - EXPECT_EQ(1, mapped_addr->family()); - EXPECT_EQ(server_ext_addr.port(), mapped_addr->port()); - EXPECT_EQ(server_ext_addr.ipaddr(), mapped_addr->ipaddr()); - - const StunUInt32Attribute* lifetime_attr = - res->GetUInt32(STUN_ATTR_LIFETIME); - ASSERT_TRUE(lifetime_attr != NULL); - EXPECT_EQ(LIFETIME, lifetime_attr->value()); -} - -// Send a request from another client and see that it arrives at the first -// client in the binding. -TEST_F(RelayServerTest, TestRemoteBind) { - Allocate(); - - rtc::scoped_ptr<StunMessage> req( - CreateStunMessage(STUN_BINDING_REQUEST)), res; - AddUsernameAttr(req.get(), username_); - - Send2(req.get()); - res.reset(Receive1()); - - ASSERT_TRUE(res); - EXPECT_EQ(STUN_DATA_INDICATION, res->type()); - - const StunByteStringAttribute* recv_data = - res->GetByteString(STUN_ATTR_DATA); - ASSERT_TRUE(recv_data != NULL); - - rtc::ByteBuffer buf(recv_data->bytes(), recv_data->length()); - rtc::scoped_ptr<StunMessage> res2(new StunMessage()); - EXPECT_TRUE(res2->Read(&buf)); - EXPECT_EQ(STUN_BINDING_REQUEST, res2->type()); - EXPECT_EQ(req->transaction_id(), res2->transaction_id()); - - const StunAddressAttribute* src_addr = - res->GetAddress(STUN_ATTR_SOURCE_ADDRESS2); - ASSERT_TRUE(src_addr != NULL); - EXPECT_EQ(1, src_addr->family()); - EXPECT_EQ(client2_addr.ipaddr(), src_addr->ipaddr()); - EXPECT_EQ(client2_addr.port(), src_addr->port()); - - EXPECT_TRUE(Receive2() == NULL); -} - -// Send a complete nonsense message to the established connection and verify -// that it is dropped by the server. -TEST_F(RelayServerTest, TestRemoteBadRequest) { - Allocate(); - Bind(); - - SendRaw1(bad, static_cast<int>(strlen(bad))); - EXPECT_TRUE(Receive1() == NULL); - EXPECT_TRUE(Receive2() == NULL); -} - -// Send a send request without a username and verify it is rejected. -TEST_F(RelayServerTest, TestSendRequestMissingUsername) { - Allocate(); - Bind(); - - rtc::scoped_ptr<StunMessage> req( - CreateStunMessage(STUN_SEND_REQUEST)), res; - AddMagicCookieAttr(req.get()); - - Send1(req.get()); - res.reset(Receive1()); - - ASSERT_TRUE(res); - EXPECT_EQ(STUN_SEND_ERROR_RESPONSE, res->type()); - EXPECT_EQ(req->transaction_id(), res->transaction_id()); - - const StunErrorCodeAttribute* err = res->GetErrorCode(); - ASSERT_TRUE(err != NULL); - EXPECT_EQ(4, err->eclass()); - EXPECT_EQ(32, err->number()); - EXPECT_EQ("Missing Username", err->reason()); -} - -// Send a send request with the wrong username and verify it is rejected. -TEST_F(RelayServerTest, TestSendRequestBadUsername) { - Allocate(); - Bind(); - - rtc::scoped_ptr<StunMessage> req( - CreateStunMessage(STUN_SEND_REQUEST)), res; - AddMagicCookieAttr(req.get()); - AddUsernameAttr(req.get(), "foobarbizbaz"); - - Send1(req.get()); - res.reset(Receive1()); - - ASSERT_TRUE(res); - EXPECT_EQ(STUN_SEND_ERROR_RESPONSE, res->type()); - EXPECT_EQ(req->transaction_id(), res->transaction_id()); - - const StunErrorCodeAttribute* err = res->GetErrorCode(); - ASSERT_TRUE(err != NULL); - EXPECT_EQ(4, err->eclass()); - EXPECT_EQ(30, err->number()); - EXPECT_EQ("Stale Credentials", err->reason()); -} - -// Send a send request without a destination address and verify that it is -// rejected. -TEST_F(RelayServerTest, TestSendRequestNoDestinationAddress) { - Allocate(); - Bind(); - - rtc::scoped_ptr<StunMessage> req( - CreateStunMessage(STUN_SEND_REQUEST)), res; - AddMagicCookieAttr(req.get()); - AddUsernameAttr(req.get(), username_); - - Send1(req.get()); - res.reset(Receive1()); - - ASSERT_TRUE(res); - EXPECT_EQ(STUN_SEND_ERROR_RESPONSE, res->type()); - EXPECT_EQ(req->transaction_id(), res->transaction_id()); - - const StunErrorCodeAttribute* err = res->GetErrorCode(); - ASSERT_TRUE(err != NULL); - EXPECT_EQ(4, err->eclass()); - EXPECT_EQ(0, err->number()); - EXPECT_EQ("Bad Request", err->reason()); -} - -// Send a send request without data and verify that it is rejected. -TEST_F(RelayServerTest, TestSendRequestNoData) { - Allocate(); - Bind(); - - rtc::scoped_ptr<StunMessage> req( - CreateStunMessage(STUN_SEND_REQUEST)), res; - AddMagicCookieAttr(req.get()); - AddUsernameAttr(req.get(), username_); - AddDestinationAttr(req.get(), client2_addr); - - Send1(req.get()); - res.reset(Receive1()); - - ASSERT_TRUE(res); - EXPECT_EQ(STUN_SEND_ERROR_RESPONSE, res->type()); - EXPECT_EQ(req->transaction_id(), res->transaction_id()); - - const StunErrorCodeAttribute* err = res->GetErrorCode(); - ASSERT_TRUE(err != NULL); - EXPECT_EQ(4, err->eclass()); - EXPECT_EQ(00, err->number()); - EXPECT_EQ("Bad Request", err->reason()); -} - -// Send a binding request after an allocate and verify that it is rejected. -TEST_F(RelayServerTest, TestSendRequestWrongType) { - Allocate(); - Bind(); - - rtc::scoped_ptr<StunMessage> req( - CreateStunMessage(STUN_BINDING_REQUEST)), res; - AddMagicCookieAttr(req.get()); - AddUsernameAttr(req.get(), username_); - - Send1(req.get()); - res.reset(Receive1()); - - ASSERT_TRUE(res); - EXPECT_EQ(STUN_BINDING_ERROR_RESPONSE, res->type()); - EXPECT_EQ(req->transaction_id(), res->transaction_id()); - - const StunErrorCodeAttribute* err = res->GetErrorCode(); - ASSERT_TRUE(err != NULL); - EXPECT_EQ(6, err->eclass()); - EXPECT_EQ(0, err->number()); - EXPECT_EQ("Operation Not Supported", err->reason()); -} - -// Verify that we can send traffic back and forth between the clients after a -// successful allocate and bind. -TEST_F(RelayServerTest, TestSendRaw) { - Allocate(); - Bind(); - - for (int i = 0; i < 10; i++) { - rtc::scoped_ptr<StunMessage> req( - CreateStunMessage(STUN_SEND_REQUEST)), res; - AddMagicCookieAttr(req.get()); - AddUsernameAttr(req.get(), username_); - AddDestinationAttr(req.get(), client2_addr); - - StunByteStringAttribute* send_data = - StunAttribute::CreateByteString(STUN_ATTR_DATA); - send_data->CopyBytes(msg1); - req->AddAttribute(send_data); - - Send1(req.get()); - EXPECT_EQ(msg1, ReceiveRaw2()); - SendRaw2(msg2, static_cast<int>(strlen(msg2))); - res.reset(Receive1()); - - ASSERT_TRUE(res); - EXPECT_EQ(STUN_DATA_INDICATION, res->type()); - - const StunAddressAttribute* src_addr = - res->GetAddress(STUN_ATTR_SOURCE_ADDRESS2); - ASSERT_TRUE(src_addr != NULL); - EXPECT_EQ(1, src_addr->family()); - EXPECT_EQ(client2_addr.ipaddr(), src_addr->ipaddr()); - EXPECT_EQ(client2_addr.port(), src_addr->port()); - - const StunByteStringAttribute* recv_data = - res->GetByteString(STUN_ATTR_DATA); - ASSERT_TRUE(recv_data != NULL); - EXPECT_EQ(strlen(msg2), recv_data->length()); - EXPECT_EQ(0, memcmp(msg2, recv_data->bytes(), recv_data->length())); - } -} - -// Verify that a binding expires properly, and rejects send requests. -TEST_F(RelayServerTest, TestExpiration) { - Allocate(); - Bind(); - - // Wait twice the lifetime to make sure the server has expired the binding. - rtc::Thread::Current()->ProcessMessages((LIFETIME * 2) * 1000); - - rtc::scoped_ptr<StunMessage> req( - CreateStunMessage(STUN_SEND_REQUEST)), res; - AddMagicCookieAttr(req.get()); - AddUsernameAttr(req.get(), username_); - AddDestinationAttr(req.get(), client2_addr); - - StunByteStringAttribute* data_attr = - StunAttribute::CreateByteString(STUN_ATTR_DATA); - data_attr->CopyBytes(msg1); - req->AddAttribute(data_attr); - - Send1(req.get()); - res.reset(Receive1()); - - ASSERT_TRUE(res.get() != NULL); - EXPECT_EQ(STUN_SEND_ERROR_RESPONSE, res->type()); - - const StunErrorCodeAttribute* err = res->GetErrorCode(); - ASSERT_TRUE(err != NULL); - EXPECT_EQ(6, err->eclass()); - EXPECT_EQ(0, err->number()); - EXPECT_EQ("Operation Not Supported", err->reason()); - - // Also verify that traffic from the external client is ignored. - SendRaw2(msg2, static_cast<int>(strlen(msg2))); - EXPECT_TRUE(ReceiveRaw1().empty()); -} diff --git a/talk/p2p/base/session.cc b/talk/p2p/base/session.cc deleted file mode 100644 index c4db1cf02..000000000 --- a/talk/p2p/base/session.cc +++ /dev/null @@ -1,1777 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "webrtc/p2p/base/session.h" - -#include "webrtc/p2p/base/dtlstransport.h" -#include "webrtc/p2p/base/p2ptransport.h" -#include "webrtc/p2p/base/sessionclient.h" -#include "webrtc/p2p/base/transport.h" -#include "webrtc/p2p/base/transportchannelproxy.h" -#include "webrtc/p2p/base/transportinfo.h" -#include "webrtc/libjingle/xmpp/constants.h" -#include "webrtc/libjingle/xmpp/jid.h" -#include "webrtc/base/bind.h" -#include "webrtc/base/common.h" -#include "webrtc/base/helpers.h" -#include "webrtc/base/logging.h" -#include "webrtc/base/scoped_ptr.h" -#include "webrtc/base/sslstreamadapter.h" - -#include "webrtc/p2p/base/constants.h" - -namespace cricket { - -using rtc::Bind; - -bool BadMessage(const buzz::QName type, - const std::string& text, - MessageError* err) { - err->SetType(type); - err->SetText(text); - return false; -} - -TransportProxy::~TransportProxy() { - for (ChannelMap::iterator iter = channels_.begin(); - iter != channels_.end(); ++iter) { - iter->second->SignalDestroyed(iter->second); - delete iter->second; - } -} - -const std::string& TransportProxy::type() const { - return transport_->get()->type(); -} - -TransportChannel* TransportProxy::GetChannel(int component) { - ASSERT(rtc::Thread::Current() == worker_thread_); - return GetChannelProxy(component); -} - -TransportChannel* TransportProxy::CreateChannel( - const std::string& name, int component) { - ASSERT(rtc::Thread::Current() == worker_thread_); - ASSERT(GetChannel(component) == NULL); - ASSERT(!transport_->get()->HasChannel(component)); - - // We always create a proxy in case we need to change out the transport later. - TransportChannelProxy* channel = - new TransportChannelProxy(content_name(), name, component); - channels_[component] = channel; - - // If we're already negotiated, create an impl and hook it up to the proxy - // channel. If we're connecting, create an impl but don't hook it up yet. - if (negotiated_) { - SetupChannelProxy_w(component, channel); - } else if (connecting_) { - GetOrCreateChannelProxyImpl_w(component); - } - return channel; -} - -bool TransportProxy::HasChannel(int component) { - return transport_->get()->HasChannel(component); -} - -void TransportProxy::DestroyChannel(int component) { - ASSERT(rtc::Thread::Current() == worker_thread_); - TransportChannel* channel = GetChannel(component); - if (channel) { - // If the state of TransportProxy is not NEGOTIATED - // then TransportChannelProxy and its impl are not - // connected. Both must be connected before - // deletion. - if (!negotiated_) { - SetupChannelProxy_w(component, GetChannelProxy(component)); - } - - channels_.erase(component); - channel->SignalDestroyed(channel); - delete channel; - } -} - -void TransportProxy::ConnectChannels() { - if (!connecting_) { - if (!negotiated_) { - for (ChannelMap::iterator iter = channels_.begin(); - iter != channels_.end(); ++iter) { - GetOrCreateChannelProxyImpl(iter->first); - } - } - connecting_ = true; - } - // TODO(juberti): Right now Transport::ConnectChannels doesn't work if we - // don't have any channels yet, so we need to allow this method to be called - // multiple times. Once we fix Transport, we can move this call inside the - // if (!connecting_) block. - transport_->get()->ConnectChannels(); -} - -void TransportProxy::CompleteNegotiation() { - if (!negotiated_) { - for (ChannelMap::iterator iter = channels_.begin(); - iter != channels_.end(); ++iter) { - SetupChannelProxy(iter->first, iter->second); - } - negotiated_ = true; - } -} - -void TransportProxy::AddSentCandidates(const Candidates& candidates) { - for (Candidates::const_iterator cand = candidates.begin(); - cand != candidates.end(); ++cand) { - sent_candidates_.push_back(*cand); - } -} - -void TransportProxy::AddUnsentCandidates(const Candidates& candidates) { - for (Candidates::const_iterator cand = candidates.begin(); - cand != candidates.end(); ++cand) { - unsent_candidates_.push_back(*cand); - } -} - -bool TransportProxy::GetChannelNameFromComponent( - int component, std::string* channel_name) const { - const TransportChannelProxy* channel = GetChannelProxy(component); - if (channel == NULL) { - return false; - } - - *channel_name = channel->name(); - return true; -} - -bool TransportProxy::GetComponentFromChannelName( - const std::string& channel_name, int* component) const { - const TransportChannelProxy* channel = GetChannelProxyByName(channel_name); - if (channel == NULL) { - return false; - } - - *component = channel->component(); - return true; -} - -TransportChannelProxy* TransportProxy::GetChannelProxy(int component) const { - ChannelMap::const_iterator iter = channels_.find(component); - return (iter != channels_.end()) ? iter->second : NULL; -} - -TransportChannelProxy* TransportProxy::GetChannelProxyByName( - const std::string& name) const { - for (ChannelMap::const_iterator iter = channels_.begin(); - iter != channels_.end(); - ++iter) { - if (iter->second->name() == name) { - return iter->second; - } - } - return NULL; -} - -TransportChannelImpl* TransportProxy::GetOrCreateChannelProxyImpl( - int component) { - return worker_thread_->Invoke<TransportChannelImpl*>(Bind( - &TransportProxy::GetOrCreateChannelProxyImpl_w, this, component)); -} - -TransportChannelImpl* TransportProxy::GetOrCreateChannelProxyImpl_w( - int component) { - ASSERT(rtc::Thread::Current() == worker_thread_); - TransportChannelImpl* impl = transport_->get()->GetChannel(component); - if (impl == NULL) { - impl = transport_->get()->CreateChannel(component); - } - return impl; -} - -void TransportProxy::SetupChannelProxy( - int component, TransportChannelProxy* transproxy) { - worker_thread_->Invoke<void>(Bind( - &TransportProxy::SetupChannelProxy_w, this, component, transproxy)); -} - -void TransportProxy::SetupChannelProxy_w( - int component, TransportChannelProxy* transproxy) { - ASSERT(rtc::Thread::Current() == worker_thread_); - TransportChannelImpl* impl = GetOrCreateChannelProxyImpl(component); - ASSERT(impl != NULL); - transproxy->SetImplementation(impl); -} - -void TransportProxy::ReplaceChannelProxyImpl(TransportChannelProxy* proxy, - TransportChannelImpl* impl) { - worker_thread_->Invoke<void>(Bind( - &TransportProxy::ReplaceChannelProxyImpl_w, this, proxy, impl)); -} - -void TransportProxy::ReplaceChannelProxyImpl_w(TransportChannelProxy* proxy, - TransportChannelImpl* impl) { - ASSERT(rtc::Thread::Current() == worker_thread_); - ASSERT(proxy != NULL); - proxy->SetImplementation(impl); -} - -// This function muxes |this| onto |target| by repointing |this| at -// |target|'s transport and setting our TransportChannelProxies -// to point to |target|'s underlying implementations. -bool TransportProxy::SetupMux(TransportProxy* target) { - // Bail out if there's nothing to do. - if (transport_ == target->transport_) { - return true; - } - - // Run through all channels and remove any non-rtp transport channels before - // setting target transport channels. - for (ChannelMap::const_iterator iter = channels_.begin(); - iter != channels_.end(); ++iter) { - if (!target->transport_->get()->HasChannel(iter->first)) { - // Remove if channel doesn't exist in |transport_|. - ReplaceChannelProxyImpl(iter->second, NULL); - } else { - // Replace the impl for all the TransportProxyChannels with the channels - // from |target|'s transport. Fail if there's not an exact match. - ReplaceChannelProxyImpl( - iter->second, target->transport_->get()->CreateChannel(iter->first)); - } - } - - // Now replace our transport. Must happen afterwards because - // it deletes all impls as a side effect. - transport_ = target->transport_; - transport_->get()->SignalCandidatesReady.connect( - this, &TransportProxy::OnTransportCandidatesReady); - set_candidates_allocated(target->candidates_allocated()); - return true; -} - -void TransportProxy::SetIceRole(IceRole role) { - transport_->get()->SetIceRole(role); -} - -bool TransportProxy::SetLocalTransportDescription( - const TransportDescription& description, - ContentAction action, - std::string* error_desc) { - // If this is an answer, finalize the negotiation. - if (action == CA_ANSWER) { - CompleteNegotiation(); - } - bool result = transport_->get()->SetLocalTransportDescription(description, - action, - error_desc); - if (result) - local_description_set_ = true; - return result; -} - -bool TransportProxy::SetRemoteTransportDescription( - const TransportDescription& description, - ContentAction action, - std::string* error_desc) { - // If this is an answer, finalize the negotiation. - if (action == CA_ANSWER) { - CompleteNegotiation(); - } - bool result = transport_->get()->SetRemoteTransportDescription(description, - action, - error_desc); - if (result) - remote_description_set_ = true; - return result; -} - -void TransportProxy::OnSignalingReady() { - // If we're starting a new allocation sequence, reset our state. - set_candidates_allocated(false); - transport_->get()->OnSignalingReady(); -} - -bool TransportProxy::OnRemoteCandidates(const Candidates& candidates, - std::string* error) { - // Ensure the transport is negotiated before handling candidates. - // TODO(juberti): Remove this once everybody calls SetLocalTD. - CompleteNegotiation(); - - // Verify each candidate before passing down to transport layer. - for (Candidates::const_iterator cand = candidates.begin(); - cand != candidates.end(); ++cand) { - if (!transport_->get()->VerifyCandidate(*cand, error)) - return false; - if (!HasChannel(cand->component())) { - *error = "Candidate has unknown component: " + cand->ToString() + - " for content: " + content_name_; - return false; - } - } - transport_->get()->OnRemoteCandidates(candidates); - return true; -} - -void TransportProxy::SetIdentity( - rtc::SSLIdentity* identity) { - transport_->get()->SetIdentity(identity); -} - -std::string BaseSession::StateToString(State state) { - switch (state) { - case Session::STATE_INIT: - return "STATE_INIT"; - case Session::STATE_SENTINITIATE: - return "STATE_SENTINITIATE"; - case Session::STATE_RECEIVEDINITIATE: - return "STATE_RECEIVEDINITIATE"; - case Session::STATE_SENTPRACCEPT: - return "STATE_SENTPRACCEPT"; - case Session::STATE_SENTACCEPT: - return "STATE_SENTACCEPT"; - case Session::STATE_RECEIVEDPRACCEPT: - return "STATE_RECEIVEDPRACCEPT"; - case Session::STATE_RECEIVEDACCEPT: - return "STATE_RECEIVEDACCEPT"; - case Session::STATE_SENTMODIFY: - return "STATE_SENTMODIFY"; - case Session::STATE_RECEIVEDMODIFY: - return "STATE_RECEIVEDMODIFY"; - case Session::STATE_SENTREJECT: - return "STATE_SENTREJECT"; - case Session::STATE_RECEIVEDREJECT: - return "STATE_RECEIVEDREJECT"; - case Session::STATE_SENTREDIRECT: - return "STATE_SENTREDIRECT"; - case Session::STATE_SENTTERMINATE: - return "STATE_SENTTERMINATE"; - case Session::STATE_RECEIVEDTERMINATE: - return "STATE_RECEIVEDTERMINATE"; - case Session::STATE_INPROGRESS: - return "STATE_INPROGRESS"; - case Session::STATE_DEINIT: - return "STATE_DEINIT"; - default: - break; - } - return "STATE_" + rtc::ToString(state); -} - -BaseSession::BaseSession(rtc::Thread* signaling_thread, - rtc::Thread* worker_thread, - PortAllocator* port_allocator, - const std::string& sid, - const std::string& content_type, - bool initiator) - : state_(STATE_INIT), - error_(ERROR_NONE), - signaling_thread_(signaling_thread), - worker_thread_(worker_thread), - port_allocator_(port_allocator), - sid_(sid), - content_type_(content_type), - transport_type_(NS_GINGLE_P2P), - initiator_(initiator), - identity_(NULL), - ice_tiebreaker_(rtc::CreateRandomId64()), - role_switch_(false) { - ASSERT(signaling_thread->IsCurrent()); -} - -BaseSession::~BaseSession() { - ASSERT(signaling_thread()->IsCurrent()); - - ASSERT(state_ != STATE_DEINIT); - LogState(state_, STATE_DEINIT); - state_ = STATE_DEINIT; - SignalState(this, state_); - - for (TransportMap::iterator iter = transports_.begin(); - iter != transports_.end(); ++iter) { - delete iter->second; - } -} - -const SessionDescription* BaseSession::local_description() const { - // TODO(tommi): Assert on thread correctness. - return local_description_.get(); -} - -const SessionDescription* BaseSession::remote_description() const { - // TODO(tommi): Assert on thread correctness. - return remote_description_.get(); -} - -SessionDescription* BaseSession::remote_description() { - // TODO(tommi): Assert on thread correctness. - return remote_description_.get(); -} - -void BaseSession::set_local_description(const SessionDescription* sdesc) { - // TODO(tommi): Assert on thread correctness. - if (sdesc != local_description_.get()) - local_description_.reset(sdesc); -} - -void BaseSession::set_remote_description(SessionDescription* sdesc) { - // TODO(tommi): Assert on thread correctness. - if (sdesc != remote_description_) - remote_description_.reset(sdesc); -} - -const SessionDescription* BaseSession::initiator_description() const { - // TODO(tommi): Assert on thread correctness. - return initiator_ ? local_description_.get() : remote_description_.get(); -} - -bool BaseSession::SetIdentity(rtc::SSLIdentity* identity) { - if (identity_) - return false; - identity_ = identity; - for (TransportMap::iterator iter = transports_.begin(); - iter != transports_.end(); ++iter) { - iter->second->SetIdentity(identity_); - } - return true; -} - -bool BaseSession::PushdownTransportDescription(ContentSource source, - ContentAction action, - std::string* error_desc) { - if (source == CS_LOCAL) { - return PushdownLocalTransportDescription(local_description(), - action, - error_desc); - } - return PushdownRemoteTransportDescription(remote_description(), - action, - error_desc); -} - -bool BaseSession::PushdownLocalTransportDescription( - const SessionDescription* sdesc, - ContentAction action, - std::string* error_desc) { - // Update the Transports with the right information, and trigger them to - // start connecting. - for (TransportMap::iterator iter = transports_.begin(); - iter != transports_.end(); ++iter) { - // If no transport info was in this session description, ret == false - // and we just skip this one. - TransportDescription tdesc; - bool ret = GetTransportDescription( - sdesc, iter->second->content_name(), &tdesc); - if (ret) { - if (!iter->second->SetLocalTransportDescription(tdesc, action, - error_desc)) { - return false; - } - - iter->second->ConnectChannels(); - } - } - - return true; -} - -bool BaseSession::PushdownRemoteTransportDescription( - const SessionDescription* sdesc, - ContentAction action, - std::string* error_desc) { - // Update the Transports with the right information. - for (TransportMap::iterator iter = transports_.begin(); - iter != transports_.end(); ++iter) { - TransportDescription tdesc; - - // If no transport info was in this session description, ret == false - // and we just skip this one. - bool ret = GetTransportDescription( - sdesc, iter->second->content_name(), &tdesc); - if (ret) { - if (!iter->second->SetRemoteTransportDescription(tdesc, action, - error_desc)) { - return false; - } - } - } - - return true; -} - -TransportChannel* BaseSession::CreateChannel(const std::string& content_name, - const std::string& channel_name, - int component) { - // We create the proxy "on demand" here because we need to support - // creating channels at any time, even before we send or receive - // initiate messages, which is before we create the transports. - TransportProxy* transproxy = GetOrCreateTransportProxy(content_name); - return transproxy->CreateChannel(channel_name, component); -} - -TransportChannel* BaseSession::GetChannel(const std::string& content_name, - int component) { - TransportProxy* transproxy = GetTransportProxy(content_name); - if (transproxy == NULL) - return NULL; - - return transproxy->GetChannel(component); -} - -void BaseSession::DestroyChannel(const std::string& content_name, - int component) { - TransportProxy* transproxy = GetTransportProxy(content_name); - ASSERT(transproxy != NULL); - transproxy->DestroyChannel(component); -} - -TransportProxy* BaseSession::GetOrCreateTransportProxy( - const std::string& content_name) { - TransportProxy* transproxy = GetTransportProxy(content_name); - if (transproxy) - return transproxy; - - Transport* transport = CreateTransport(content_name); - transport->SetIceRole(initiator_ ? ICEROLE_CONTROLLING : ICEROLE_CONTROLLED); - transport->SetIceTiebreaker(ice_tiebreaker_); - // TODO: Connect all the Transport signals to TransportProxy - // then to the BaseSession. - transport->SignalConnecting.connect( - this, &BaseSession::OnTransportConnecting); - transport->SignalWritableState.connect( - this, &BaseSession::OnTransportWritable); - transport->SignalRequestSignaling.connect( - this, &BaseSession::OnTransportRequestSignaling); - transport->SignalTransportError.connect( - this, &BaseSession::OnTransportSendError); - transport->SignalRouteChange.connect( - this, &BaseSession::OnTransportRouteChange); - transport->SignalCandidatesAllocationDone.connect( - this, &BaseSession::OnTransportCandidatesAllocationDone); - transport->SignalRoleConflict.connect( - this, &BaseSession::OnRoleConflict); - transport->SignalCompleted.connect( - this, &BaseSession::OnTransportCompleted); - transport->SignalFailed.connect( - this, &BaseSession::OnTransportFailed); - - transproxy = new TransportProxy(worker_thread_, sid_, content_name, - new TransportWrapper(transport)); - transproxy->SignalCandidatesReady.connect( - this, &BaseSession::OnTransportProxyCandidatesReady); - if (identity_) - transproxy->SetIdentity(identity_); - transports_[content_name] = transproxy; - - return transproxy; -} - -Transport* BaseSession::GetTransport(const std::string& content_name) { - TransportProxy* transproxy = GetTransportProxy(content_name); - if (transproxy == NULL) - return NULL; - return transproxy->impl(); -} - -TransportProxy* BaseSession::GetTransportProxy( - const std::string& content_name) { - TransportMap::iterator iter = transports_.find(content_name); - return (iter != transports_.end()) ? iter->second : NULL; -} - -TransportProxy* BaseSession::GetTransportProxy(const Transport* transport) { - for (TransportMap::iterator iter = transports_.begin(); - iter != transports_.end(); ++iter) { - TransportProxy* transproxy = iter->second; - if (transproxy->impl() == transport) { - return transproxy; - } - } - return NULL; -} - -TransportProxy* BaseSession::GetFirstTransportProxy() { - if (transports_.empty()) - return NULL; - return transports_.begin()->second; -} - -void BaseSession::DestroyTransportProxy( - const std::string& content_name) { - TransportMap::iterator iter = transports_.find(content_name); - if (iter != transports_.end()) { - delete iter->second; - transports_.erase(content_name); - } -} - -cricket::Transport* BaseSession::CreateTransport( - const std::string& content_name) { - ASSERT(transport_type_ == NS_GINGLE_P2P); - return new cricket::DtlsTransport<P2PTransport>( - signaling_thread(), worker_thread(), content_name, - port_allocator(), identity_); -} - -bool BaseSession::GetStats(SessionStats* stats) { - for (TransportMap::iterator iter = transports_.begin(); - iter != transports_.end(); ++iter) { - std::string proxy_id = iter->second->content_name(); - // We are ignoring not-yet-instantiated transports. - if (iter->second->impl()) { - std::string transport_id = iter->second->impl()->content_name(); - stats->proxy_to_transport[proxy_id] = transport_id; - if (stats->transport_stats.find(transport_id) - == stats->transport_stats.end()) { - TransportStats subinfos; - if (!iter->second->impl()->GetStats(&subinfos)) { - return false; - } - stats->transport_stats[transport_id] = subinfos; - } - } - } - return true; -} - -void BaseSession::SetState(State state) { - ASSERT(signaling_thread_->IsCurrent()); - if (state != state_) { - LogState(state_, state); - state_ = state; - SignalState(this, state_); - signaling_thread_->Post(this, MSG_STATE); - } - SignalNewDescription(); -} - -void BaseSession::SetError(Error error, const std::string& error_desc) { - ASSERT(signaling_thread_->IsCurrent()); - if (error != error_) { - error_ = error; - error_desc_ = error_desc; - SignalError(this, error); - } -} - -void BaseSession::OnSignalingReady() { - ASSERT(signaling_thread()->IsCurrent()); - for (TransportMap::iterator iter = transports_.begin(); - iter != transports_.end(); ++iter) { - iter->second->OnSignalingReady(); - } -} - -// TODO(juberti): Since PushdownLocalTD now triggers the connection process to -// start, remove this method once everyone calls PushdownLocalTD. -void BaseSession::SpeculativelyConnectAllTransportChannels() { - // Put all transports into the connecting state. - for (TransportMap::iterator iter = transports_.begin(); - iter != transports_.end(); ++iter) { - iter->second->ConnectChannels(); - } -} - -bool BaseSession::OnRemoteCandidates(const std::string& content_name, - const Candidates& candidates, - std::string* error) { - // Give candidates to the appropriate transport, and tell that transport - // to start connecting, if it's not already doing so. - TransportProxy* transproxy = GetTransportProxy(content_name); - if (!transproxy) { - *error = "Unknown content name " + content_name; - return false; - } - if (!transproxy->OnRemoteCandidates(candidates, error)) { - return false; - } - // TODO(juberti): Remove this call once we can be sure that we always have - // a local transport description (which will trigger the connection). - transproxy->ConnectChannels(); - return true; -} - -bool BaseSession::MaybeEnableMuxingSupport() { - // We need both a local and remote description to decide if we should mux. - if ((state_ == STATE_SENTINITIATE || - state_ == STATE_RECEIVEDINITIATE) && - ((local_description_ == NULL) || - (remote_description_ == NULL))) { - return false; - } - - // In order to perform the multiplexing, we need all proxies to be in the - // negotiated state, i.e. to have implementations underneath. - // Ensure that this is the case, regardless of whether we are going to mux. - for (TransportMap::iterator iter = transports_.begin(); - iter != transports_.end(); ++iter) { - ASSERT(iter->second->negotiated()); - if (!iter->second->negotiated()) - return false; - } - - // If both sides agree to BUNDLE, mux all the specified contents onto the - // transport belonging to the first content name in the BUNDLE group. - // If the contents are already muxed, this will be a no-op. - // TODO(juberti): Should this check that local and remote have configured - // BUNDLE the same way? - bool candidates_allocated = IsCandidateAllocationDone(); - const ContentGroup* local_bundle_group = - local_description()->GetGroupByName(GROUP_TYPE_BUNDLE); - const ContentGroup* remote_bundle_group = - remote_description()->GetGroupByName(GROUP_TYPE_BUNDLE); - if (local_bundle_group && remote_bundle_group && - local_bundle_group->FirstContentName()) { - const std::string* content_name = local_bundle_group->FirstContentName(); - const ContentInfo* content = - local_description_->GetContentByName(*content_name); - ASSERT(content != NULL); - if (!SetSelectedProxy(content->name, local_bundle_group)) { - LOG(LS_WARNING) << "Failed to set up BUNDLE"; - return false; - } - - // If we weren't done gathering before, we might be done now, as a result - // of enabling mux. - LOG(LS_INFO) << "Enabling BUNDLE, bundling onto transport: " - << *content_name; - if (!candidates_allocated) { - MaybeCandidateAllocationDone(); - } - } else { - LOG(LS_INFO) << "No BUNDLE information, not bundling."; - } - return true; -} - -bool BaseSession::SetSelectedProxy(const std::string& content_name, - const ContentGroup* muxed_group) { - TransportProxy* selected_proxy = GetTransportProxy(content_name); - if (!selected_proxy) { - return false; - } - - ASSERT(selected_proxy->negotiated()); - for (TransportMap::iterator iter = transports_.begin(); - iter != transports_.end(); ++iter) { - // If content is part of the mux group, then repoint its proxy at the - // transport object that we have chosen to mux onto. If the proxy - // is already pointing at the right object, it will be a no-op. - if (muxed_group->HasContentName(iter->first) && - !iter->second->SetupMux(selected_proxy)) { - return false; - } - } - return true; -} - -void BaseSession::OnTransportCandidatesAllocationDone(Transport* transport) { - // TODO(juberti): This is a clunky way of processing the done signal. Instead, - // TransportProxy should receive the done signal directly, set its allocated - // flag internally, and then reissue the done signal to Session. - // Overall we should make TransportProxy receive *all* the signals from - // Transport, since this removes the need to manually iterate over all - // the transports, as is needed to make sure signals are handled properly - // when BUNDLEing. - // TODO(juberti): Per b/7998978, devs and QA are hitting this assert in ways - // that make it prohibitively difficult to run dbg builds. Disabled for now. - //ASSERT(!IsCandidateAllocationDone()); - for (TransportMap::iterator iter = transports_.begin(); - iter != transports_.end(); ++iter) { - if (iter->second->impl() == transport) { - iter->second->set_candidates_allocated(true); - } - } - MaybeCandidateAllocationDone(); -} - -bool BaseSession::IsCandidateAllocationDone() const { - for (TransportMap::const_iterator iter = transports_.begin(); - iter != transports_.end(); ++iter) { - if (!iter->second->candidates_allocated()) - return false; - } - return true; -} - -void BaseSession::MaybeCandidateAllocationDone() { - if (IsCandidateAllocationDone()) { - LOG(LS_INFO) << "Candidate gathering is complete."; - OnCandidatesAllocationDone(); - } -} - -void BaseSession::OnRoleConflict() { - if (role_switch_) { - LOG(LS_WARNING) << "Repeat of role conflict signal from Transport."; - return; - } - - role_switch_ = true; - for (TransportMap::iterator iter = transports_.begin(); - iter != transports_.end(); ++iter) { - // Role will be reverse of initial role setting. - IceRole role = initiator_ ? ICEROLE_CONTROLLED : ICEROLE_CONTROLLING; - iter->second->SetIceRole(role); - } -} - -void BaseSession::LogState(State old_state, State new_state) { - LOG(LS_INFO) << "Session:" << id() - << " Old state:" << StateToString(old_state) - << " New state:" << StateToString(new_state) - << " Type:" << content_type() - << " Transport:" << transport_type(); -} - -// static -bool BaseSession::GetTransportDescription(const SessionDescription* description, - const std::string& content_name, - TransportDescription* tdesc) { - if (!description || !tdesc) { - return false; - } - const TransportInfo* transport_info = - description->GetTransportInfoByName(content_name); - if (!transport_info) { - return false; - } - *tdesc = transport_info->description; - return true; -} - -void BaseSession::SignalNewDescription() { - ContentAction action; - ContentSource source; - if (!GetContentAction(&action, &source)) { - return; - } - if (source == CS_LOCAL) { - SignalNewLocalDescription(this, action); - } else { - SignalNewRemoteDescription(this, action); - } -} - -bool BaseSession::GetContentAction(ContentAction* action, - ContentSource* source) { - switch (state_) { - // new local description - case STATE_SENTINITIATE: - *action = CA_OFFER; - *source = CS_LOCAL; - break; - case STATE_SENTPRACCEPT: - *action = CA_PRANSWER; - *source = CS_LOCAL; - break; - case STATE_SENTACCEPT: - *action = CA_ANSWER; - *source = CS_LOCAL; - break; - // new remote description - case STATE_RECEIVEDINITIATE: - *action = CA_OFFER; - *source = CS_REMOTE; - break; - case STATE_RECEIVEDPRACCEPT: - *action = CA_PRANSWER; - *source = CS_REMOTE; - break; - case STATE_RECEIVEDACCEPT: - *action = CA_ANSWER; - *source = CS_REMOTE; - break; - default: - return false; - } - return true; -} - -void BaseSession::OnMessage(rtc::Message *pmsg) { - switch (pmsg->message_id) { - case MSG_TIMEOUT: - // Session timeout has occured. - SetError(ERROR_TIME, "Session timeout has occured."); - break; - - case MSG_STATE: - switch (state_) { - case STATE_SENTACCEPT: - case STATE_RECEIVEDACCEPT: - SetState(STATE_INPROGRESS); - break; - - default: - // Explicitly ignoring some states here. - break; - } - break; - } -} - -Session::Session(SessionManager* session_manager, - const std::string& local_name, - const std::string& initiator_name, - const std::string& sid, - const std::string& content_type, - SessionClient* client) - : BaseSession(session_manager->signaling_thread(), - session_manager->worker_thread(), - session_manager->port_allocator(), - sid, content_type, initiator_name == local_name) { - ASSERT(client != NULL); - session_manager_ = session_manager; - local_name_ = local_name; - initiator_name_ = initiator_name; - transport_parser_ = new P2PTransportParser(); - client_ = client; - initiate_acked_ = false; - current_protocol_ = PROTOCOL_HYBRID; -} - -Session::~Session() { - delete transport_parser_; -} - -bool Session::Initiate(const std::string& to, - const SessionDescription* sdesc) { - ASSERT(signaling_thread()->IsCurrent()); - SessionError error; - - // Only from STATE_INIT - if (state() != STATE_INIT) - return false; - - // Setup for signaling. - set_remote_name(to); - set_local_description(sdesc); - if (!CreateTransportProxies(GetEmptyTransportInfos(sdesc->contents()), - &error)) { - LOG(LS_ERROR) << "Could not create transports: " << error.text; - return false; - } - - if (!SendInitiateMessage(sdesc, &error)) { - LOG(LS_ERROR) << "Could not send initiate message: " << error.text; - return false; - } - - // We need to connect transport proxy and impl here so that we can process - // the TransportDescriptions. - SpeculativelyConnectAllTransportChannels(); - - PushdownTransportDescription(CS_LOCAL, CA_OFFER, NULL); - SetState(Session::STATE_SENTINITIATE); - return true; -} - -bool Session::Accept(const SessionDescription* sdesc) { - ASSERT(signaling_thread()->IsCurrent()); - - // Only if just received initiate - if (state() != STATE_RECEIVEDINITIATE) - return false; - - // Setup for signaling. - set_local_description(sdesc); - - SessionError error; - if (!SendAcceptMessage(sdesc, &error)) { - LOG(LS_ERROR) << "Could not send accept message: " << error.text; - return false; - } - // TODO(juberti): Add BUNDLE support to transport-info messages. - PushdownTransportDescription(CS_LOCAL, CA_ANSWER, NULL); - MaybeEnableMuxingSupport(); // Enable transport channel mux if supported. - SetState(Session::STATE_SENTACCEPT); - return true; -} - -bool Session::Reject(const std::string& reason) { - ASSERT(signaling_thread()->IsCurrent()); - - // Reject is sent in response to an initiate or modify, to reject the - // request - if (state() != STATE_RECEIVEDINITIATE && state() != STATE_RECEIVEDMODIFY) - return false; - - SessionError error; - if (!SendRejectMessage(reason, &error)) { - LOG(LS_ERROR) << "Could not send reject message: " << error.text; - return false; - } - - SetState(STATE_SENTREJECT); - return true; -} - -bool Session::TerminateWithReason(const std::string& reason) { - ASSERT(signaling_thread()->IsCurrent()); - - // Either side can terminate, at any time. - switch (state()) { - case STATE_SENTTERMINATE: - case STATE_RECEIVEDTERMINATE: - return false; - - case STATE_SENTREJECT: - case STATE_RECEIVEDREJECT: - // We don't need to send terminate if we sent or received a reject... - // it's implicit. - break; - - default: - SessionError error; - if (!SendTerminateMessage(reason, &error)) { - LOG(LS_ERROR) << "Could not send terminate message: " << error.text; - return false; - } - break; - } - - SetState(STATE_SENTTERMINATE); - return true; -} - -bool Session::SendInfoMessage(const XmlElements& elems, - const std::string& remote_name) { - ASSERT(signaling_thread()->IsCurrent()); - SessionError error; - if (!SendMessage(ACTION_SESSION_INFO, elems, remote_name, &error)) { - LOG(LS_ERROR) << "Could not send info message " << error.text; - return false; - } - return true; -} - -bool Session::SendDescriptionInfoMessage(const ContentInfos& contents) { - XmlElements elems; - WriteError write_error; - if (!WriteDescriptionInfo(current_protocol_, - contents, - GetContentParsers(), - &elems, &write_error)) { - LOG(LS_ERROR) << "Could not write description info message: " - << write_error.text; - return false; - } - SessionError error; - if (!SendMessage(ACTION_DESCRIPTION_INFO, elems, &error)) { - LOG(LS_ERROR) << "Could not send description info message: " - << error.text; - return false; - } - return true; -} - -TransportInfos Session::GetEmptyTransportInfos( - const ContentInfos& contents) const { - TransportInfos tinfos; - for (ContentInfos::const_iterator content = contents.begin(); - content != contents.end(); ++content) { - tinfos.push_back(TransportInfo(content->name, - TransportDescription(transport_type(), - std::string(), - std::string()))); - } - return tinfos; -} - -bool Session::OnRemoteCandidates( - const TransportInfos& tinfos, ParseError* error) { - for (TransportInfos::const_iterator tinfo = tinfos.begin(); - tinfo != tinfos.end(); ++tinfo) { - std::string str_error; - if (!BaseSession::OnRemoteCandidates( - tinfo->content_name, tinfo->description.candidates, &str_error)) { - return BadParse(str_error, error); - } - } - return true; -} - -bool Session::CreateTransportProxies(const TransportInfos& tinfos, - SessionError* error) { - for (TransportInfos::const_iterator tinfo = tinfos.begin(); - tinfo != tinfos.end(); ++tinfo) { - if (tinfo->description.transport_type != transport_type()) { - error->SetText("No supported transport in offer."); - return false; - } - - GetOrCreateTransportProxy(tinfo->content_name); - } - return true; -} - -TransportParserMap Session::GetTransportParsers() { - TransportParserMap parsers; - parsers[transport_type()] = transport_parser_; - return parsers; -} - -CandidateTranslatorMap Session::GetCandidateTranslators() { - CandidateTranslatorMap translators; - // NOTE: This technique makes it impossible to parse G-ICE - // candidates in session-initiate messages because the channels - // aren't yet created at that point. Since we don't use candidates - // in session-initiate messages, we should be OK. Once we switch to - // ICE, this translation shouldn't be necessary. - for (TransportMap::const_iterator iter = transport_proxies().begin(); - iter != transport_proxies().end(); ++iter) { - translators[iter->first] = iter->second; - } - return translators; -} - -ContentParserMap Session::GetContentParsers() { - ContentParserMap parsers; - parsers[content_type()] = client_; - // We need to be able parse both RTP-based and SCTP-based Jingle - // with the same client. - if (content_type() == NS_JINGLE_RTP) { - parsers[NS_JINGLE_DRAFT_SCTP] = client_; - } - return parsers; -} - -void Session::OnTransportRequestSignaling(Transport* transport) { - ASSERT(signaling_thread()->IsCurrent()); - TransportProxy* transproxy = GetTransportProxy(transport); - ASSERT(transproxy != NULL); - if (transproxy) { - // Reset candidate allocation status for the transport proxy. - transproxy->set_candidates_allocated(false); - } - SignalRequestSignaling(this); -} - -void Session::OnTransportConnecting(Transport* transport) { - // This is an indication that we should begin watching the writability - // state of the transport. - OnTransportWritable(transport); -} - -void Session::OnTransportWritable(Transport* transport) { - ASSERT(signaling_thread()->IsCurrent()); - - // If the transport is not writable, start a timer to make sure that it - // becomes writable within a reasonable amount of time. If it does not, we - // terminate since we can't actually send data. If the transport is writable, - // cancel the timer. Note that writability transitions may occur repeatedly - // during the lifetime of the session. - signaling_thread()->Clear(this, MSG_TIMEOUT); - if (transport->HasChannels() && !transport->writable()) { - signaling_thread()->PostDelayed( - session_manager_->session_timeout() * 1000, this, MSG_TIMEOUT); - } -} - -void Session::OnTransportProxyCandidatesReady(TransportProxy* transproxy, - const Candidates& candidates) { - ASSERT(signaling_thread()->IsCurrent()); - if (transproxy != NULL) { - if (initiator() && !initiate_acked_) { - // TODO: This is to work around server re-ordering - // messages. We send the candidates once the session-initiate - // is acked. Once we have fixed the server to guarantee message - // order, we can remove this case. - transproxy->AddUnsentCandidates(candidates); - } else { - if (!transproxy->negotiated()) { - transproxy->AddSentCandidates(candidates); - } - SessionError error; - if (!SendTransportInfoMessage(transproxy, candidates, &error)) { - LOG(LS_ERROR) << "Could not send transport info message: " - << error.text; - return; - } - } - } -} - -void Session::OnTransportSendError(Transport* transport, - const buzz::XmlElement* stanza, - const buzz::QName& name, - const std::string& type, - const std::string& text, - const buzz::XmlElement* extra_info) { - ASSERT(signaling_thread()->IsCurrent()); - SignalErrorMessage(this, stanza, name, type, text, extra_info); -} - -void Session::OnIncomingMessage(const SessionMessage& msg) { - ASSERT(signaling_thread()->IsCurrent()); - ASSERT(state() == STATE_INIT || msg.from == remote_name()); - - if (current_protocol_== PROTOCOL_HYBRID) { - if (msg.protocol == PROTOCOL_GINGLE) { - current_protocol_ = PROTOCOL_GINGLE; - } else { - current_protocol_ = PROTOCOL_JINGLE; - } - } - - bool valid = false; - MessageError error; - switch (msg.type) { - case ACTION_SESSION_INITIATE: - valid = OnInitiateMessage(msg, &error); - break; - case ACTION_SESSION_INFO: - valid = OnInfoMessage(msg); - break; - case ACTION_SESSION_ACCEPT: - valid = OnAcceptMessage(msg, &error); - break; - case ACTION_SESSION_REJECT: - valid = OnRejectMessage(msg, &error); - break; - case ACTION_SESSION_TERMINATE: - valid = OnTerminateMessage(msg, &error); - break; - case ACTION_TRANSPORT_INFO: - valid = OnTransportInfoMessage(msg, &error); - break; - case ACTION_TRANSPORT_ACCEPT: - valid = OnTransportAcceptMessage(msg, &error); - break; - case ACTION_DESCRIPTION_INFO: - valid = OnDescriptionInfoMessage(msg, &error); - break; - default: - valid = BadMessage(buzz::QN_STANZA_BAD_REQUEST, - "unknown session message type", - &error); - } - - if (valid) { - SendAcknowledgementMessage(msg.stanza); - } else { - SignalErrorMessage(this, msg.stanza, error.type, - "modify", error.text, NULL); - } -} - -void Session::OnIncomingResponse(const buzz::XmlElement* orig_stanza, - const buzz::XmlElement* response_stanza, - const SessionMessage& msg) { - ASSERT(signaling_thread()->IsCurrent()); - - if (msg.type == ACTION_SESSION_INITIATE) { - OnInitiateAcked(); - } -} - -void Session::OnInitiateAcked() { - // TODO: This is to work around server re-ordering - // messages. We send the candidates once the session-initiate - // is acked. Once we have fixed the server to guarantee message - // order, we can remove this case. - if (!initiate_acked_) { - initiate_acked_ = true; - SessionError error; - SendAllUnsentTransportInfoMessages(&error); - } -} - -void Session::OnFailedSend(const buzz::XmlElement* orig_stanza, - const buzz::XmlElement* error_stanza) { - ASSERT(signaling_thread()->IsCurrent()); - - SessionMessage msg; - ParseError parse_error; - if (!ParseSessionMessage(orig_stanza, &msg, &parse_error)) { - LOG(LS_ERROR) << "Error parsing failed send: " << parse_error.text - << ":" << orig_stanza; - return; - } - - // If the error is a session redirect, call OnRedirectError, which will - // continue the session with a new remote JID. - SessionRedirect redirect; - if (FindSessionRedirect(error_stanza, &redirect)) { - SessionError error; - if (!OnRedirectError(redirect, &error)) { - // TODO: Should we send a message back? The standard - // says nothing about it. - std::ostringstream desc; - desc << "Failed to redirect: " << error.text; - LOG(LS_ERROR) << desc.str(); - SetError(ERROR_RESPONSE, desc.str()); - } - return; - } - - std::string error_type = "cancel"; - - const buzz::XmlElement* error = error_stanza->FirstNamed(buzz::QN_ERROR); - if (error) { - error_type = error->Attr(buzz::QN_TYPE); - - LOG(LS_ERROR) << "Session error:\n" << error->Str() << "\n" - << "in response to:\n" << orig_stanza->Str(); - } else { - // don't crash if <error> is missing - LOG(LS_ERROR) << "Session error without <error/> element, ignoring"; - return; - } - - if (msg.type == ACTION_TRANSPORT_INFO) { - // Transport messages frequently generate errors because they are sent right - // when we detect a network failure. For that reason, we ignore such - // errors, because if we do not establish writability again, we will - // terminate anyway. The exceptions are transport-specific error tags, - // which we pass on to the respective transport. - } else if ((error_type != "continue") && (error_type != "wait")) { - // We do not set an error if the other side said it is okay to continue - // (possibly after waiting). These errors can be ignored. - SetError(ERROR_RESPONSE, ""); - } -} - -bool Session::OnInitiateMessage(const SessionMessage& msg, - MessageError* error) { - if (!CheckState(STATE_INIT, error)) - return false; - - SessionInitiate init; - if (!ParseSessionInitiate(msg.protocol, msg.action_elem, - GetContentParsers(), GetTransportParsers(), - GetCandidateTranslators(), - &init, error)) - return false; - - SessionError session_error; - if (!CreateTransportProxies(init.transports, &session_error)) { - return BadMessage(buzz::QN_STANZA_NOT_ACCEPTABLE, - session_error.text, error); - } - - set_remote_name(msg.from); - set_initiator_name(msg.initiator); - set_remote_description(new SessionDescription(init.ClearContents(), - init.transports, - init.groups)); - // Updating transport with TransportDescription. - PushdownTransportDescription(CS_REMOTE, CA_OFFER, NULL); - SetState(STATE_RECEIVEDINITIATE); - - // Users of Session may listen to state change and call Reject(). - if (state() != STATE_SENTREJECT) { - if (!OnRemoteCandidates(init.transports, error)) - return false; - - // TODO(juberti): Auto-generate and push down the local transport answer. - // This is necessary for trickling to work with RFC 5245 ICE. - } - return true; -} - -bool Session::OnAcceptMessage(const SessionMessage& msg, MessageError* error) { - if (!CheckState(STATE_SENTINITIATE, error)) - return false; - - SessionAccept accept; - if (!ParseSessionAccept(msg.protocol, msg.action_elem, - GetContentParsers(), GetTransportParsers(), - GetCandidateTranslators(), - &accept, error)) { - return false; - } - - // If we get an accept, we can assume the initiate has been - // received, even if we haven't gotten an IQ response. - OnInitiateAcked(); - - set_remote_description(new SessionDescription(accept.ClearContents(), - accept.transports, - accept.groups)); - // Updating transport with TransportDescription. - PushdownTransportDescription(CS_REMOTE, CA_ANSWER, NULL); - MaybeEnableMuxingSupport(); // Enable transport channel mux if supported. - SetState(STATE_RECEIVEDACCEPT); - - if (!OnRemoteCandidates(accept.transports, error)) - return false; - - return true; -} - -bool Session::OnRejectMessage(const SessionMessage& msg, MessageError* error) { - if (!CheckState(STATE_SENTINITIATE, error)) - return false; - - SetState(STATE_RECEIVEDREJECT); - return true; -} - -bool Session::OnInfoMessage(const SessionMessage& msg) { - SignalInfoMessage(this, msg.action_elem); - return true; -} - -bool Session::OnTerminateMessage(const SessionMessage& msg, - MessageError* error) { - SessionTerminate term; - if (!ParseSessionTerminate(msg.protocol, msg.action_elem, &term, error)) - return false; - - SignalReceivedTerminateReason(this, term.reason); - if (term.debug_reason != buzz::STR_EMPTY) { - LOG(LS_VERBOSE) << "Received error on call: " << term.debug_reason; - } - - SetState(STATE_RECEIVEDTERMINATE); - return true; -} - -bool Session::OnTransportInfoMessage(const SessionMessage& msg, - MessageError* error) { - TransportInfos tinfos; - if (!ParseTransportInfos(msg.protocol, msg.action_elem, - initiator_description()->contents(), - GetTransportParsers(), GetCandidateTranslators(), - &tinfos, error)) - return false; - - if (!OnRemoteCandidates(tinfos, error)) - return false; - - return true; -} - -bool Session::OnTransportAcceptMessage(const SessionMessage& msg, - MessageError* error) { - // TODO: Currently here only for compatibility with - // Gingle 1.1 clients (notably, Google Voice). - return true; -} - -bool Session::OnDescriptionInfoMessage(const SessionMessage& msg, - MessageError* error) { - if (!CheckState(STATE_INPROGRESS, error)) - return false; - - DescriptionInfo description_info; - if (!ParseDescriptionInfo(msg.protocol, msg.action_elem, - GetContentParsers(), GetTransportParsers(), - GetCandidateTranslators(), - &description_info, error)) { - return false; - } - - ContentInfos& updated_contents = description_info.contents; - - // TODO: Currently, reflector sends back - // video stream updates even for an audio-only call, which causes - // this to fail. Put this back once reflector is fixed. - // - // ContentInfos::iterator it; - // First, ensure all updates are valid before modifying remote_description_. - // for (it = updated_contents.begin(); it != updated_contents.end(); ++it) { - // if (remote_description()->GetContentByName(it->name) == NULL) { - // return false; - // } - // } - - // TODO: We used to replace contents from an update, but - // that no longer works with partial updates. We need to figure out - // a way to merge patial updates into contents. For now, users of - // Session should listen to SignalRemoteDescriptionUpdate and handle - // updates. They should not expect remote_description to be the - // latest value. - // - // for (it = updated_contents.begin(); it != updated_contents.end(); ++it) { - // remote_description()->RemoveContentByName(it->name); - // remote_description()->AddContent(it->name, it->type, it->description); - // } - // } - - SignalRemoteDescriptionUpdate(this, updated_contents); - return true; -} - -bool BareJidsEqual(const std::string& name1, - const std::string& name2) { - buzz::Jid jid1(name1); - buzz::Jid jid2(name2); - - return jid1.IsValid() && jid2.IsValid() && jid1.BareEquals(jid2); -} - -bool Session::OnRedirectError(const SessionRedirect& redirect, - SessionError* error) { - MessageError message_error; - if (!CheckState(STATE_SENTINITIATE, &message_error)) { - return BadWrite(message_error.text, error); - } - - if (!BareJidsEqual(remote_name(), redirect.target)) - return BadWrite("Redirection not allowed: must be the same bare jid.", - error); - - // When we receive a redirect, we point the session at the new JID - // and resend the candidates. - set_remote_name(redirect.target); - return (SendInitiateMessage(local_description(), error) && - ResendAllTransportInfoMessages(error)); -} - -bool Session::CheckState(State expected, MessageError* error) { - if (state() != expected) { - // The server can deliver messages out of order/repeated for various - // reasons. For example, if the server does not recive our iq response, - // it could assume that the iq it sent was lost, and will then send - // it again. Ideally, we should implement reliable messaging with - // duplicate elimination. - return BadMessage(buzz::QN_STANZA_NOT_ALLOWED, - "message not allowed in current state", - error); - } - return true; -} - -void Session::SetError(Error error, const std::string& error_desc) { - BaseSession::SetError(error, error_desc); - if (error != ERROR_NONE) - signaling_thread()->Post(this, MSG_ERROR); -} - -void Session::OnMessage(rtc::Message* pmsg) { - // preserve this because BaseSession::OnMessage may modify it - State orig_state = state(); - - BaseSession::OnMessage(pmsg); - - switch (pmsg->message_id) { - case MSG_ERROR: - TerminateWithReason(STR_TERMINATE_ERROR); - break; - - case MSG_STATE: - switch (orig_state) { - case STATE_SENTREJECT: - case STATE_RECEIVEDREJECT: - // Assume clean termination. - Terminate(); - break; - - case STATE_SENTTERMINATE: - case STATE_RECEIVEDTERMINATE: - session_manager_->DestroySession(this); - break; - - default: - // Explicitly ignoring some states here. - break; - } - break; - } -} - -bool Session::SendInitiateMessage(const SessionDescription* sdesc, - SessionError* error) { - SessionInitiate init; - init.contents = sdesc->contents(); - init.transports = GetEmptyTransportInfos(init.contents); - init.groups = sdesc->groups(); - return SendMessage(ACTION_SESSION_INITIATE, init, error); -} - -bool Session::WriteSessionAction( - SignalingProtocol protocol, const SessionInitiate& init, - XmlElements* elems, WriteError* error) { - return WriteSessionInitiate(protocol, init.contents, init.transports, - GetContentParsers(), GetTransportParsers(), - GetCandidateTranslators(), init.groups, - elems, error); -} - -bool Session::SendAcceptMessage(const SessionDescription* sdesc, - SessionError* error) { - XmlElements elems; - if (!WriteSessionAccept(current_protocol_, - sdesc->contents(), - GetEmptyTransportInfos(sdesc->contents()), - GetContentParsers(), GetTransportParsers(), - GetCandidateTranslators(), sdesc->groups(), - &elems, error)) { - return false; - } - return SendMessage(ACTION_SESSION_ACCEPT, elems, error); -} - -bool Session::SendRejectMessage(const std::string& reason, - SessionError* error) { - SessionTerminate term(reason); - return SendMessage(ACTION_SESSION_REJECT, term, error); -} - -bool Session::SendTerminateMessage(const std::string& reason, - SessionError* error) { - SessionTerminate term(reason); - return SendMessage(ACTION_SESSION_TERMINATE, term, error); -} - -bool Session::WriteSessionAction(SignalingProtocol protocol, - const SessionTerminate& term, - XmlElements* elems, WriteError* error) { - WriteSessionTerminate(protocol, term, elems); - return true; -} - -bool Session::SendTransportInfoMessage(const TransportInfo& tinfo, - SessionError* error) { - return SendMessage(ACTION_TRANSPORT_INFO, tinfo, error); -} - -bool Session::SendTransportInfoMessage(const TransportProxy* transproxy, - const Candidates& candidates, - SessionError* error) { - return SendTransportInfoMessage(TransportInfo(transproxy->content_name(), - TransportDescription(transproxy->type(), std::vector<std::string>(), - std::string(), std::string(), ICEMODE_FULL, - CONNECTIONROLE_NONE, NULL, candidates)), error); -} - -bool Session::WriteSessionAction(SignalingProtocol protocol, - const TransportInfo& tinfo, - XmlElements* elems, WriteError* error) { - TransportInfos tinfos; - tinfos.push_back(tinfo); - return WriteTransportInfos(protocol, tinfos, - GetTransportParsers(), GetCandidateTranslators(), - elems, error); -} - -bool Session::ResendAllTransportInfoMessages(SessionError* error) { - for (TransportMap::const_iterator iter = transport_proxies().begin(); - iter != transport_proxies().end(); ++iter) { - TransportProxy* transproxy = iter->second; - if (transproxy->sent_candidates().size() > 0) { - if (!SendTransportInfoMessage( - transproxy, transproxy->sent_candidates(), error)) { - LOG(LS_ERROR) << "Could not resend transport info messages: " - << error->text; - return false; - } - transproxy->ClearSentCandidates(); - } - } - return true; -} - -bool Session::SendAllUnsentTransportInfoMessages(SessionError* error) { - for (TransportMap::const_iterator iter = transport_proxies().begin(); - iter != transport_proxies().end(); ++iter) { - TransportProxy* transproxy = iter->second; - if (transproxy->unsent_candidates().size() > 0) { - if (!SendTransportInfoMessage( - transproxy, transproxy->unsent_candidates(), error)) { - LOG(LS_ERROR) << "Could not send unsent transport info messages: " - << error->text; - return false; - } - transproxy->ClearUnsentCandidates(); - } - } - return true; -} - -bool Session::SendMessage(ActionType type, const XmlElements& action_elems, - SessionError* error) { - return SendMessage(type, action_elems, remote_name(), error); -} - -bool Session::SendMessage(ActionType type, const XmlElements& action_elems, - const std::string& remote_name, SessionError* error) { - rtc::scoped_ptr<buzz::XmlElement> stanza( - new buzz::XmlElement(buzz::QN_IQ)); - - SessionMessage msg(current_protocol_, type, id(), initiator_name()); - msg.to = remote_name; - WriteSessionMessage(msg, action_elems, stanza.get()); - - SignalOutgoingMessage(this, stanza.get()); - return true; -} - -template <typename Action> -bool Session::SendMessage(ActionType type, const Action& action, - SessionError* error) { - rtc::scoped_ptr<buzz::XmlElement> stanza( - new buzz::XmlElement(buzz::QN_IQ)); - if (!WriteActionMessage(type, action, stanza.get(), error)) - return false; - - SignalOutgoingMessage(this, stanza.get()); - return true; -} - -template <typename Action> -bool Session::WriteActionMessage(ActionType type, const Action& action, - buzz::XmlElement* stanza, - WriteError* error) { - if (current_protocol_ == PROTOCOL_HYBRID) { - if (!WriteActionMessage(PROTOCOL_JINGLE, type, action, stanza, error)) - return false; - if (!WriteActionMessage(PROTOCOL_GINGLE, type, action, stanza, error)) - return false; - } else { - if (!WriteActionMessage(current_protocol_, type, action, stanza, error)) - return false; - } - return true; -} - -template <typename Action> -bool Session::WriteActionMessage(SignalingProtocol protocol, - ActionType type, const Action& action, - buzz::XmlElement* stanza, WriteError* error) { - XmlElements action_elems; - if (!WriteSessionAction(protocol, action, &action_elems, error)) - return false; - - SessionMessage msg(protocol, type, id(), initiator_name()); - msg.to = remote_name(); - - WriteSessionMessage(msg, action_elems, stanza); - return true; -} - -void Session::SendAcknowledgementMessage(const buzz::XmlElement* stanza) { - rtc::scoped_ptr<buzz::XmlElement> ack( - new buzz::XmlElement(buzz::QN_IQ)); - ack->SetAttr(buzz::QN_TO, remote_name()); - ack->SetAttr(buzz::QN_ID, stanza->Attr(buzz::QN_ID)); - ack->SetAttr(buzz::QN_TYPE, "result"); - - SignalOutgoingMessage(this, ack.get()); -} - -} // namespace cricket diff --git a/talk/p2p/base/session.h b/talk/p2p/base/session.h deleted file mode 100644 index cbe350f01..000000000 --- a/talk/p2p/base/session.h +++ /dev/null @@ -1,747 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef WEBRTC_P2P_BASE_SESSION_H_ -#define WEBRTC_P2P_BASE_SESSION_H_ - -#include <list> -#include <map> -#include <string> -#include <vector> - -#include "webrtc/p2p/base/parsing.h" -#include "webrtc/p2p/base/port.h" -#include "webrtc/p2p/base/sessionclient.h" -#include "webrtc/p2p/base/sessionmanager.h" -#include "webrtc/p2p/base/sessionmessages.h" -#include "webrtc/p2p/base/transport.h" -#include "webrtc/libjingle/xmllite/xmlelement.h" -#include "webrtc/libjingle/xmpp/constants.h" -#include "webrtc/base/refcount.h" -#include "webrtc/base/scoped_ptr.h" -#include "webrtc/base/scoped_ref_ptr.h" -#include "webrtc/base/socketaddress.h" - -namespace cricket { - -class BaseSession; -class P2PTransportChannel; -class Transport; -class TransportChannel; -class TransportChannelProxy; -class TransportChannelImpl; - -typedef rtc::RefCountedObject<rtc::scoped_ptr<Transport> > -TransportWrapper; - -// Used for errors that will send back a specific error message to the -// remote peer. We add "type" to the errors because it's needed for -// SignalErrorMessage. -struct MessageError : ParseError { - buzz::QName type; - - // if unset, assume type is a parse error - MessageError() : ParseError(), type(buzz::QN_STANZA_BAD_REQUEST) {} - - void SetType(const buzz::QName type) { - this->type = type; - } -}; - -// Used for errors that may be returned by public session methods that -// can fail. -// TODO: Use this error in Session::Initiate and -// Session::Accept. -struct SessionError : WriteError { -}; - -// Bundles a Transport and ChannelMap together. ChannelMap is used to -// create transport channels before receiving or sending a session -// initiate, and for speculatively connecting channels. Previously, a -// session had one ChannelMap and transport. Now, with multiple -// transports per session, we need multiple ChannelMaps as well. - -typedef std::map<int, TransportChannelProxy*> ChannelMap; - -class TransportProxy : public sigslot::has_slots<>, - public CandidateTranslator { - public: - TransportProxy( - rtc::Thread* worker_thread, - const std::string& sid, - const std::string& content_name, - TransportWrapper* transport) - : worker_thread_(worker_thread), - sid_(sid), - content_name_(content_name), - transport_(transport), - connecting_(false), - negotiated_(false), - sent_candidates_(false), - candidates_allocated_(false), - local_description_set_(false), - remote_description_set_(false) { - transport_->get()->SignalCandidatesReady.connect( - this, &TransportProxy::OnTransportCandidatesReady); - } - ~TransportProxy(); - - const std::string& content_name() const { return content_name_; } - // TODO(juberti): It's not good form to expose the object you're wrapping, - // since callers can mutate it. Can we make this return a const Transport*? - Transport* impl() const { return transport_->get(); } - - const std::string& type() const; - bool negotiated() const { return negotiated_; } - const Candidates& sent_candidates() const { return sent_candidates_; } - const Candidates& unsent_candidates() const { return unsent_candidates_; } - bool candidates_allocated() const { return candidates_allocated_; } - void set_candidates_allocated(bool allocated) { - candidates_allocated_ = allocated; - } - - TransportChannel* GetChannel(int component); - TransportChannel* CreateChannel(const std::string& channel_name, - int component); - bool HasChannel(int component); - void DestroyChannel(int component); - - void AddSentCandidates(const Candidates& candidates); - void AddUnsentCandidates(const Candidates& candidates); - void ClearSentCandidates() { sent_candidates_.clear(); } - void ClearUnsentCandidates() { unsent_candidates_.clear(); } - - // Start the connection process for any channels, creating impls if needed. - void ConnectChannels(); - // Hook up impls to the proxy channels. Doesn't change connect state. - void CompleteNegotiation(); - - // Mux this proxy onto the specified proxy's transport. - bool SetupMux(TransportProxy* proxy); - - // Simple functions that thunk down to the same functions on Transport. - void SetIceRole(IceRole role); - void SetIdentity(rtc::SSLIdentity* identity); - bool SetLocalTransportDescription(const TransportDescription& description, - ContentAction action, - std::string* error_desc); - bool SetRemoteTransportDescription(const TransportDescription& description, - ContentAction action, - std::string* error_desc); - void OnSignalingReady(); - bool OnRemoteCandidates(const Candidates& candidates, std::string* error); - - // CandidateTranslator methods. - virtual bool GetChannelNameFromComponent( - int component, std::string* channel_name) const; - virtual bool GetComponentFromChannelName( - const std::string& channel_name, int* component) const; - - // Called when a transport signals that it has new candidates. - void OnTransportCandidatesReady(cricket::Transport* transport, - const Candidates& candidates) { - SignalCandidatesReady(this, candidates); - } - - bool local_description_set() const { - return local_description_set_; - } - bool remote_description_set() const { - return remote_description_set_; - } - - // Handles sending of ready candidates and receiving of remote candidates. - sigslot::signal2<TransportProxy*, - const std::vector<Candidate>&> SignalCandidatesReady; - - private: - TransportChannelProxy* GetChannelProxy(int component) const; - TransportChannelProxy* GetChannelProxyByName(const std::string& name) const; - - TransportChannelImpl* GetOrCreateChannelProxyImpl(int component); - TransportChannelImpl* GetOrCreateChannelProxyImpl_w(int component); - - // Manipulators of transportchannelimpl in channel proxy. - void SetupChannelProxy(int component, - TransportChannelProxy* proxy); - void SetupChannelProxy_w(int component, - TransportChannelProxy* proxy); - void ReplaceChannelProxyImpl(TransportChannelProxy* proxy, - TransportChannelImpl* impl); - void ReplaceChannelProxyImpl_w(TransportChannelProxy* proxy, - TransportChannelImpl* impl); - - rtc::Thread* const worker_thread_; - const std::string sid_; - const std::string content_name_; - rtc::scoped_refptr<TransportWrapper> transport_; - bool connecting_; - bool negotiated_; - ChannelMap channels_; - Candidates sent_candidates_; - Candidates unsent_candidates_; - bool candidates_allocated_; - bool local_description_set_; - bool remote_description_set_; -}; - -typedef std::map<std::string, TransportProxy*> TransportMap; - -// Statistics for all the transports of this session. -typedef std::map<std::string, TransportStats> TransportStatsMap; -typedef std::map<std::string, std::string> ProxyTransportMap; - -struct SessionStats { - ProxyTransportMap proxy_to_transport; - TransportStatsMap transport_stats; -}; - -// A BaseSession manages general session state. This includes negotiation -// of both the application-level and network-level protocols: the former -// defines what will be sent and the latter defines how it will be sent. Each -// network-level protocol is represented by a Transport object. Each Transport -// participates in the network-level negotiation. The individual streams of -// packets are represented by TransportChannels. The application-level protocol -// is represented by SessionDecription objects. -class BaseSession : public sigslot::has_slots<>, - public rtc::MessageHandler { - public: - enum { - MSG_TIMEOUT = 0, - MSG_ERROR, - MSG_STATE, - }; - - enum State { - STATE_INIT = 0, - STATE_SENTINITIATE, // sent initiate, waiting for Accept or Reject - STATE_RECEIVEDINITIATE, // received an initiate. Call Accept or Reject - STATE_SENTPRACCEPT, // sent provisional Accept - STATE_SENTACCEPT, // sent accept. begin connecting transport - STATE_RECEIVEDPRACCEPT, // received provisional Accept, waiting for Accept - STATE_RECEIVEDACCEPT, // received accept. begin connecting transport - STATE_SENTMODIFY, // sent modify, waiting for Accept or Reject - STATE_RECEIVEDMODIFY, // received modify, call Accept or Reject - STATE_SENTREJECT, // sent reject after receiving initiate - STATE_RECEIVEDREJECT, // received reject after sending initiate - STATE_SENTREDIRECT, // sent direct after receiving initiate - STATE_SENTTERMINATE, // sent terminate (any time / either side) - STATE_RECEIVEDTERMINATE, // received terminate (any time / either side) - STATE_INPROGRESS, // session accepted and in progress - STATE_DEINIT, // session is being destroyed - }; - - enum Error { - ERROR_NONE = 0, // no error - ERROR_TIME = 1, // no response to signaling - ERROR_RESPONSE = 2, // error during signaling - ERROR_NETWORK = 3, // network error, could not allocate network resources - ERROR_CONTENT = 4, // channel errors in SetLocalContent/SetRemoteContent - ERROR_TRANSPORT = 5, // transport error of some kind - }; - - // Convert State to a readable string. - static std::string StateToString(State state); - - BaseSession(rtc::Thread* signaling_thread, - rtc::Thread* worker_thread, - PortAllocator* port_allocator, - const std::string& sid, - const std::string& content_type, - bool initiator); - virtual ~BaseSession(); - - // These are const to allow them to be called from const methods. - rtc::Thread* signaling_thread() const { return signaling_thread_; } - rtc::Thread* worker_thread() const { return worker_thread_; } - PortAllocator* port_allocator() const { return port_allocator_; } - - // The ID of this session. - const std::string& id() const { return sid_; } - - // TODO(juberti): This data is largely redundant, as it can now be obtained - // from local/remote_description(). Remove these functions and members. - // Returns the XML namespace identifying the type of this session. - const std::string& content_type() const { return content_type_; } - // Returns the XML namespace identifying the transport used for this session. - const std::string& transport_type() const { return transport_type_; } - - // Indicates whether we initiated this session. - bool initiator() const { return initiator_; } - - // Returns the application-level description given by our client. - // If we are the recipient, this will be NULL until we send an accept. - const SessionDescription* local_description() const; - - // Returns the application-level description given by the other client. - // If we are the initiator, this will be NULL until we receive an accept. - const SessionDescription* remote_description() const; - - SessionDescription* remote_description(); - - // Takes ownership of SessionDescription* - void set_local_description(const SessionDescription* sdesc); - - // Takes ownership of SessionDescription* - void set_remote_description(SessionDescription* sdesc); - - const SessionDescription* initiator_description() const; - - // Returns the current state of the session. See the enum above for details. - // Each time the state changes, we will fire this signal. - State state() const { return state_; } - sigslot::signal2<BaseSession* , State> SignalState; - - // Returns the last error in the session. See the enum above for details. - // Each time the an error occurs, we will fire this signal. - Error error() const { return error_; } - const std::string& error_desc() const { return error_desc_; } - sigslot::signal2<BaseSession* , Error> SignalError; - - // Updates the state, signaling if necessary. - virtual void SetState(State state); - - // Updates the error state, signaling if necessary. - // TODO(ronghuawu): remove the SetError method that doesn't take |error_desc|. - virtual void SetError(Error error, const std::string& error_desc); - - // Fired when the remote description is updated, with the updated - // contents. - sigslot::signal2<BaseSession* , const ContentInfos&> - SignalRemoteDescriptionUpdate; - - // Fired when SetState is called (regardless if there's a state change), which - // indicates the session description might have be updated. - sigslot::signal2<BaseSession*, ContentAction> SignalNewLocalDescription; - - // Fired when SetState is called (regardless if there's a state change), which - // indicates the session description might have be updated. - sigslot::signal2<BaseSession*, ContentAction> SignalNewRemoteDescription; - - // Returns the transport that has been negotiated or NULL if - // negotiation is still in progress. - virtual Transport* GetTransport(const std::string& content_name); - - // Creates a new channel with the given names. This method may be called - // immediately after creating the session. However, the actual - // implementation may not be fixed until transport negotiation completes. - // This will usually be called from the worker thread, but that - // shouldn't be an issue since the main thread will be blocked in - // Send when doing so. - virtual TransportChannel* CreateChannel(const std::string& content_name, - const std::string& channel_name, - int component); - - // Returns the channel with the given names. - virtual TransportChannel* GetChannel(const std::string& content_name, - int component); - - // Destroys the channel with the given names. - // This will usually be called from the worker thread, but that - // shouldn't be an issue since the main thread will be blocked in - // Send when doing so. - virtual void DestroyChannel(const std::string& content_name, - int component); - - // Returns stats for all channels of all transports. - // This avoids exposing the internal structures used to track them. - virtual bool GetStats(SessionStats* stats); - - rtc::SSLIdentity* identity() { return identity_; } - - protected: - // Specifies the identity to use in this session. - bool SetIdentity(rtc::SSLIdentity* identity); - - bool PushdownTransportDescription(ContentSource source, - ContentAction action, - std::string* error_desc); - void set_initiator(bool initiator) { initiator_ = initiator; } - - const TransportMap& transport_proxies() const { return transports_; } - // Get a TransportProxy by content_name or transport. NULL if not found. - TransportProxy* GetTransportProxy(const std::string& content_name); - TransportProxy* GetTransportProxy(const Transport* transport); - TransportProxy* GetFirstTransportProxy(); - void DestroyTransportProxy(const std::string& content_name); - // TransportProxy is owned by session. Return proxy just for convenience. - TransportProxy* GetOrCreateTransportProxy(const std::string& content_name); - // Creates the actual transport object. Overridable for testing. - virtual Transport* CreateTransport(const std::string& content_name); - - void OnSignalingReady(); - void SpeculativelyConnectAllTransportChannels(); - // Helper method to provide remote candidates to the transport. - bool OnRemoteCandidates(const std::string& content_name, - const Candidates& candidates, - std::string* error); - - // This method will mux transport channels by content_name. - // First content is used for muxing. - bool MaybeEnableMuxingSupport(); - - // Called when a transport requests signaling. - virtual void OnTransportRequestSignaling(Transport* transport) { - } - - // Called when the first channel of a transport begins connecting. We use - // this to start a timer, to make sure that the connection completes in a - // reasonable amount of time. - virtual void OnTransportConnecting(Transport* transport) { - } - - // Called when a transport changes its writable state. We track this to make - // sure that the transport becomes writable within a reasonable amount of - // time. If this does not occur, we signal an error. - virtual void OnTransportWritable(Transport* transport) { - } - virtual void OnTransportReadable(Transport* transport) { - } - - // Called when a transport has found its steady-state connections. - virtual void OnTransportCompleted(Transport* transport) { - } - - // Called when a transport has failed permanently. - virtual void OnTransportFailed(Transport* transport) { - } - - // Called when a transport signals that it has new candidates. - virtual void OnTransportProxyCandidatesReady(TransportProxy* proxy, - const Candidates& candidates) { - } - - // Called when a transport signals that it found an error in an incoming - // message. - virtual void OnTransportSendError(Transport* transport, - const buzz::XmlElement* stanza, - const buzz::QName& name, - const std::string& type, - const std::string& text, - const buzz::XmlElement* extra_info) { - } - - virtual void OnTransportRouteChange( - Transport* transport, - int component, - const cricket::Candidate& remote_candidate) { - } - - virtual void OnTransportCandidatesAllocationDone(Transport* transport); - - // Called when all transport channels allocated required candidates. - // This method should be used as an indication of candidates gathering process - // is completed and application can now send local candidates list to remote. - virtual void OnCandidatesAllocationDone() { - } - - // Handles the ice role change callback from Transport. This must be - // propagated to all the transports. - virtual void OnRoleConflict(); - - // Handles messages posted to us. - virtual void OnMessage(rtc::Message *pmsg); - - protected: - State state_; - Error error_; - std::string error_desc_; - - private: - // Helper methods to push local and remote transport descriptions. - bool PushdownLocalTransportDescription( - const SessionDescription* sdesc, ContentAction action, - std::string* error_desc); - bool PushdownRemoteTransportDescription( - const SessionDescription* sdesc, ContentAction action, - std::string* error_desc); - - bool IsCandidateAllocationDone() const; - void MaybeCandidateAllocationDone(); - - // This method will delete the Transport and TransportChannelImpls and - // replace those with the selected Transport objects. Selection is done - // based on the content_name and in this case first MediaContent information - // is used for mux. - bool SetSelectedProxy(const std::string& content_name, - const ContentGroup* muxed_group); - // Log session state. - void LogState(State old_state, State new_state); - - // Returns true and the TransportInfo of the given |content_name| - // from |description|. Returns false if it's not available. - static bool GetTransportDescription(const SessionDescription* description, - const std::string& content_name, - TransportDescription* info); - - // Fires the new description signal according to the current state. - void SignalNewDescription(); - - // Gets the ContentAction and ContentSource according to the session state. - bool GetContentAction(ContentAction* action, ContentSource* source); - - rtc::Thread* const signaling_thread_; - rtc::Thread* const worker_thread_; - PortAllocator* const port_allocator_; - const std::string sid_; - const std::string content_type_; - const std::string transport_type_; - bool initiator_; - rtc::SSLIdentity* identity_; - rtc::scoped_ptr<const SessionDescription> local_description_; - rtc::scoped_ptr<SessionDescription> remote_description_; - uint64 ice_tiebreaker_; - // This flag will be set to true after the first role switch. This flag - // will enable us to stop any role switch during the call. - bool role_switch_; - TransportMap transports_; -}; - -// A specific Session created by the SessionManager, using XMPP for protocol. -class Session : public BaseSession { - public: - // Returns the manager that created and owns this session. - SessionManager* session_manager() const { return session_manager_; } - - // Returns the client that is handling the application data of this session. - SessionClient* client() const { return client_; } - - // Returns the JID of this client. - const std::string& local_name() const { return local_name_; } - - // Returns the JID of the other peer in this session. - const std::string& remote_name() const { return remote_name_; } - - // Set the JID of the other peer in this session. - // Typically the remote_name_ is set when the session is initiated. - // However, sometimes (e.g when a proxy is used) the peer name is - // known after the BaseSession has been initiated and it must be updated - // explicitly. - void set_remote_name(const std::string& name) { remote_name_ = name; } - - // Set the JID of the initiator of this session. Allows for the overriding - // of the initiator to be a third-party, eg. the MUC JID when creating p2p - // sessions. - void set_initiator_name(const std::string& name) { initiator_name_ = name; } - - // Indicates the JID of the entity who initiated this session. - // In special cases, may be different than both local_name and remote_name. - const std::string& initiator_name() const { return initiator_name_; } - - SignalingProtocol current_protocol() const { return current_protocol_; } - - void set_current_protocol(SignalingProtocol protocol) { - current_protocol_ = protocol; - } - - // Updates the error state, signaling if necessary. - virtual void SetError(Error error, const std::string& error_desc); - - // When the session needs to send signaling messages, it beings by requesting - // signaling. The client should handle this by calling OnSignalingReady once - // it is ready to send the messages. - // (These are called only by SessionManager.) - sigslot::signal1<Session*> SignalRequestSignaling; - void OnSignalingReady() { BaseSession::OnSignalingReady(); } - - // Takes ownership of session description. - // TODO: Add an error argument to pass back to the caller. - bool Initiate(const std::string& to, - const SessionDescription* sdesc); - - // When we receive an initiate, we create a session in the - // RECEIVEDINITIATE state and respond by accepting or rejecting. - // Takes ownership of session description. - // TODO: Add an error argument to pass back to the caller. - bool Accept(const SessionDescription* sdesc); - bool Reject(const std::string& reason); - bool Terminate() { - return TerminateWithReason(STR_TERMINATE_SUCCESS); - } - bool TerminateWithReason(const std::string& reason); - // Fired whenever we receive a terminate message along with a reason - sigslot::signal2<Session*, const std::string&> SignalReceivedTerminateReason; - - // The two clients in the session may also send one another - // arbitrary XML messages, which are called "info" messages. Sending - // takes ownership of the given elements. The signal does not; the - // parent element will be deleted after the signal. - bool SendInfoMessage(const XmlElements& elems, - const std::string& remote_name); - bool SendDescriptionInfoMessage(const ContentInfos& contents); - sigslot::signal2<Session*, const buzz::XmlElement*> SignalInfoMessage; - - private: - // Creates or destroys a session. (These are called only SessionManager.) - Session(SessionManager *session_manager, - const std::string& local_name, const std::string& initiator_name, - const std::string& sid, const std::string& content_type, - SessionClient* client); - ~Session(); - // For each transport info, create a transport proxy. Can fail for - // incompatible transport types. - bool CreateTransportProxies(const TransportInfos& tinfos, - SessionError* error); - bool OnRemoteCandidates(const TransportInfos& tinfos, - ParseError* error); - // Returns a TransportInfo without candidates for each content name. - // Uses the transport_type_ of the session. - TransportInfos GetEmptyTransportInfos(const ContentInfos& contents) const; - - // Maps passed to serialization functions. - TransportParserMap GetTransportParsers(); - ContentParserMap GetContentParsers(); - CandidateTranslatorMap GetCandidateTranslators(); - - virtual void OnTransportRequestSignaling(Transport* transport); - virtual void OnTransportConnecting(Transport* transport); - virtual void OnTransportWritable(Transport* transport); - virtual void OnTransportProxyCandidatesReady(TransportProxy* proxy, - const Candidates& candidates); - virtual void OnTransportSendError(Transport* transport, - const buzz::XmlElement* stanza, - const buzz::QName& name, - const std::string& type, - const std::string& text, - const buzz::XmlElement* extra_info); - virtual void OnMessage(rtc::Message *pmsg); - - // Send various kinds of session messages. - bool SendInitiateMessage(const SessionDescription* sdesc, - SessionError* error); - bool SendAcceptMessage(const SessionDescription* sdesc, SessionError* error); - bool SendRejectMessage(const std::string& reason, SessionError* error); - bool SendTerminateMessage(const std::string& reason, SessionError* error); - bool SendTransportInfoMessage(const TransportInfo& tinfo, - SessionError* error); - bool SendTransportInfoMessage(const TransportProxy* transproxy, - const Candidates& candidates, - SessionError* error); - - bool ResendAllTransportInfoMessages(SessionError* error); - bool SendAllUnsentTransportInfoMessages(SessionError* error); - - // All versions of SendMessage send a message of the given type to - // the other client. Can pass either a set of elements or an - // "action", which must have a WriteSessionAction method to go along - // with it. Sending with an action supports sending a "hybrid" - // message. Sending with elements must be sent as Jingle or Gingle. - - // When passing elems, must be either Jingle or Gingle protocol. - // Takes ownership of action_elems. - bool SendMessage(ActionType type, const XmlElements& action_elems, - SessionError* error); - // Sends a messge, but overrides the remote name. - bool SendMessage(ActionType type, const XmlElements& action_elems, - const std::string& remote_name, - SessionError* error); - // When passing an action, may be Hybrid protocol. - template <typename Action> - bool SendMessage(ActionType type, const Action& action, - SessionError* error); - - // Helper methods to write the session message stanza. - template <typename Action> - bool WriteActionMessage(ActionType type, const Action& action, - buzz::XmlElement* stanza, WriteError* error); - template <typename Action> - bool WriteActionMessage(SignalingProtocol protocol, - ActionType type, const Action& action, - buzz::XmlElement* stanza, WriteError* error); - - // Sending messages in hybrid form requires being able to write them - // on a per-protocol basis with a common method signature, which all - // of these have. - bool WriteSessionAction(SignalingProtocol protocol, - const SessionInitiate& init, - XmlElements* elems, WriteError* error); - bool WriteSessionAction(SignalingProtocol protocol, - const TransportInfo& tinfo, - XmlElements* elems, WriteError* error); - bool WriteSessionAction(SignalingProtocol protocol, - const SessionTerminate& term, - XmlElements* elems, WriteError* error); - - // Sends a message back to the other client indicating that we have received - // and accepted their message. - void SendAcknowledgementMessage(const buzz::XmlElement* stanza); - - // Once signaling is ready, the session will use this signal to request the - // sending of each message. When messages are received by the other client, - // they should be handed to OnIncomingMessage. - // (These are called only by SessionManager.) - sigslot::signal2<Session* , const buzz::XmlElement*> SignalOutgoingMessage; - void OnIncomingMessage(const SessionMessage& msg); - - void OnIncomingResponse(const buzz::XmlElement* orig_stanza, - const buzz::XmlElement* response_stanza, - const SessionMessage& msg); - void OnInitiateAcked(); - void OnFailedSend(const buzz::XmlElement* orig_stanza, - const buzz::XmlElement* error_stanza); - - // Invoked when an error is found in an incoming message. This is translated - // into the appropriate XMPP response by SessionManager. - sigslot::signal6<BaseSession*, - const buzz::XmlElement*, - const buzz::QName&, - const std::string&, - const std::string&, - const buzz::XmlElement*> SignalErrorMessage; - - // Handlers for the various types of messages. These functions may take - // pointers to the whole stanza or to just the session element. - bool OnInitiateMessage(const SessionMessage& msg, MessageError* error); - bool OnAcceptMessage(const SessionMessage& msg, MessageError* error); - bool OnRejectMessage(const SessionMessage& msg, MessageError* error); - bool OnInfoMessage(const SessionMessage& msg); - bool OnTerminateMessage(const SessionMessage& msg, MessageError* error); - bool OnTransportInfoMessage(const SessionMessage& msg, MessageError* error); - bool OnTransportAcceptMessage(const SessionMessage& msg, MessageError* error); - bool OnDescriptionInfoMessage(const SessionMessage& msg, MessageError* error); - bool OnRedirectError(const SessionRedirect& redirect, SessionError* error); - - // Verifies that we are in the appropriate state to receive this message. - bool CheckState(State state, MessageError* error); - - SessionManager* session_manager_; - bool initiate_acked_; - std::string local_name_; - std::string initiator_name_; - std::string remote_name_; - SessionClient* client_; - TransportParser* transport_parser_; - // Keeps track of what protocol we are speaking. - SignalingProtocol current_protocol_; - - friend class SessionManager; // For access to constructor, destructor, - // and signaling related methods. -}; - -} // namespace cricket - -#endif // WEBRTC_P2P_BASE_SESSION_H_ diff --git a/talk/p2p/base/session_unittest.cc b/talk/p2p/base/session_unittest.cc deleted file mode 100644 index c7a3db9cd..000000000 --- a/talk/p2p/base/session_unittest.cc +++ /dev/null @@ -1,2447 +0,0 @@ -/* - * libjingle - * Copyright 2004 Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <string.h> - -#include <deque> -#include <map> -#include <sstream> - -#include "webrtc/p2p/base/basicpacketsocketfactory.h" -#include "webrtc/p2p/base/constants.h" -#include "webrtc/p2p/base/p2ptransport.h" -#include "webrtc/p2p/base/parsing.h" -#include "webrtc/p2p/base/portallocator.h" -#include "webrtc/p2p/base/relayport.h" -#include "webrtc/p2p/base/relayserver.h" -#include "webrtc/p2p/base/session.h" -#include "webrtc/p2p/base/sessionclient.h" -#include "webrtc/p2p/base/sessionmanager.h" -#include "webrtc/p2p/base/stunport.h" -#include "webrtc/p2p/base/stunserver.h" -#include "webrtc/p2p/base/transportchannel.h" -#include "webrtc/p2p/base/transportchannelproxy.h" -#include "webrtc/p2p/base/udpport.h" -#include "webrtc/libjingle/xmpp/constants.h" -#include "webrtc/base/base64.h" -#include "webrtc/base/common.h" -#include "webrtc/base/gunit.h" -#include "webrtc/base/helpers.h" -#include "webrtc/base/logging.h" -#include "webrtc/base/natserver.h" -#include "webrtc/base/natsocketfactory.h" -#include "webrtc/base/stringencode.h" - -using cricket::SignalingProtocol; -using cricket::PROTOCOL_HYBRID; -using cricket::PROTOCOL_JINGLE; -using cricket::PROTOCOL_GINGLE; - -static const std::string kInitiator = "init@init.com"; -static const std::string kResponder = "resp@resp.com"; -// Expected from test random number generator. -static const std::string kSessionId = "9254631414740579489"; -// TODO: When we need to test more than one transport type, -// allow this to be injected like the content types are. -static const std::string kTransportType = "http://www.google.com/transport/p2p"; - -// Controls how long we wait for a session to send messages that we -// expect, in milliseconds. We put it high to avoid flaky tests. -static const int kEventTimeout = 5000; - -static const int kNumPorts = 2; -static const int kPort0 = 28653; -static const int kPortStep = 5; - -int GetPort(int port_index) { - return kPort0 + (port_index * kPortStep); -} - -std::string GetPortString(int port_index) { - return rtc::ToString(GetPort(port_index)); -} - -// Only works for port_index < 10, which is fine for our purposes. -std::string GetUsername(int port_index) { - return "username" + std::string(8, rtc::ToString(port_index)[0]); -} - -// Only works for port_index < 10, which is fine for our purposes. -std::string GetPassword(int port_index) { - return "password" + std::string(8, rtc::ToString(port_index)[0]); -} - -std::string IqAck(const std::string& id, - const std::string& from, - const std::string& to) { - return "<cli:iq" - " to=\"" + to + "\"" - " id=\"" + id + "\"" - " type=\"result\"" - " from=\"" + from + "\"" - " xmlns:cli=\"jabber:client\"" - "/>"; -} - -std::string IqSet(const std::string& id, - const std::string& from, - const std::string& to, - const std::string& content) { - return "<cli:iq" - " to=\"" + to + "\"" - " type=\"set\"" - " from=\"" + from + "\"" - " id=\"" + id + "\"" - " xmlns:cli=\"jabber:client\"" - ">" - + content + - "</cli:iq>"; -} - -std::string IqError(const std::string& id, - const std::string& from, - const std::string& to, - const std::string& content) { - return "<cli:error" - " to=\"" + to + "\"" - " type=\"error\"" - " from=\"" + from + "\"" - " id=\"" + id + "\"" - " xmlns:cli=\"jabber:client\"" - ">" - + content + - "</cli:error>"; -} - -std::string GingleSessionXml(const std::string& type, - const std::string& content) { - return "<session" - " xmlns=\"http://www.google.com/session\"" - " type=\"" + type + "\"" - " id=\"" + kSessionId + "\"" - " initiator=\"" + kInitiator + "\"" - ">" - + content + - "</session>"; -} - -std::string GingleDescriptionXml(const std::string& content_type) { - return "<description" - " xmlns=\"" + content_type + "\"" - "/>"; -} - -std::string P2pCandidateXml(const std::string& name, int port_index) { - // Port will update the rtcp username by +1 on the last character. So we need - // to compensate here. See Port::username_fragment() for detail. - std::string username = GetUsername(port_index); - // TODO: Use the component id instead of the channel name to - // determinte if we need to covert the username here. - if (name == "rtcp" || name == "video_rtcp" || name == "chanb") { - char next_ch = username[username.size() - 1]; - ASSERT(username.size() > 0); - rtc::Base64::GetNextBase64Char(next_ch, &next_ch); - username[username.size() - 1] = next_ch; - } - return "<candidate" - " name=\"" + name + "\"" - " address=\"127.0.0.1\"" - " port=\"" + GetPortString(port_index) + "\"" - " preference=\"0.99\"" - " username=\"" + username + "\"" - " protocol=\"udp\"" - " generation=\"0\"" - " password=\"" + GetPassword(port_index) + "\"" - " type=\"local\"" - " network=\"network\"" - "/>"; -} - -std::string JingleActionXml(const std::string& action, - const std::string& content) { - return "<jingle" - " xmlns=\"urn:xmpp:jingle:1\"" - " action=\"" + action + "\"" - " sid=\"" + kSessionId + "\"" - ">" - + content + - "</jingle>"; -} - -std::string JingleInitiateActionXml(const std::string& content) { - return "<jingle" - " xmlns=\"urn:xmpp:jingle:1\"" - " action=\"session-initiate\"" - " sid=\"" + kSessionId + "\"" - " initiator=\"" + kInitiator + "\"" - ">" - + content + - "</jingle>"; -} - -std::string JingleGroupInfoXml(const std::string& content_name_a, - const std::string& content_name_b) { - std::string group_info = "<jin:group" - " type=\"BUNDLE\"" - " xmlns:jin=\"google:jingle\"" - ">"; - if (!content_name_a.empty()) - group_info += "<content name=\"" + content_name_a + "\"" - "/>"; - if (!content_name_b.empty()) - group_info += "<content name=\"" + content_name_b + "\"" - "/>"; - group_info += "</jin:group>"; - return group_info; -} - - -std::string JingleEmptyContentXml(const std::string& content_name, - const std::string& content_type, - const std::string& transport_type) { - return "<content" - " name=\"" + content_name + "\"" - " creator=\"initiator\"" - ">" - "<description" - " xmlns=\"" + content_type + "\"" - "/>" - "<transport" - " xmlns=\"" + transport_type + "\"" - "/>" - "</content>"; -} - -std::string JingleContentXml(const std::string& content_name, - const std::string& content_type, - const std::string& transport_type, - const std::string& transport_main) { - std::string transport = transport_type.empty() ? "" : - "<transport" - " xmlns=\"" + transport_type + "\"" - ">" - + transport_main + - "</transport>"; - - return"<content" - " name=\"" + content_name + "\"" - " creator=\"initiator\"" - ">" - "<description" - " xmlns=\"" + content_type + "\"" - "/>" - + transport + - "</content>"; -} - -std::string JingleTransportContentXml(const std::string& content_name, - const std::string& transport_type, - const std::string& content) { - return "<content" - " name=\"" + content_name + "\"" - " creator=\"initiator\"" - ">" - "<transport" - " xmlns=\"" + transport_type + "\"" - ">" - + content + - "</transport>" - "</content>"; -} - -std::string GingleInitiateXml(const std::string& content_type) { - return GingleSessionXml( - "initiate", - GingleDescriptionXml(content_type)); -} - -std::string JingleInitiateXml(const std::string& content_name_a, - const std::string& content_type_a, - const std::string& content_name_b, - const std::string& content_type_b, - bool bundle = false) { - std::string content_xml; - if (content_name_b.empty()) { - content_xml = JingleEmptyContentXml( - content_name_a, content_type_a, kTransportType); - } else { - content_xml = JingleEmptyContentXml( - content_name_a, content_type_a, kTransportType) + - JingleEmptyContentXml( - content_name_b, content_type_b, kTransportType); - if (bundle) { - content_xml += JingleGroupInfoXml(content_name_a, content_name_b); - } - } - return JingleInitiateActionXml(content_xml); -} - -std::string GingleAcceptXml(const std::string& content_type) { - return GingleSessionXml( - "accept", - GingleDescriptionXml(content_type)); -} - -std::string JingleAcceptXml(const std::string& content_name_a, - const std::string& content_type_a, - const std::string& content_name_b, - const std::string& content_type_b, - bool bundle = false) { - std::string content_xml; - if (content_name_b.empty()) { - content_xml = JingleEmptyContentXml( - content_name_a, content_type_a, kTransportType); - } else { - content_xml = JingleEmptyContentXml( - content_name_a, content_type_a, kTransportType) + - JingleEmptyContentXml( - content_name_b, content_type_b, kTransportType); - } - if (bundle) { - content_xml += JingleGroupInfoXml(content_name_a, content_name_b); - } - - return JingleActionXml("session-accept", content_xml); -} - -std::string Gingle2CandidatesXml(const std::string& channel_name, - int port_index0, - int port_index1) { - return GingleSessionXml( - "candidates", - P2pCandidateXml(channel_name, port_index0) + - P2pCandidateXml(channel_name, port_index1)); -} - -std::string Gingle4CandidatesXml(const std::string& channel_name_a, - int port_index0, - int port_index1, - const std::string& channel_name_b, - int port_index2, - int port_index3) { - return GingleSessionXml( - "candidates", - P2pCandidateXml(channel_name_a, port_index0) + - P2pCandidateXml(channel_name_a, port_index1) + - P2pCandidateXml(channel_name_b, port_index2) + - P2pCandidateXml(channel_name_b, port_index3)); -} - -std::string Jingle2TransportInfoXml(const std::string& content_name, - const std::string& channel_name, - int port_index0, - int port_index1) { - return JingleActionXml( - "transport-info", - JingleTransportContentXml( - content_name, kTransportType, - P2pCandidateXml(channel_name, port_index0) + - P2pCandidateXml(channel_name, port_index1))); -} - -std::string Jingle4TransportInfoXml(const std::string& content_name, - const std::string& channel_name_a, - int port_index0, - int port_index1, - const std::string& channel_name_b, - int port_index2, - int port_index3) { - return JingleActionXml( - "transport-info", - JingleTransportContentXml( - content_name, kTransportType, - P2pCandidateXml(channel_name_a, port_index0) + - P2pCandidateXml(channel_name_a, port_index1) + - P2pCandidateXml(channel_name_b, port_index2) + - P2pCandidateXml(channel_name_b, port_index3))); -} - -std::string JingleDescriptionInfoXml(const std::string& content_name, - const std::string& content_type) { - return JingleActionXml( - "description-info", - JingleContentXml(content_name, content_type, "", "")); -} - -std::string GingleRejectXml(const std::string& reason) { - return GingleSessionXml( - "reject", - "<" + reason + "/>"); -} - -std::string JingleTerminateXml(const std::string& reason) { - return JingleActionXml( - "session-terminate", - "<reason><" + reason + "/></reason>"); -} - -std::string GingleTerminateXml(const std::string& reason) { - return GingleSessionXml( - "terminate", - "<" + reason + "/>"); -} - -std::string GingleRedirectXml(const std::string& intitiate, - const std::string& target) { - return intitiate + - "<error code=\"302\" type=\"modify\">" - "<redirect xmlns=\"http://www.google.com/session\">" - "xmpp:" + target + - "</redirect>" - "</error>"; -} - -std::string JingleRedirectXml(const std::string& intitiate, - const std::string& target) { - return intitiate + - "<error code=\"302\" type=\"modify\">" - "<redirect xmlns=\"urn:ietf:params:xml:ns:xmpp-stanzas\">" - "xmpp:" + target + - "</redirect>" - "</error>"; -} - -std::string InitiateXml(SignalingProtocol protocol, - const std::string& gingle_content_type, - const std::string& content_name_a, - const std::string& content_type_a, - const std::string& content_name_b, - const std::string& content_type_b, - bool bundle = false) { - switch (protocol) { - case PROTOCOL_JINGLE: - return JingleInitiateXml(content_name_a, content_type_a, - content_name_b, content_type_b, - bundle); - case PROTOCOL_GINGLE: - return GingleInitiateXml(gingle_content_type); - case PROTOCOL_HYBRID: - return JingleInitiateXml(content_name_a, content_type_a, - content_name_b, content_type_b) + - GingleInitiateXml(gingle_content_type); - } - return ""; -} - -std::string InitiateXml(SignalingProtocol protocol, - const std::string& content_name, - const std::string& content_type) { - return InitiateXml(protocol, - content_type, - content_name, content_type, - "", ""); -} - -std::string AcceptXml(SignalingProtocol protocol, - const std::string& gingle_content_type, - const std::string& content_name_a, - const std::string& content_type_a, - const std::string& content_name_b, - const std::string& content_type_b, - bool bundle = false) { - switch (protocol) { - case PROTOCOL_JINGLE: - return JingleAcceptXml(content_name_a, content_type_a, - content_name_b, content_type_b, bundle); - case PROTOCOL_GINGLE: - return GingleAcceptXml(gingle_content_type); - case PROTOCOL_HYBRID: - return - JingleAcceptXml(content_name_a, content_type_a, - content_name_b, content_type_b) + - GingleAcceptXml(gingle_content_type); - } - return ""; -} - - -std::string AcceptXml(SignalingProtocol protocol, - const std::string& content_name, - const std::string& content_type, - bool bundle = false) { - return AcceptXml(protocol, - content_type, - content_name, content_type, - "", ""); -} - -std::string TransportInfo2Xml(SignalingProtocol protocol, - const std::string& content_name, - const std::string& channel_name, - int port_index0, - int port_index1) { - switch (protocol) { - case PROTOCOL_JINGLE: - return Jingle2TransportInfoXml( - content_name, - channel_name, port_index0, port_index1); - case PROTOCOL_GINGLE: - return Gingle2CandidatesXml( - channel_name, port_index0, port_index1); - case PROTOCOL_HYBRID: - return - Jingle2TransportInfoXml( - content_name, - channel_name, port_index0, port_index1) + - Gingle2CandidatesXml( - channel_name, port_index0, port_index1); - } - return ""; -} - -std::string TransportInfo4Xml(SignalingProtocol protocol, - const std::string& content_name, - const std::string& channel_name_a, - int port_index0, - int port_index1, - const std::string& channel_name_b, - int port_index2, - int port_index3) { - switch (protocol) { - case PROTOCOL_JINGLE: - return Jingle4TransportInfoXml( - content_name, - channel_name_a, port_index0, port_index1, - channel_name_b, port_index2, port_index3); - case PROTOCOL_GINGLE: - return Gingle4CandidatesXml( - channel_name_a, port_index0, port_index1, - channel_name_b, port_index2, port_index3); - case PROTOCOL_HYBRID: - return - Jingle4TransportInfoXml( - content_name, - channel_name_a, port_index0, port_index1, - channel_name_b, port_index2, port_index3) + - Gingle4CandidatesXml( - channel_name_a, port_index0, port_index1, - channel_name_b, port_index2, port_index3); - } - return ""; -} - -std::string RejectXml(SignalingProtocol protocol, - const std::string& reason) { - switch (protocol) { - case PROTOCOL_JINGLE: - return JingleTerminateXml(reason); - case PROTOCOL_GINGLE: - return GingleRejectXml(reason); - case PROTOCOL_HYBRID: - return JingleTerminateXml(reason) + - GingleRejectXml(reason); - } - return ""; -} - -std::string TerminateXml(SignalingProtocol protocol, - const std::string& reason) { - switch (protocol) { - case PROTOCOL_JINGLE: - return JingleTerminateXml(reason); - case PROTOCOL_GINGLE: - return GingleTerminateXml(reason); - case PROTOCOL_HYBRID: - return JingleTerminateXml(reason) + - GingleTerminateXml(reason); - } - return ""; -} - -std::string RedirectXml(SignalingProtocol protocol, - const std::string& initiate, - const std::string& target) { - switch (protocol) { - case PROTOCOL_JINGLE: - return JingleRedirectXml(initiate, target); - case PROTOCOL_GINGLE: - return GingleRedirectXml(initiate, target); - default: - break; - } - return ""; -} - -// TODO: Break out and join with fakeportallocator.h -class TestPortAllocatorSession : public cricket::PortAllocatorSession { - public: - TestPortAllocatorSession(const std::string& content_name, - int component, - const std::string& ice_ufrag, - const std::string& ice_pwd, - const int port_offset) - : PortAllocatorSession(content_name, component, ice_ufrag, ice_pwd, 0), - port_offset_(port_offset), - ports_(kNumPorts), - address_("127.0.0.1", 0), - network_("network", "unittest", - rtc::IPAddress(INADDR_LOOPBACK), 8), - socket_factory_(rtc::Thread::Current()), - running_(false) { - network_.AddIP(address_.ipaddr()); - } - - ~TestPortAllocatorSession() { - for (size_t i = 0; i < ports_.size(); i++) - delete ports_[i]; - } - - virtual void StartGettingPorts() { - for (int i = 0; i < kNumPorts; i++) { - int index = port_offset_ + i; - ports_[i] = cricket::UDPPort::Create( - rtc::Thread::Current(), &socket_factory_, - &network_, address_.ipaddr(), GetPort(index), GetPort(index), - GetUsername(index), GetPassword(index)); - AddPort(ports_[i]); - } - running_ = true; - } - - virtual void StopGettingPorts() { running_ = false; } - virtual bool IsGettingPorts() { return running_; } - - void AddPort(cricket::Port* port) { - port->set_component(component_); - port->set_generation(0); - port->SignalDestroyed.connect( - this, &TestPortAllocatorSession::OnPortDestroyed); - port->SignalPortComplete.connect( - this, &TestPortAllocatorSession::OnPortComplete); - port->PrepareAddress(); - SignalPortReady(this, port); - } - - void OnPortDestroyed(cricket::PortInterface* port) { - for (size_t i = 0; i < ports_.size(); i++) { - if (ports_[i] == port) - ports_[i] = NULL; - } - } - - void OnPortComplete(cricket::Port* port) { - SignalCandidatesReady(this, port->Candidates()); - } - - private: - int port_offset_; - std::vector<cricket::Port*> ports_; - rtc::SocketAddress address_; - rtc::Network network_; - rtc::BasicPacketSocketFactory socket_factory_; - bool running_; -}; - -class TestPortAllocator : public cricket::PortAllocator { - public: - TestPortAllocator() : port_offset_(0) {} - - virtual cricket::PortAllocatorSession* - CreateSessionInternal( - const std::string& content_name, - int component, - const std::string& ice_ufrag, - const std::string& ice_pwd) { - port_offset_ += 2; - return new TestPortAllocatorSession(content_name, component, - ice_ufrag, ice_pwd, port_offset_ - 2); - } - - int port_offset_; -}; - -class TestContentDescription : public cricket::ContentDescription { - public: - explicit TestContentDescription(const std::string& gingle_content_type, - const std::string& content_type) - : gingle_content_type(gingle_content_type), - content_type(content_type) { - } - virtual ContentDescription* Copy() const { - return new TestContentDescription(*this); - } - - std::string gingle_content_type; - std::string content_type; -}; - -cricket::SessionDescription* NewTestSessionDescription( - const std::string gingle_content_type, - const std::string& content_name_a, const std::string& content_type_a, - const std::string& content_name_b, const std::string& content_type_b) { - - cricket::SessionDescription* offer = new cricket::SessionDescription(); - offer->AddContent(content_name_a, content_type_a, - new TestContentDescription(gingle_content_type, - content_type_a)); - cricket::TransportDescription desc(cricket::NS_GINGLE_P2P, - std::string(), std::string()); - offer->AddTransportInfo(cricket::TransportInfo(content_name_a, desc)); - - if (content_name_a != content_name_b) { - offer->AddContent(content_name_b, content_type_b, - new TestContentDescription(gingle_content_type, - content_type_b)); - offer->AddTransportInfo(cricket::TransportInfo(content_name_b, desc)); - } - return offer; -} - -cricket::SessionDescription* NewTestSessionDescription( - const std::string& content_name, const std::string& content_type) { - - cricket::SessionDescription* offer = new cricket::SessionDescription(); - offer->AddContent(content_name, content_type, - new TestContentDescription(content_type, - content_type)); - offer->AddTransportInfo(cricket::TransportInfo - (content_name, cricket::TransportDescription( - cricket::NS_GINGLE_P2P, - std::string(), std::string()))); - return offer; -} - -struct TestSessionClient: public cricket::SessionClient, - public sigslot::has_slots<> { - public: - TestSessionClient() { - } - - ~TestSessionClient() { - } - - virtual bool ParseContent(SignalingProtocol protocol, - const buzz::XmlElement* elem, - cricket::ContentDescription** content, - cricket::ParseError* error) { - std::string content_type; - std::string gingle_content_type; - if (protocol == PROTOCOL_GINGLE) { - gingle_content_type = elem->Name().Namespace(); - } else { - content_type = elem->Name().Namespace(); - } - - *content = new TestContentDescription(gingle_content_type, content_type); - return true; - } - - virtual bool WriteContent(SignalingProtocol protocol, - const cricket::ContentDescription* untyped_content, - buzz::XmlElement** elem, - cricket::WriteError* error) { - const TestContentDescription* content = - static_cast<const TestContentDescription*>(untyped_content); - std::string content_type = (protocol == PROTOCOL_GINGLE ? - content->gingle_content_type : - content->content_type); - *elem = new buzz::XmlElement( - buzz::QName(content_type, "description"), true); - return true; - } - - void OnSessionCreate(cricket::Session* session, bool initiate) { - } - - void OnSessionDestroy(cricket::Session* session) { - } -}; - -struct ChannelHandler : sigslot::has_slots<> { - explicit ChannelHandler(cricket::TransportChannel* p, const std::string& name) - : channel(p), last_readable(false), last_writable(false), data_count(0), - last_size(0), name(name) { - p->SignalReadableState.connect(this, &ChannelHandler::OnReadableState); - p->SignalWritableState.connect(this, &ChannelHandler::OnWritableState); - p->SignalReadPacket.connect(this, &ChannelHandler::OnReadPacket); - } - - bool writable() const { - return last_writable && channel->writable(); - } - - bool readable() const { - return last_readable && channel->readable(); - } - - void OnReadableState(cricket::TransportChannel* p) { - EXPECT_EQ(channel, p); - last_readable = channel->readable(); - } - - void OnWritableState(cricket::TransportChannel* p) { - EXPECT_EQ(channel, p); - last_writable = channel->writable(); - } - - void OnReadPacket(cricket::TransportChannel* p, const char* buf, - size_t size, const rtc::PacketTime& time, int flags) { - if (memcmp(buf, name.c_str(), name.size()) != 0) - return; // drop packet if packet doesn't belong to this channel. This - // can happen when transport channels are muxed together. - buf += name.size(); // Remove channel name from the message. - size -= name.size(); // Decrement size by channel name string size. - EXPECT_EQ(channel, p); - EXPECT_LE(size, sizeof(last_data)); - data_count += 1; - last_size = size; - memcpy(last_data, buf, size); - } - - void Send(const char* data, size_t size) { - rtc::PacketOptions options; - std::string data_with_id(name); - data_with_id += data; - int result = channel->SendPacket(data_with_id.c_str(), data_with_id.size(), - options, 0); - EXPECT_EQ(static_cast<int>(data_with_id.size()), result); - } - - cricket::TransportChannel* channel; - bool last_readable, last_writable; - int data_count; - char last_data[4096]; - size_t last_size; - std::string name; -}; - -void PrintStanza(const std::string& message, - const buzz::XmlElement* stanza) { - printf("%s: %s\n", message.c_str(), stanza->Str().c_str()); -} - -class TestClient : public sigslot::has_slots<> { - public: - // TODO: Add channel_component_a/b as inputs to the ctor. - TestClient(cricket::PortAllocator* port_allocator, - int* next_message_id, - const std::string& local_name, - SignalingProtocol start_protocol, - const std::string& content_type, - const std::string& content_name_a, - const std::string& channel_name_a, - const std::string& content_name_b, - const std::string& channel_name_b) { - Construct(port_allocator, next_message_id, local_name, start_protocol, - content_type, content_name_a, channel_name_a, - content_name_b, channel_name_b); - } - - ~TestClient() { - if (session) { - session_manager->DestroySession(session); - EXPECT_EQ(1U, session_destroyed_count); - } - delete session_manager; - delete client; - for (std::deque<buzz::XmlElement*>::iterator it = sent_stanzas.begin(); - it != sent_stanzas.end(); ++it) { - delete *it; - } - } - - void Construct(cricket::PortAllocator* pa, - int* message_id, - const std::string& lname, - SignalingProtocol protocol, - const std::string& cont_type, - const std::string& cont_name_a, - const std::string& chan_name_a, - const std::string& cont_name_b, - const std::string& chan_name_b) { - port_allocator_ = pa; - next_message_id = message_id; - local_name = lname; - start_protocol = protocol; - content_type = cont_type; - content_name_a = cont_name_a; - channel_name_a = chan_name_a; - content_name_b = cont_name_b; - channel_name_b = chan_name_b; - session_created_count = 0; - session_destroyed_count = 0; - session_remote_description_update_count = 0; - new_local_description = false; - new_remote_description = false; - last_content_action = cricket::CA_OFFER; - last_content_source = cricket::CS_LOCAL; - session = NULL; - last_session_state = cricket::BaseSession::STATE_INIT; - blow_up_on_error = true; - error_count = 0; - - session_manager = new cricket::SessionManager(port_allocator_); - session_manager->SignalSessionCreate.connect( - this, &TestClient::OnSessionCreate); - session_manager->SignalSessionDestroy.connect( - this, &TestClient::OnSessionDestroy); - session_manager->SignalOutgoingMessage.connect( - this, &TestClient::OnOutgoingMessage); - - client = new TestSessionClient(); - session_manager->AddClient(content_type, client); - EXPECT_EQ(client, session_manager->GetClient(content_type)); - } - - uint32 sent_stanza_count() const { - return static_cast<uint32>(sent_stanzas.size()); - } - - const buzz::XmlElement* stanza() const { - return last_expected_sent_stanza.get(); - } - - cricket::BaseSession::State session_state() const { - EXPECT_EQ(last_session_state, session->state()); - return session->state(); - } - - void SetSessionState(cricket::BaseSession::State state) { - session->SetState(state); - EXPECT_EQ_WAIT(last_session_state, session->state(), kEventTimeout); - } - - void CreateSession() { - session_manager->CreateSession(local_name, content_type); - } - - void DeliverStanza(const buzz::XmlElement* stanza) { - session_manager->OnIncomingMessage(stanza); - } - - void DeliverStanza(const std::string& str) { - buzz::XmlElement* stanza = buzz::XmlElement::ForStr(str); - session_manager->OnIncomingMessage(stanza); - delete stanza; - } - - void DeliverAckToLastStanza() { - const buzz::XmlElement* orig_stanza = stanza(); - const buzz::XmlElement* response_stanza = - buzz::XmlElement::ForStr(IqAck(orig_stanza->Attr(buzz::QN_IQ), "", "")); - session_manager->OnIncomingResponse(orig_stanza, response_stanza); - delete response_stanza; - } - - void ExpectSentStanza(const std::string& expected) { - EXPECT_TRUE(!sent_stanzas.empty()) << - "Found no stanza when expected " << expected; - - last_expected_sent_stanza.reset(sent_stanzas.front()); - sent_stanzas.pop_front(); - - std::string actual = last_expected_sent_stanza->Str(); - EXPECT_EQ(expected, actual); - } - - void SkipUnsentStanza() { - GetNextOutgoingMessageID(); - } - - bool HasTransport(const std::string& content_name) const { - ASSERT(session != NULL); - const cricket::Transport* transport = session->GetTransport(content_name); - return transport != NULL && (kTransportType == transport->type()); - } - - bool HasChannel(const std::string& content_name, - int component) const { - ASSERT(session != NULL); - const cricket::TransportChannel* channel = - session->GetChannel(content_name, component); - return channel != NULL && (component == channel->component()); - } - - cricket::TransportChannel* GetChannel(const std::string& content_name, - int component) const { - ASSERT(session != NULL); - return session->GetChannel(content_name, component); - } - - void OnSessionCreate(cricket::Session* created_session, bool initiate) { - session_created_count += 1; - - session = created_session; - session->set_current_protocol(start_protocol); - session->SignalState.connect(this, &TestClient::OnSessionState); - session->SignalError.connect(this, &TestClient::OnSessionError); - session->SignalRemoteDescriptionUpdate.connect( - this, &TestClient::OnSessionRemoteDescriptionUpdate); - session->SignalNewLocalDescription.connect( - this, &TestClient::OnNewLocalDescription); - session->SignalNewRemoteDescription.connect( - this, &TestClient::OnNewRemoteDescription); - - CreateChannels(); - } - - void OnSessionDestroy(cricket::Session *session) { - session_destroyed_count += 1; - } - - void OnSessionState(cricket::BaseSession* session, - cricket::BaseSession::State state) { - // EXPECT_EQ does not allow use of this, hence the tmp variable. - cricket::BaseSession* tmp = this->session; - EXPECT_EQ(tmp, session); - last_session_state = state; - } - - void OnSessionError(cricket::BaseSession* session, - cricket::BaseSession::Error error) { - // EXPECT_EQ does not allow use of this, hence the tmp variable. - cricket::BaseSession* tmp = this->session; - EXPECT_EQ(tmp, session); - if (blow_up_on_error) { - EXPECT_TRUE(false); - } else { - error_count++; - } - } - - void OnSessionRemoteDescriptionUpdate(cricket::BaseSession* session, - const cricket::ContentInfos& contents) { - session_remote_description_update_count++; - } - - void OnNewLocalDescription(cricket::BaseSession* session, - cricket::ContentAction action) { - new_local_description = true; - last_content_action = action; - last_content_source = cricket::CS_LOCAL; - } - - void OnNewRemoteDescription(cricket::BaseSession* session, - cricket::ContentAction action) { - new_remote_description = true; - last_content_action = action; - last_content_source = cricket::CS_REMOTE; - } - - void PrepareCandidates() { - session_manager->OnSignalingReady(); - } - - void OnOutgoingMessage(cricket::SessionManager* manager, - const buzz::XmlElement* stanza) { - buzz::XmlElement* elem = new buzz::XmlElement(*stanza); - EXPECT_TRUE(elem->Name() == buzz::QN_IQ); - EXPECT_TRUE(elem->HasAttr(buzz::QN_TO)); - EXPECT_FALSE(elem->HasAttr(buzz::QN_FROM)); - EXPECT_TRUE(elem->HasAttr(buzz::QN_TYPE)); - EXPECT_TRUE((elem->Attr(buzz::QN_TYPE) == "set") || - (elem->Attr(buzz::QN_TYPE) == "result") || - (elem->Attr(buzz::QN_TYPE) == "error")); - - elem->SetAttr(buzz::QN_FROM, local_name); - if (elem->Attr(buzz::QN_TYPE) == "set") { - EXPECT_FALSE(elem->HasAttr(buzz::QN_ID)); - elem->SetAttr(buzz::QN_ID, GetNextOutgoingMessageID()); - } - - // Uncommenting this is useful for debugging. - // PrintStanza("OutgoingMessage", elem); - sent_stanzas.push_back(elem); - } - - std::string GetNextOutgoingMessageID() { - int message_id = (*next_message_id)++; - std::ostringstream ost; - ost << message_id; - return ost.str(); - } - - void CreateChannels() { - ASSERT(session != NULL); - // We either have a single content with multiple components (RTP/RTCP), or - // multiple contents with single components, but not both. - int component_a = 1; - int component_b = (content_name_a == content_name_b) ? 2 : 1; - chan_a.reset(new ChannelHandler( - session->CreateChannel(content_name_a, channel_name_a, component_a), - channel_name_a)); - chan_b.reset(new ChannelHandler( - session->CreateChannel(content_name_b, channel_name_b, component_b), - channel_name_b)); - } - - int* next_message_id; - std::string local_name; - SignalingProtocol start_protocol; - std::string content_type; - std::string content_name_a; - std::string channel_name_a; - std::string content_name_b; - std::string channel_name_b; - - uint32 session_created_count; - uint32 session_destroyed_count; - uint32 session_remote_description_update_count; - bool new_local_description; - bool new_remote_description; - cricket::ContentAction last_content_action; - cricket::ContentSource last_content_source; - std::deque<buzz::XmlElement*> sent_stanzas; - rtc::scoped_ptr<buzz::XmlElement> last_expected_sent_stanza; - - cricket::SessionManager* session_manager; - TestSessionClient* client; - cricket::PortAllocator* port_allocator_; - cricket::Session* session; - cricket::BaseSession::State last_session_state; - rtc::scoped_ptr<ChannelHandler> chan_a; - rtc::scoped_ptr<ChannelHandler> chan_b; - bool blow_up_on_error; - int error_count; -}; - -class SessionTest : public testing::Test { - protected: - virtual void SetUp() { - // Seed needed for each test to satisfy expectations. - rtc::SetRandomTestMode(true); - } - - virtual void TearDown() { - rtc::SetRandomTestMode(false); - } - - // Tests sending data between two clients, over two channels. - void TestSendRecv(ChannelHandler* chan1a, - ChannelHandler* chan1b, - ChannelHandler* chan2a, - ChannelHandler* chan2b) { - const char* dat1a = "spamspamspamspamspamspamspambakedbeansspam"; - const char* dat2a = "mapssnaebdekabmapsmapsmapsmapsmapsmapsmaps"; - const char* dat1b = "Lobster Thermidor a Crevette with a mornay sauce..."; - const char* dat2b = "...ecuas yanrom a htiw etteverC a rodimrehT retsboL"; - - for (int i = 0; i < 20; i++) { - chan1a->Send(dat1a, strlen(dat1a)); - chan1b->Send(dat1b, strlen(dat1b)); - chan2a->Send(dat2a, strlen(dat2a)); - chan2b->Send(dat2b, strlen(dat2b)); - - EXPECT_EQ_WAIT(i + 1, chan1a->data_count, kEventTimeout); - EXPECT_EQ_WAIT(i + 1, chan1b->data_count, kEventTimeout); - EXPECT_EQ_WAIT(i + 1, chan2a->data_count, kEventTimeout); - EXPECT_EQ_WAIT(i + 1, chan2b->data_count, kEventTimeout); - - EXPECT_EQ(strlen(dat2a), chan1a->last_size); - EXPECT_EQ(strlen(dat2b), chan1b->last_size); - EXPECT_EQ(strlen(dat1a), chan2a->last_size); - EXPECT_EQ(strlen(dat1b), chan2b->last_size); - - EXPECT_EQ(0, memcmp(chan1a->last_data, dat2a, strlen(dat2a))); - EXPECT_EQ(0, memcmp(chan1b->last_data, dat2b, strlen(dat2b))); - EXPECT_EQ(0, memcmp(chan2a->last_data, dat1a, strlen(dat1a))); - EXPECT_EQ(0, memcmp(chan2b->last_data, dat1b, strlen(dat1b))); - } - } - - // Test an initiate from one client to another, each with - // independent initial protocols. Checks for the correct initiates, - // candidates, and accept messages, and tests that working network - // channels are established. - void TestSession(SignalingProtocol initiator_protocol, - SignalingProtocol responder_protocol, - SignalingProtocol resulting_protocol, - const std::string& gingle_content_type, - const std::string& content_type, - const std::string& content_name_a, - const std::string& channel_name_a, - const std::string& content_name_b, - const std::string& channel_name_b, - const std::string& initiate_xml, - const std::string& transport_info_a_xml, - const std::string& transport_info_b_xml, - const std::string& transport_info_reply_a_xml, - const std::string& transport_info_reply_b_xml, - const std::string& accept_xml, - bool bundle = false) { - rtc::scoped_ptr<cricket::PortAllocator> allocator( - new TestPortAllocator()); - int next_message_id = 0; - - rtc::scoped_ptr<TestClient> initiator( - new TestClient(allocator.get(), &next_message_id, - kInitiator, initiator_protocol, - content_type, - content_name_a, channel_name_a, - content_name_b, channel_name_b)); - rtc::scoped_ptr<TestClient> responder( - new TestClient(allocator.get(), &next_message_id, - kResponder, responder_protocol, - content_type, - content_name_a, channel_name_a, - content_name_b, channel_name_b)); - - // Create Session and check channels and state. - initiator->CreateSession(); - EXPECT_EQ(1U, initiator->session_created_count); - EXPECT_EQ(kSessionId, initiator->session->id()); - EXPECT_EQ(initiator->session->local_name(), kInitiator); - EXPECT_EQ(cricket::BaseSession::STATE_INIT, - initiator->session_state()); - - // See comment in CreateChannels about how we choose component IDs. - int component_a = 1; - int component_b = (content_name_a == content_name_b) ? 2 : 1; - EXPECT_TRUE(initiator->HasTransport(content_name_a)); - EXPECT_TRUE(initiator->HasChannel(content_name_a, component_a)); - EXPECT_TRUE(initiator->HasTransport(content_name_b)); - EXPECT_TRUE(initiator->HasChannel(content_name_b, component_b)); - - // Initiate and expect initiate message sent. - cricket::SessionDescription* offer = NewTestSessionDescription( - gingle_content_type, - content_name_a, content_type, - content_name_b, content_type); - if (bundle) { - cricket::ContentGroup group(cricket::GROUP_TYPE_BUNDLE); - group.AddContentName(content_name_a); - group.AddContentName(content_name_b); - EXPECT_TRUE(group.HasContentName(content_name_a)); - EXPECT_TRUE(group.HasContentName(content_name_b)); - offer->AddGroup(group); - } - EXPECT_TRUE(initiator->session->Initiate(kResponder, offer)); - EXPECT_EQ(initiator->session->remote_name(), kResponder); - EXPECT_EQ(initiator->session->local_description(), offer); - - EXPECT_TRUE_WAIT(initiator->sent_stanza_count() > 0, kEventTimeout); - EXPECT_EQ(cricket::BaseSession::STATE_SENTINITIATE, - initiator->session_state()); - - initiator->ExpectSentStanza( - IqSet("0", kInitiator, kResponder, initiate_xml)); - - // Deliver the initiate. Expect ack and session created with - // transports. - responder->DeliverStanza(initiator->stanza()); - responder->ExpectSentStanza( - IqAck("0", kResponder, kInitiator)); - EXPECT_EQ(0U, responder->sent_stanza_count()); - - EXPECT_EQ(1U, responder->session_created_count); - EXPECT_EQ(kSessionId, responder->session->id()); - EXPECT_EQ(responder->session->local_name(), kResponder); - EXPECT_EQ(responder->session->remote_name(), kInitiator); - EXPECT_EQ(cricket::BaseSession::STATE_RECEIVEDINITIATE, - responder->session_state()); - - EXPECT_TRUE(responder->HasTransport(content_name_a)); - EXPECT_TRUE(responder->HasChannel(content_name_a, component_a)); - EXPECT_TRUE(responder->HasTransport(content_name_b)); - EXPECT_TRUE(responder->HasChannel(content_name_b, component_b)); - - // Expect transport-info message from initiator. - // But don't send candidates until initiate ack is received. - initiator->PrepareCandidates(); - WAIT(initiator->sent_stanza_count() > 0, 100); - EXPECT_EQ(0U, initiator->sent_stanza_count()); - initiator->DeliverAckToLastStanza(); - EXPECT_TRUE_WAIT(initiator->sent_stanza_count() > 0, kEventTimeout); - initiator->ExpectSentStanza( - IqSet("1", kInitiator, kResponder, transport_info_a_xml)); - - // Deliver transport-info and expect ack. - responder->DeliverStanza(initiator->stanza()); - responder->ExpectSentStanza( - IqAck("1", kResponder, kInitiator)); - - if (!transport_info_b_xml.empty()) { - // Expect second transport-info message from initiator. - EXPECT_TRUE_WAIT(initiator->sent_stanza_count() > 0, kEventTimeout); - initiator->ExpectSentStanza( - IqSet("2", kInitiator, kResponder, transport_info_b_xml)); - EXPECT_EQ(0U, initiator->sent_stanza_count()); - - // Deliver second transport-info message and expect ack. - responder->DeliverStanza(initiator->stanza()); - responder->ExpectSentStanza( - IqAck("2", kResponder, kInitiator)); - } else { - EXPECT_EQ(0U, initiator->sent_stanza_count()); - EXPECT_EQ(0U, responder->sent_stanza_count()); - initiator->SkipUnsentStanza(); - } - - // Expect reply transport-info message from responder. - responder->PrepareCandidates(); - EXPECT_TRUE_WAIT(responder->sent_stanza_count() > 0, kEventTimeout); - responder->ExpectSentStanza( - IqSet("3", kResponder, kInitiator, transport_info_reply_a_xml)); - - // Deliver reply transport-info and expect ack. - initiator->DeliverStanza(responder->stanza()); - initiator->ExpectSentStanza( - IqAck("3", kInitiator, kResponder)); - - if (!transport_info_reply_b_xml.empty()) { - // Expect second reply transport-info message from responder. - EXPECT_TRUE_WAIT(responder->sent_stanza_count() > 0, kEventTimeout); - responder->ExpectSentStanza( - IqSet("4", kResponder, kInitiator, transport_info_reply_b_xml)); - EXPECT_EQ(0U, responder->sent_stanza_count()); - - // Deliver second reply transport-info message and expect ack. - initiator->DeliverStanza(responder->stanza()); - initiator->ExpectSentStanza( - IqAck("4", kInitiator, kResponder)); - EXPECT_EQ(0U, initiator->sent_stanza_count()); - } else { - EXPECT_EQ(0U, initiator->sent_stanza_count()); - EXPECT_EQ(0U, responder->sent_stanza_count()); - responder->SkipUnsentStanza(); - } - - // The channels should be able to become writable at this point. This - // requires pinging, so it may take a little while. - EXPECT_TRUE_WAIT(initiator->chan_a->writable() && - initiator->chan_a->readable(), kEventTimeout); - EXPECT_TRUE_WAIT(initiator->chan_b->writable() && - initiator->chan_b->readable(), kEventTimeout); - EXPECT_TRUE_WAIT(responder->chan_a->writable() && - responder->chan_a->readable(), kEventTimeout); - EXPECT_TRUE_WAIT(responder->chan_b->writable() && - responder->chan_b->readable(), kEventTimeout); - - // Accept the session and expect accept stanza. - cricket::SessionDescription* answer = NewTestSessionDescription( - gingle_content_type, - content_name_a, content_type, - content_name_b, content_type); - if (bundle) { - cricket::ContentGroup group(cricket::GROUP_TYPE_BUNDLE); - group.AddContentName(content_name_a); - group.AddContentName(content_name_b); - EXPECT_TRUE(group.HasContentName(content_name_a)); - EXPECT_TRUE(group.HasContentName(content_name_b)); - answer->AddGroup(group); - } - EXPECT_TRUE(responder->session->Accept(answer)); - EXPECT_EQ(responder->session->local_description(), answer); - - responder->ExpectSentStanza( - IqSet("5", kResponder, kInitiator, accept_xml)); - - EXPECT_EQ(0U, responder->sent_stanza_count()); - - // Deliver the accept message and expect an ack. - initiator->DeliverStanza(responder->stanza()); - EXPECT_TRUE_WAIT(initiator->sent_stanza_count() > 0, kEventTimeout); - initiator->ExpectSentStanza( - IqAck("5", kInitiator, kResponder)); - EXPECT_EQ(0U, initiator->sent_stanza_count()); - - // Both sessions should be in progress and have functioning - // channels. - EXPECT_EQ(resulting_protocol, initiator->session->current_protocol()); - EXPECT_EQ(resulting_protocol, responder->session->current_protocol()); - EXPECT_EQ_WAIT(cricket::BaseSession::STATE_INPROGRESS, - initiator->session_state(), kEventTimeout); - EXPECT_EQ_WAIT(cricket::BaseSession::STATE_INPROGRESS, - responder->session_state(), kEventTimeout); - if (bundle) { - cricket::TransportChannel* initiator_chan_a = initiator->chan_a->channel; - cricket::TransportChannel* initiator_chan_b = initiator->chan_b->channel; - - // Since we know these are TransportChannelProxy, type cast it. - cricket::TransportChannelProxy* initiator_proxy_chan_a = - static_cast<cricket::TransportChannelProxy*>(initiator_chan_a); - cricket::TransportChannelProxy* initiator_proxy_chan_b = - static_cast<cricket::TransportChannelProxy*>(initiator_chan_b); - EXPECT_TRUE(initiator_proxy_chan_a->impl() != NULL); - EXPECT_TRUE(initiator_proxy_chan_b->impl() != NULL); - EXPECT_EQ(initiator_proxy_chan_a->impl(), initiator_proxy_chan_b->impl()); - - cricket::TransportChannel* responder_chan_a = responder->chan_a->channel; - cricket::TransportChannel* responder_chan_b = responder->chan_b->channel; - - // Since we know these are TransportChannelProxy, type cast it. - cricket::TransportChannelProxy* responder_proxy_chan_a = - static_cast<cricket::TransportChannelProxy*>(responder_chan_a); - cricket::TransportChannelProxy* responder_proxy_chan_b = - static_cast<cricket::TransportChannelProxy*>(responder_chan_b); - EXPECT_TRUE(responder_proxy_chan_a->impl() != NULL); - EXPECT_TRUE(responder_proxy_chan_b->impl() != NULL); - EXPECT_EQ(responder_proxy_chan_a->impl(), responder_proxy_chan_b->impl()); - } - TestSendRecv(initiator->chan_a.get(), initiator->chan_b.get(), - responder->chan_a.get(), responder->chan_b.get()); - - if (resulting_protocol == PROTOCOL_JINGLE) { - // Deliver a description-info message to the initiator and check if the - // content description changes. - EXPECT_EQ(0U, initiator->session_remote_description_update_count); - - const cricket::SessionDescription* old_session_desc = - initiator->session->remote_description(); - const cricket::ContentInfo* old_content_a = - old_session_desc->GetContentByName(content_name_a); - const cricket::ContentDescription* old_content_desc_a = - old_content_a->description; - const cricket::ContentInfo* old_content_b = - old_session_desc->GetContentByName(content_name_b); - const cricket::ContentDescription* old_content_desc_b = - old_content_b->description; - EXPECT_TRUE(old_content_desc_a != NULL); - EXPECT_TRUE(old_content_desc_b != NULL); - - LOG(LS_INFO) << "A " << old_content_a->name; - LOG(LS_INFO) << "B " << old_content_b->name; - - std::string description_info_xml = - JingleDescriptionInfoXml(content_name_a, content_type); - initiator->DeliverStanza( - IqSet("6", kResponder, kInitiator, description_info_xml)); - responder->SkipUnsentStanza(); - EXPECT_EQ(1U, initiator->session_remote_description_update_count); - - const cricket::SessionDescription* new_session_desc = - initiator->session->remote_description(); - const cricket::ContentInfo* new_content_a = - new_session_desc->GetContentByName(content_name_a); - const cricket::ContentDescription* new_content_desc_a = - new_content_a->description; - const cricket::ContentInfo* new_content_b = - new_session_desc->GetContentByName(content_name_b); - const cricket::ContentDescription* new_content_desc_b = - new_content_b->description; - EXPECT_TRUE(new_content_desc_a != NULL); - EXPECT_TRUE(new_content_desc_b != NULL); - - // TODO: We used to replace contents from an update, but - // that no longer works with partial updates. We need to figure out - // a way to merge patial updates into contents. For now, users of - // Session should listen to SignalRemoteDescriptionUpdate and handle - // updates. They should not expect remote_description to be the - // latest value. - // See session.cc OnDescriptionInfoMessage. - - // EXPECT_NE(old_content_desc_a, new_content_desc_a); - - // if (content_name_a != content_name_b) { - // // If content_name_a != content_name_b, then b's content description - // // should not have changed since the description-info message only - // // contained an update for content_name_a. - // EXPECT_EQ(old_content_desc_b, new_content_desc_b); - // } - - EXPECT_TRUE_WAIT(initiator->sent_stanza_count() > 0, kEventTimeout); - initiator->ExpectSentStanza( - IqAck("6", kInitiator, kResponder)); - EXPECT_EQ(0U, initiator->sent_stanza_count()); - } else { - responder->SkipUnsentStanza(); - } - - initiator->session->Terminate(); - initiator->ExpectSentStanza( - IqSet("7", kInitiator, kResponder, - TerminateXml(resulting_protocol, - cricket::STR_TERMINATE_SUCCESS))); - - responder->DeliverStanza(initiator->stanza()); - responder->ExpectSentStanza( - IqAck("7", kResponder, kInitiator)); - EXPECT_EQ(cricket::BaseSession::STATE_SENTTERMINATE, - initiator->session_state()); - EXPECT_EQ(cricket::BaseSession::STATE_RECEIVEDTERMINATE, - responder->session_state()); - } - - // Test an initiate with other content, called "main". - void TestOtherContent(SignalingProtocol initiator_protocol, - SignalingProtocol responder_protocol, - SignalingProtocol resulting_protocol) { - std::string content_name = "main"; - std::string content_type = "http://oink.splat/session"; - std::string content_name_a = content_name; - std::string channel_name_a = "rtp"; - std::string content_name_b = content_name; - std::string channel_name_b = "rtcp"; - std::string initiate_xml = InitiateXml( - initiator_protocol, - content_name_a, content_type); - std::string transport_info_a_xml = TransportInfo4Xml( - initiator_protocol, content_name, - channel_name_a, 0, 1, - channel_name_b, 2, 3); - std::string transport_info_b_xml = ""; - std::string transport_info_reply_a_xml = TransportInfo4Xml( - resulting_protocol, content_name, - channel_name_a, 4, 5, - channel_name_b, 6, 7); - std::string transport_info_reply_b_xml = ""; - std::string accept_xml = AcceptXml( - resulting_protocol, - content_name_a, content_type); - - - TestSession(initiator_protocol, responder_protocol, resulting_protocol, - content_type, - content_type, - content_name_a, channel_name_a, - content_name_b, channel_name_b, - initiate_xml, - transport_info_a_xml, transport_info_b_xml, - transport_info_reply_a_xml, transport_info_reply_b_xml, - accept_xml); - } - - // Test an initiate with audio content. - void TestAudioContent(SignalingProtocol initiator_protocol, - SignalingProtocol responder_protocol, - SignalingProtocol resulting_protocol) { - std::string gingle_content_type = cricket::NS_GINGLE_AUDIO; - std::string content_name = cricket::CN_AUDIO; - std::string content_type = cricket::NS_JINGLE_RTP; - std::string channel_name_a = "rtp"; - std::string channel_name_b = "rtcp"; - std::string initiate_xml = InitiateXml( - initiator_protocol, - gingle_content_type, - content_name, content_type, - "", ""); - std::string transport_info_a_xml = TransportInfo4Xml( - initiator_protocol, content_name, - channel_name_a, 0, 1, - channel_name_b, 2, 3); - std::string transport_info_b_xml = ""; - std::string transport_info_reply_a_xml = TransportInfo4Xml( - resulting_protocol, content_name, - channel_name_a, 4, 5, - channel_name_b, 6, 7); - std::string transport_info_reply_b_xml = ""; - std::string accept_xml = AcceptXml( - resulting_protocol, - gingle_content_type, - content_name, content_type, - "", ""); - - - TestSession(initiator_protocol, responder_protocol, resulting_protocol, - gingle_content_type, - content_type, - content_name, channel_name_a, - content_name, channel_name_b, - initiate_xml, - transport_info_a_xml, transport_info_b_xml, - transport_info_reply_a_xml, transport_info_reply_b_xml, - accept_xml); - } - - // Since media content is "split" into two contents (audio and - // video), we need to treat it special. - void TestVideoContents(SignalingProtocol initiator_protocol, - SignalingProtocol responder_protocol, - SignalingProtocol resulting_protocol) { - std::string content_type = cricket::NS_JINGLE_RTP; - std::string gingle_content_type = cricket::NS_GINGLE_VIDEO; - std::string content_name_a = cricket::CN_AUDIO; - std::string channel_name_a = "rtp"; - std::string content_name_b = cricket::CN_VIDEO; - std::string channel_name_b = "video_rtp"; - - std::string initiate_xml = InitiateXml( - initiator_protocol, - gingle_content_type, - content_name_a, content_type, - content_name_b, content_type); - std::string transport_info_a_xml = TransportInfo2Xml( - initiator_protocol, content_name_a, - channel_name_a, 0, 1); - std::string transport_info_b_xml = TransportInfo2Xml( - initiator_protocol, content_name_b, - channel_name_b, 2, 3); - std::string transport_info_reply_a_xml = TransportInfo2Xml( - resulting_protocol, content_name_a, - channel_name_a, 4, 5); - std::string transport_info_reply_b_xml = TransportInfo2Xml( - resulting_protocol, content_name_b, - channel_name_b, 6, 7); - std::string accept_xml = AcceptXml( - resulting_protocol, - gingle_content_type, - content_name_a, content_type, - content_name_b, content_type); - - TestSession(initiator_protocol, responder_protocol, resulting_protocol, - gingle_content_type, - content_type, - content_name_a, channel_name_a, - content_name_b, channel_name_b, - initiate_xml, - transport_info_a_xml, transport_info_b_xml, - transport_info_reply_a_xml, transport_info_reply_b_xml, - accept_xml); - } - - void TestBadRedirect(SignalingProtocol protocol) { - std::string content_name = "main"; - std::string content_type = "http://oink.splat/session"; - std::string channel_name_a = "chana"; - std::string channel_name_b = "chanb"; - std::string initiate_xml = InitiateXml( - protocol, content_name, content_type); - std::string transport_info_xml = TransportInfo4Xml( - protocol, content_name, - channel_name_a, 0, 1, - channel_name_b, 2, 3); - std::string transport_info_reply_xml = TransportInfo4Xml( - protocol, content_name, - channel_name_a, 4, 5, - channel_name_b, 6, 7); - std::string accept_xml = AcceptXml( - protocol, content_name, content_type); - std::string responder_full = kResponder + "/full"; - - rtc::scoped_ptr<cricket::PortAllocator> allocator( - new TestPortAllocator()); - int next_message_id = 0; - - rtc::scoped_ptr<TestClient> initiator( - new TestClient(allocator.get(), &next_message_id, - kInitiator, protocol, - content_type, - content_name, channel_name_a, - content_name, channel_name_b)); - - rtc::scoped_ptr<TestClient> responder( - new TestClient(allocator.get(), &next_message_id, - responder_full, protocol, - content_type, - content_name, channel_name_a, - content_name, channel_name_b)); - - // Create Session and check channels and state. - initiator->CreateSession(); - EXPECT_EQ(1U, initiator->session_created_count); - EXPECT_EQ(kSessionId, initiator->session->id()); - EXPECT_EQ(initiator->session->local_name(), kInitiator); - EXPECT_EQ(cricket::BaseSession::STATE_INIT, - initiator->session_state()); - - EXPECT_TRUE(initiator->HasChannel(content_name, 1)); - EXPECT_TRUE(initiator->HasChannel(content_name, 2)); - - // Initiate and expect initiate message sent. - cricket::SessionDescription* offer = NewTestSessionDescription( - content_name, content_type); - EXPECT_TRUE(initiator->session->Initiate(kResponder, offer)); - EXPECT_EQ(initiator->session->remote_name(), kResponder); - EXPECT_EQ(initiator->session->local_description(), offer); - - EXPECT_TRUE_WAIT(initiator->sent_stanza_count() > 0, kEventTimeout); - EXPECT_EQ(cricket::BaseSession::STATE_SENTINITIATE, - initiator->session_state()); - initiator->ExpectSentStanza( - IqSet("0", kInitiator, kResponder, initiate_xml)); - - // Expect transport-info message from initiator. - initiator->DeliverAckToLastStanza(); - initiator->PrepareCandidates(); - EXPECT_TRUE_WAIT(initiator->sent_stanza_count() > 0, kEventTimeout); - initiator->ExpectSentStanza( - IqSet("1", kInitiator, kResponder, transport_info_xml)); - - // Send an unauthorized redirect to the initiator and expect it be ignored. - initiator->blow_up_on_error = false; - const buzz::XmlElement* initiate_stanza = initiator->stanza(); - rtc::scoped_ptr<buzz::XmlElement> redirect_stanza( - buzz::XmlElement::ForStr( - IqError("ER", kResponder, kInitiator, - RedirectXml(protocol, initiate_xml, "not@allowed.com")))); - initiator->session_manager->OnFailedSend( - initiate_stanza, redirect_stanza.get()); - EXPECT_EQ(initiator->session->remote_name(), kResponder); - initiator->blow_up_on_error = true; - EXPECT_EQ(initiator->error_count, 1); - } - - void TestGoodRedirect(SignalingProtocol protocol) { - std::string content_name = "main"; - std::string content_type = "http://oink.splat/session"; - std::string channel_name_a = "chana"; - std::string channel_name_b = "chanb"; - std::string initiate_xml = InitiateXml( - protocol, content_name, content_type); - std::string transport_info_xml = TransportInfo4Xml( - protocol, content_name, - channel_name_a, 0, 1, - channel_name_b, 2, 3); - std::string transport_info_reply_xml = TransportInfo4Xml( - protocol, content_name, - channel_name_a, 4, 5, - channel_name_b, 6, 7); - std::string accept_xml = AcceptXml( - protocol, content_name, content_type); - std::string responder_full = kResponder + "/full"; - - rtc::scoped_ptr<cricket::PortAllocator> allocator( - new TestPortAllocator()); - int next_message_id = 0; - - rtc::scoped_ptr<TestClient> initiator( - new TestClient(allocator.get(), &next_message_id, - kInitiator, protocol, - content_type, - content_name, channel_name_a, - content_name, channel_name_b)); - - rtc::scoped_ptr<TestClient> responder( - new TestClient(allocator.get(), &next_message_id, - responder_full, protocol, - content_type, - content_name, channel_name_a, - content_name, channel_name_b)); - - // Create Session and check channels and state. - initiator->CreateSession(); - EXPECT_EQ(1U, initiator->session_created_count); - EXPECT_EQ(kSessionId, initiator->session->id()); - EXPECT_EQ(initiator->session->local_name(), kInitiator); - EXPECT_EQ(cricket::BaseSession::STATE_INIT, - initiator->session_state()); - - EXPECT_TRUE(initiator->HasChannel(content_name, 1)); - EXPECT_TRUE(initiator->HasChannel(content_name, 2)); - - // Initiate and expect initiate message sent. - cricket::SessionDescription* offer = NewTestSessionDescription( - content_name, content_type); - EXPECT_TRUE(initiator->session->Initiate(kResponder, offer)); - EXPECT_EQ(initiator->session->remote_name(), kResponder); - EXPECT_EQ(initiator->session->local_description(), offer); - - EXPECT_TRUE_WAIT(initiator->sent_stanza_count() > 0, kEventTimeout); - EXPECT_EQ(cricket::BaseSession::STATE_SENTINITIATE, - initiator->session_state()); - initiator->ExpectSentStanza( - IqSet("0", kInitiator, kResponder, initiate_xml)); - - // Expect transport-info message from initiator. - initiator->DeliverAckToLastStanza(); - initiator->PrepareCandidates(); - EXPECT_TRUE_WAIT(initiator->sent_stanza_count() > 0, kEventTimeout); - initiator->ExpectSentStanza( - IqSet("1", kInitiator, kResponder, transport_info_xml)); - - // Send a redirect to the initiator and expect all of the message - // to be resent. - const buzz::XmlElement* initiate_stanza = initiator->stanza(); - rtc::scoped_ptr<buzz::XmlElement> redirect_stanza( - buzz::XmlElement::ForStr( - IqError("ER2", kResponder, kInitiator, - RedirectXml(protocol, initiate_xml, responder_full)))); - initiator->session_manager->OnFailedSend( - initiate_stanza, redirect_stanza.get()); - EXPECT_EQ(initiator->session->remote_name(), responder_full); - - EXPECT_TRUE_WAIT(initiator->sent_stanza_count() > 0, kEventTimeout); - initiator->ExpectSentStanza( - IqSet("2", kInitiator, responder_full, initiate_xml)); - initiator->ExpectSentStanza( - IqSet("3", kInitiator, responder_full, transport_info_xml)); - - // Deliver the initiate. Expect ack and session created with - // transports. - responder->DeliverStanza( - IqSet("2", kInitiator, responder_full, initiate_xml)); - responder->ExpectSentStanza( - IqAck("2", responder_full, kInitiator)); - EXPECT_EQ(0U, responder->sent_stanza_count()); - - EXPECT_EQ(1U, responder->session_created_count); - EXPECT_EQ(kSessionId, responder->session->id()); - EXPECT_EQ(responder->session->local_name(), responder_full); - EXPECT_EQ(responder->session->remote_name(), kInitiator); - EXPECT_EQ(cricket::BaseSession::STATE_RECEIVEDINITIATE, - responder->session_state()); - - EXPECT_TRUE(responder->HasChannel(content_name, 1)); - EXPECT_TRUE(responder->HasChannel(content_name, 2)); - - // Deliver transport-info and expect ack. - responder->DeliverStanza( - IqSet("3", kInitiator, responder_full, transport_info_xml)); - responder->ExpectSentStanza( - IqAck("3", responder_full, kInitiator)); - - // Expect reply transport-infos sent to new remote JID - responder->PrepareCandidates(); - EXPECT_TRUE_WAIT(responder->sent_stanza_count() > 0, kEventTimeout); - responder->ExpectSentStanza( - IqSet("4", responder_full, kInitiator, transport_info_reply_xml)); - - initiator->DeliverStanza(responder->stanza()); - initiator->ExpectSentStanza( - IqAck("4", kInitiator, responder_full)); - - // The channels should be able to become writable at this point. This - // requires pinging, so it may take a little while. - EXPECT_TRUE_WAIT(initiator->chan_a->writable() && - initiator->chan_a->readable(), kEventTimeout); - EXPECT_TRUE_WAIT(initiator->chan_b->writable() && - initiator->chan_b->readable(), kEventTimeout); - EXPECT_TRUE_WAIT(responder->chan_a->writable() && - responder->chan_a->readable(), kEventTimeout); - EXPECT_TRUE_WAIT(responder->chan_b->writable() && - responder->chan_b->readable(), kEventTimeout); - - // Accept the session and expect accept stanza. - cricket::SessionDescription* answer = NewTestSessionDescription( - content_name, content_type); - EXPECT_TRUE(responder->session->Accept(answer)); - EXPECT_EQ(responder->session->local_description(), answer); - - responder->ExpectSentStanza( - IqSet("5", responder_full, kInitiator, accept_xml)); - EXPECT_EQ(0U, responder->sent_stanza_count()); - - // Deliver the accept message and expect an ack. - initiator->DeliverStanza(responder->stanza()); - EXPECT_TRUE_WAIT(initiator->sent_stanza_count() > 0, kEventTimeout); - initiator->ExpectSentStanza( - IqAck("5", kInitiator, responder_full)); - EXPECT_EQ(0U, initiator->sent_stanza_count()); - - // Both sessions should be in progress and have functioning - // channels. - EXPECT_EQ_WAIT(cricket::BaseSession::STATE_INPROGRESS, - initiator->session_state(), kEventTimeout); - EXPECT_EQ_WAIT(cricket::BaseSession::STATE_INPROGRESS, - responder->session_state(), kEventTimeout); - TestSendRecv(initiator->chan_a.get(), initiator->chan_b.get(), - responder->chan_a.get(), responder->chan_b.get()); - } - - void TestCandidatesInInitiateAndAccept(const std::string& test_name) { - std::string content_name = "main"; - std::string content_type = "http://oink.splat/session"; - std::string channel_name_a = "rtp"; - std::string channel_name_b = "rtcp"; - cricket::SignalingProtocol protocol = PROTOCOL_JINGLE; - - rtc::scoped_ptr<cricket::PortAllocator> allocator( - new TestPortAllocator()); - int next_message_id = 0; - - rtc::scoped_ptr<TestClient> initiator( - new TestClient(allocator.get(), &next_message_id, - kInitiator, protocol, - content_type, - content_name, channel_name_a, - content_name, channel_name_b)); - - rtc::scoped_ptr<TestClient> responder( - new TestClient(allocator.get(), &next_message_id, - kResponder, protocol, - content_type, - content_name, channel_name_a, - content_name, channel_name_b)); - - // Create Session and check channels and state. - initiator->CreateSession(); - EXPECT_TRUE(initiator->HasTransport(content_name)); - EXPECT_TRUE(initiator->HasChannel(content_name, 1)); - EXPECT_TRUE(initiator->HasTransport(content_name)); - EXPECT_TRUE(initiator->HasChannel(content_name, 2)); - - // Initiate and expect initiate message sent. - cricket::SessionDescription* offer = NewTestSessionDescription( - content_name, content_type); - EXPECT_TRUE(initiator->session->Initiate(kResponder, offer)); - - EXPECT_TRUE_WAIT(initiator->sent_stanza_count() > 0, kEventTimeout); - EXPECT_EQ(cricket::BaseSession::STATE_SENTINITIATE, - initiator->session_state()); - initiator->ExpectSentStanza( - IqSet("0", kInitiator, kResponder, - InitiateXml(protocol, content_name, content_type))); - - // Fake the delivery the initiate and candidates together. - responder->DeliverStanza( - IqSet("A", kInitiator, kResponder, - JingleInitiateActionXml( - JingleContentXml( - content_name, content_type, kTransportType, - P2pCandidateXml(channel_name_a, 0) + - P2pCandidateXml(channel_name_a, 1) + - P2pCandidateXml(channel_name_b, 2) + - P2pCandidateXml(channel_name_b, 3))))); - responder->ExpectSentStanza( - IqAck("A", kResponder, kInitiator)); - EXPECT_EQ(0U, responder->sent_stanza_count()); - - EXPECT_EQ(1U, responder->session_created_count); - EXPECT_EQ(kSessionId, responder->session->id()); - EXPECT_EQ(responder->session->local_name(), kResponder); - EXPECT_EQ(responder->session->remote_name(), kInitiator); - EXPECT_EQ(cricket::BaseSession::STATE_RECEIVEDINITIATE, - responder->session_state()); - - EXPECT_TRUE(responder->HasTransport(content_name)); - EXPECT_TRUE(responder->HasChannel(content_name, 1)); - EXPECT_TRUE(responder->HasTransport(content_name)); - EXPECT_TRUE(responder->HasChannel(content_name, 2)); - - // Expect transport-info message from initiator. - // But don't send candidates until initiate ack is received. - initiator->DeliverAckToLastStanza(); - initiator->PrepareCandidates(); - EXPECT_TRUE_WAIT(initiator->sent_stanza_count() > 0, kEventTimeout); - initiator->ExpectSentStanza( - IqSet("1", kInitiator, kResponder, - TransportInfo4Xml(protocol, content_name, - channel_name_a, 0, 1, - channel_name_b, 2, 3))); - - responder->PrepareCandidates(); - EXPECT_TRUE_WAIT(responder->sent_stanza_count() > 0, kEventTimeout); - responder->ExpectSentStanza( - IqSet("2", kResponder, kInitiator, - TransportInfo4Xml(protocol, content_name, - channel_name_a, 4, 5, - channel_name_b, 6, 7))); - - // Accept the session and expect accept stanza. - cricket::SessionDescription* answer = NewTestSessionDescription( - content_name, content_type); - EXPECT_TRUE(responder->session->Accept(answer)); - - responder->ExpectSentStanza( - IqSet("3", kResponder, kInitiator, - AcceptXml(protocol, content_name, content_type))); - EXPECT_EQ(0U, responder->sent_stanza_count()); - - // Fake the delivery the accept and candidates together. - initiator->DeliverStanza( - IqSet("B", kResponder, kInitiator, - JingleActionXml("session-accept", - JingleContentXml( - content_name, content_type, kTransportType, - P2pCandidateXml(channel_name_a, 4) + - P2pCandidateXml(channel_name_a, 5) + - P2pCandidateXml(channel_name_b, 6) + - P2pCandidateXml(channel_name_b, 7))))); - EXPECT_TRUE_WAIT(initiator->sent_stanza_count() > 0, kEventTimeout); - initiator->ExpectSentStanza( - IqAck("B", kInitiator, kResponder)); - EXPECT_EQ(0U, initiator->sent_stanza_count()); - - // The channels should be able to become writable at this point. This - // requires pinging, so it may take a little while. - EXPECT_TRUE_WAIT(initiator->chan_a->writable() && - initiator->chan_a->readable(), kEventTimeout); - EXPECT_TRUE_WAIT(initiator->chan_b->writable() && - initiator->chan_b->readable(), kEventTimeout); - EXPECT_TRUE_WAIT(responder->chan_a->writable() && - responder->chan_a->readable(), kEventTimeout); - EXPECT_TRUE_WAIT(responder->chan_b->writable() && - responder->chan_b->readable(), kEventTimeout); - - - // Both sessions should be in progress and have functioning - // channels. - EXPECT_EQ(protocol, initiator->session->current_protocol()); - EXPECT_EQ(protocol, responder->session->current_protocol()); - EXPECT_EQ_WAIT(cricket::BaseSession::STATE_INPROGRESS, - initiator->session_state(), kEventTimeout); - EXPECT_EQ_WAIT(cricket::BaseSession::STATE_INPROGRESS, - responder->session_state(), kEventTimeout); - TestSendRecv(initiator->chan_a.get(), initiator->chan_b.get(), - responder->chan_a.get(), responder->chan_b.get()); - } - - // Tests that when an initiator terminates right after initiate, - // everything behaves correctly. - void TestEarlyTerminationFromInitiator(SignalingProtocol protocol) { - std::string content_name = "main"; - std::string content_type = "http://oink.splat/session"; - - rtc::scoped_ptr<cricket::PortAllocator> allocator( - new TestPortAllocator()); - int next_message_id = 0; - - rtc::scoped_ptr<TestClient> initiator( - new TestClient(allocator.get(), &next_message_id, - kInitiator, protocol, - content_type, - content_name, "a", - content_name, "b")); - - rtc::scoped_ptr<TestClient> responder( - new TestClient(allocator.get(), &next_message_id, - kResponder, protocol, - content_type, - content_name, "a", - content_name, "b")); - - // Send initiate - initiator->CreateSession(); - EXPECT_TRUE(initiator->session->Initiate( - kResponder, NewTestSessionDescription(content_name, content_type))); - initiator->ExpectSentStanza( - IqSet("0", kInitiator, kResponder, - InitiateXml(protocol, content_name, content_type))); - EXPECT_EQ(cricket::BaseSession::STATE_SENTINITIATE, - initiator->session_state()); - - responder->DeliverStanza(initiator->stanza()); - responder->ExpectSentStanza( - IqAck("0", kResponder, kInitiator)); - EXPECT_EQ(cricket::BaseSession::STATE_RECEIVEDINITIATE, - responder->session_state()); - - initiator->session->TerminateWithReason(cricket::STR_TERMINATE_ERROR); - initiator->ExpectSentStanza( - IqSet("1", kInitiator, kResponder, - TerminateXml(protocol, cricket::STR_TERMINATE_ERROR))); - EXPECT_EQ(cricket::BaseSession::STATE_SENTTERMINATE, - initiator->session_state()); - - responder->DeliverStanza(initiator->stanza()); - responder->ExpectSentStanza( - IqAck("1", kResponder, kInitiator)); - EXPECT_EQ(cricket::BaseSession::STATE_RECEIVEDTERMINATE, - responder->session_state()); - } - - // Tests that when the responder rejects, everything behaves - // correctly. - void TestRejection(SignalingProtocol protocol) { - std::string content_name = "main"; - std::string content_type = "http://oink.splat/session"; - - rtc::scoped_ptr<cricket::PortAllocator> allocator( - new TestPortAllocator()); - int next_message_id = 0; - - rtc::scoped_ptr<TestClient> initiator( - new TestClient(allocator.get(), &next_message_id, - kInitiator, protocol, - content_type, - content_name, "a", - content_name, "b")); - - // Send initiate - initiator->CreateSession(); - EXPECT_TRUE(initiator->session->Initiate( - kResponder, NewTestSessionDescription(content_name, content_type))); - initiator->ExpectSentStanza( - IqSet("0", kInitiator, kResponder, - InitiateXml(protocol, content_name, content_type))); - EXPECT_EQ(cricket::BaseSession::STATE_SENTINITIATE, - initiator->session_state()); - - initiator->DeliverStanza( - IqSet("1", kResponder, kInitiator, - RejectXml(protocol, cricket::STR_TERMINATE_ERROR))); - initiator->ExpectSentStanza( - IqAck("1", kInitiator, kResponder)); - if (protocol == PROTOCOL_JINGLE) { - EXPECT_EQ(cricket::BaseSession::STATE_RECEIVEDTERMINATE, - initiator->session_state()); - } else { - EXPECT_EQ(cricket::BaseSession::STATE_RECEIVEDREJECT, - initiator->session_state()); - } - } - - void TestTransportMux() { - SignalingProtocol initiator_protocol = PROTOCOL_JINGLE; - SignalingProtocol responder_protocol = PROTOCOL_JINGLE; - SignalingProtocol resulting_protocol = PROTOCOL_JINGLE; - std::string content_type = cricket::NS_JINGLE_RTP; - std::string gingle_content_type = cricket::NS_GINGLE_VIDEO; - std::string content_name_a = cricket::CN_AUDIO; - std::string channel_name_a = "rtp"; - std::string content_name_b = cricket::CN_VIDEO; - std::string channel_name_b = "video_rtp"; - - std::string initiate_xml = InitiateXml( - initiator_protocol, - gingle_content_type, - content_name_a, content_type, - content_name_b, content_type, true); - std::string transport_info_a_xml = TransportInfo2Xml( - initiator_protocol, content_name_a, - channel_name_a, 0, 1); - std::string transport_info_b_xml = TransportInfo2Xml( - initiator_protocol, content_name_b, - channel_name_b, 2, 3); - std::string transport_info_reply_a_xml = TransportInfo2Xml( - resulting_protocol, content_name_a, - channel_name_a, 4, 5); - std::string transport_info_reply_b_xml = TransportInfo2Xml( - resulting_protocol, content_name_b, - channel_name_b, 6, 7); - std::string accept_xml = AcceptXml( - resulting_protocol, - gingle_content_type, - content_name_a, content_type, - content_name_b, content_type, true); - - TestSession(initiator_protocol, responder_protocol, resulting_protocol, - gingle_content_type, - content_type, - content_name_a, channel_name_a, - content_name_b, channel_name_b, - initiate_xml, - transport_info_a_xml, transport_info_b_xml, - transport_info_reply_a_xml, transport_info_reply_b_xml, - accept_xml, - true); - } - - void TestSendDescriptionInfo() { - rtc::scoped_ptr<cricket::PortAllocator> allocator( - new TestPortAllocator()); - int next_message_id = 0; - - std::string content_name = "content-name"; - std::string content_type = "content-type"; - rtc::scoped_ptr<TestClient> initiator( - new TestClient(allocator.get(), &next_message_id, - kInitiator, PROTOCOL_JINGLE, - content_type, - content_name, "", - "", "")); - - initiator->CreateSession(); - cricket::SessionDescription* offer = NewTestSessionDescription( - content_name, content_type); - std::string initiate_xml = InitiateXml( - PROTOCOL_JINGLE, content_name, content_type); - - cricket::ContentInfos contents; - TestContentDescription content(content_type, content_type); - contents.push_back( - cricket::ContentInfo(content_name, content_type, &content)); - std::string description_info_xml = JingleDescriptionInfoXml( - content_name, content_type); - - EXPECT_TRUE(initiator->session->Initiate(kResponder, offer)); - initiator->ExpectSentStanza( - IqSet("0", kInitiator, kResponder, initiate_xml)); - - EXPECT_TRUE(initiator->session->SendDescriptionInfoMessage(contents)); - initiator->ExpectSentStanza( - IqSet("1", kInitiator, kResponder, description_info_xml)); - } - - void DoTestSignalNewDescription( - TestClient* client, - cricket::BaseSession::State state, - cricket::ContentAction expected_content_action, - cricket::ContentSource expected_content_source) { - // Clean up before the new test. - client->new_local_description = false; - client->new_remote_description = false; - - client->SetSessionState(state); - EXPECT_EQ((expected_content_source == cricket::CS_LOCAL), - client->new_local_description); - EXPECT_EQ((expected_content_source == cricket::CS_REMOTE), - client->new_remote_description); - EXPECT_EQ(expected_content_action, client->last_content_action); - EXPECT_EQ(expected_content_source, client->last_content_source); - } - - void TestCallerSignalNewDescription() { - rtc::scoped_ptr<cricket::PortAllocator> allocator( - new TestPortAllocator()); - int next_message_id = 0; - - std::string content_name = "content-name"; - std::string content_type = "content-type"; - rtc::scoped_ptr<TestClient> initiator( - new TestClient(allocator.get(), &next_message_id, - kInitiator, PROTOCOL_JINGLE, - content_type, - content_name, "", - "", "")); - - initiator->CreateSession(); - - // send offer -> send update offer -> - // receive pr answer -> receive update pr answer -> - // receive answer - DoTestSignalNewDescription( - initiator.get(), cricket::BaseSession::STATE_SENTINITIATE, - cricket::CA_OFFER, cricket::CS_LOCAL); - - DoTestSignalNewDescription( - initiator.get(), cricket::BaseSession::STATE_SENTINITIATE, - cricket::CA_OFFER, cricket::CS_LOCAL); - - DoTestSignalNewDescription( - initiator.get(), cricket::BaseSession::STATE_RECEIVEDPRACCEPT, - cricket::CA_PRANSWER, cricket::CS_REMOTE); - - DoTestSignalNewDescription( - initiator.get(), cricket::BaseSession::STATE_RECEIVEDPRACCEPT, - cricket::CA_PRANSWER, cricket::CS_REMOTE); - - DoTestSignalNewDescription( - initiator.get(), cricket::BaseSession::STATE_RECEIVEDACCEPT, - cricket::CA_ANSWER, cricket::CS_REMOTE); - } - - void TestCalleeSignalNewDescription() { - rtc::scoped_ptr<cricket::PortAllocator> allocator( - new TestPortAllocator()); - int next_message_id = 0; - - std::string content_name = "content-name"; - std::string content_type = "content-type"; - rtc::scoped_ptr<TestClient> initiator( - new TestClient(allocator.get(), &next_message_id, - kInitiator, PROTOCOL_JINGLE, - content_type, - content_name, "", - "", "")); - - initiator->CreateSession(); - - // receive offer -> receive update offer -> - // send pr answer -> send update pr answer -> - // send answer - DoTestSignalNewDescription( - initiator.get(), cricket::BaseSession::STATE_RECEIVEDINITIATE, - cricket::CA_OFFER, cricket::CS_REMOTE); - - DoTestSignalNewDescription( - initiator.get(), cricket::BaseSession::STATE_RECEIVEDINITIATE, - cricket::CA_OFFER, cricket::CS_REMOTE); - - DoTestSignalNewDescription( - initiator.get(), cricket::BaseSession::STATE_SENTPRACCEPT, - cricket::CA_PRANSWER, cricket::CS_LOCAL); - - DoTestSignalNewDescription( - initiator.get(), cricket::BaseSession::STATE_SENTPRACCEPT, - cricket::CA_PRANSWER, cricket::CS_LOCAL); - - DoTestSignalNewDescription( - initiator.get(), cricket::BaseSession::STATE_SENTACCEPT, - cricket::CA_ANSWER, cricket::CS_LOCAL); - } - - void TestGetTransportStats() { - rtc::scoped_ptr<cricket::PortAllocator> allocator( - new TestPortAllocator()); - int next_message_id = 0; - - std::string content_name = "content-name"; - std::string content_type = "content-type"; - rtc::scoped_ptr<TestClient> initiator( - new TestClient(allocator.get(), &next_message_id, - kInitiator, PROTOCOL_JINGLE, - content_type, - content_name, "", - "", "")); - initiator->CreateSession(); - - cricket::SessionStats stats; - EXPECT_TRUE(initiator->session->GetStats(&stats)); - // At initiation, there are 2 transports. - EXPECT_EQ(2ul, stats.proxy_to_transport.size()); - EXPECT_EQ(2ul, stats.transport_stats.size()); - } -}; - -// For each of these, "X => Y = Z" means "if a client with protocol X -// initiates to a client with protocol Y, they end up speaking protocol Z. - -// Gingle => Gingle = Gingle (with other content) -TEST_F(SessionTest, GingleToGingleOtherContent) { - TestOtherContent(PROTOCOL_GINGLE, PROTOCOL_GINGLE, PROTOCOL_GINGLE); -} - -// Gingle => Gingle = Gingle (with audio content) -TEST_F(SessionTest, GingleToGingleAudioContent) { - TestAudioContent(PROTOCOL_GINGLE, PROTOCOL_GINGLE, PROTOCOL_GINGLE); -} - -// Gingle => Gingle = Gingle (with video contents) -TEST_F(SessionTest, GingleToGingleVideoContents) { - TestVideoContents(PROTOCOL_GINGLE, PROTOCOL_GINGLE, PROTOCOL_GINGLE); -} - -// Jingle => Jingle = Jingle (with other content) -TEST_F(SessionTest, JingleToJingleOtherContent) { - TestOtherContent(PROTOCOL_JINGLE, PROTOCOL_JINGLE, PROTOCOL_JINGLE); -} - -// Jingle => Jingle = Jingle (with audio content) -TEST_F(SessionTest, JingleToJingleAudioContent) { - TestAudioContent(PROTOCOL_JINGLE, PROTOCOL_JINGLE, PROTOCOL_JINGLE); -} - -// Jingle => Jingle = Jingle (with video contents) -TEST_F(SessionTest, JingleToJingleVideoContents) { - TestVideoContents(PROTOCOL_JINGLE, PROTOCOL_JINGLE, PROTOCOL_JINGLE); -} - -// Hybrid => Hybrid = Jingle (with other content) -TEST_F(SessionTest, HybridToHybridOtherContent) { - TestOtherContent(PROTOCOL_HYBRID, PROTOCOL_HYBRID, PROTOCOL_JINGLE); -} - -// Hybrid => Hybrid = Jingle (with audio content) -TEST_F(SessionTest, HybridToHybridAudioContent) { - TestAudioContent(PROTOCOL_HYBRID, PROTOCOL_HYBRID, PROTOCOL_JINGLE); -} - -// Hybrid => Hybrid = Jingle (with video contents) -TEST_F(SessionTest, HybridToHybridVideoContents) { - TestVideoContents(PROTOCOL_HYBRID, PROTOCOL_HYBRID, PROTOCOL_JINGLE); -} - -// Gingle => Hybrid = Gingle (with other content) -TEST_F(SessionTest, GingleToHybridOtherContent) { - TestOtherContent(PROTOCOL_GINGLE, PROTOCOL_HYBRID, PROTOCOL_GINGLE); -} - -// Gingle => Hybrid = Gingle (with audio content) -TEST_F(SessionTest, GingleToHybridAudioContent) { - TestAudioContent(PROTOCOL_GINGLE, PROTOCOL_HYBRID, PROTOCOL_GINGLE); -} - -// Gingle => Hybrid = Gingle (with video contents) -TEST_F(SessionTest, GingleToHybridVideoContents) { - TestVideoContents(PROTOCOL_GINGLE, PROTOCOL_HYBRID, PROTOCOL_GINGLE); -} - -// Jingle => Hybrid = Jingle (with other content) -TEST_F(SessionTest, JingleToHybridOtherContent) { - TestOtherContent(PROTOCOL_JINGLE, PROTOCOL_HYBRID, PROTOCOL_JINGLE); -} - -// Jingle => Hybrid = Jingle (with audio content) -TEST_F(SessionTest, JingleToHybridAudioContent) { - TestAudioContent(PROTOCOL_JINGLE, PROTOCOL_HYBRID, PROTOCOL_JINGLE); -} - -// Jingle => Hybrid = Jingle (with video contents) -TEST_F(SessionTest, JingleToHybridVideoContents) { - TestVideoContents(PROTOCOL_JINGLE, PROTOCOL_HYBRID, PROTOCOL_JINGLE); -} - -// Hybrid => Gingle = Gingle (with other content) -TEST_F(SessionTest, HybridToGingleOtherContent) { - TestOtherContent(PROTOCOL_HYBRID, PROTOCOL_GINGLE, PROTOCOL_GINGLE); -} - -// Hybrid => Gingle = Gingle (with audio content) -TEST_F(SessionTest, HybridToGingleAudioContent) { - TestAudioContent(PROTOCOL_HYBRID, PROTOCOL_GINGLE, PROTOCOL_GINGLE); -} - -// Hybrid => Gingle = Gingle (with video contents) -TEST_F(SessionTest, HybridToGingleVideoContents) { - TestVideoContents(PROTOCOL_HYBRID, PROTOCOL_GINGLE, PROTOCOL_GINGLE); -} - -// Hybrid => Jingle = Jingle (with other content) -TEST_F(SessionTest, HybridToJingleOtherContent) { - TestOtherContent(PROTOCOL_HYBRID, PROTOCOL_JINGLE, PROTOCOL_JINGLE); -} - -// Hybrid => Jingle = Jingle (with audio content) -TEST_F(SessionTest, HybridToJingleAudioContent) { - TestAudioContent(PROTOCOL_HYBRID, PROTOCOL_JINGLE, PROTOCOL_JINGLE); -} - -// Hybrid => Jingle = Jingle (with video contents) -TEST_F(SessionTest, HybridToJingleVideoContents) { - TestVideoContents(PROTOCOL_HYBRID, PROTOCOL_JINGLE, PROTOCOL_JINGLE); -} - -TEST_F(SessionTest, GingleEarlyTerminationFromInitiator) { - TestEarlyTerminationFromInitiator(PROTOCOL_GINGLE); -} - -TEST_F(SessionTest, JingleEarlyTerminationFromInitiator) { - TestEarlyTerminationFromInitiator(PROTOCOL_JINGLE); -} - -TEST_F(SessionTest, HybridEarlyTerminationFromInitiator) { - TestEarlyTerminationFromInitiator(PROTOCOL_HYBRID); -} - -TEST_F(SessionTest, GingleRejection) { - TestRejection(PROTOCOL_GINGLE); -} - -TEST_F(SessionTest, JingleRejection) { - TestRejection(PROTOCOL_JINGLE); -} - -TEST_F(SessionTest, GingleGoodRedirect) { - TestGoodRedirect(PROTOCOL_GINGLE); -} - -TEST_F(SessionTest, JingleGoodRedirect) { - TestGoodRedirect(PROTOCOL_JINGLE); -} - -TEST_F(SessionTest, GingleBadRedirect) { - TestBadRedirect(PROTOCOL_GINGLE); -} - -TEST_F(SessionTest, JingleBadRedirect) { - TestBadRedirect(PROTOCOL_JINGLE); -} - -TEST_F(SessionTest, TestCandidatesInInitiateAndAccept) { - TestCandidatesInInitiateAndAccept("Candidates in initiate/accept"); -} - -TEST_F(SessionTest, TestTransportMux) { - TestTransportMux(); -} - -TEST_F(SessionTest, TestSendDescriptionInfo) { - TestSendDescriptionInfo(); -} - -TEST_F(SessionTest, TestCallerSignalNewDescription) { - TestCallerSignalNewDescription(); -} - -TEST_F(SessionTest, TestCalleeSignalNewDescription) { - TestCalleeSignalNewDescription(); -} - -TEST_F(SessionTest, TestGetTransportStats) { - TestGetTransportStats(); -} diff --git a/talk/p2p/base/sessionclient.h b/talk/p2p/base/sessionclient.h deleted file mode 100644 index f7952f052..000000000 --- a/talk/p2p/base/sessionclient.h +++ /dev/null @@ -1,95 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef WEBRTC_P2P_BASE_SESSIONCLIENT_H_ -#define WEBRTC_P2P_BASE_SESSIONCLIENT_H_ - -#include "webrtc/p2p/base/constants.h" - -namespace buzz { -class XmlElement; -} - -namespace cricket { - -struct ParseError; -class Session; -class ContentDescription; - -class ContentParser { - public: - virtual bool ParseContent(SignalingProtocol protocol, - const buzz::XmlElement* elem, - ContentDescription** content, - ParseError* error) = 0; - // If not IsWriteable, then a given content should be "skipped" when - // writing in the given protocol, as if it didn't exist. We assume - // most things are writeable. We do this to avoid strange cases - // like data contents in Gingle, which aren't writable. - virtual bool IsWritable(SignalingProtocol protocol, - const ContentDescription* content) { - return true; - } - virtual bool WriteContent(SignalingProtocol protocol, - const ContentDescription* content, - buzz::XmlElement** elem, - WriteError* error) = 0; - virtual ~ContentParser() {} -}; - -// A SessionClient exists in 1-1 relation with each session. The implementor -// of this interface is the one that understands *what* the two sides are -// trying to send to one another. The lower-level layers only know how to send -// data; they do not know what is being sent. -class SessionClient : public ContentParser { - public: - // Notifies the client of the creation / destruction of sessions of this type. - // - // IMPORTANT: The SessionClient, in its handling of OnSessionCreate, must - // create whatever channels are indicate in the description. This is because - // the remote client may already be attempting to connect those channels. If - // we do not create our channel right away, then connection may fail or be - // delayed. - virtual void OnSessionCreate(Session* session, bool received_initiate) = 0; - virtual void OnSessionDestroy(Session* session) = 0; - - virtual bool ParseContent(SignalingProtocol protocol, - const buzz::XmlElement* elem, - ContentDescription** content, - ParseError* error) = 0; - virtual bool WriteContent(SignalingProtocol protocol, - const ContentDescription* content, - buzz::XmlElement** elem, - WriteError* error) = 0; - protected: - // The SessionClient interface explicitly does not include destructor - virtual ~SessionClient() { } -}; - -} // namespace cricket - -#endif // WEBRTC_P2P_BASE_SESSIONCLIENT_H_ diff --git a/talk/p2p/base/sessiondescription.cc b/talk/p2p/base/sessiondescription.cc deleted file mode 100644 index 57f08c9c1..000000000 --- a/talk/p2p/base/sessiondescription.cc +++ /dev/null @@ -1,239 +0,0 @@ -/* - * libjingle - * Copyright 2010, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "webrtc/p2p/base/sessiondescription.h" - -#include "webrtc/libjingle/xmllite/xmlelement.h" - -namespace cricket { - -ContentInfo* FindContentInfoByName( - ContentInfos& contents, const std::string& name) { - for (ContentInfos::iterator content = contents.begin(); - content != contents.end(); ++content) { - if (content->name == name) { - return &(*content); - } - } - return NULL; -} - -const ContentInfo* FindContentInfoByName( - const ContentInfos& contents, const std::string& name) { - for (ContentInfos::const_iterator content = contents.begin(); - content != contents.end(); ++content) { - if (content->name == name) { - return &(*content); - } - } - return NULL; -} - -const ContentInfo* FindContentInfoByType( - const ContentInfos& contents, const std::string& type) { - for (ContentInfos::const_iterator content = contents.begin(); - content != contents.end(); ++content) { - if (content->type == type) { - return &(*content); - } - } - return NULL; -} - -const std::string* ContentGroup::FirstContentName() const { - return (!content_names_.empty()) ? &(*content_names_.begin()) : NULL; -} - -bool ContentGroup::HasContentName(const std::string& content_name) const { - return (std::find(content_names_.begin(), content_names_.end(), - content_name) != content_names_.end()); -} - -void ContentGroup::AddContentName(const std::string& content_name) { - if (!HasContentName(content_name)) { - content_names_.push_back(content_name); - } -} - -bool ContentGroup::RemoveContentName(const std::string& content_name) { - ContentNames::iterator iter = std::find( - content_names_.begin(), content_names_.end(), content_name); - if (iter == content_names_.end()) { - return false; - } - content_names_.erase(iter); - return true; -} - -SessionDescription* SessionDescription::Copy() const { - SessionDescription* copy = new SessionDescription(*this); - // Copy all ContentDescriptions. - for (ContentInfos::iterator content = copy->contents_.begin(); - content != copy->contents().end(); ++content) { - content->description = content->description->Copy(); - } - return copy; -} - -const ContentInfo* SessionDescription::GetContentByName( - const std::string& name) const { - return FindContentInfoByName(contents_, name); -} - -ContentInfo* SessionDescription::GetContentByName( - const std::string& name) { - return FindContentInfoByName(contents_, name); -} - -const ContentDescription* SessionDescription::GetContentDescriptionByName( - const std::string& name) const { - const ContentInfo* cinfo = FindContentInfoByName(contents_, name); - if (cinfo == NULL) { - return NULL; - } - - return cinfo->description; -} - -ContentDescription* SessionDescription::GetContentDescriptionByName( - const std::string& name) { - ContentInfo* cinfo = FindContentInfoByName(contents_, name); - if (cinfo == NULL) { - return NULL; - } - - return cinfo->description; -} - -const ContentInfo* SessionDescription::FirstContentByType( - const std::string& type) const { - return FindContentInfoByType(contents_, type); -} - -const ContentInfo* SessionDescription::FirstContent() const { - return (contents_.empty()) ? NULL : &(*contents_.begin()); -} - -void SessionDescription::AddContent(const std::string& name, - const std::string& type, - ContentDescription* description) { - contents_.push_back(ContentInfo(name, type, description)); -} - -void SessionDescription::AddContent(const std::string& name, - const std::string& type, - bool rejected, - ContentDescription* description) { - contents_.push_back(ContentInfo(name, type, rejected, description)); -} - -bool SessionDescription::RemoveContentByName(const std::string& name) { - for (ContentInfos::iterator content = contents_.begin(); - content != contents_.end(); ++content) { - if (content->name == name) { - delete content->description; - contents_.erase(content); - return true; - } - } - - return false; -} - -bool SessionDescription::AddTransportInfo(const TransportInfo& transport_info) { - if (GetTransportInfoByName(transport_info.content_name) != NULL) { - return false; - } - transport_infos_.push_back(transport_info); - return true; -} - -bool SessionDescription::RemoveTransportInfoByName(const std::string& name) { - for (TransportInfos::iterator transport_info = transport_infos_.begin(); - transport_info != transport_infos_.end(); ++transport_info) { - if (transport_info->content_name == name) { - transport_infos_.erase(transport_info); - return true; - } - } - return false; -} - -const TransportInfo* SessionDescription::GetTransportInfoByName( - const std::string& name) const { - for (TransportInfos::const_iterator iter = transport_infos_.begin(); - iter != transport_infos_.end(); ++iter) { - if (iter->content_name == name) { - return &(*iter); - } - } - return NULL; -} - -TransportInfo* SessionDescription::GetTransportInfoByName( - const std::string& name) { - for (TransportInfos::iterator iter = transport_infos_.begin(); - iter != transport_infos_.end(); ++iter) { - if (iter->content_name == name) { - return &(*iter); - } - } - return NULL; -} - -void SessionDescription::RemoveGroupByName(const std::string& name) { - for (ContentGroups::iterator iter = content_groups_.begin(); - iter != content_groups_.end(); ++iter) { - if (iter->semantics() == name) { - content_groups_.erase(iter); - break; - } - } -} - -bool SessionDescription::HasGroup(const std::string& name) const { - for (ContentGroups::const_iterator iter = content_groups_.begin(); - iter != content_groups_.end(); ++iter) { - if (iter->semantics() == name) { - return true; - } - } - return false; -} - -const ContentGroup* SessionDescription::GetGroupByName( - const std::string& name) const { - for (ContentGroups::const_iterator iter = content_groups_.begin(); - iter != content_groups_.end(); ++iter) { - if (iter->semantics() == name) { - return &(*iter); - } - } - return NULL; -} - -} // namespace cricket diff --git a/talk/p2p/base/sessiondescription.h b/talk/p2p/base/sessiondescription.h deleted file mode 100644 index bc76761e0..000000000 --- a/talk/p2p/base/sessiondescription.h +++ /dev/null @@ -1,202 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef WEBRTC_P2P_BASE_SESSIONDESCRIPTION_H_ -#define WEBRTC_P2P_BASE_SESSIONDESCRIPTION_H_ - -#include <string> -#include <vector> - -#include "webrtc/p2p/base/transportinfo.h" -#include "webrtc/base/constructormagic.h" - -namespace cricket { - -// Describes a session content. Individual content types inherit from -// this class. Analagous to a <jingle><content><description> or -// <session><description>. -class ContentDescription { - public: - virtual ~ContentDescription() {} - virtual ContentDescription* Copy() const = 0; -}; - -// Analagous to a <jingle><content> or <session><description>. -// name = name of <content name="..."> -// type = xmlns of <content> -struct ContentInfo { - ContentInfo() : description(NULL) {} - ContentInfo(const std::string& name, - const std::string& type, - ContentDescription* description) : - name(name), type(type), rejected(false), description(description) {} - ContentInfo(const std::string& name, - const std::string& type, - bool rejected, - ContentDescription* description) : - name(name), type(type), rejected(rejected), description(description) {} - std::string name; - std::string type; - bool rejected; - ContentDescription* description; -}; - -typedef std::vector<std::string> ContentNames; - -// This class provides a mechanism to aggregate different media contents into a -// group. This group can also be shared with the peers in a pre-defined format. -// GroupInfo should be populated only with the |content_name| of the -// MediaDescription. -class ContentGroup { - public: - explicit ContentGroup(const std::string& semantics) : - semantics_(semantics) {} - - const std::string& semantics() const { return semantics_; } - const ContentNames& content_names() const { return content_names_; } - - const std::string* FirstContentName() const; - bool HasContentName(const std::string& content_name) const; - void AddContentName(const std::string& content_name); - bool RemoveContentName(const std::string& content_name); - - private: - std::string semantics_; - ContentNames content_names_; -}; - -typedef std::vector<ContentInfo> ContentInfos; -typedef std::vector<ContentGroup> ContentGroups; - -const ContentInfo* FindContentInfoByName( - const ContentInfos& contents, const std::string& name); -const ContentInfo* FindContentInfoByType( - const ContentInfos& contents, const std::string& type); - -// Describes a collection of contents, each with its own name and -// type. Analogous to a <jingle> or <session> stanza. Assumes that -// contents are unique be name, but doesn't enforce that. -class SessionDescription { - public: - SessionDescription() {} - explicit SessionDescription(const ContentInfos& contents) : - contents_(contents) {} - SessionDescription(const ContentInfos& contents, - const ContentGroups& groups) : - contents_(contents), - content_groups_(groups) {} - SessionDescription(const ContentInfos& contents, - const TransportInfos& transports, - const ContentGroups& groups) : - contents_(contents), - transport_infos_(transports), - content_groups_(groups) {} - ~SessionDescription() { - for (ContentInfos::iterator content = contents_.begin(); - content != contents_.end(); ++content) { - delete content->description; - } - } - - SessionDescription* Copy() const; - - // Content accessors. - const ContentInfos& contents() const { return contents_; } - ContentInfos& contents() { return contents_; } - const ContentInfo* GetContentByName(const std::string& name) const; - ContentInfo* GetContentByName(const std::string& name); - const ContentDescription* GetContentDescriptionByName( - const std::string& name) const; - ContentDescription* GetContentDescriptionByName(const std::string& name); - const ContentInfo* FirstContentByType(const std::string& type) const; - const ContentInfo* FirstContent() const; - - // Content mutators. - // Adds a content to this description. Takes ownership of ContentDescription*. - void AddContent(const std::string& name, - const std::string& type, - ContentDescription* description); - void AddContent(const std::string& name, - const std::string& type, - bool rejected, - ContentDescription* description); - bool RemoveContentByName(const std::string& name); - - // Transport accessors. - const TransportInfos& transport_infos() const { return transport_infos_; } - TransportInfos& transport_infos() { return transport_infos_; } - const TransportInfo* GetTransportInfoByName( - const std::string& name) const; - TransportInfo* GetTransportInfoByName(const std::string& name); - const TransportDescription* GetTransportDescriptionByName( - const std::string& name) const { - const TransportInfo* tinfo = GetTransportInfoByName(name); - return tinfo ? &tinfo->description : NULL; - } - - // Transport mutators. - void set_transport_infos(const TransportInfos& transport_infos) { - transport_infos_ = transport_infos; - } - // Adds a TransportInfo to this description. - // Returns false if a TransportInfo with the same name already exists. - bool AddTransportInfo(const TransportInfo& transport_info); - bool RemoveTransportInfoByName(const std::string& name); - - // Group accessors. - const ContentGroups& groups() const { return content_groups_; } - const ContentGroup* GetGroupByName(const std::string& name) const; - bool HasGroup(const std::string& name) const; - - // Group mutators. - void AddGroup(const ContentGroup& group) { content_groups_.push_back(group); } - // Remove the first group with the same semantics specified by |name|. - void RemoveGroupByName(const std::string& name); - - private: - ContentInfos contents_; - TransportInfos transport_infos_; - ContentGroups content_groups_; -}; - -// Indicates whether a ContentDescription was an offer or an answer, as -// described in http://www.ietf.org/rfc/rfc3264.txt. CA_UPDATE -// indicates a jingle update message which contains a subset of a full -// session description -enum ContentAction { - CA_OFFER, CA_PRANSWER, CA_ANSWER, CA_UPDATE -}; - -// Indicates whether a ContentDescription was sent by the local client -// or received from the remote client. -enum ContentSource { - CS_LOCAL, CS_REMOTE -}; - -} // namespace cricket - -#endif // WEBRTC_P2P_BASE_SESSIONDESCRIPTION_H_ diff --git a/talk/p2p/base/sessionid.h b/talk/p2p/base/sessionid.h deleted file mode 100644 index 52ee99061..000000000 --- a/talk/p2p/base/sessionid.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef WEBRTC_P2P_BASE_SESSIONID_H_ -#define WEBRTC_P2P_BASE_SESSIONID_H_ - -// TODO: Remove this file. - -namespace cricket { - -} // namespace cricket - -#endif // WEBRTC_P2P_BASE_SESSIONID_H_ diff --git a/talk/p2p/base/sessionmanager.cc b/talk/p2p/base/sessionmanager.cc deleted file mode 100644 index 7f27f6cd1..000000000 --- a/talk/p2p/base/sessionmanager.cc +++ /dev/null @@ -1,326 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "webrtc/p2p/base/sessionmanager.h" - -#include "webrtc/p2p/base/constants.h" -#include "webrtc/p2p/base/session.h" -#include "webrtc/p2p/base/sessionmessages.h" -#include "webrtc/libjingle/xmpp/constants.h" -#include "webrtc/libjingle/xmpp/jid.h" -#include "webrtc/base/common.h" -#include "webrtc/base/helpers.h" -#include "webrtc/base/logging.h" -#include "webrtc/base/scoped_ptr.h" -#include "webrtc/base/stringencode.h" - -namespace cricket { - -SessionManager::SessionManager(PortAllocator *allocator, - rtc::Thread *worker) { - allocator_ = allocator; - signaling_thread_ = rtc::Thread::Current(); - if (worker == NULL) { - worker_thread_ = rtc::Thread::Current(); - } else { - worker_thread_ = worker; - } - timeout_ = 50; -} - -SessionManager::~SessionManager() { - // Note: Session::Terminate occurs asynchronously, so it's too late to - // delete them now. They better be all gone. - ASSERT(session_map_.empty()); - // TerminateAll(); - SignalDestroyed(); -} - -void SessionManager::AddClient(const std::string& content_type, - SessionClient* client) { - ASSERT(client_map_.find(content_type) == client_map_.end()); - client_map_[content_type] = client; -} - -void SessionManager::RemoveClient(const std::string& content_type) { - ClientMap::iterator iter = client_map_.find(content_type); - ASSERT(iter != client_map_.end()); - client_map_.erase(iter); -} - -SessionClient* SessionManager::GetClient(const std::string& content_type) { - ClientMap::iterator iter = client_map_.find(content_type); - return (iter != client_map_.end()) ? iter->second : NULL; -} - -Session* SessionManager::CreateSession(const std::string& local_name, - const std::string& content_type) { - std::string id; - return CreateSession(id, local_name, content_type); -} - -Session* SessionManager::CreateSession(const std::string& id, - const std::string& local_name, - const std::string& content_type) { - std::string sid = - id.empty() ? rtc::ToString(rtc::CreateRandomId64()) : id; - return CreateSession(local_name, local_name, sid, content_type, false); -} - -Session* SessionManager::CreateSession( - const std::string& local_name, const std::string& initiator_name, - const std::string& sid, const std::string& content_type, - bool received_initiate) { - SessionClient* client = GetClient(content_type); - ASSERT(client != NULL); - - Session* session = new Session(this, local_name, initiator_name, - sid, content_type, client); - session->SetIdentity(transport_desc_factory_.identity()); - session_map_[session->id()] = session; - session->SignalRequestSignaling.connect( - this, &SessionManager::OnRequestSignaling); - session->SignalOutgoingMessage.connect( - this, &SessionManager::OnOutgoingMessage); - session->SignalErrorMessage.connect(this, &SessionManager::OnErrorMessage); - SignalSessionCreate(session, received_initiate); - session->client()->OnSessionCreate(session, received_initiate); - return session; -} - -void SessionManager::DestroySession(Session* session) { - if (session != NULL) { - SessionMap::iterator it = session_map_.find(session->id()); - if (it != session_map_.end()) { - SignalSessionDestroy(session); - session->client()->OnSessionDestroy(session); - session_map_.erase(it); - delete session; - } - } -} - -Session* SessionManager::GetSession(const std::string& sid) { - SessionMap::iterator it = session_map_.find(sid); - if (it != session_map_.end()) - return it->second; - return NULL; -} - -void SessionManager::TerminateAll() { - while (session_map_.begin() != session_map_.end()) { - Session* session = session_map_.begin()->second; - session->Terminate(); - } -} - -bool SessionManager::IsSessionMessage(const buzz::XmlElement* stanza) { - return cricket::IsSessionMessage(stanza); -} - -Session* SessionManager::FindSession(const std::string& sid, - const std::string& remote_name) { - SessionMap::iterator iter = session_map_.find(sid); - if (iter == session_map_.end()) - return NULL; - - Session* session = iter->second; - if (buzz::Jid(remote_name) != buzz::Jid(session->remote_name())) - return NULL; - - return session; -} - -void SessionManager::OnIncomingMessage(const buzz::XmlElement* stanza) { - SessionMessage msg; - ParseError error; - - if (!ParseSessionMessage(stanza, &msg, &error)) { - SendErrorMessage(stanza, buzz::QN_STANZA_BAD_REQUEST, "modify", - error.text, NULL); - return; - } - - Session* session = FindSession(msg.sid, msg.from); - if (session) { - session->OnIncomingMessage(msg); - return; - } - if (msg.type != ACTION_SESSION_INITIATE) { - SendErrorMessage(stanza, buzz::QN_STANZA_BAD_REQUEST, "modify", - "unknown session", NULL); - return; - } - - std::string content_type; - if (!ParseContentType(msg.protocol, msg.action_elem, - &content_type, &error)) { - SendErrorMessage(stanza, buzz::QN_STANZA_BAD_REQUEST, "modify", - error.text, NULL); - return; - } - - if (!GetClient(content_type)) { - SendErrorMessage(stanza, buzz::QN_STANZA_BAD_REQUEST, "modify", - "unknown content type: " + content_type, NULL); - return; - } - - session = CreateSession(msg.to, msg.initiator, msg.sid, - content_type, true); - session->OnIncomingMessage(msg); -} - -void SessionManager::OnIncomingResponse(const buzz::XmlElement* orig_stanza, - const buzz::XmlElement* response_stanza) { - if (orig_stanza == NULL || response_stanza == NULL) { - return; - } - - SessionMessage msg; - ParseError error; - if (!ParseSessionMessage(orig_stanza, &msg, &error)) { - LOG(LS_WARNING) << "Error parsing incoming response: " << error.text - << ":" << orig_stanza; - return; - } - - Session* session = FindSession(msg.sid, msg.to); - if (!session) { - // Also try the QN_FROM in the response stanza, in case we sent the request - // to a bare JID but got the response from a full JID. - std::string ack_from = response_stanza->Attr(buzz::QN_FROM); - session = FindSession(msg.sid, ack_from); - } - if (session) { - session->OnIncomingResponse(orig_stanza, response_stanza, msg); - } -} - -void SessionManager::OnFailedSend(const buzz::XmlElement* orig_stanza, - const buzz::XmlElement* error_stanza) { - SessionMessage msg; - ParseError error; - if (!ParseSessionMessage(orig_stanza, &msg, &error)) { - return; // TODO: log somewhere? - } - - Session* session = FindSession(msg.sid, msg.to); - if (session) { - rtc::scoped_ptr<buzz::XmlElement> synthetic_error; - if (!error_stanza) { - // A failed send is semantically equivalent to an error response, so we - // can just turn the former into the latter. - synthetic_error.reset( - CreateErrorMessage(orig_stanza, buzz::QN_STANZA_ITEM_NOT_FOUND, - "cancel", "Recipient did not respond", NULL)); - error_stanza = synthetic_error.get(); - } - - session->OnFailedSend(orig_stanza, error_stanza); - } -} - -void SessionManager::SendErrorMessage(const buzz::XmlElement* stanza, - const buzz::QName& name, - const std::string& type, - const std::string& text, - const buzz::XmlElement* extra_info) { - rtc::scoped_ptr<buzz::XmlElement> msg( - CreateErrorMessage(stanza, name, type, text, extra_info)); - SignalOutgoingMessage(this, msg.get()); -} - -buzz::XmlElement* SessionManager::CreateErrorMessage( - const buzz::XmlElement* stanza, - const buzz::QName& name, - const std::string& type, - const std::string& text, - const buzz::XmlElement* extra_info) { - buzz::XmlElement* iq = new buzz::XmlElement(buzz::QN_IQ); - iq->SetAttr(buzz::QN_TO, stanza->Attr(buzz::QN_FROM)); - iq->SetAttr(buzz::QN_ID, stanza->Attr(buzz::QN_ID)); - iq->SetAttr(buzz::QN_TYPE, "error"); - - CopyXmlChildren(stanza, iq); - - buzz::XmlElement* error = new buzz::XmlElement(buzz::QN_ERROR); - error->SetAttr(buzz::QN_TYPE, type); - iq->AddElement(error); - - // If the error name is not in the standard namespace, we have to first add - // some error from that namespace. - if (name.Namespace() != buzz::NS_STANZA) { - error->AddElement( - new buzz::XmlElement(buzz::QN_STANZA_UNDEFINED_CONDITION)); - } - error->AddElement(new buzz::XmlElement(name)); - - if (extra_info) - error->AddElement(new buzz::XmlElement(*extra_info)); - - if (text.size() > 0) { - // It's okay to always use English here. This text is for debugging - // purposes only. - buzz::XmlElement* text_elem = new buzz::XmlElement(buzz::QN_STANZA_TEXT); - text_elem->SetAttr(buzz::QN_XML_LANG, "en"); - text_elem->SetBodyText(text); - error->AddElement(text_elem); - } - - // TODO: Should we include error codes as well for SIP compatibility? - - return iq; -} - -void SessionManager::OnOutgoingMessage(Session* session, - const buzz::XmlElement* stanza) { - SignalOutgoingMessage(this, stanza); -} - -void SessionManager::OnErrorMessage(BaseSession* session, - const buzz::XmlElement* stanza, - const buzz::QName& name, - const std::string& type, - const std::string& text, - const buzz::XmlElement* extra_info) { - SendErrorMessage(stanza, name, type, text, extra_info); -} - -void SessionManager::OnSignalingReady() { - for (SessionMap::iterator it = session_map_.begin(); - it != session_map_.end(); - ++it) { - it->second->OnSignalingReady(); - } -} - -void SessionManager::OnRequestSignaling(Session* session) { - SignalRequestSignaling(); -} - -} // namespace cricket diff --git a/talk/p2p/base/sessionmanager.h b/talk/p2p/base/sessionmanager.h deleted file mode 100644 index 0e0e9a43a..000000000 --- a/talk/p2p/base/sessionmanager.h +++ /dev/null @@ -1,211 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef WEBRTC_P2P_BASE_SESSIONMANAGER_H_ -#define WEBRTC_P2P_BASE_SESSIONMANAGER_H_ - -#include <map> -#include <string> -#include <utility> -#include <vector> - -#include "webrtc/p2p/base/portallocator.h" -#include "webrtc/p2p/base/transportdescriptionfactory.h" -#include "webrtc/base/sigslot.h" -#include "webrtc/base/thread.h" - -namespace buzz { -class QName; -class XmlElement; -} - -namespace cricket { - -class Session; -class BaseSession; -class SessionClient; - -// SessionManager manages session instances. -class SessionManager : public sigslot::has_slots<> { - public: - SessionManager(PortAllocator *allocator, - rtc::Thread *worker_thread = NULL); - virtual ~SessionManager(); - - PortAllocator *port_allocator() const { return allocator_; } - rtc::Thread *worker_thread() const { return worker_thread_; } - rtc::Thread *signaling_thread() const { return signaling_thread_; } - - int session_timeout() const { return timeout_; } - void set_session_timeout(int timeout) { timeout_ = timeout; } - - // Set what transport protocol we want to default to. - void set_transport_protocol(TransportProtocol proto) { - transport_desc_factory_.set_protocol(proto); - } - - // Control use of DTLS. An identity must be supplied if DTLS is enabled. - void set_secure(SecurePolicy policy) { - transport_desc_factory_.set_secure(policy); - } - void set_identity(rtc::SSLIdentity* identity) { - transport_desc_factory_.set_identity(identity); - } - const TransportDescriptionFactory* transport_desc_factory() const { - return &transport_desc_factory_; - } - - // Registers support for the given client. If we receive an initiate - // describing a session of the given type, we will automatically create a - // Session object and notify this client. The client may then accept or - // reject the session. - void AddClient(const std::string& content_type, SessionClient* client); - void RemoveClient(const std::string& content_type); - SessionClient* GetClient(const std::string& content_type); - - // Creates a new session. The given name is the JID of the client on whose - // behalf we initiate the session. - Session *CreateSession(const std::string& local_name, - const std::string& content_type); - - Session *CreateSession(const std::string& id, - const std::string& local_name, - const std::string& content_type); - - // Destroys the given session. - void DestroySession(Session *session); - - // Returns the session with the given ID or NULL if none exists. - Session *GetSession(const std::string& sid); - - // Terminates all of the sessions created by this manager. - void TerminateAll(); - - // These are signaled whenever the set of existing sessions changes. - sigslot::signal2<Session *, bool> SignalSessionCreate; - sigslot::signal1<Session *> SignalSessionDestroy; - - // Determines whether the given stanza is intended for some session. - bool IsSessionMessage(const buzz::XmlElement* stanza); - - // Given a sid, initiator, and remote_name, this finds the matching Session - Session* FindSession(const std::string& sid, - const std::string& remote_name); - - // Called when we receive a stanza for which IsSessionMessage is true. - void OnIncomingMessage(const buzz::XmlElement* stanza); - - // Called when we get a response to a message that we sent. - void OnIncomingResponse(const buzz::XmlElement* orig_stanza, - const buzz::XmlElement* response_stanza); - - // Called if an attempted to send times out or an error is returned. In the - // timeout case error_stanza will be NULL - void OnFailedSend(const buzz::XmlElement* orig_stanza, - const buzz::XmlElement* error_stanza); - - // Signalled each time a session generates a signaling message to send. - // Also signalled on errors, but with a NULL session. - sigslot::signal2<SessionManager*, - const buzz::XmlElement*> SignalOutgoingMessage; - - // Signaled before sessions try to send certain signaling messages. The - // client should call OnSignalingReady once it is safe to send them. These - // steps are taken so that we don't send signaling messages trying to - // re-establish the connectivity of a session when the client cannot send - // the messages (and would probably just drop them on the floor). - // - // Note: you can connect this directly to OnSignalingReady(), if a signalling - // check is not supported. - sigslot::signal0<> SignalRequestSignaling; - void OnSignalingReady(); - - // Signaled when this SessionManager is deleted. - sigslot::signal0<> SignalDestroyed; - - private: - typedef std::map<std::string, Session*> SessionMap; - typedef std::map<std::string, SessionClient*> ClientMap; - - // Helper function for CreateSession. This is also invoked when we receive - // a message attempting to initiate a session with this client. - Session *CreateSession(const std::string& local_name, - const std::string& initiator, - const std::string& sid, - const std::string& content_type, - bool received_initiate); - - // Attempts to find a registered session type whose description appears as - // a child of the session element. Such a child should be present indicating - // the application they hope to initiate. - std::string FindClient(const buzz::XmlElement* session); - - // Sends a message back to the other client indicating that we found an error - // in the stanza they sent. name identifies the error, type is one of the - // standard XMPP types (cancel, continue, modify, auth, wait), and text is a - // description for debugging purposes. - void SendErrorMessage(const buzz::XmlElement* stanza, - const buzz::QName& name, - const std::string& type, - const std::string& text, - const buzz::XmlElement* extra_info); - - // Creates and returns an error message from the given components. The - // caller is responsible for deleting this. - buzz::XmlElement* CreateErrorMessage( - const buzz::XmlElement* stanza, - const buzz::QName& name, - const std::string& type, - const std::string& text, - const buzz::XmlElement* extra_info); - - // Called each time a session requests signaling. - void OnRequestSignaling(Session* session); - - // Called each time a session has an outgoing message. - void OnOutgoingMessage(Session* session, const buzz::XmlElement* stanza); - - // Called each time a session has an error to send. - void OnErrorMessage(BaseSession* session, - const buzz::XmlElement* stanza, - const buzz::QName& name, - const std::string& type, - const std::string& text, - const buzz::XmlElement* extra_info); - - PortAllocator *allocator_; - rtc::Thread *signaling_thread_; - rtc::Thread *worker_thread_; - int timeout_; - TransportDescriptionFactory transport_desc_factory_; - SessionMap session_map_; - ClientMap client_map_; -}; - -} // namespace cricket - -#endif // WEBRTC_P2P_BASE_SESSIONMANAGER_H_ diff --git a/talk/p2p/base/sessionmessages.cc b/talk/p2p/base/sessionmessages.cc deleted file mode 100644 index 0534271d7..000000000 --- a/talk/p2p/base/sessionmessages.cc +++ /dev/null @@ -1,1149 +0,0 @@ -/* - * libjingle - * Copyright 2010, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "webrtc/p2p/base/sessionmessages.h" - -#include <stdio.h> -#include <string> - -#include "webrtc/p2p/base/constants.h" -#include "webrtc/p2p/base/p2ptransport.h" -#include "webrtc/p2p/base/parsing.h" -#include "webrtc/p2p/base/sessionclient.h" -#include "webrtc/p2p/base/sessiondescription.h" -#include "webrtc/p2p/base/transport.h" -#include "webrtc/libjingle/xmllite/xmlconstants.h" -#include "webrtc/libjingle/xmpp/constants.h" -#include "webrtc/base/logging.h" -#include "webrtc/base/scoped_ptr.h" -#include "webrtc/base/stringutils.h" - -namespace cricket { - -ActionType ToActionType(const std::string& type) { - if (type == GINGLE_ACTION_INITIATE) - return ACTION_SESSION_INITIATE; - if (type == GINGLE_ACTION_INFO) - return ACTION_SESSION_INFO; - if (type == GINGLE_ACTION_ACCEPT) - return ACTION_SESSION_ACCEPT; - if (type == GINGLE_ACTION_REJECT) - return ACTION_SESSION_REJECT; - if (type == GINGLE_ACTION_TERMINATE) - return ACTION_SESSION_TERMINATE; - if (type == GINGLE_ACTION_CANDIDATES) - return ACTION_TRANSPORT_INFO; - if (type == JINGLE_ACTION_SESSION_INITIATE) - return ACTION_SESSION_INITIATE; - if (type == JINGLE_ACTION_TRANSPORT_INFO) - return ACTION_TRANSPORT_INFO; - if (type == JINGLE_ACTION_TRANSPORT_ACCEPT) - return ACTION_TRANSPORT_ACCEPT; - if (type == JINGLE_ACTION_SESSION_INFO) - return ACTION_SESSION_INFO; - if (type == JINGLE_ACTION_SESSION_ACCEPT) - return ACTION_SESSION_ACCEPT; - if (type == JINGLE_ACTION_SESSION_TERMINATE) - return ACTION_SESSION_TERMINATE; - if (type == JINGLE_ACTION_TRANSPORT_INFO) - return ACTION_TRANSPORT_INFO; - if (type == JINGLE_ACTION_TRANSPORT_ACCEPT) - return ACTION_TRANSPORT_ACCEPT; - if (type == JINGLE_ACTION_DESCRIPTION_INFO) - return ACTION_DESCRIPTION_INFO; - if (type == GINGLE_ACTION_UPDATE) - return ACTION_DESCRIPTION_INFO; - - return ACTION_UNKNOWN; -} - -std::string ToJingleString(ActionType type) { - switch (type) { - case ACTION_SESSION_INITIATE: - return JINGLE_ACTION_SESSION_INITIATE; - case ACTION_SESSION_INFO: - return JINGLE_ACTION_SESSION_INFO; - case ACTION_DESCRIPTION_INFO: - return JINGLE_ACTION_DESCRIPTION_INFO; - case ACTION_SESSION_ACCEPT: - return JINGLE_ACTION_SESSION_ACCEPT; - // Notice that reject and terminate both go to - // "session-terminate", but there is no "session-reject". - case ACTION_SESSION_REJECT: - case ACTION_SESSION_TERMINATE: - return JINGLE_ACTION_SESSION_TERMINATE; - case ACTION_TRANSPORT_INFO: - return JINGLE_ACTION_TRANSPORT_INFO; - case ACTION_TRANSPORT_ACCEPT: - return JINGLE_ACTION_TRANSPORT_ACCEPT; - default: - return ""; - } -} - -std::string ToGingleString(ActionType type) { - switch (type) { - case ACTION_SESSION_INITIATE: - return GINGLE_ACTION_INITIATE; - case ACTION_SESSION_INFO: - return GINGLE_ACTION_INFO; - case ACTION_SESSION_ACCEPT: - return GINGLE_ACTION_ACCEPT; - case ACTION_SESSION_REJECT: - return GINGLE_ACTION_REJECT; - case ACTION_SESSION_TERMINATE: - return GINGLE_ACTION_TERMINATE; - case ACTION_TRANSPORT_INFO: - return GINGLE_ACTION_CANDIDATES; - default: - return ""; - } -} - - -bool IsJingleMessage(const buzz::XmlElement* stanza) { - const buzz::XmlElement* jingle = stanza->FirstNamed(QN_JINGLE); - if (jingle == NULL) - return false; - - return (jingle->HasAttr(buzz::QN_ACTION) && jingle->HasAttr(QN_SID)); -} - -bool IsGingleMessage(const buzz::XmlElement* stanza) { - const buzz::XmlElement* session = stanza->FirstNamed(QN_GINGLE_SESSION); - if (session == NULL) - return false; - - return (session->HasAttr(buzz::QN_TYPE) && - session->HasAttr(buzz::QN_ID) && - session->HasAttr(QN_INITIATOR)); -} - -bool IsSessionMessage(const buzz::XmlElement* stanza) { - return (stanza->Name() == buzz::QN_IQ && - stanza->Attr(buzz::QN_TYPE) == buzz::STR_SET && - (IsJingleMessage(stanza) || - IsGingleMessage(stanza))); -} - -bool ParseGingleSessionMessage(const buzz::XmlElement* session, - SessionMessage* msg, - ParseError* error) { - msg->protocol = PROTOCOL_GINGLE; - std::string type_string = session->Attr(buzz::QN_TYPE); - msg->type = ToActionType(type_string); - msg->sid = session->Attr(buzz::QN_ID); - msg->initiator = session->Attr(QN_INITIATOR); - msg->action_elem = session; - - if (msg->type == ACTION_UNKNOWN) - return BadParse("unknown action: " + type_string, error); - - return true; -} - -bool ParseJingleSessionMessage(const buzz::XmlElement* jingle, - SessionMessage* msg, - ParseError* error) { - msg->protocol = PROTOCOL_JINGLE; - std::string type_string = jingle->Attr(buzz::QN_ACTION); - msg->type = ToActionType(type_string); - msg->sid = jingle->Attr(QN_SID); - msg->initiator = GetXmlAttr(jingle, QN_INITIATOR, buzz::STR_EMPTY); - msg->action_elem = jingle; - - if (msg->type == ACTION_UNKNOWN) - return BadParse("unknown action: " + type_string, error); - - return true; -} - -bool ParseHybridSessionMessage(const buzz::XmlElement* jingle, - SessionMessage* msg, - ParseError* error) { - if (!ParseJingleSessionMessage(jingle, msg, error)) - return false; - msg->protocol = PROTOCOL_HYBRID; - - return true; -} - -bool ParseSessionMessage(const buzz::XmlElement* stanza, - SessionMessage* msg, - ParseError* error) { - msg->id = stanza->Attr(buzz::QN_ID); - msg->from = stanza->Attr(buzz::QN_FROM); - msg->to = stanza->Attr(buzz::QN_TO); - msg->stanza = stanza; - - const buzz::XmlElement* jingle = stanza->FirstNamed(QN_JINGLE); - const buzz::XmlElement* session = stanza->FirstNamed(QN_GINGLE_SESSION); - if (jingle && session) - return ParseHybridSessionMessage(jingle, msg, error); - if (jingle != NULL) - return ParseJingleSessionMessage(jingle, msg, error); - if (session != NULL) - return ParseGingleSessionMessage(session, msg, error); - return false; -} - -buzz::XmlElement* WriteGingleAction(const SessionMessage& msg, - const XmlElements& action_elems) { - buzz::XmlElement* session = new buzz::XmlElement(QN_GINGLE_SESSION, true); - session->AddAttr(buzz::QN_TYPE, ToGingleString(msg.type)); - session->AddAttr(buzz::QN_ID, msg.sid); - session->AddAttr(QN_INITIATOR, msg.initiator); - AddXmlChildren(session, action_elems); - return session; -} - -buzz::XmlElement* WriteJingleAction(const SessionMessage& msg, - const XmlElements& action_elems) { - buzz::XmlElement* jingle = new buzz::XmlElement(QN_JINGLE, true); - jingle->AddAttr(buzz::QN_ACTION, ToJingleString(msg.type)); - jingle->AddAttr(QN_SID, msg.sid); - if (msg.type == ACTION_SESSION_INITIATE) { - jingle->AddAttr(QN_INITIATOR, msg.initiator); - } - AddXmlChildren(jingle, action_elems); - return jingle; -} - -void WriteSessionMessage(const SessionMessage& msg, - const XmlElements& action_elems, - buzz::XmlElement* stanza) { - stanza->SetAttr(buzz::QN_TO, msg.to); - stanza->SetAttr(buzz::QN_TYPE, buzz::STR_SET); - - if (msg.protocol == PROTOCOL_GINGLE) { - stanza->AddElement(WriteGingleAction(msg, action_elems)); - } else { - stanza->AddElement(WriteJingleAction(msg, action_elems)); - } -} - - -TransportParser* GetTransportParser(const TransportParserMap& trans_parsers, - const std::string& transport_type) { - TransportParserMap::const_iterator map = trans_parsers.find(transport_type); - if (map == trans_parsers.end()) { - return NULL; - } else { - return map->second; - } -} - -CandidateTranslator* GetCandidateTranslator( - const CandidateTranslatorMap& translators, - const std::string& content_name) { - CandidateTranslatorMap::const_iterator map = translators.find(content_name); - if (map == translators.end()) { - return NULL; - } else { - return map->second; - } -} - -bool GetParserAndTranslator(const TransportParserMap& trans_parsers, - const CandidateTranslatorMap& translators, - const std::string& transport_type, - const std::string& content_name, - TransportParser** parser, - CandidateTranslator** translator, - ParseError* error) { - *parser = GetTransportParser(trans_parsers, transport_type); - if (*parser == NULL) { - return BadParse("unknown transport type: " + transport_type, error); - } - // Not having a translator isn't fatal when parsing. If this is called for an - // initiate message, we won't have our proxies set up to do the translation. - // Fortunately, for the cases where translation is needed, candidates are - // never sent in initiates. - *translator = GetCandidateTranslator(translators, content_name); - return true; -} - -bool GetParserAndTranslator(const TransportParserMap& trans_parsers, - const CandidateTranslatorMap& translators, - const std::string& transport_type, - const std::string& content_name, - TransportParser** parser, - CandidateTranslator** translator, - WriteError* error) { - *parser = GetTransportParser(trans_parsers, transport_type); - if (*parser == NULL) { - return BadWrite("unknown transport type: " + transport_type, error); - } - *translator = GetCandidateTranslator(translators, content_name); - if (*translator == NULL) { - return BadWrite("unknown content name: " + content_name, error); - } - return true; -} - -bool ParseGingleCandidate(const buzz::XmlElement* candidate_elem, - const TransportParserMap& trans_parsers, - const CandidateTranslatorMap& translators, - const std::string& content_name, - Candidates* candidates, - ParseError* error) { - TransportParser* trans_parser; - CandidateTranslator* translator; - if (!GetParserAndTranslator(trans_parsers, translators, - NS_GINGLE_P2P, content_name, - &trans_parser, &translator, error)) - return false; - - Candidate candidate; - if (!trans_parser->ParseGingleCandidate( - candidate_elem, translator, &candidate, error)) { - return false; - } - - candidates->push_back(candidate); - return true; -} - -bool ParseGingleCandidates(const buzz::XmlElement* parent, - const TransportParserMap& trans_parsers, - const CandidateTranslatorMap& translators, - const std::string& content_name, - Candidates* candidates, - ParseError* error) { - for (const buzz::XmlElement* candidate_elem = parent->FirstElement(); - candidate_elem != NULL; - candidate_elem = candidate_elem->NextElement()) { - if (candidate_elem->Name().LocalPart() == LN_CANDIDATE) { - if (!ParseGingleCandidate(candidate_elem, trans_parsers, translators, - content_name, candidates, error)) { - return false; - } - } - } - return true; -} - -bool ParseGingleTransportInfos(const buzz::XmlElement* action_elem, - const ContentInfos& contents, - const TransportParserMap& trans_parsers, - const CandidateTranslatorMap& translators, - TransportInfos* tinfos, - ParseError* error) { - bool has_audio = FindContentInfoByName(contents, CN_AUDIO) != NULL; - bool has_video = FindContentInfoByName(contents, CN_VIDEO) != NULL; - - // If we don't have media, no need to separate the candidates. - if (!has_audio && !has_video) { - TransportInfo tinfo(CN_OTHER, - TransportDescription(NS_GINGLE_P2P, std::string(), std::string())); - if (!ParseGingleCandidates(action_elem, trans_parsers, translators, - CN_OTHER, &tinfo.description.candidates, - error)) { - return false; - } - - tinfos->push_back(tinfo); - return true; - } - - // If we have media, separate the candidates. - TransportInfo audio_tinfo( - CN_AUDIO, - TransportDescription(NS_GINGLE_P2P, std::string(), std::string())); - TransportInfo video_tinfo( - CN_VIDEO, - TransportDescription(NS_GINGLE_P2P, std::string(), std::string())); - for (const buzz::XmlElement* candidate_elem = action_elem->FirstElement(); - candidate_elem != NULL; - candidate_elem = candidate_elem->NextElement()) { - if (candidate_elem->Name().LocalPart() == LN_CANDIDATE) { - const std::string& channel_name = candidate_elem->Attr(buzz::QN_NAME); - if (has_audio && - (channel_name == GICE_CHANNEL_NAME_RTP || - channel_name == GICE_CHANNEL_NAME_RTCP)) { - if (!ParseGingleCandidate( - candidate_elem, trans_parsers, - translators, CN_AUDIO, - &audio_tinfo.description.candidates, error)) { - return false; - } - } else if (has_video && - (channel_name == GICE_CHANNEL_NAME_VIDEO_RTP || - channel_name == GICE_CHANNEL_NAME_VIDEO_RTCP)) { - if (!ParseGingleCandidate( - candidate_elem, trans_parsers, - translators, CN_VIDEO, - &video_tinfo.description.candidates, error)) { - return false; - } - } else { - return BadParse("Unknown channel name: " + channel_name, error); - } - } - } - - if (has_audio) { - tinfos->push_back(audio_tinfo); - } - if (has_video) { - tinfos->push_back(video_tinfo); - } - return true; -} - -bool ParseJingleTransportInfo(const buzz::XmlElement* trans_elem, - const std::string& content_name, - const TransportParserMap& trans_parsers, - const CandidateTranslatorMap& translators, - TransportInfo* tinfo, - ParseError* error) { - TransportParser* trans_parser; - CandidateTranslator* translator; - if (!GetParserAndTranslator(trans_parsers, translators, - trans_elem->Name().Namespace(), content_name, - &trans_parser, &translator, error)) - return false; - - TransportDescription tdesc; - if (!trans_parser->ParseTransportDescription(trans_elem, translator, - &tdesc, error)) - return false; - - *tinfo = TransportInfo(content_name, tdesc); - return true; -} - -bool ParseJingleTransportInfos(const buzz::XmlElement* jingle, - const ContentInfos& contents, - const TransportParserMap trans_parsers, - const CandidateTranslatorMap& translators, - TransportInfos* tinfos, - ParseError* error) { - for (const buzz::XmlElement* pair_elem - = jingle->FirstNamed(QN_JINGLE_CONTENT); - pair_elem != NULL; - pair_elem = pair_elem->NextNamed(QN_JINGLE_CONTENT)) { - std::string content_name; - if (!RequireXmlAttr(pair_elem, QN_JINGLE_CONTENT_NAME, - &content_name, error)) - return false; - - const ContentInfo* content = FindContentInfoByName(contents, content_name); - if (!content) - return BadParse("Unknown content name: " + content_name, error); - - const buzz::XmlElement* trans_elem; - if (!RequireXmlChild(pair_elem, LN_TRANSPORT, &trans_elem, error)) - return false; - - TransportInfo tinfo; - if (!ParseJingleTransportInfo(trans_elem, content->name, - trans_parsers, translators, - &tinfo, error)) - return false; - - tinfos->push_back(tinfo); - } - - return true; -} - -buzz::XmlElement* NewTransportElement(const std::string& name) { - return new buzz::XmlElement(buzz::QName(name, LN_TRANSPORT), true); -} - -bool WriteGingleCandidates(const Candidates& candidates, - const TransportParserMap& trans_parsers, - const std::string& transport_type, - const CandidateTranslatorMap& translators, - const std::string& content_name, - XmlElements* elems, - WriteError* error) { - TransportParser* trans_parser; - CandidateTranslator* translator; - if (!GetParserAndTranslator(trans_parsers, translators, - transport_type, content_name, - &trans_parser, &translator, error)) - return false; - - for (size_t i = 0; i < candidates.size(); ++i) { - rtc::scoped_ptr<buzz::XmlElement> element; - if (!trans_parser->WriteGingleCandidate(candidates[i], translator, - element.accept(), error)) { - return false; - } - - elems->push_back(element.release()); - } - - return true; -} - -bool WriteGingleTransportInfos(const TransportInfos& tinfos, - const TransportParserMap& trans_parsers, - const CandidateTranslatorMap& translators, - XmlElements* elems, - WriteError* error) { - for (TransportInfos::const_iterator tinfo = tinfos.begin(); - tinfo != tinfos.end(); ++tinfo) { - if (!WriteGingleCandidates(tinfo->description.candidates, - trans_parsers, tinfo->description.transport_type, - translators, tinfo->content_name, - elems, error)) - return false; - } - - return true; -} - -bool WriteJingleTransportInfo(const TransportInfo& tinfo, - const TransportParserMap& trans_parsers, - const CandidateTranslatorMap& translators, - XmlElements* elems, - WriteError* error) { - std::string transport_type = tinfo.description.transport_type; - TransportParser* trans_parser; - CandidateTranslator* translator; - if (!GetParserAndTranslator(trans_parsers, translators, - transport_type, tinfo.content_name, - &trans_parser, &translator, error)) - return false; - - buzz::XmlElement* trans_elem; - if (!trans_parser->WriteTransportDescription(tinfo.description, translator, - &trans_elem, error)) { - return false; - } - - elems->push_back(trans_elem); - return true; -} - -void WriteJingleContent(const std::string name, - const XmlElements& child_elems, - XmlElements* elems) { - buzz::XmlElement* content_elem = new buzz::XmlElement(QN_JINGLE_CONTENT); - content_elem->SetAttr(QN_JINGLE_CONTENT_NAME, name); - content_elem->SetAttr(QN_CREATOR, LN_INITIATOR); - AddXmlChildren(content_elem, child_elems); - - elems->push_back(content_elem); -} - -bool WriteJingleTransportInfos(const TransportInfos& tinfos, - const TransportParserMap& trans_parsers, - const CandidateTranslatorMap& translators, - XmlElements* elems, - WriteError* error) { - for (TransportInfos::const_iterator tinfo = tinfos.begin(); - tinfo != tinfos.end(); ++tinfo) { - XmlElements content_child_elems; - if (!WriteJingleTransportInfo(*tinfo, trans_parsers, translators, - &content_child_elems, error)) - - return false; - - WriteJingleContent(tinfo->content_name, content_child_elems, elems); - } - - return true; -} - -ContentParser* GetContentParser(const ContentParserMap& content_parsers, - const std::string& type) { - ContentParserMap::const_iterator map = content_parsers.find(type); - if (map == content_parsers.end()) { - return NULL; - } else { - return map->second; - } -} - -bool ParseContentInfo(SignalingProtocol protocol, - const std::string& name, - const std::string& type, - const buzz::XmlElement* elem, - const ContentParserMap& parsers, - ContentInfos* contents, - ParseError* error) { - ContentParser* parser = GetContentParser(parsers, type); - if (parser == NULL) - return BadParse("unknown application content: " + type, error); - - ContentDescription* desc; - if (!parser->ParseContent(protocol, elem, &desc, error)) - return false; - - contents->push_back(ContentInfo(name, type, desc)); - return true; -} - -bool ParseContentType(const buzz::XmlElement* parent_elem, - std::string* content_type, - const buzz::XmlElement** content_elem, - ParseError* error) { - if (!RequireXmlChild(parent_elem, LN_DESCRIPTION, content_elem, error)) - return false; - - *content_type = (*content_elem)->Name().Namespace(); - return true; -} - -bool ParseGingleContentInfos(const buzz::XmlElement* session, - const ContentParserMap& content_parsers, - ContentInfos* contents, - ParseError* error) { - std::string content_type; - const buzz::XmlElement* content_elem; - if (!ParseContentType(session, &content_type, &content_elem, error)) - return false; - - if (content_type == NS_GINGLE_VIDEO) { - // A parser parsing audio or video content should look at the - // namespace and only parse the codecs relevant to that namespace. - // We use this to control which codecs get parsed: first audio, - // then video. - rtc::scoped_ptr<buzz::XmlElement> audio_elem( - new buzz::XmlElement(QN_GINGLE_AUDIO_CONTENT)); - CopyXmlChildren(content_elem, audio_elem.get()); - if (!ParseContentInfo(PROTOCOL_GINGLE, CN_AUDIO, NS_JINGLE_RTP, - audio_elem.get(), content_parsers, - contents, error)) - return false; - - if (!ParseContentInfo(PROTOCOL_GINGLE, CN_VIDEO, NS_JINGLE_RTP, - content_elem, content_parsers, - contents, error)) - return false; - } else if (content_type == NS_GINGLE_AUDIO) { - if (!ParseContentInfo(PROTOCOL_GINGLE, CN_AUDIO, NS_JINGLE_RTP, - content_elem, content_parsers, - contents, error)) - return false; - } else { - if (!ParseContentInfo(PROTOCOL_GINGLE, CN_OTHER, content_type, - content_elem, content_parsers, - contents, error)) - return false; - } - return true; -} - -bool ParseJingleContentInfos(const buzz::XmlElement* jingle, - const ContentParserMap& content_parsers, - ContentInfos* contents, - ParseError* error) { - for (const buzz::XmlElement* pair_elem - = jingle->FirstNamed(QN_JINGLE_CONTENT); - pair_elem != NULL; - pair_elem = pair_elem->NextNamed(QN_JINGLE_CONTENT)) { - std::string content_name; - if (!RequireXmlAttr(pair_elem, QN_JINGLE_CONTENT_NAME, - &content_name, error)) - return false; - - std::string content_type; - const buzz::XmlElement* content_elem; - if (!ParseContentType(pair_elem, &content_type, &content_elem, error)) - return false; - - if (!ParseContentInfo(PROTOCOL_JINGLE, content_name, content_type, - content_elem, content_parsers, - contents, error)) - return false; - } - return true; -} - -bool ParseJingleGroupInfos(const buzz::XmlElement* jingle, - ContentGroups* groups, - ParseError* error) { - for (const buzz::XmlElement* pair_elem - = jingle->FirstNamed(QN_JINGLE_DRAFT_GROUP); - pair_elem != NULL; - pair_elem = pair_elem->NextNamed(QN_JINGLE_DRAFT_GROUP)) { - std::string group_name; - if (!RequireXmlAttr(pair_elem, QN_JINGLE_DRAFT_GROUP_TYPE, - &group_name, error)) - return false; - - ContentGroup group(group_name); - for (const buzz::XmlElement* child_elem - = pair_elem->FirstNamed(QN_JINGLE_CONTENT); - child_elem != NULL; - child_elem = child_elem->NextNamed(QN_JINGLE_CONTENT)) { - std::string content_name; - if (!RequireXmlAttr(child_elem, QN_JINGLE_CONTENT_NAME, - &content_name, error)) - return false; - group.AddContentName(content_name); - } - groups->push_back(group); - } - return true; -} - -buzz::XmlElement* WriteContentInfo(SignalingProtocol protocol, - const ContentInfo& content, - const ContentParserMap& parsers, - WriteError* error) { - ContentParser* parser = GetContentParser(parsers, content.type); - if (parser == NULL) { - BadWrite("unknown content type: " + content.type, error); - return NULL; - } - - buzz::XmlElement* elem = NULL; - if (!parser->WriteContent(protocol, content.description, &elem, error)) - return NULL; - - return elem; -} - -bool IsWritable(SignalingProtocol protocol, - const ContentInfo& content, - const ContentParserMap& parsers) { - ContentParser* parser = GetContentParser(parsers, content.type); - if (parser == NULL) { - return false; - } - - return parser->IsWritable(protocol, content.description); -} - -bool WriteGingleContentInfos(const ContentInfos& contents, - const ContentParserMap& parsers, - XmlElements* elems, - WriteError* error) { - if (contents.size() == 1 || - (contents.size() == 2 && - !IsWritable(PROTOCOL_GINGLE, contents.at(1), parsers))) { - if (contents.front().rejected) { - return BadWrite("Gingle protocol may not reject individual contents.", - error); - } - buzz::XmlElement* elem = WriteContentInfo( - PROTOCOL_GINGLE, contents.front(), parsers, error); - if (!elem) - return false; - - elems->push_back(elem); - } else if (contents.size() >= 2 && - contents.at(0).type == NS_JINGLE_RTP && - contents.at(1).type == NS_JINGLE_RTP) { - // Special-case audio + video contents so that they are "merged" - // into one "video" content. - if (contents.at(0).rejected || contents.at(1).rejected) { - return BadWrite("Gingle protocol may not reject individual contents.", - error); - } - buzz::XmlElement* audio = WriteContentInfo( - PROTOCOL_GINGLE, contents.at(0), parsers, error); - if (!audio) - return false; - - buzz::XmlElement* video = WriteContentInfo( - PROTOCOL_GINGLE, contents.at(1), parsers, error); - if (!video) { - delete audio; - return false; - } - - CopyXmlChildren(audio, video); - elems->push_back(video); - delete audio; - } else { - return BadWrite("Gingle protocol may only have one content.", error); - } - - return true; -} - -const TransportInfo* GetTransportInfoByContentName( - const TransportInfos& tinfos, const std::string& content_name) { - for (TransportInfos::const_iterator tinfo = tinfos.begin(); - tinfo != tinfos.end(); ++tinfo) { - if (content_name == tinfo->content_name) { - return &*tinfo; - } - } - return NULL; -} - -bool WriteJingleContents(const ContentInfos& contents, - const ContentParserMap& content_parsers, - const TransportInfos& tinfos, - const TransportParserMap& trans_parsers, - const CandidateTranslatorMap& translators, - XmlElements* elems, - WriteError* error) { - for (ContentInfos::const_iterator content = contents.begin(); - content != contents.end(); ++content) { - if (content->rejected) { - continue; - } - const TransportInfo* tinfo = - GetTransportInfoByContentName(tinfos, content->name); - if (!tinfo) - return BadWrite("No transport for content: " + content->name, error); - - XmlElements pair_elems; - buzz::XmlElement* elem = WriteContentInfo( - PROTOCOL_JINGLE, *content, content_parsers, error); - if (!elem) - return false; - pair_elems.push_back(elem); - - if (!WriteJingleTransportInfo(*tinfo, trans_parsers, translators, - &pair_elems, error)) - return false; - - WriteJingleContent(content->name, pair_elems, elems); - } - return true; -} - -bool WriteJingleContentInfos(const ContentInfos& contents, - const ContentParserMap& content_parsers, - XmlElements* elems, - WriteError* error) { - for (ContentInfos::const_iterator content = contents.begin(); - content != contents.end(); ++content) { - if (content->rejected) { - continue; - } - XmlElements content_child_elems; - buzz::XmlElement* elem = WriteContentInfo( - PROTOCOL_JINGLE, *content, content_parsers, error); - if (!elem) - return false; - content_child_elems.push_back(elem); - WriteJingleContent(content->name, content_child_elems, elems); - } - return true; -} - -bool WriteJingleGroupInfo(const ContentInfos& contents, - const ContentGroups& groups, - XmlElements* elems, - WriteError* error) { - if (!groups.empty()) { - buzz::XmlElement* pair_elem = new buzz::XmlElement(QN_JINGLE_DRAFT_GROUP); - pair_elem->SetAttr(QN_JINGLE_DRAFT_GROUP_TYPE, GROUP_TYPE_BUNDLE); - - XmlElements pair_elems; - for (ContentInfos::const_iterator content = contents.begin(); - content != contents.end(); ++content) { - buzz::XmlElement* child_elem = - new buzz::XmlElement(QN_JINGLE_CONTENT, false); - child_elem->SetAttr(QN_JINGLE_CONTENT_NAME, content->name); - pair_elems.push_back(child_elem); - } - AddXmlChildren(pair_elem, pair_elems); - elems->push_back(pair_elem); - } - return true; -} - -bool ParseContentType(SignalingProtocol protocol, - const buzz::XmlElement* action_elem, - std::string* content_type, - ParseError* error) { - const buzz::XmlElement* content_elem; - if (protocol == PROTOCOL_GINGLE) { - if (!ParseContentType(action_elem, content_type, &content_elem, error)) - return false; - - // Internally, we only use NS_JINGLE_RTP. - if (*content_type == NS_GINGLE_AUDIO || - *content_type == NS_GINGLE_VIDEO) - *content_type = NS_JINGLE_RTP; - } else { - const buzz::XmlElement* pair_elem - = action_elem->FirstNamed(QN_JINGLE_CONTENT); - if (pair_elem == NULL) - return BadParse("No contents found", error); - - if (!ParseContentType(pair_elem, content_type, &content_elem, error)) - return false; - } - - return true; -} - -static bool ParseContentMessage( - SignalingProtocol protocol, - const buzz::XmlElement* action_elem, - bool expect_transports, - const ContentParserMap& content_parsers, - const TransportParserMap& trans_parsers, - const CandidateTranslatorMap& translators, - SessionInitiate* init, - ParseError* error) { - init->owns_contents = true; - if (protocol == PROTOCOL_GINGLE) { - if (!ParseGingleContentInfos(action_elem, content_parsers, - &init->contents, error)) - return false; - - if (expect_transports && - !ParseGingleTransportInfos(action_elem, init->contents, - trans_parsers, translators, - &init->transports, error)) - return false; - } else { - if (!ParseJingleContentInfos(action_elem, content_parsers, - &init->contents, error)) - return false; - if (!ParseJingleGroupInfos(action_elem, &init->groups, error)) - return false; - - if (expect_transports && - !ParseJingleTransportInfos(action_elem, init->contents, - trans_parsers, translators, - &init->transports, error)) - return false; - } - - return true; -} - -static bool WriteContentMessage( - SignalingProtocol protocol, - const ContentInfos& contents, - const TransportInfos& tinfos, - const ContentParserMap& content_parsers, - const TransportParserMap& transport_parsers, - const CandidateTranslatorMap& translators, - const ContentGroups& groups, - XmlElements* elems, - WriteError* error) { - if (protocol == PROTOCOL_GINGLE) { - if (!WriteGingleContentInfos(contents, content_parsers, elems, error)) - return false; - - if (!WriteGingleTransportInfos(tinfos, transport_parsers, translators, - elems, error)) - return false; - } else { - if (!WriteJingleContents(contents, content_parsers, - tinfos, transport_parsers, translators, - elems, error)) - return false; - if (!WriteJingleGroupInfo(contents, groups, elems, error)) - return false; - } - - return true; -} - -bool ParseSessionInitiate(SignalingProtocol protocol, - const buzz::XmlElement* action_elem, - const ContentParserMap& content_parsers, - const TransportParserMap& trans_parsers, - const CandidateTranslatorMap& translators, - SessionInitiate* init, - ParseError* error) { - bool expect_transports = true; - return ParseContentMessage(protocol, action_elem, expect_transports, - content_parsers, trans_parsers, translators, - init, error); -} - - -bool WriteSessionInitiate(SignalingProtocol protocol, - const ContentInfos& contents, - const TransportInfos& tinfos, - const ContentParserMap& content_parsers, - const TransportParserMap& transport_parsers, - const CandidateTranslatorMap& translators, - const ContentGroups& groups, - XmlElements* elems, - WriteError* error) { - return WriteContentMessage(protocol, contents, tinfos, - content_parsers, transport_parsers, translators, - groups, - elems, error); -} - -bool ParseSessionAccept(SignalingProtocol protocol, - const buzz::XmlElement* action_elem, - const ContentParserMap& content_parsers, - const TransportParserMap& transport_parsers, - const CandidateTranslatorMap& translators, - SessionAccept* accept, - ParseError* error) { - bool expect_transports = true; - return ParseContentMessage(protocol, action_elem, expect_transports, - content_parsers, transport_parsers, translators, - accept, error); -} - -bool WriteSessionAccept(SignalingProtocol protocol, - const ContentInfos& contents, - const TransportInfos& tinfos, - const ContentParserMap& content_parsers, - const TransportParserMap& transport_parsers, - const CandidateTranslatorMap& translators, - const ContentGroups& groups, - XmlElements* elems, - WriteError* error) { - return WriteContentMessage(protocol, contents, tinfos, - content_parsers, transport_parsers, translators, - groups, - elems, error); -} - -bool ParseSessionTerminate(SignalingProtocol protocol, - const buzz::XmlElement* action_elem, - SessionTerminate* term, - ParseError* error) { - if (protocol == PROTOCOL_GINGLE) { - const buzz::XmlElement* reason_elem = action_elem->FirstElement(); - if (reason_elem != NULL) { - term->reason = reason_elem->Name().LocalPart(); - const buzz::XmlElement *debug_elem = reason_elem->FirstElement(); - if (debug_elem != NULL) { - term->debug_reason = debug_elem->Name().LocalPart(); - } - } - return true; - } else { - const buzz::XmlElement* reason_elem = - action_elem->FirstNamed(QN_JINGLE_REASON); - if (reason_elem) { - reason_elem = reason_elem->FirstElement(); - if (reason_elem) { - term->reason = reason_elem->Name().LocalPart(); - } - } - return true; - } -} - -void WriteSessionTerminate(SignalingProtocol protocol, - const SessionTerminate& term, - XmlElements* elems) { - if (protocol == PROTOCOL_GINGLE) { - elems->push_back(new buzz::XmlElement(buzz::QName(NS_GINGLE, term.reason))); - } else { - if (!term.reason.empty()) { - buzz::XmlElement* reason_elem = new buzz::XmlElement(QN_JINGLE_REASON); - reason_elem->AddElement(new buzz::XmlElement( - buzz::QName(NS_JINGLE, term.reason))); - elems->push_back(reason_elem); - } - } -} - -bool ParseDescriptionInfo(SignalingProtocol protocol, - const buzz::XmlElement* action_elem, - const ContentParserMap& content_parsers, - const TransportParserMap& transport_parsers, - const CandidateTranslatorMap& translators, - DescriptionInfo* description_info, - ParseError* error) { - bool expect_transports = false; - return ParseContentMessage(protocol, action_elem, expect_transports, - content_parsers, transport_parsers, translators, - description_info, error); -} - -bool WriteDescriptionInfo(SignalingProtocol protocol, - const ContentInfos& contents, - const ContentParserMap& content_parsers, - XmlElements* elems, - WriteError* error) { - if (protocol == PROTOCOL_GINGLE) { - return WriteGingleContentInfos(contents, content_parsers, elems, error); - } else { - return WriteJingleContentInfos(contents, content_parsers, elems, error); - } -} - -bool ParseTransportInfos(SignalingProtocol protocol, - const buzz::XmlElement* action_elem, - const ContentInfos& contents, - const TransportParserMap& trans_parsers, - const CandidateTranslatorMap& translators, - TransportInfos* tinfos, - ParseError* error) { - if (protocol == PROTOCOL_GINGLE) { - return ParseGingleTransportInfos( - action_elem, contents, trans_parsers, translators, tinfos, error); - } else { - return ParseJingleTransportInfos( - action_elem, contents, trans_parsers, translators, tinfos, error); - } -} - -bool WriteTransportInfos(SignalingProtocol protocol, - const TransportInfos& tinfos, - const TransportParserMap& trans_parsers, - const CandidateTranslatorMap& translators, - XmlElements* elems, - WriteError* error) { - if (protocol == PROTOCOL_GINGLE) { - return WriteGingleTransportInfos(tinfos, trans_parsers, translators, - elems, error); - } else { - return WriteJingleTransportInfos(tinfos, trans_parsers, translators, - elems, error); - } -} - -bool GetUriTarget(const std::string& prefix, const std::string& str, - std::string* after) { - size_t pos = str.find(prefix); - if (pos == std::string::npos) - return false; - - *after = str.substr(pos + prefix.size(), std::string::npos); - return true; -} - -bool FindSessionRedirect(const buzz::XmlElement* stanza, - SessionRedirect* redirect) { - const buzz::XmlElement* error_elem = GetXmlChild(stanza, LN_ERROR); - if (error_elem == NULL) - return false; - - const buzz::XmlElement* redirect_elem = - error_elem->FirstNamed(QN_GINGLE_REDIRECT); - if (redirect_elem == NULL) - redirect_elem = error_elem->FirstNamed(buzz::QN_STANZA_REDIRECT); - if (redirect_elem == NULL) - return false; - - if (!GetUriTarget(STR_REDIRECT_PREFIX, redirect_elem->BodyText(), - &redirect->target)) - return false; - - return true; -} - -} // namespace cricket diff --git a/talk/p2p/base/sessionmessages.h b/talk/p2p/base/sessionmessages.h deleted file mode 100644 index 0ab56ce3d..000000000 --- a/talk/p2p/base/sessionmessages.h +++ /dev/null @@ -1,243 +0,0 @@ -/* - * libjingle - * Copyright 2010, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef WEBRTC_P2P_BASE_SESSIONMESSAGES_H_ -#define WEBRTC_P2P_BASE_SESSIONMESSAGES_H_ - -#include <map> -#include <string> -#include <vector> - -#include "webrtc/p2p/base/constants.h" -#include "webrtc/p2p/base/parsing.h" -#include "webrtc/p2p/base/sessiondescription.h" // Needed to delete contents. -#include "webrtc/p2p/base/transportinfo.h" -#include "webrtc/libjingle/xmllite/xmlelement.h" -#include "webrtc/base/basictypes.h" - -namespace cricket { - -struct ParseError; -struct WriteError; -class Candidate; -class ContentParser; -class TransportParser; - -typedef std::vector<Candidate> Candidates; -typedef std::map<std::string, ContentParser*> ContentParserMap; -typedef std::map<std::string, TransportParser*> TransportParserMap; - -enum ActionType { - ACTION_UNKNOWN, - - ACTION_SESSION_INITIATE, - ACTION_SESSION_INFO, - ACTION_SESSION_ACCEPT, - ACTION_SESSION_REJECT, - ACTION_SESSION_TERMINATE, - - ACTION_TRANSPORT_INFO, - ACTION_TRANSPORT_ACCEPT, - - ACTION_DESCRIPTION_INFO, -}; - -// Abstraction of a <jingle> element within an <iq> stanza, per XMPP -// standard XEP-166. Can be serialized into multiple protocols, -// including the standard (Jingle) and the draft standard (Gingle). -// In general, used to communicate actions related to a p2p session, -// such accept, initiate, terminate, etc. - -struct SessionMessage { - SessionMessage() : action_elem(NULL), stanza(NULL) {} - - SessionMessage(SignalingProtocol protocol, ActionType type, - const std::string& sid, const std::string& initiator) : - protocol(protocol), type(type), sid(sid), initiator(initiator), - action_elem(NULL), stanza(NULL) {} - - std::string id; - std::string from; - std::string to; - SignalingProtocol protocol; - ActionType type; - std::string sid; // session id - std::string initiator; - - // Used for further parsing when necessary. - // Represents <session> or <jingle>. - const buzz::XmlElement* action_elem; - // Mostly used for debugging. - const buzz::XmlElement* stanza; -}; - -// TODO: Break up this class so we don't have to typedef it into -// different classes. -struct ContentMessage { - ContentMessage() : owns_contents(false) {} - - ~ContentMessage() { - if (owns_contents) { - for (ContentInfos::iterator content = contents.begin(); - content != contents.end(); content++) { - delete content->description; - } - } - } - - // Caller takes ownership of contents. - ContentInfos ClearContents() { - ContentInfos out; - contents.swap(out); - owns_contents = false; - return out; - } - - bool owns_contents; - ContentInfos contents; - TransportInfos transports; - ContentGroups groups; -}; - -typedef ContentMessage SessionInitiate; -typedef ContentMessage SessionAccept; -// Note that a DescriptionInfo does not have TransportInfos. -typedef ContentMessage DescriptionInfo; - -struct SessionTerminate { - SessionTerminate() {} - - explicit SessionTerminate(const std::string& reason) : - reason(reason) {} - - std::string reason; - std::string debug_reason; -}; - -struct SessionRedirect { - std::string target; -}; - -// Used during parsing and writing to map component to channel name -// and back. This is primarily for converting old G-ICE candidate -// signalling to new ICE candidate classes. -class CandidateTranslator { - public: - virtual bool GetChannelNameFromComponent( - int component, std::string* channel_name) const = 0; - virtual bool GetComponentFromChannelName( - const std::string& channel_name, int* component) const = 0; -}; - -// Content name => translator -typedef std::map<std::string, CandidateTranslator*> CandidateTranslatorMap; - -bool IsSessionMessage(const buzz::XmlElement* stanza); -bool ParseSessionMessage(const buzz::XmlElement* stanza, - SessionMessage* msg, - ParseError* error); -// Will return an error if there is more than one content type. -bool ParseContentType(SignalingProtocol protocol, - const buzz::XmlElement* action_elem, - std::string* content_type, - ParseError* error); -void WriteSessionMessage(const SessionMessage& msg, - const XmlElements& action_elems, - buzz::XmlElement* stanza); -bool ParseSessionInitiate(SignalingProtocol protocol, - const buzz::XmlElement* action_elem, - const ContentParserMap& content_parsers, - const TransportParserMap& transport_parsers, - const CandidateTranslatorMap& translators, - SessionInitiate* init, - ParseError* error); -bool WriteSessionInitiate(SignalingProtocol protocol, - const ContentInfos& contents, - const TransportInfos& tinfos, - const ContentParserMap& content_parsers, - const TransportParserMap& transport_parsers, - const CandidateTranslatorMap& translators, - const ContentGroups& groups, - XmlElements* elems, - WriteError* error); -bool ParseSessionAccept(SignalingProtocol protocol, - const buzz::XmlElement* action_elem, - const ContentParserMap& content_parsers, - const TransportParserMap& transport_parsers, - const CandidateTranslatorMap& translators, - SessionAccept* accept, - ParseError* error); -bool WriteSessionAccept(SignalingProtocol protocol, - const ContentInfos& contents, - const TransportInfos& tinfos, - const ContentParserMap& content_parsers, - const TransportParserMap& transport_parsers, - const CandidateTranslatorMap& translators, - const ContentGroups& groups, - XmlElements* elems, - WriteError* error); -bool ParseSessionTerminate(SignalingProtocol protocol, - const buzz::XmlElement* action_elem, - SessionTerminate* term, - ParseError* error); -void WriteSessionTerminate(SignalingProtocol protocol, - const SessionTerminate& term, - XmlElements* elems); -bool ParseDescriptionInfo(SignalingProtocol protocol, - const buzz::XmlElement* action_elem, - const ContentParserMap& content_parsers, - const TransportParserMap& transport_parsers, - const CandidateTranslatorMap& translators, - DescriptionInfo* description_info, - ParseError* error); -bool WriteDescriptionInfo(SignalingProtocol protocol, - const ContentInfos& contents, - const ContentParserMap& content_parsers, - XmlElements* elems, - WriteError* error); -// Since a TransportInfo is not a transport-info message, and a -// transport-info message is just a collection of TransportInfos, we -// say Parse/Write TransportInfos for transport-info messages. -bool ParseTransportInfos(SignalingProtocol protocol, - const buzz::XmlElement* action_elem, - const ContentInfos& contents, - const TransportParserMap& trans_parsers, - const CandidateTranslatorMap& translators, - TransportInfos* tinfos, - ParseError* error); -bool WriteTransportInfos(SignalingProtocol protocol, - const TransportInfos& tinfos, - const TransportParserMap& trans_parsers, - const CandidateTranslatorMap& translators, - XmlElements* elems, - WriteError* error); -// Handles both Gingle and Jingle syntax. -bool FindSessionRedirect(const buzz::XmlElement* stanza, - SessionRedirect* redirect); -} // namespace cricket - -#endif // WEBRTC_P2P_BASE_SESSIONMESSAGES_H_ diff --git a/talk/p2p/base/stun.cc b/talk/p2p/base/stun.cc deleted file mode 100644 index 6bdf77e04..000000000 --- a/talk/p2p/base/stun.cc +++ /dev/null @@ -1,932 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "webrtc/p2p/base/stun.h" - -#include <string.h> - -#include "webrtc/base/byteorder.h" -#include "webrtc/base/common.h" -#include "webrtc/base/crc32.h" -#include "webrtc/base/logging.h" -#include "webrtc/base/messagedigest.h" -#include "webrtc/base/scoped_ptr.h" -#include "webrtc/base/stringencode.h" - -using rtc::ByteBuffer; - -namespace cricket { - -const char STUN_ERROR_REASON_TRY_ALTERNATE_SERVER[] = "Try Alternate Server"; -const char STUN_ERROR_REASON_BAD_REQUEST[] = "Bad Request"; -const char STUN_ERROR_REASON_UNAUTHORIZED[] = "Unauthorized"; -const char STUN_ERROR_REASON_FORBIDDEN[] = "Forbidden"; -const char STUN_ERROR_REASON_STALE_CREDENTIALS[] = "Stale Credentials"; -const char STUN_ERROR_REASON_ALLOCATION_MISMATCH[] = "Allocation Mismatch"; -const char STUN_ERROR_REASON_STALE_NONCE[] = "Stale Nonce"; -const char STUN_ERROR_REASON_WRONG_CREDENTIALS[] = "Wrong Credentials"; -const char STUN_ERROR_REASON_UNSUPPORTED_PROTOCOL[] = "Unsupported Protocol"; -const char STUN_ERROR_REASON_ROLE_CONFLICT[] = "Role Conflict"; -const char STUN_ERROR_REASON_SERVER_ERROR[] = "Server Error"; - -const char TURN_MAGIC_COOKIE_VALUE[] = { '\x72', '\xC6', '\x4B', '\xC6' }; -const char EMPTY_TRANSACTION_ID[] = "0000000000000000"; -const uint32 STUN_FINGERPRINT_XOR_VALUE = 0x5354554E; - -// StunMessage - -StunMessage::StunMessage() - : type_(0), - length_(0), - transaction_id_(EMPTY_TRANSACTION_ID) { - ASSERT(IsValidTransactionId(transaction_id_)); - attrs_ = new std::vector<StunAttribute*>(); -} - -StunMessage::~StunMessage() { - for (size_t i = 0; i < attrs_->size(); i++) - delete (*attrs_)[i]; - delete attrs_; -} - -bool StunMessage::IsLegacy() const { - if (transaction_id_.size() == kStunLegacyTransactionIdLength) - return true; - ASSERT(transaction_id_.size() == kStunTransactionIdLength); - return false; -} - -bool StunMessage::SetTransactionID(const std::string& str) { - if (!IsValidTransactionId(str)) { - return false; - } - transaction_id_ = str; - return true; -} - -bool StunMessage::AddAttribute(StunAttribute* attr) { - // Fail any attributes that aren't valid for this type of message. - if (attr->value_type() != GetAttributeValueType(attr->type())) { - return false; - } - attrs_->push_back(attr); - attr->SetOwner(this); - size_t attr_length = attr->length(); - if (attr_length % 4 != 0) { - attr_length += (4 - (attr_length % 4)); - } - length_ += static_cast<uint16>(attr_length + 4); - return true; -} - -const StunAddressAttribute* StunMessage::GetAddress(int type) const { - switch (type) { - case STUN_ATTR_MAPPED_ADDRESS: { - // Return XOR-MAPPED-ADDRESS when MAPPED-ADDRESS attribute is - // missing. - const StunAttribute* mapped_address = - GetAttribute(STUN_ATTR_MAPPED_ADDRESS); - if (!mapped_address) - mapped_address = GetAttribute(STUN_ATTR_XOR_MAPPED_ADDRESS); - return reinterpret_cast<const StunAddressAttribute*>(mapped_address); - } - - default: - return static_cast<const StunAddressAttribute*>(GetAttribute(type)); - } -} - -const StunUInt32Attribute* StunMessage::GetUInt32(int type) const { - return static_cast<const StunUInt32Attribute*>(GetAttribute(type)); -} - -const StunUInt64Attribute* StunMessage::GetUInt64(int type) const { - return static_cast<const StunUInt64Attribute*>(GetAttribute(type)); -} - -const StunByteStringAttribute* StunMessage::GetByteString(int type) const { - return static_cast<const StunByteStringAttribute*>(GetAttribute(type)); -} - -const StunErrorCodeAttribute* StunMessage::GetErrorCode() const { - return static_cast<const StunErrorCodeAttribute*>( - GetAttribute(STUN_ATTR_ERROR_CODE)); -} - -const StunUInt16ListAttribute* StunMessage::GetUnknownAttributes() const { - return static_cast<const StunUInt16ListAttribute*>( - GetAttribute(STUN_ATTR_UNKNOWN_ATTRIBUTES)); -} - -// Verifies a STUN message has a valid MESSAGE-INTEGRITY attribute, using the -// procedure outlined in RFC 5389, section 15.4. -bool StunMessage::ValidateMessageIntegrity(const char* data, size_t size, - const std::string& password) { - // Verifying the size of the message. - if ((size % 4) != 0) { - return false; - } - - // Getting the message length from the STUN header. - uint16 msg_length = rtc::GetBE16(&data[2]); - if (size != (msg_length + kStunHeaderSize)) { - return false; - } - - // Finding Message Integrity attribute in stun message. - size_t current_pos = kStunHeaderSize; - bool has_message_integrity_attr = false; - while (current_pos < size) { - uint16 attr_type, attr_length; - // Getting attribute type and length. - attr_type = rtc::GetBE16(&data[current_pos]); - attr_length = rtc::GetBE16(&data[current_pos + sizeof(attr_type)]); - - // If M-I, sanity check it, and break out. - if (attr_type == STUN_ATTR_MESSAGE_INTEGRITY) { - if (attr_length != kStunMessageIntegritySize || - current_pos + attr_length > size) { - return false; - } - has_message_integrity_attr = true; - break; - } - - // Otherwise, skip to the next attribute. - current_pos += sizeof(attr_type) + sizeof(attr_length) + attr_length; - if ((attr_length % 4) != 0) { - current_pos += (4 - (attr_length % 4)); - } - } - - if (!has_message_integrity_attr) { - return false; - } - - // Getting length of the message to calculate Message Integrity. - size_t mi_pos = current_pos; - rtc::scoped_ptr<char[]> temp_data(new char[current_pos]); - memcpy(temp_data.get(), data, current_pos); - if (size > mi_pos + kStunAttributeHeaderSize + kStunMessageIntegritySize) { - // Stun message has other attributes after message integrity. - // Adjust the length parameter in stun message to calculate HMAC. - size_t extra_offset = size - - (mi_pos + kStunAttributeHeaderSize + kStunMessageIntegritySize); - size_t new_adjusted_len = size - extra_offset - kStunHeaderSize; - - // Writing new length of the STUN message @ Message Length in temp buffer. - // 0 1 2 3 - // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - // |0 0| STUN Message Type | Message Length | - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - rtc::SetBE16(temp_data.get() + 2, - static_cast<uint16>(new_adjusted_len)); - } - - char hmac[kStunMessageIntegritySize]; - size_t ret = rtc::ComputeHmac(rtc::DIGEST_SHA_1, - password.c_str(), password.size(), - temp_data.get(), mi_pos, - hmac, sizeof(hmac)); - ASSERT(ret == sizeof(hmac)); - if (ret != sizeof(hmac)) - return false; - - // Comparing the calculated HMAC with the one present in the message. - return memcmp(data + current_pos + kStunAttributeHeaderSize, - hmac, - sizeof(hmac)) == 0; -} - -bool StunMessage::AddMessageIntegrity(const std::string& password) { - return AddMessageIntegrity(password.c_str(), password.size()); -} - -bool StunMessage::AddMessageIntegrity(const char* key, - size_t keylen) { - // Add the attribute with a dummy value. Since this is a known attribute, it - // can't fail. - StunByteStringAttribute* msg_integrity_attr = - new StunByteStringAttribute(STUN_ATTR_MESSAGE_INTEGRITY, - std::string(kStunMessageIntegritySize, '0')); - VERIFY(AddAttribute(msg_integrity_attr)); - - // Calculate the HMAC for the message. - rtc::ByteBuffer buf; - if (!Write(&buf)) - return false; - - int msg_len_for_hmac = static_cast<int>( - buf.Length() - kStunAttributeHeaderSize - msg_integrity_attr->length()); - char hmac[kStunMessageIntegritySize]; - size_t ret = rtc::ComputeHmac(rtc::DIGEST_SHA_1, - key, keylen, - buf.Data(), msg_len_for_hmac, - hmac, sizeof(hmac)); - ASSERT(ret == sizeof(hmac)); - if (ret != sizeof(hmac)) { - LOG(LS_ERROR) << "HMAC computation failed. Message-Integrity " - << "has dummy value."; - return false; - } - - // Insert correct HMAC into the attribute. - msg_integrity_attr->CopyBytes(hmac, sizeof(hmac)); - return true; -} - -// Verifies a message is in fact a STUN message, by performing the checks -// outlined in RFC 5389, section 7.3, including the FINGERPRINT check detailed -// in section 15.5. -bool StunMessage::ValidateFingerprint(const char* data, size_t size) { - // Check the message length. - size_t fingerprint_attr_size = - kStunAttributeHeaderSize + StunUInt32Attribute::SIZE; - if (size % 4 != 0 || size < kStunHeaderSize + fingerprint_attr_size) - return false; - - // Skip the rest if the magic cookie isn't present. - const char* magic_cookie = - data + kStunTransactionIdOffset - kStunMagicCookieLength; - if (rtc::GetBE32(magic_cookie) != kStunMagicCookie) - return false; - - // Check the fingerprint type and length. - const char* fingerprint_attr_data = data + size - fingerprint_attr_size; - if (rtc::GetBE16(fingerprint_attr_data) != STUN_ATTR_FINGERPRINT || - rtc::GetBE16(fingerprint_attr_data + sizeof(uint16)) != - StunUInt32Attribute::SIZE) - return false; - - // Check the fingerprint value. - uint32 fingerprint = - rtc::GetBE32(fingerprint_attr_data + kStunAttributeHeaderSize); - return ((fingerprint ^ STUN_FINGERPRINT_XOR_VALUE) == - rtc::ComputeCrc32(data, size - fingerprint_attr_size)); -} - -bool StunMessage::AddFingerprint() { - // Add the attribute with a dummy value. Since this is a known attribute, - // it can't fail. - StunUInt32Attribute* fingerprint_attr = - new StunUInt32Attribute(STUN_ATTR_FINGERPRINT, 0); - VERIFY(AddAttribute(fingerprint_attr)); - - // Calculate the CRC-32 for the message and insert it. - rtc::ByteBuffer buf; - if (!Write(&buf)) - return false; - - int msg_len_for_crc32 = static_cast<int>( - buf.Length() - kStunAttributeHeaderSize - fingerprint_attr->length()); - uint32 c = rtc::ComputeCrc32(buf.Data(), msg_len_for_crc32); - - // Insert the correct CRC-32, XORed with a constant, into the attribute. - fingerprint_attr->SetValue(c ^ STUN_FINGERPRINT_XOR_VALUE); - return true; -} - -bool StunMessage::Read(ByteBuffer* buf) { - if (!buf->ReadUInt16(&type_)) - return false; - - if (type_ & 0x8000) { - // RTP and RTCP set the MSB of first byte, since first two bits are version, - // and version is always 2 (10). If set, this is not a STUN packet. - return false; - } - - if (!buf->ReadUInt16(&length_)) - return false; - - std::string magic_cookie; - if (!buf->ReadString(&magic_cookie, kStunMagicCookieLength)) - return false; - - std::string transaction_id; - if (!buf->ReadString(&transaction_id, kStunTransactionIdLength)) - return false; - - uint32 magic_cookie_int = - *reinterpret_cast<const uint32*>(magic_cookie.data()); - if (rtc::NetworkToHost32(magic_cookie_int) != kStunMagicCookie) { - // If magic cookie is invalid it means that the peer implements - // RFC3489 instead of RFC5389. - transaction_id.insert(0, magic_cookie); - } - ASSERT(IsValidTransactionId(transaction_id)); - transaction_id_ = transaction_id; - - if (length_ != buf->Length()) - return false; - - attrs_->resize(0); - - size_t rest = buf->Length() - length_; - while (buf->Length() > rest) { - uint16 attr_type, attr_length; - if (!buf->ReadUInt16(&attr_type)) - return false; - if (!buf->ReadUInt16(&attr_length)) - return false; - - StunAttribute* attr = CreateAttribute(attr_type, attr_length); - if (!attr) { - // Skip any unknown or malformed attributes. - if ((attr_length % 4) != 0) { - attr_length += (4 - (attr_length % 4)); - } - if (!buf->Consume(attr_length)) - return false; - } else { - if (!attr->Read(buf)) - return false; - attrs_->push_back(attr); - } - } - - ASSERT(buf->Length() == rest); - return true; -} - -bool StunMessage::Write(ByteBuffer* buf) const { - buf->WriteUInt16(type_); - buf->WriteUInt16(length_); - if (!IsLegacy()) - buf->WriteUInt32(kStunMagicCookie); - buf->WriteString(transaction_id_); - - for (size_t i = 0; i < attrs_->size(); ++i) { - buf->WriteUInt16((*attrs_)[i]->type()); - buf->WriteUInt16(static_cast<uint16>((*attrs_)[i]->length())); - if (!(*attrs_)[i]->Write(buf)) - return false; - } - - return true; -} - -StunAttributeValueType StunMessage::GetAttributeValueType(int type) const { - switch (type) { - case STUN_ATTR_MAPPED_ADDRESS: return STUN_VALUE_ADDRESS; - case STUN_ATTR_USERNAME: return STUN_VALUE_BYTE_STRING; - case STUN_ATTR_MESSAGE_INTEGRITY: return STUN_VALUE_BYTE_STRING; - case STUN_ATTR_ERROR_CODE: return STUN_VALUE_ERROR_CODE; - case STUN_ATTR_UNKNOWN_ATTRIBUTES: return STUN_VALUE_UINT16_LIST; - case STUN_ATTR_REALM: return STUN_VALUE_BYTE_STRING; - case STUN_ATTR_NONCE: return STUN_VALUE_BYTE_STRING; - case STUN_ATTR_XOR_MAPPED_ADDRESS: return STUN_VALUE_XOR_ADDRESS; - case STUN_ATTR_SOFTWARE: return STUN_VALUE_BYTE_STRING; - case STUN_ATTR_ALTERNATE_SERVER: return STUN_VALUE_ADDRESS; - case STUN_ATTR_FINGERPRINT: return STUN_VALUE_UINT32; - case STUN_ATTR_RETRANSMIT_COUNT: return STUN_VALUE_UINT32; - default: return STUN_VALUE_UNKNOWN; - } -} - -StunAttribute* StunMessage::CreateAttribute(int type, size_t length) /*const*/ { - StunAttributeValueType value_type = GetAttributeValueType(type); - return StunAttribute::Create(value_type, type, - static_cast<uint16>(length), this); -} - -const StunAttribute* StunMessage::GetAttribute(int type) const { - for (size_t i = 0; i < attrs_->size(); ++i) { - if ((*attrs_)[i]->type() == type) - return (*attrs_)[i]; - } - return NULL; -} - -bool StunMessage::IsValidTransactionId(const std::string& transaction_id) { - return transaction_id.size() == kStunTransactionIdLength || - transaction_id.size() == kStunLegacyTransactionIdLength; -} - -// StunAttribute - -StunAttribute::StunAttribute(uint16 type, uint16 length) - : type_(type), length_(length) { -} - -void StunAttribute::ConsumePadding(rtc::ByteBuffer* buf) const { - int remainder = length_ % 4; - if (remainder > 0) { - buf->Consume(4 - remainder); - } -} - -void StunAttribute::WritePadding(rtc::ByteBuffer* buf) const { - int remainder = length_ % 4; - if (remainder > 0) { - char zeroes[4] = {0}; - buf->WriteBytes(zeroes, 4 - remainder); - } -} - -StunAttribute* StunAttribute::Create(StunAttributeValueType value_type, - uint16 type, uint16 length, - StunMessage* owner) { - switch (value_type) { - case STUN_VALUE_ADDRESS: - return new StunAddressAttribute(type, length); - case STUN_VALUE_XOR_ADDRESS: - return new StunXorAddressAttribute(type, length, owner); - case STUN_VALUE_UINT32: - return new StunUInt32Attribute(type); - case STUN_VALUE_UINT64: - return new StunUInt64Attribute(type); - case STUN_VALUE_BYTE_STRING: - return new StunByteStringAttribute(type, length); - case STUN_VALUE_ERROR_CODE: - return new StunErrorCodeAttribute(type, length); - case STUN_VALUE_UINT16_LIST: - return new StunUInt16ListAttribute(type, length); - default: - return NULL; - } -} - -StunAddressAttribute* StunAttribute::CreateAddress(uint16 type) { - return new StunAddressAttribute(type, 0); -} - -StunXorAddressAttribute* StunAttribute::CreateXorAddress(uint16 type) { - return new StunXorAddressAttribute(type, 0, NULL); -} - -StunUInt64Attribute* StunAttribute::CreateUInt64(uint16 type) { - return new StunUInt64Attribute(type); -} - -StunUInt32Attribute* StunAttribute::CreateUInt32(uint16 type) { - return new StunUInt32Attribute(type); -} - -StunByteStringAttribute* StunAttribute::CreateByteString(uint16 type) { - return new StunByteStringAttribute(type, 0); -} - -StunErrorCodeAttribute* StunAttribute::CreateErrorCode() { - return new StunErrorCodeAttribute( - STUN_ATTR_ERROR_CODE, StunErrorCodeAttribute::MIN_SIZE); -} - -StunUInt16ListAttribute* StunAttribute::CreateUnknownAttributes() { - return new StunUInt16ListAttribute(STUN_ATTR_UNKNOWN_ATTRIBUTES, 0); -} - -StunAddressAttribute::StunAddressAttribute(uint16 type, - const rtc::SocketAddress& addr) - : StunAttribute(type, 0) { - SetAddress(addr); -} - -StunAddressAttribute::StunAddressAttribute(uint16 type, uint16 length) - : StunAttribute(type, length) { -} - -bool StunAddressAttribute::Read(ByteBuffer* buf) { - uint8 dummy; - if (!buf->ReadUInt8(&dummy)) - return false; - - uint8 stun_family; - if (!buf->ReadUInt8(&stun_family)) { - return false; - } - uint16 port; - if (!buf->ReadUInt16(&port)) - return false; - if (stun_family == STUN_ADDRESS_IPV4) { - in_addr v4addr; - if (length() != SIZE_IP4) { - return false; - } - if (!buf->ReadBytes(reinterpret_cast<char*>(&v4addr), sizeof(v4addr))) { - return false; - } - rtc::IPAddress ipaddr(v4addr); - SetAddress(rtc::SocketAddress(ipaddr, port)); - } else if (stun_family == STUN_ADDRESS_IPV6) { - in6_addr v6addr; - if (length() != SIZE_IP6) { - return false; - } - if (!buf->ReadBytes(reinterpret_cast<char*>(&v6addr), sizeof(v6addr))) { - return false; - } - rtc::IPAddress ipaddr(v6addr); - SetAddress(rtc::SocketAddress(ipaddr, port)); - } else { - return false; - } - return true; -} - -bool StunAddressAttribute::Write(ByteBuffer* buf) const { - StunAddressFamily address_family = family(); - if (address_family == STUN_ADDRESS_UNDEF) { - LOG(LS_ERROR) << "Error writing address attribute: unknown family."; - return false; - } - buf->WriteUInt8(0); - buf->WriteUInt8(address_family); - buf->WriteUInt16(address_.port()); - switch (address_.family()) { - case AF_INET: { - in_addr v4addr = address_.ipaddr().ipv4_address(); - buf->WriteBytes(reinterpret_cast<char*>(&v4addr), sizeof(v4addr)); - break; - } - case AF_INET6: { - in6_addr v6addr = address_.ipaddr().ipv6_address(); - buf->WriteBytes(reinterpret_cast<char*>(&v6addr), sizeof(v6addr)); - break; - } - } - return true; -} - -StunXorAddressAttribute::StunXorAddressAttribute(uint16 type, - const rtc::SocketAddress& addr) - : StunAddressAttribute(type, addr), owner_(NULL) { -} - -StunXorAddressAttribute::StunXorAddressAttribute(uint16 type, - uint16 length, - StunMessage* owner) - : StunAddressAttribute(type, length), owner_(owner) {} - -rtc::IPAddress StunXorAddressAttribute::GetXoredIP() const { - if (owner_) { - rtc::IPAddress ip = ipaddr(); - switch (ip.family()) { - case AF_INET: { - in_addr v4addr = ip.ipv4_address(); - v4addr.s_addr = - (v4addr.s_addr ^ rtc::HostToNetwork32(kStunMagicCookie)); - return rtc::IPAddress(v4addr); - } - case AF_INET6: { - in6_addr v6addr = ip.ipv6_address(); - const std::string& transaction_id = owner_->transaction_id(); - if (transaction_id.length() == kStunTransactionIdLength) { - uint32 transactionid_as_ints[3]; - memcpy(&transactionid_as_ints[0], transaction_id.c_str(), - transaction_id.length()); - uint32* ip_as_ints = reinterpret_cast<uint32*>(&v6addr.s6_addr); - // Transaction ID is in network byte order, but magic cookie - // is stored in host byte order. - ip_as_ints[0] = - (ip_as_ints[0] ^ rtc::HostToNetwork32(kStunMagicCookie)); - ip_as_ints[1] = (ip_as_ints[1] ^ transactionid_as_ints[0]); - ip_as_ints[2] = (ip_as_ints[2] ^ transactionid_as_ints[1]); - ip_as_ints[3] = (ip_as_ints[3] ^ transactionid_as_ints[2]); - return rtc::IPAddress(v6addr); - } - break; - } - } - } - // Invalid ip family or transaction ID, or missing owner. - // Return an AF_UNSPEC address. - return rtc::IPAddress(); -} - -bool StunXorAddressAttribute::Read(ByteBuffer* buf) { - if (!StunAddressAttribute::Read(buf)) - return false; - uint16 xoredport = port() ^ (kStunMagicCookie >> 16); - rtc::IPAddress xored_ip = GetXoredIP(); - SetAddress(rtc::SocketAddress(xored_ip, xoredport)); - return true; -} - -bool StunXorAddressAttribute::Write(ByteBuffer* buf) const { - StunAddressFamily address_family = family(); - if (address_family == STUN_ADDRESS_UNDEF) { - LOG(LS_ERROR) << "Error writing xor-address attribute: unknown family."; - return false; - } - rtc::IPAddress xored_ip = GetXoredIP(); - if (xored_ip.family() == AF_UNSPEC) { - return false; - } - buf->WriteUInt8(0); - buf->WriteUInt8(family()); - buf->WriteUInt16(port() ^ (kStunMagicCookie >> 16)); - switch (xored_ip.family()) { - case AF_INET: { - in_addr v4addr = xored_ip.ipv4_address(); - buf->WriteBytes(reinterpret_cast<const char*>(&v4addr), sizeof(v4addr)); - break; - } - case AF_INET6: { - in6_addr v6addr = xored_ip.ipv6_address(); - buf->WriteBytes(reinterpret_cast<const char*>(&v6addr), sizeof(v6addr)); - break; - } - } - return true; -} - -StunUInt32Attribute::StunUInt32Attribute(uint16 type, uint32 value) - : StunAttribute(type, SIZE), bits_(value) { -} - -StunUInt32Attribute::StunUInt32Attribute(uint16 type) - : StunAttribute(type, SIZE), bits_(0) { -} - -bool StunUInt32Attribute::GetBit(size_t index) const { - ASSERT(index < 32); - return static_cast<bool>((bits_ >> index) & 0x1); -} - -void StunUInt32Attribute::SetBit(size_t index, bool value) { - ASSERT(index < 32); - bits_ &= ~(1 << index); - bits_ |= value ? (1 << index) : 0; -} - -bool StunUInt32Attribute::Read(ByteBuffer* buf) { - if (length() != SIZE || !buf->ReadUInt32(&bits_)) - return false; - return true; -} - -bool StunUInt32Attribute::Write(ByteBuffer* buf) const { - buf->WriteUInt32(bits_); - return true; -} - -StunUInt64Attribute::StunUInt64Attribute(uint16 type, uint64 value) - : StunAttribute(type, SIZE), bits_(value) { -} - -StunUInt64Attribute::StunUInt64Attribute(uint16 type) - : StunAttribute(type, SIZE), bits_(0) { -} - -bool StunUInt64Attribute::Read(ByteBuffer* buf) { - if (length() != SIZE || !buf->ReadUInt64(&bits_)) - return false; - return true; -} - -bool StunUInt64Attribute::Write(ByteBuffer* buf) const { - buf->WriteUInt64(bits_); - return true; -} - -StunByteStringAttribute::StunByteStringAttribute(uint16 type) - : StunAttribute(type, 0), bytes_(NULL) { -} - -StunByteStringAttribute::StunByteStringAttribute(uint16 type, - const std::string& str) - : StunAttribute(type, 0), bytes_(NULL) { - CopyBytes(str.c_str(), str.size()); -} - -StunByteStringAttribute::StunByteStringAttribute(uint16 type, - const void* bytes, - size_t length) - : StunAttribute(type, 0), bytes_(NULL) { - CopyBytes(bytes, length); -} - -StunByteStringAttribute::StunByteStringAttribute(uint16 type, uint16 length) - : StunAttribute(type, length), bytes_(NULL) { -} - -StunByteStringAttribute::~StunByteStringAttribute() { - delete [] bytes_; -} - -void StunByteStringAttribute::CopyBytes(const char* bytes) { - CopyBytes(bytes, strlen(bytes)); -} - -void StunByteStringAttribute::CopyBytes(const void* bytes, size_t length) { - char* new_bytes = new char[length]; - memcpy(new_bytes, bytes, length); - SetBytes(new_bytes, length); -} - -uint8 StunByteStringAttribute::GetByte(size_t index) const { - ASSERT(bytes_ != NULL); - ASSERT(index < length()); - return static_cast<uint8>(bytes_[index]); -} - -void StunByteStringAttribute::SetByte(size_t index, uint8 value) { - ASSERT(bytes_ != NULL); - ASSERT(index < length()); - bytes_[index] = value; -} - -bool StunByteStringAttribute::Read(ByteBuffer* buf) { - bytes_ = new char[length()]; - if (!buf->ReadBytes(bytes_, length())) { - return false; - } - - ConsumePadding(buf); - return true; -} - -bool StunByteStringAttribute::Write(ByteBuffer* buf) const { - buf->WriteBytes(bytes_, length()); - WritePadding(buf); - return true; -} - -void StunByteStringAttribute::SetBytes(char* bytes, size_t length) { - delete [] bytes_; - bytes_ = bytes; - SetLength(static_cast<uint16>(length)); -} - -StunErrorCodeAttribute::StunErrorCodeAttribute(uint16 type, int code, - const std::string& reason) - : StunAttribute(type, 0) { - SetCode(code); - SetReason(reason); -} - -StunErrorCodeAttribute::StunErrorCodeAttribute(uint16 type, uint16 length) - : StunAttribute(type, length), class_(0), number_(0) { -} - -StunErrorCodeAttribute::~StunErrorCodeAttribute() { -} - -int StunErrorCodeAttribute::code() const { - return class_ * 100 + number_; -} - -void StunErrorCodeAttribute::SetCode(int code) { - class_ = static_cast<uint8>(code / 100); - number_ = static_cast<uint8>(code % 100); -} - -void StunErrorCodeAttribute::SetReason(const std::string& reason) { - SetLength(MIN_SIZE + static_cast<uint16>(reason.size())); - reason_ = reason; -} - -bool StunErrorCodeAttribute::Read(ByteBuffer* buf) { - uint32 val; - if (length() < MIN_SIZE || !buf->ReadUInt32(&val)) - return false; - - if ((val >> 11) != 0) - LOG(LS_ERROR) << "error-code bits not zero"; - - class_ = ((val >> 8) & 0x7); - number_ = (val & 0xff); - - if (!buf->ReadString(&reason_, length() - 4)) - return false; - - ConsumePadding(buf); - return true; -} - -bool StunErrorCodeAttribute::Write(ByteBuffer* buf) const { - buf->WriteUInt32(class_ << 8 | number_); - buf->WriteString(reason_); - WritePadding(buf); - return true; -} - -StunUInt16ListAttribute::StunUInt16ListAttribute(uint16 type, uint16 length) - : StunAttribute(type, length) { - attr_types_ = new std::vector<uint16>(); -} - -StunUInt16ListAttribute::~StunUInt16ListAttribute() { - delete attr_types_; -} - -size_t StunUInt16ListAttribute::Size() const { - return attr_types_->size(); -} - -uint16 StunUInt16ListAttribute::GetType(int index) const { - return (*attr_types_)[index]; -} - -void StunUInt16ListAttribute::SetType(int index, uint16 value) { - (*attr_types_)[index] = value; -} - -void StunUInt16ListAttribute::AddType(uint16 value) { - attr_types_->push_back(value); - SetLength(static_cast<uint16>(attr_types_->size() * 2)); -} - -bool StunUInt16ListAttribute::Read(ByteBuffer* buf) { - if (length() % 2) - return false; - - for (size_t i = 0; i < length() / 2; i++) { - uint16 attr; - if (!buf->ReadUInt16(&attr)) - return false; - attr_types_->push_back(attr); - } - // Padding of these attributes is done in RFC 5389 style. This is - // slightly different from RFC3489, but it shouldn't be important. - // RFC3489 pads out to a 32 bit boundary by duplicating one of the - // entries in the list (not necessarily the last one - it's unspecified). - // RFC5389 pads on the end, and the bytes are always ignored. - ConsumePadding(buf); - return true; -} - -bool StunUInt16ListAttribute::Write(ByteBuffer* buf) const { - for (size_t i = 0; i < attr_types_->size(); ++i) { - buf->WriteUInt16((*attr_types_)[i]); - } - WritePadding(buf); - return true; -} - -int GetStunSuccessResponseType(int req_type) { - return IsStunRequestType(req_type) ? (req_type | 0x100) : -1; -} - -int GetStunErrorResponseType(int req_type) { - return IsStunRequestType(req_type) ? (req_type | 0x110) : -1; -} - -bool IsStunRequestType(int msg_type) { - return ((msg_type & kStunTypeMask) == 0x000); -} - -bool IsStunIndicationType(int msg_type) { - return ((msg_type & kStunTypeMask) == 0x010); -} - -bool IsStunSuccessResponseType(int msg_type) { - return ((msg_type & kStunTypeMask) == 0x100); -} - -bool IsStunErrorResponseType(int msg_type) { - return ((msg_type & kStunTypeMask) == 0x110); -} - -bool ComputeStunCredentialHash(const std::string& username, - const std::string& realm, - const std::string& password, - std::string* hash) { - // http://tools.ietf.org/html/rfc5389#section-15.4 - // long-term credentials will be calculated using the key and key is - // key = MD5(username ":" realm ":" SASLprep(password)) - std::string input = username; - input += ':'; - input += realm; - input += ':'; - input += password; - - char digest[rtc::MessageDigest::kMaxSize]; - size_t size = rtc::ComputeDigest( - rtc::DIGEST_MD5, input.c_str(), input.size(), - digest, sizeof(digest)); - if (size == 0) { - return false; - } - - *hash = std::string(digest, size); - return true; -} - -} // namespace cricket diff --git a/talk/p2p/base/stun.h b/talk/p2p/base/stun.h deleted file mode 100644 index 5a43a3ccc..000000000 --- a/talk/p2p/base/stun.h +++ /dev/null @@ -1,649 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef WEBRTC_P2P_BASE_STUN_H_ -#define WEBRTC_P2P_BASE_STUN_H_ - -// This file contains classes for dealing with the STUN protocol, as specified -// in RFC 5389, and its descendants. - -#include <string> -#include <vector> - -#include "webrtc/base/basictypes.h" -#include "webrtc/base/bytebuffer.h" -#include "webrtc/base/socketaddress.h" - -namespace cricket { - -// These are the types of STUN messages defined in RFC 5389. -enum StunMessageType { - STUN_BINDING_REQUEST = 0x0001, - STUN_BINDING_INDICATION = 0x0011, - STUN_BINDING_RESPONSE = 0x0101, - STUN_BINDING_ERROR_RESPONSE = 0x0111, -}; - -// These are all known STUN attributes, defined in RFC 5389 and elsewhere. -// Next to each is the name of the class (T is StunTAttribute) that implements -// that type. -// RETRANSMIT_COUNT is the number of outstanding pings without a response at -// the time the packet is generated. -enum StunAttributeType { - STUN_ATTR_MAPPED_ADDRESS = 0x0001, // Address - STUN_ATTR_USERNAME = 0x0006, // ByteString - STUN_ATTR_MESSAGE_INTEGRITY = 0x0008, // ByteString, 20 bytes - STUN_ATTR_ERROR_CODE = 0x0009, // ErrorCode - STUN_ATTR_UNKNOWN_ATTRIBUTES = 0x000a, // UInt16List - STUN_ATTR_REALM = 0x0014, // ByteString - STUN_ATTR_NONCE = 0x0015, // ByteString - STUN_ATTR_XOR_MAPPED_ADDRESS = 0x0020, // XorAddress - STUN_ATTR_SOFTWARE = 0x8022, // ByteString - STUN_ATTR_ALTERNATE_SERVER = 0x8023, // Address - STUN_ATTR_FINGERPRINT = 0x8028, // UInt32 - STUN_ATTR_RETRANSMIT_COUNT = 0xFF00 // UInt32 -}; - -// These are the types of the values associated with the attributes above. -// This allows us to perform some basic validation when reading or adding -// attributes. Note that these values are for our own use, and not defined in -// RFC 5389. -enum StunAttributeValueType { - STUN_VALUE_UNKNOWN = 0, - STUN_VALUE_ADDRESS = 1, - STUN_VALUE_XOR_ADDRESS = 2, - STUN_VALUE_UINT32 = 3, - STUN_VALUE_UINT64 = 4, - STUN_VALUE_BYTE_STRING = 5, - STUN_VALUE_ERROR_CODE = 6, - STUN_VALUE_UINT16_LIST = 7 -}; - -// These are the types of STUN addresses defined in RFC 5389. -enum StunAddressFamily { - // NB: UNDEF is not part of the STUN spec. - STUN_ADDRESS_UNDEF = 0, - STUN_ADDRESS_IPV4 = 1, - STUN_ADDRESS_IPV6 = 2 -}; - -// These are the types of STUN error codes defined in RFC 5389. -enum StunErrorCode { - STUN_ERROR_TRY_ALTERNATE = 300, - STUN_ERROR_BAD_REQUEST = 400, - STUN_ERROR_UNAUTHORIZED = 401, - STUN_ERROR_UNKNOWN_ATTRIBUTE = 420, - STUN_ERROR_STALE_CREDENTIALS = 430, // GICE only - STUN_ERROR_STALE_NONCE = 438, - STUN_ERROR_SERVER_ERROR = 500, - STUN_ERROR_GLOBAL_FAILURE = 600 -}; - -// Strings for the error codes above. -extern const char STUN_ERROR_REASON_TRY_ALTERNATE_SERVER[]; -extern const char STUN_ERROR_REASON_BAD_REQUEST[]; -extern const char STUN_ERROR_REASON_UNAUTHORIZED[]; -extern const char STUN_ERROR_REASON_UNKNOWN_ATTRIBUTE[]; -extern const char STUN_ERROR_REASON_STALE_CREDENTIALS[]; -extern const char STUN_ERROR_REASON_STALE_NONCE[]; -extern const char STUN_ERROR_REASON_SERVER_ERROR[]; - -// The mask used to determine whether a STUN message is a request/response etc. -const uint32 kStunTypeMask = 0x0110; - -// STUN Attribute header length. -const size_t kStunAttributeHeaderSize = 4; - -// Following values correspond to RFC5389. -const size_t kStunHeaderSize = 20; -const size_t kStunTransactionIdOffset = 8; -const size_t kStunTransactionIdLength = 12; -const uint32 kStunMagicCookie = 0x2112A442; -const size_t kStunMagicCookieLength = sizeof(kStunMagicCookie); - -// Following value corresponds to an earlier version of STUN from -// RFC3489. -const size_t kStunLegacyTransactionIdLength = 16; - -// STUN Message Integrity HMAC length. -const size_t kStunMessageIntegritySize = 20; - -class StunAttribute; -class StunAddressAttribute; -class StunXorAddressAttribute; -class StunUInt32Attribute; -class StunUInt64Attribute; -class StunByteStringAttribute; -class StunErrorCodeAttribute; -class StunUInt16ListAttribute; - -// Records a complete STUN/TURN message. Each message consists of a type and -// any number of attributes. Each attribute is parsed into an instance of an -// appropriate class (see above). The Get* methods will return instances of -// that attribute class. -class StunMessage { - public: - StunMessage(); - virtual ~StunMessage(); - - int type() const { return type_; } - size_t length() const { return length_; } - const std::string& transaction_id() const { return transaction_id_; } - - // Returns true if the message confirms to RFC3489 rather than - // RFC5389. The main difference between two version of the STUN - // protocol is the presence of the magic cookie and different length - // of transaction ID. For outgoing packets version of the protocol - // is determined by the lengths of the transaction ID. - bool IsLegacy() const; - - void SetType(int type) { type_ = static_cast<uint16>(type); } - bool SetTransactionID(const std::string& str); - - // Gets the desired attribute value, or NULL if no such attribute type exists. - const StunAddressAttribute* GetAddress(int type) const; - const StunUInt32Attribute* GetUInt32(int type) const; - const StunUInt64Attribute* GetUInt64(int type) const; - const StunByteStringAttribute* GetByteString(int type) const; - - // Gets these specific attribute values. - const StunErrorCodeAttribute* GetErrorCode() const; - const StunUInt16ListAttribute* GetUnknownAttributes() const; - - // Takes ownership of the specified attribute, verifies it is of the correct - // type, and adds it to the message. The return value indicates whether this - // was successful. - bool AddAttribute(StunAttribute* attr); - - // Validates that a raw STUN message has a correct MESSAGE-INTEGRITY value. - // This can't currently be done on a StunMessage, since it is affected by - // padding data (which we discard when reading a StunMessage). - static bool ValidateMessageIntegrity(const char* data, size_t size, - const std::string& password); - // Adds a MESSAGE-INTEGRITY attribute that is valid for the current message. - bool AddMessageIntegrity(const std::string& password); - bool AddMessageIntegrity(const char* key, size_t keylen); - - // Verifies that a given buffer is STUN by checking for a correct FINGERPRINT. - static bool ValidateFingerprint(const char* data, size_t size); - - // Adds a FINGERPRINT attribute that is valid for the current message. - bool AddFingerprint(); - - // Parses the STUN packet in the given buffer and records it here. The - // return value indicates whether this was successful. - bool Read(rtc::ByteBuffer* buf); - - // Writes this object into a STUN packet. The return value indicates whether - // this was successful. - bool Write(rtc::ByteBuffer* buf) const; - - // Creates an empty message. Overridable by derived classes. - virtual StunMessage* CreateNew() const { return new StunMessage(); } - - protected: - // Verifies that the given attribute is allowed for this message. - virtual StunAttributeValueType GetAttributeValueType(int type) const; - - private: - StunAttribute* CreateAttribute(int type, size_t length) /* const*/; - const StunAttribute* GetAttribute(int type) const; - static bool IsValidTransactionId(const std::string& transaction_id); - - uint16 type_; - uint16 length_; - std::string transaction_id_; - std::vector<StunAttribute*>* attrs_; -}; - -// Base class for all STUN/TURN attributes. -class StunAttribute { - public: - virtual ~StunAttribute() { - } - - int type() const { return type_; } - size_t length() const { return length_; } - - // Return the type of this attribute. - virtual StunAttributeValueType value_type() const = 0; - - // Only XorAddressAttribute needs this so far. - virtual void SetOwner(StunMessage* owner) {} - - // Reads the body (not the type or length) for this type of attribute from - // the given buffer. Return value is true if successful. - virtual bool Read(rtc::ByteBuffer* buf) = 0; - - // Writes the body (not the type or length) to the given buffer. Return - // value is true if successful. - virtual bool Write(rtc::ByteBuffer* buf) const = 0; - - // Creates an attribute object with the given type and smallest length. - static StunAttribute* Create(StunAttributeValueType value_type, uint16 type, - uint16 length, StunMessage* owner); - // TODO: Allow these create functions to take parameters, to reduce - // the amount of work callers need to do to initialize attributes. - static StunAddressAttribute* CreateAddress(uint16 type); - static StunXorAddressAttribute* CreateXorAddress(uint16 type); - static StunUInt32Attribute* CreateUInt32(uint16 type); - static StunUInt64Attribute* CreateUInt64(uint16 type); - static StunByteStringAttribute* CreateByteString(uint16 type); - static StunErrorCodeAttribute* CreateErrorCode(); - static StunUInt16ListAttribute* CreateUnknownAttributes(); - - protected: - StunAttribute(uint16 type, uint16 length); - void SetLength(uint16 length) { length_ = length; } - void WritePadding(rtc::ByteBuffer* buf) const; - void ConsumePadding(rtc::ByteBuffer* buf) const; - - private: - uint16 type_; - uint16 length_; -}; - -// Implements STUN attributes that record an Internet address. -class StunAddressAttribute : public StunAttribute { - public: - static const uint16 SIZE_UNDEF = 0; - static const uint16 SIZE_IP4 = 8; - static const uint16 SIZE_IP6 = 20; - StunAddressAttribute(uint16 type, const rtc::SocketAddress& addr); - StunAddressAttribute(uint16 type, uint16 length); - - virtual StunAttributeValueType value_type() const { - return STUN_VALUE_ADDRESS; - } - - StunAddressFamily family() const { - switch (address_.ipaddr().family()) { - case AF_INET: - return STUN_ADDRESS_IPV4; - case AF_INET6: - return STUN_ADDRESS_IPV6; - } - return STUN_ADDRESS_UNDEF; - } - - const rtc::SocketAddress& GetAddress() const { return address_; } - const rtc::IPAddress& ipaddr() const { return address_.ipaddr(); } - uint16 port() const { return address_.port(); } - - void SetAddress(const rtc::SocketAddress& addr) { - address_ = addr; - EnsureAddressLength(); - } - void SetIP(const rtc::IPAddress& ip) { - address_.SetIP(ip); - EnsureAddressLength(); - } - void SetPort(uint16 port) { address_.SetPort(port); } - - virtual bool Read(rtc::ByteBuffer* buf); - virtual bool Write(rtc::ByteBuffer* buf) const; - - private: - void EnsureAddressLength() { - switch (family()) { - case STUN_ADDRESS_IPV4: { - SetLength(SIZE_IP4); - break; - } - case STUN_ADDRESS_IPV6: { - SetLength(SIZE_IP6); - break; - } - default: { - SetLength(SIZE_UNDEF); - break; - } - } - } - rtc::SocketAddress address_; -}; - -// Implements STUN attributes that record an Internet address. When encoded -// in a STUN message, the address contained in this attribute is XORed with the -// transaction ID of the message. -class StunXorAddressAttribute : public StunAddressAttribute { - public: - StunXorAddressAttribute(uint16 type, const rtc::SocketAddress& addr); - StunXorAddressAttribute(uint16 type, uint16 length, - StunMessage* owner); - - virtual StunAttributeValueType value_type() const { - return STUN_VALUE_XOR_ADDRESS; - } - virtual void SetOwner(StunMessage* owner) { - owner_ = owner; - } - virtual bool Read(rtc::ByteBuffer* buf); - virtual bool Write(rtc::ByteBuffer* buf) const; - - private: - rtc::IPAddress GetXoredIP() const; - StunMessage* owner_; -}; - -// Implements STUN attributes that record a 32-bit integer. -class StunUInt32Attribute : public StunAttribute { - public: - static const uint16 SIZE = 4; - StunUInt32Attribute(uint16 type, uint32 value); - explicit StunUInt32Attribute(uint16 type); - - virtual StunAttributeValueType value_type() const { - return STUN_VALUE_UINT32; - } - - uint32 value() const { return bits_; } - void SetValue(uint32 bits) { bits_ = bits; } - - bool GetBit(size_t index) const; - void SetBit(size_t index, bool value); - - virtual bool Read(rtc::ByteBuffer* buf); - virtual bool Write(rtc::ByteBuffer* buf) const; - - private: - uint32 bits_; -}; - -class StunUInt64Attribute : public StunAttribute { - public: - static const uint16 SIZE = 8; - StunUInt64Attribute(uint16 type, uint64 value); - explicit StunUInt64Attribute(uint16 type); - - virtual StunAttributeValueType value_type() const { - return STUN_VALUE_UINT64; - } - - uint64 value() const { return bits_; } - void SetValue(uint64 bits) { bits_ = bits; } - - virtual bool Read(rtc::ByteBuffer* buf); - virtual bool Write(rtc::ByteBuffer* buf) const; - - private: - uint64 bits_; -}; - -// Implements STUN attributes that record an arbitrary byte string. -class StunByteStringAttribute : public StunAttribute { - public: - explicit StunByteStringAttribute(uint16 type); - StunByteStringAttribute(uint16 type, const std::string& str); - StunByteStringAttribute(uint16 type, const void* bytes, size_t length); - StunByteStringAttribute(uint16 type, uint16 length); - ~StunByteStringAttribute(); - - virtual StunAttributeValueType value_type() const { - return STUN_VALUE_BYTE_STRING; - } - - const char* bytes() const { return bytes_; } - std::string GetString() const { return std::string(bytes_, length()); } - - void CopyBytes(const char* bytes); // uses strlen - void CopyBytes(const void* bytes, size_t length); - - uint8 GetByte(size_t index) const; - void SetByte(size_t index, uint8 value); - - virtual bool Read(rtc::ByteBuffer* buf); - virtual bool Write(rtc::ByteBuffer* buf) const; - - private: - void SetBytes(char* bytes, size_t length); - - char* bytes_; -}; - -// Implements STUN attributes that record an error code. -class StunErrorCodeAttribute : public StunAttribute { - public: - static const uint16 MIN_SIZE = 4; - StunErrorCodeAttribute(uint16 type, int code, const std::string& reason); - StunErrorCodeAttribute(uint16 type, uint16 length); - ~StunErrorCodeAttribute(); - - virtual StunAttributeValueType value_type() const { - return STUN_VALUE_ERROR_CODE; - } - - // The combined error and class, e.g. 0x400. - int code() const; - void SetCode(int code); - - // The individual error components. - int eclass() const { return class_; } - int number() const { return number_; } - const std::string& reason() const { return reason_; } - void SetClass(uint8 eclass) { class_ = eclass; } - void SetNumber(uint8 number) { number_ = number; } - void SetReason(const std::string& reason); - - bool Read(rtc::ByteBuffer* buf); - bool Write(rtc::ByteBuffer* buf) const; - - private: - uint8 class_; - uint8 number_; - std::string reason_; -}; - -// Implements STUN attributes that record a list of attribute names. -class StunUInt16ListAttribute : public StunAttribute { - public: - StunUInt16ListAttribute(uint16 type, uint16 length); - ~StunUInt16ListAttribute(); - - virtual StunAttributeValueType value_type() const { - return STUN_VALUE_UINT16_LIST; - } - - size_t Size() const; - uint16 GetType(int index) const; - void SetType(int index, uint16 value); - void AddType(uint16 value); - - bool Read(rtc::ByteBuffer* buf); - bool Write(rtc::ByteBuffer* buf) const; - - private: - std::vector<uint16>* attr_types_; -}; - -// Returns the (successful) response type for the given request type. -// Returns -1 if |request_type| is not a valid request type. -int GetStunSuccessResponseType(int request_type); - -// Returns the error response type for the given request type. -// Returns -1 if |request_type| is not a valid request type. -int GetStunErrorResponseType(int request_type); - -// Returns whether a given message is a request type. -bool IsStunRequestType(int msg_type); - -// Returns whether a given message is an indication type. -bool IsStunIndicationType(int msg_type); - -// Returns whether a given response is a success type. -bool IsStunSuccessResponseType(int msg_type); - -// Returns whether a given response is an error type. -bool IsStunErrorResponseType(int msg_type); - -// Computes the STUN long-term credential hash. -bool ComputeStunCredentialHash(const std::string& username, - const std::string& realm, const std::string& password, std::string* hash); - -// TODO: Move the TURN/ICE stuff below out to separate files. -extern const char TURN_MAGIC_COOKIE_VALUE[4]; - -// "GTURN" STUN methods. -// TODO: Rename these methods to GTURN_ to make it clear they aren't -// part of standard STUN/TURN. -enum RelayMessageType { - // For now, using the same defs from TurnMessageType below. - // STUN_ALLOCATE_REQUEST = 0x0003, - // STUN_ALLOCATE_RESPONSE = 0x0103, - // STUN_ALLOCATE_ERROR_RESPONSE = 0x0113, - STUN_SEND_REQUEST = 0x0004, - STUN_SEND_RESPONSE = 0x0104, - STUN_SEND_ERROR_RESPONSE = 0x0114, - STUN_DATA_INDICATION = 0x0115, -}; - -// "GTURN"-specific STUN attributes. -// TODO: Rename these attributes to GTURN_ to avoid conflicts. -enum RelayAttributeType { - STUN_ATTR_LIFETIME = 0x000d, // UInt32 - STUN_ATTR_MAGIC_COOKIE = 0x000f, // ByteString, 4 bytes - STUN_ATTR_BANDWIDTH = 0x0010, // UInt32 - STUN_ATTR_DESTINATION_ADDRESS = 0x0011, // Address - STUN_ATTR_SOURCE_ADDRESS2 = 0x0012, // Address - STUN_ATTR_DATA = 0x0013, // ByteString - STUN_ATTR_OPTIONS = 0x8001, // UInt32 -}; - -// A "GTURN" STUN message. -class RelayMessage : public StunMessage { - protected: - virtual StunAttributeValueType GetAttributeValueType(int type) const { - switch (type) { - case STUN_ATTR_LIFETIME: return STUN_VALUE_UINT32; - case STUN_ATTR_MAGIC_COOKIE: return STUN_VALUE_BYTE_STRING; - case STUN_ATTR_BANDWIDTH: return STUN_VALUE_UINT32; - case STUN_ATTR_DESTINATION_ADDRESS: return STUN_VALUE_ADDRESS; - case STUN_ATTR_SOURCE_ADDRESS2: return STUN_VALUE_ADDRESS; - case STUN_ATTR_DATA: return STUN_VALUE_BYTE_STRING; - case STUN_ATTR_OPTIONS: return STUN_VALUE_UINT32; - default: return StunMessage::GetAttributeValueType(type); - } - } - virtual StunMessage* CreateNew() const { return new RelayMessage(); } -}; - -// Defined in TURN RFC 5766. -enum TurnMessageType { - STUN_ALLOCATE_REQUEST = 0x0003, - STUN_ALLOCATE_RESPONSE = 0x0103, - STUN_ALLOCATE_ERROR_RESPONSE = 0x0113, - TURN_REFRESH_REQUEST = 0x0004, - TURN_REFRESH_RESPONSE = 0x0104, - TURN_REFRESH_ERROR_RESPONSE = 0x0114, - TURN_SEND_INDICATION = 0x0016, - TURN_DATA_INDICATION = 0x0017, - TURN_CREATE_PERMISSION_REQUEST = 0x0008, - TURN_CREATE_PERMISSION_RESPONSE = 0x0108, - TURN_CREATE_PERMISSION_ERROR_RESPONSE = 0x0118, - TURN_CHANNEL_BIND_REQUEST = 0x0009, - TURN_CHANNEL_BIND_RESPONSE = 0x0109, - TURN_CHANNEL_BIND_ERROR_RESPONSE = 0x0119, -}; - -enum TurnAttributeType { - STUN_ATTR_CHANNEL_NUMBER = 0x000C, // UInt32 - STUN_ATTR_TURN_LIFETIME = 0x000d, // UInt32 - STUN_ATTR_XOR_PEER_ADDRESS = 0x0012, // XorAddress - // TODO(mallinath) - Uncomment after RelayAttributes are renamed. - // STUN_ATTR_DATA = 0x0013, // ByteString - STUN_ATTR_XOR_RELAYED_ADDRESS = 0x0016, // XorAddress - STUN_ATTR_EVEN_PORT = 0x0018, // ByteString, 1 byte. - STUN_ATTR_REQUESTED_TRANSPORT = 0x0019, // UInt32 - STUN_ATTR_DONT_FRAGMENT = 0x001A, // No content, Length = 0 - STUN_ATTR_RESERVATION_TOKEN = 0x0022, // ByteString, 8 bytes. - // TODO(mallinath) - Rename STUN_ATTR_TURN_LIFETIME to STUN_ATTR_LIFETIME and - // STUN_ATTR_TURN_DATA to STUN_ATTR_DATA. Also rename RelayMessage attributes - // by appending G to attribute name. -}; - -// RFC 5766-defined errors. -enum TurnErrorType { - STUN_ERROR_FORBIDDEN = 403, - STUN_ERROR_ALLOCATION_MISMATCH = 437, - STUN_ERROR_WRONG_CREDENTIALS = 441, - STUN_ERROR_UNSUPPORTED_PROTOCOL = 442 -}; -extern const char STUN_ERROR_REASON_FORBIDDEN[]; -extern const char STUN_ERROR_REASON_ALLOCATION_MISMATCH[]; -extern const char STUN_ERROR_REASON_WRONG_CREDENTIALS[]; -extern const char STUN_ERROR_REASON_UNSUPPORTED_PROTOCOL[]; -class TurnMessage : public StunMessage { - protected: - virtual StunAttributeValueType GetAttributeValueType(int type) const { - switch (type) { - case STUN_ATTR_CHANNEL_NUMBER: return STUN_VALUE_UINT32; - case STUN_ATTR_TURN_LIFETIME: return STUN_VALUE_UINT32; - case STUN_ATTR_XOR_PEER_ADDRESS: return STUN_VALUE_XOR_ADDRESS; - case STUN_ATTR_DATA: return STUN_VALUE_BYTE_STRING; - case STUN_ATTR_XOR_RELAYED_ADDRESS: return STUN_VALUE_XOR_ADDRESS; - case STUN_ATTR_EVEN_PORT: return STUN_VALUE_BYTE_STRING; - case STUN_ATTR_REQUESTED_TRANSPORT: return STUN_VALUE_UINT32; - case STUN_ATTR_DONT_FRAGMENT: return STUN_VALUE_BYTE_STRING; - case STUN_ATTR_RESERVATION_TOKEN: return STUN_VALUE_BYTE_STRING; - default: return StunMessage::GetAttributeValueType(type); - } - } - virtual StunMessage* CreateNew() const { return new TurnMessage(); } -}; - -// RFC 5245 ICE STUN attributes. -enum IceAttributeType { - STUN_ATTR_PRIORITY = 0x0024, // UInt32 - STUN_ATTR_USE_CANDIDATE = 0x0025, // No content, Length = 0 - STUN_ATTR_ICE_CONTROLLED = 0x8029, // UInt64 - STUN_ATTR_ICE_CONTROLLING = 0x802A // UInt64 -}; - -// RFC 5245-defined errors. -enum IceErrorCode { - STUN_ERROR_ROLE_CONFLICT = 487, -}; -extern const char STUN_ERROR_REASON_ROLE_CONFLICT[]; - -// A RFC 5245 ICE STUN message. -class IceMessage : public StunMessage { - protected: - virtual StunAttributeValueType GetAttributeValueType(int type) const { - switch (type) { - case STUN_ATTR_PRIORITY: return STUN_VALUE_UINT32; - case STUN_ATTR_USE_CANDIDATE: return STUN_VALUE_BYTE_STRING; - case STUN_ATTR_ICE_CONTROLLED: return STUN_VALUE_UINT64; - case STUN_ATTR_ICE_CONTROLLING: return STUN_VALUE_UINT64; - default: return StunMessage::GetAttributeValueType(type); - } - } - virtual StunMessage* CreateNew() const { return new IceMessage(); } -}; - -} // namespace cricket - -#endif // WEBRTC_P2P_BASE_STUN_H_ diff --git a/talk/p2p/base/stun_unittest.cc b/talk/p2p/base/stun_unittest.cc deleted file mode 100644 index 34a47cb11..000000000 --- a/talk/p2p/base/stun_unittest.cc +++ /dev/null @@ -1,1419 +0,0 @@ -/* - * libjingle - * Copyright 2004 Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <string> - -#include "webrtc/p2p/base/stun.h" -#include "webrtc/base/bytebuffer.h" -#include "webrtc/base/gunit.h" -#include "webrtc/base/logging.h" -#include "webrtc/base/messagedigest.h" -#include "webrtc/base/scoped_ptr.h" -#include "webrtc/base/socketaddress.h" - -namespace cricket { - -class StunTest : public ::testing::Test { - protected: - void CheckStunHeader(const StunMessage& msg, StunMessageType expected_type, - size_t expected_length) { - ASSERT_EQ(expected_type, msg.type()); - ASSERT_EQ(expected_length, msg.length()); - } - - void CheckStunTransactionID(const StunMessage& msg, - const unsigned char* expectedID, size_t length) { - ASSERT_EQ(length, msg.transaction_id().size()); - ASSERT_EQ(length == kStunTransactionIdLength + 4, msg.IsLegacy()); - ASSERT_EQ(length == kStunTransactionIdLength, !msg.IsLegacy()); - ASSERT_EQ(0, memcmp(msg.transaction_id().c_str(), expectedID, length)); - } - - void CheckStunAddressAttribute(const StunAddressAttribute* addr, - StunAddressFamily expected_family, - int expected_port, - rtc::IPAddress expected_address) { - ASSERT_EQ(expected_family, addr->family()); - ASSERT_EQ(expected_port, addr->port()); - - if (addr->family() == STUN_ADDRESS_IPV4) { - in_addr v4_address = expected_address.ipv4_address(); - in_addr stun_address = addr->ipaddr().ipv4_address(); - ASSERT_EQ(0, memcmp(&v4_address, &stun_address, sizeof(stun_address))); - } else if (addr->family() == STUN_ADDRESS_IPV6) { - in6_addr v6_address = expected_address.ipv6_address(); - in6_addr stun_address = addr->ipaddr().ipv6_address(); - ASSERT_EQ(0, memcmp(&v6_address, &stun_address, sizeof(stun_address))); - } else { - ASSERT_TRUE(addr->family() == STUN_ADDRESS_IPV6 || - addr->family() == STUN_ADDRESS_IPV4); - } - } - - size_t ReadStunMessageTestCase(StunMessage* msg, - const unsigned char* testcase, - size_t size) { - const char* input = reinterpret_cast<const char*>(testcase); - rtc::ByteBuffer buf(input, size); - if (msg->Read(&buf)) { - // Returns the size the stun message should report itself as being - return (size - 20); - } else { - return 0; - } - } -}; - - -// Sample STUN packets with various attributes -// Gathered by wiresharking pjproject's pjnath test programs -// pjproject available at www.pjsip.org - -static const unsigned char kStunMessageWithIPv6MappedAddress[] = { - 0x00, 0x01, 0x00, 0x18, // message header - 0x21, 0x12, 0xa4, 0x42, // transaction id - 0x29, 0x1f, 0xcd, 0x7c, - 0xba, 0x58, 0xab, 0xd7, - 0xf2, 0x41, 0x01, 0x00, - 0x00, 0x01, 0x00, 0x14, // Address type (mapped), length - 0x00, 0x02, 0xb8, 0x81, // family (IPv6), port - 0x24, 0x01, 0xfa, 0x00, // an IPv6 address - 0x00, 0x04, 0x10, 0x00, - 0xbe, 0x30, 0x5b, 0xff, - 0xfe, 0xe5, 0x00, 0xc3 -}; - -static const unsigned char kStunMessageWithIPv4MappedAddress[] = { - 0x01, 0x01, 0x00, 0x0c, // binding response, length 12 - 0x21, 0x12, 0xa4, 0x42, // magic cookie - 0x29, 0x1f, 0xcd, 0x7c, // transaction ID - 0xba, 0x58, 0xab, 0xd7, - 0xf2, 0x41, 0x01, 0x00, - 0x00, 0x01, 0x00, 0x08, // Mapped, 8 byte length - 0x00, 0x01, 0x9d, 0xfc, // AF_INET, unxor-ed port - 0xac, 0x17, 0x44, 0xe6 // IPv4 address -}; - -// Test XOR-mapped IP addresses: -static const unsigned char kStunMessageWithIPv6XorMappedAddress[] = { - 0x01, 0x01, 0x00, 0x18, // message header (binding response) - 0x21, 0x12, 0xa4, 0x42, // magic cookie (rfc5389) - 0xe3, 0xa9, 0x46, 0xe1, // transaction ID - 0x7c, 0x00, 0xc2, 0x62, - 0x54, 0x08, 0x01, 0x00, - 0x00, 0x20, 0x00, 0x14, // Address Type (XOR), length - 0x00, 0x02, 0xcb, 0x5b, // family, XOR-ed port - 0x05, 0x13, 0x5e, 0x42, // XOR-ed IPv6 address - 0xe3, 0xad, 0x56, 0xe1, - 0xc2, 0x30, 0x99, 0x9d, - 0xaa, 0xed, 0x01, 0xc3 -}; - -static const unsigned char kStunMessageWithIPv4XorMappedAddress[] = { - 0x01, 0x01, 0x00, 0x0c, // message header (binding response) - 0x21, 0x12, 0xa4, 0x42, // magic cookie - 0x29, 0x1f, 0xcd, 0x7c, // transaction ID - 0xba, 0x58, 0xab, 0xd7, - 0xf2, 0x41, 0x01, 0x00, - 0x00, 0x20, 0x00, 0x08, // address type (xor), length - 0x00, 0x01, 0xfc, 0xb5, // family (AF_INET), XOR-ed port - 0x8d, 0x05, 0xe0, 0xa4 // IPv4 address -}; - -// ByteString Attribute (username) -static const unsigned char kStunMessageWithByteStringAttribute[] = { - 0x00, 0x01, 0x00, 0x0c, - 0x21, 0x12, 0xa4, 0x42, - 0xe3, 0xa9, 0x46, 0xe1, - 0x7c, 0x00, 0xc2, 0x62, - 0x54, 0x08, 0x01, 0x00, - 0x00, 0x06, 0x00, 0x08, // username attribute (length 8) - 0x61, 0x62, 0x63, 0x64, // abcdefgh - 0x65, 0x66, 0x67, 0x68 -}; - -// Message with an unknown but comprehensible optional attribute. -// Parsing should succeed despite this unknown attribute. -static const unsigned char kStunMessageWithUnknownAttribute[] = { - 0x00, 0x01, 0x00, 0x14, - 0x21, 0x12, 0xa4, 0x42, - 0xe3, 0xa9, 0x46, 0xe1, - 0x7c, 0x00, 0xc2, 0x62, - 0x54, 0x08, 0x01, 0x00, - 0x00, 0xaa, 0x00, 0x07, // Unknown attribute, length 7 (needs padding!) - 0x61, 0x62, 0x63, 0x64, // abcdefg + padding - 0x65, 0x66, 0x67, 0x00, - 0x00, 0x06, 0x00, 0x03, // Followed by a known attribute we can - 0x61, 0x62, 0x63, 0x00 // check for (username of length 3) -}; - -// ByteString Attribute (username) with padding byte -static const unsigned char kStunMessageWithPaddedByteStringAttribute[] = { - 0x00, 0x01, 0x00, 0x08, - 0x21, 0x12, 0xa4, 0x42, - 0xe3, 0xa9, 0x46, 0xe1, - 0x7c, 0x00, 0xc2, 0x62, - 0x54, 0x08, 0x01, 0x00, - 0x00, 0x06, 0x00, 0x03, // username attribute (length 3) - 0x61, 0x62, 0x63, 0xcc // abc -}; - -// Message with an Unknown Attributes (uint16 list) attribute. -static const unsigned char kStunMessageWithUInt16ListAttribute[] = { - 0x00, 0x01, 0x00, 0x0c, - 0x21, 0x12, 0xa4, 0x42, - 0xe3, 0xa9, 0x46, 0xe1, - 0x7c, 0x00, 0xc2, 0x62, - 0x54, 0x08, 0x01, 0x00, - 0x00, 0x0a, 0x00, 0x06, // username attribute (length 6) - 0x00, 0x01, 0x10, 0x00, // three attributes plus padding - 0xAB, 0xCU, 0xBE, 0xEF -}; - -// Error response message (unauthorized) -static const unsigned char kStunMessageWithErrorAttribute[] = { - 0x01, 0x11, 0x00, 0x14, - 0x21, 0x12, 0xa4, 0x42, - 0x29, 0x1f, 0xcd, 0x7c, - 0xba, 0x58, 0xab, 0xd7, - 0xf2, 0x41, 0x01, 0x00, - 0x00, 0x09, 0x00, 0x10, - 0x00, 0x00, 0x04, 0x01, - 0x55, 0x6e, 0x61, 0x75, - 0x74, 0x68, 0x6f, 0x72, - 0x69, 0x7a, 0x65, 0x64 -}; - -// Sample messages with an invalid length Field - -// The actual length in bytes of the invalid messages (including STUN header) -static const int kRealLengthOfInvalidLengthTestCases = 32; - -static const unsigned char kStunMessageWithZeroLength[] = { - 0x00, 0x01, 0x00, 0x00, // length of 0 (last 2 bytes) - 0x21, 0x12, 0xA4, 0x42, // magic cookie - '0', '1', '2', '3', // transaction id - '4', '5', '6', '7', - '8', '9', 'a', 'b', - 0x00, 0x20, 0x00, 0x08, // xor mapped address - 0x00, 0x01, 0x21, 0x1F, - 0x21, 0x12, 0xA4, 0x53, -}; - -static const unsigned char kStunMessageWithExcessLength[] = { - 0x00, 0x01, 0x00, 0x55, // length of 85 - 0x21, 0x12, 0xA4, 0x42, // magic cookie - '0', '1', '2', '3', // transaction id - '4', '5', '6', '7', - '8', '9', 'a', 'b', - 0x00, 0x20, 0x00, 0x08, // xor mapped address - 0x00, 0x01, 0x21, 0x1F, - 0x21, 0x12, 0xA4, 0x53, -}; - -static const unsigned char kStunMessageWithSmallLength[] = { - 0x00, 0x01, 0x00, 0x03, // length of 3 - 0x21, 0x12, 0xA4, 0x42, // magic cookie - '0', '1', '2', '3', // transaction id - '4', '5', '6', '7', - '8', '9', 'a', 'b', - 0x00, 0x20, 0x00, 0x08, // xor mapped address - 0x00, 0x01, 0x21, 0x1F, - 0x21, 0x12, 0xA4, 0x53, -}; - -// RTCP packet, for testing we correctly ignore non stun packet types. -// V=2, P=false, RC=0, Type=200, Len=6, Sender-SSRC=85, etc -static const unsigned char kRtcpPacket[] = { - 0x80, 0xc8, 0x00, 0x06, 0x00, 0x00, 0x00, 0x55, - 0xce, 0xa5, 0x18, 0x3a, 0x39, 0xcc, 0x7d, 0x09, - 0x23, 0xed, 0x19, 0x07, 0x00, 0x00, 0x01, 0x56, - 0x00, 0x03, 0x73, 0x50, -}; - -// RFC5769 Test Vectors -// Software name (request): "STUN test client" (without quotes) -// Software name (response): "test vector" (without quotes) -// Username: "evtj:h6vY" (without quotes) -// Password: "VOkJxbRl1RmTxUk/WvJxBt" (without quotes) -static const unsigned char kRfc5769SampleMsgTransactionId[] = { - 0xb7, 0xe7, 0xa7, 0x01, 0xbc, 0x34, 0xd6, 0x86, 0xfa, 0x87, 0xdf, 0xae -}; -static const char kRfc5769SampleMsgClientSoftware[] = "STUN test client"; -static const char kRfc5769SampleMsgServerSoftware[] = "test vector"; -static const char kRfc5769SampleMsgUsername[] = "evtj:h6vY"; -static const char kRfc5769SampleMsgPassword[] = "VOkJxbRl1RmTxUk/WvJxBt"; -static const rtc::SocketAddress kRfc5769SampleMsgMappedAddress( - "192.0.2.1", 32853); -static const rtc::SocketAddress kRfc5769SampleMsgIPv6MappedAddress( - "2001:db8:1234:5678:11:2233:4455:6677", 32853); - -static const unsigned char kRfc5769SampleMsgWithAuthTransactionId[] = { - 0x78, 0xad, 0x34, 0x33, 0xc6, 0xad, 0x72, 0xc0, 0x29, 0xda, 0x41, 0x2e -}; -static const char kRfc5769SampleMsgWithAuthUsername[] = - "\xe3\x83\x9e\xe3\x83\x88\xe3\x83\xaa\xe3\x83\x83\xe3\x82\xaf\xe3\x82\xb9"; -static const char kRfc5769SampleMsgWithAuthPassword[] = "TheMatrIX"; -static const char kRfc5769SampleMsgWithAuthNonce[] = - "f//499k954d6OL34oL9FSTvy64sA"; -static const char kRfc5769SampleMsgWithAuthRealm[] = "example.org"; - -// 2.1. Sample Request -static const unsigned char kRfc5769SampleRequest[] = { - 0x00, 0x01, 0x00, 0x58, // Request type and message length - 0x21, 0x12, 0xa4, 0x42, // Magic cookie - 0xb7, 0xe7, 0xa7, 0x01, // } - 0xbc, 0x34, 0xd6, 0x86, // } Transaction ID - 0xfa, 0x87, 0xdf, 0xae, // } - 0x80, 0x22, 0x00, 0x10, // SOFTWARE attribute header - 0x53, 0x54, 0x55, 0x4e, // } - 0x20, 0x74, 0x65, 0x73, // } User-agent... - 0x74, 0x20, 0x63, 0x6c, // } ...name - 0x69, 0x65, 0x6e, 0x74, // } - 0x00, 0x24, 0x00, 0x04, // PRIORITY attribute header - 0x6e, 0x00, 0x01, 0xff, // ICE priority value - 0x80, 0x29, 0x00, 0x08, // ICE-CONTROLLED attribute header - 0x93, 0x2f, 0xf9, 0xb1, // } Pseudo-random tie breaker... - 0x51, 0x26, 0x3b, 0x36, // } ...for ICE control - 0x00, 0x06, 0x00, 0x09, // USERNAME attribute header - 0x65, 0x76, 0x74, 0x6a, // } - 0x3a, 0x68, 0x36, 0x76, // } Username (9 bytes) and padding (3 bytes) - 0x59, 0x20, 0x20, 0x20, // } - 0x00, 0x08, 0x00, 0x14, // MESSAGE-INTEGRITY attribute header - 0x9a, 0xea, 0xa7, 0x0c, // } - 0xbf, 0xd8, 0xcb, 0x56, // } - 0x78, 0x1e, 0xf2, 0xb5, // } HMAC-SHA1 fingerprint - 0xb2, 0xd3, 0xf2, 0x49, // } - 0xc1, 0xb5, 0x71, 0xa2, // } - 0x80, 0x28, 0x00, 0x04, // FINGERPRINT attribute header - 0xe5, 0x7a, 0x3b, 0xcf // CRC32 fingerprint -}; - -// 2.2. Sample IPv4 Response -static const unsigned char kRfc5769SampleResponse[] = { - 0x01, 0x01, 0x00, 0x3c, // Response type and message length - 0x21, 0x12, 0xa4, 0x42, // Magic cookie - 0xb7, 0xe7, 0xa7, 0x01, // } - 0xbc, 0x34, 0xd6, 0x86, // } Transaction ID - 0xfa, 0x87, 0xdf, 0xae, // } - 0x80, 0x22, 0x00, 0x0b, // SOFTWARE attribute header - 0x74, 0x65, 0x73, 0x74, // } - 0x20, 0x76, 0x65, 0x63, // } UTF-8 server name - 0x74, 0x6f, 0x72, 0x20, // } - 0x00, 0x20, 0x00, 0x08, // XOR-MAPPED-ADDRESS attribute header - 0x00, 0x01, 0xa1, 0x47, // Address family (IPv4) and xor'd mapped port - 0xe1, 0x12, 0xa6, 0x43, // Xor'd mapped IPv4 address - 0x00, 0x08, 0x00, 0x14, // MESSAGE-INTEGRITY attribute header - 0x2b, 0x91, 0xf5, 0x99, // } - 0xfd, 0x9e, 0x90, 0xc3, // } - 0x8c, 0x74, 0x89, 0xf9, // } HMAC-SHA1 fingerprint - 0x2a, 0xf9, 0xba, 0x53, // } - 0xf0, 0x6b, 0xe7, 0xd7, // } - 0x80, 0x28, 0x00, 0x04, // FINGERPRINT attribute header - 0xc0, 0x7d, 0x4c, 0x96 // CRC32 fingerprint -}; - -// 2.3. Sample IPv6 Response -static const unsigned char kRfc5769SampleResponseIPv6[] = { - 0x01, 0x01, 0x00, 0x48, // Response type and message length - 0x21, 0x12, 0xa4, 0x42, // Magic cookie - 0xb7, 0xe7, 0xa7, 0x01, // } - 0xbc, 0x34, 0xd6, 0x86, // } Transaction ID - 0xfa, 0x87, 0xdf, 0xae, // } - 0x80, 0x22, 0x00, 0x0b, // SOFTWARE attribute header - 0x74, 0x65, 0x73, 0x74, // } - 0x20, 0x76, 0x65, 0x63, // } UTF-8 server name - 0x74, 0x6f, 0x72, 0x20, // } - 0x00, 0x20, 0x00, 0x14, // XOR-MAPPED-ADDRESS attribute header - 0x00, 0x02, 0xa1, 0x47, // Address family (IPv6) and xor'd mapped port. - 0x01, 0x13, 0xa9, 0xfa, // } - 0xa5, 0xd3, 0xf1, 0x79, // } Xor'd mapped IPv6 address - 0xbc, 0x25, 0xf4, 0xb5, // } - 0xbe, 0xd2, 0xb9, 0xd9, // } - 0x00, 0x08, 0x00, 0x14, // MESSAGE-INTEGRITY attribute header - 0xa3, 0x82, 0x95, 0x4e, // } - 0x4b, 0xe6, 0x7b, 0xf1, // } - 0x17, 0x84, 0xc9, 0x7c, // } HMAC-SHA1 fingerprint - 0x82, 0x92, 0xc2, 0x75, // } - 0xbf, 0xe3, 0xed, 0x41, // } - 0x80, 0x28, 0x00, 0x04, // FINGERPRINT attribute header - 0xc8, 0xfb, 0x0b, 0x4c // CRC32 fingerprint -}; - -// 2.4. Sample Request with Long-Term Authentication -static const unsigned char kRfc5769SampleRequestLongTermAuth[] = { - 0x00, 0x01, 0x00, 0x60, // Request type and message length - 0x21, 0x12, 0xa4, 0x42, // Magic cookie - 0x78, 0xad, 0x34, 0x33, // } - 0xc6, 0xad, 0x72, 0xc0, // } Transaction ID - 0x29, 0xda, 0x41, 0x2e, // } - 0x00, 0x06, 0x00, 0x12, // USERNAME attribute header - 0xe3, 0x83, 0x9e, 0xe3, // } - 0x83, 0x88, 0xe3, 0x83, // } - 0xaa, 0xe3, 0x83, 0x83, // } Username value (18 bytes) and padding (2 bytes) - 0xe3, 0x82, 0xaf, 0xe3, // } - 0x82, 0xb9, 0x00, 0x00, // } - 0x00, 0x15, 0x00, 0x1c, // NONCE attribute header - 0x66, 0x2f, 0x2f, 0x34, // } - 0x39, 0x39, 0x6b, 0x39, // } - 0x35, 0x34, 0x64, 0x36, // } - 0x4f, 0x4c, 0x33, 0x34, // } Nonce value - 0x6f, 0x4c, 0x39, 0x46, // } - 0x53, 0x54, 0x76, 0x79, // } - 0x36, 0x34, 0x73, 0x41, // } - 0x00, 0x14, 0x00, 0x0b, // REALM attribute header - 0x65, 0x78, 0x61, 0x6d, // } - 0x70, 0x6c, 0x65, 0x2e, // } Realm value (11 bytes) and padding (1 byte) - 0x6f, 0x72, 0x67, 0x00, // } - 0x00, 0x08, 0x00, 0x14, // MESSAGE-INTEGRITY attribute header - 0xf6, 0x70, 0x24, 0x65, // } - 0x6d, 0xd6, 0x4a, 0x3e, // } - 0x02, 0xb8, 0xe0, 0x71, // } HMAC-SHA1 fingerprint - 0x2e, 0x85, 0xc9, 0xa2, // } - 0x8c, 0xa8, 0x96, 0x66 // } -}; - -// Length parameter is changed to 0x38 from 0x58. -// AddMessageIntegrity will add MI information and update the length param -// accordingly. -static const unsigned char kRfc5769SampleRequestWithoutMI[] = { - 0x00, 0x01, 0x00, 0x38, // Request type and message length - 0x21, 0x12, 0xa4, 0x42, // Magic cookie - 0xb7, 0xe7, 0xa7, 0x01, // } - 0xbc, 0x34, 0xd6, 0x86, // } Transaction ID - 0xfa, 0x87, 0xdf, 0xae, // } - 0x80, 0x22, 0x00, 0x10, // SOFTWARE attribute header - 0x53, 0x54, 0x55, 0x4e, // } - 0x20, 0x74, 0x65, 0x73, // } User-agent... - 0x74, 0x20, 0x63, 0x6c, // } ...name - 0x69, 0x65, 0x6e, 0x74, // } - 0x00, 0x24, 0x00, 0x04, // PRIORITY attribute header - 0x6e, 0x00, 0x01, 0xff, // ICE priority value - 0x80, 0x29, 0x00, 0x08, // ICE-CONTROLLED attribute header - 0x93, 0x2f, 0xf9, 0xb1, // } Pseudo-random tie breaker... - 0x51, 0x26, 0x3b, 0x36, // } ...for ICE control - 0x00, 0x06, 0x00, 0x09, // USERNAME attribute header - 0x65, 0x76, 0x74, 0x6a, // } - 0x3a, 0x68, 0x36, 0x76, // } Username (9 bytes) and padding (3 bytes) - 0x59, 0x20, 0x20, 0x20 // } -}; - -// This HMAC differs from the RFC 5769 SampleRequest message. This differs -// because spec uses 0x20 for the padding where as our implementation uses 0. -static const unsigned char kCalculatedHmac1[] = { - 0x79, 0x07, 0xc2, 0xd2, // } - 0xed, 0xbf, 0xea, 0x48, // } - 0x0e, 0x4c, 0x76, 0xd8, // } HMAC-SHA1 fingerprint - 0x29, 0x62, 0xd5, 0xc3, // } - 0x74, 0x2a, 0xf9, 0xe3 // } -}; - -// Length parameter is changed to 0x1c from 0x3c. -// AddMessageIntegrity will add MI information and update the length param -// accordingly. -static const unsigned char kRfc5769SampleResponseWithoutMI[] = { - 0x01, 0x01, 0x00, 0x1c, // Response type and message length - 0x21, 0x12, 0xa4, 0x42, // Magic cookie - 0xb7, 0xe7, 0xa7, 0x01, // } - 0xbc, 0x34, 0xd6, 0x86, // } Transaction ID - 0xfa, 0x87, 0xdf, 0xae, // } - 0x80, 0x22, 0x00, 0x0b, // SOFTWARE attribute header - 0x74, 0x65, 0x73, 0x74, // } - 0x20, 0x76, 0x65, 0x63, // } UTF-8 server name - 0x74, 0x6f, 0x72, 0x20, // } - 0x00, 0x20, 0x00, 0x08, // XOR-MAPPED-ADDRESS attribute header - 0x00, 0x01, 0xa1, 0x47, // Address family (IPv4) and xor'd mapped port - 0xe1, 0x12, 0xa6, 0x43 // Xor'd mapped IPv4 address -}; - -// This HMAC differs from the RFC 5769 SampleResponse message. This differs -// because spec uses 0x20 for the padding where as our implementation uses 0. -static const unsigned char kCalculatedHmac2[] = { - 0x5d, 0x6b, 0x58, 0xbe, // } - 0xad, 0x94, 0xe0, 0x7e, // } - 0xef, 0x0d, 0xfc, 0x12, // } HMAC-SHA1 fingerprint - 0x82, 0xa2, 0xbd, 0x08, // } - 0x43, 0x14, 0x10, 0x28 // } -}; - -// A transaction ID without the 'magic cookie' portion -// pjnat's test programs use this transaction ID a lot. -const unsigned char kTestTransactionId1[] = { 0x029, 0x01f, 0x0cd, 0x07c, - 0x0ba, 0x058, 0x0ab, 0x0d7, - 0x0f2, 0x041, 0x001, 0x000 }; - -// They use this one sometimes too. -const unsigned char kTestTransactionId2[] = { 0x0e3, 0x0a9, 0x046, 0x0e1, - 0x07c, 0x000, 0x0c2, 0x062, - 0x054, 0x008, 0x001, 0x000 }; - -const in6_addr kIPv6TestAddress1 = { { { 0x24, 0x01, 0xfa, 0x00, - 0x00, 0x04, 0x10, 0x00, - 0xbe, 0x30, 0x5b, 0xff, - 0xfe, 0xe5, 0x00, 0xc3 } } }; -const in6_addr kIPv6TestAddress2 = { { { 0x24, 0x01, 0xfa, 0x00, - 0x00, 0x04, 0x10, 0x12, - 0x06, 0x0c, 0xce, 0xff, - 0xfe, 0x1f, 0x61, 0xa4 } } }; - -#ifdef POSIX -const in_addr kIPv4TestAddress1 = { 0xe64417ac }; -#elif defined WIN32 -// Windows in_addr has a union with a uchar[] array first. -const in_addr kIPv4TestAddress1 = { { 0x0ac, 0x017, 0x044, 0x0e6 } }; -#endif -const char kTestUserName1[] = "abcdefgh"; -const char kTestUserName2[] = "abc"; -const char kTestErrorReason[] = "Unauthorized"; -const int kTestErrorClass = 4; -const int kTestErrorNumber = 1; -const int kTestErrorCode = 401; - -const int kTestMessagePort1 = 59977; -const int kTestMessagePort2 = 47233; -const int kTestMessagePort3 = 56743; -const int kTestMessagePort4 = 40444; - -#define ReadStunMessage(X, Y) ReadStunMessageTestCase(X, Y, sizeof(Y)); - -// Test that the GetStun*Type and IsStun*Type methods work as expected. -TEST_F(StunTest, MessageTypes) { - EXPECT_EQ(STUN_BINDING_RESPONSE, - GetStunSuccessResponseType(STUN_BINDING_REQUEST)); - EXPECT_EQ(STUN_BINDING_ERROR_RESPONSE, - GetStunErrorResponseType(STUN_BINDING_REQUEST)); - EXPECT_EQ(-1, GetStunSuccessResponseType(STUN_BINDING_INDICATION)); - EXPECT_EQ(-1, GetStunSuccessResponseType(STUN_BINDING_RESPONSE)); - EXPECT_EQ(-1, GetStunSuccessResponseType(STUN_BINDING_ERROR_RESPONSE)); - EXPECT_EQ(-1, GetStunErrorResponseType(STUN_BINDING_INDICATION)); - EXPECT_EQ(-1, GetStunErrorResponseType(STUN_BINDING_RESPONSE)); - EXPECT_EQ(-1, GetStunErrorResponseType(STUN_BINDING_ERROR_RESPONSE)); - - int types[] = { - STUN_BINDING_REQUEST, STUN_BINDING_INDICATION, - STUN_BINDING_RESPONSE, STUN_BINDING_ERROR_RESPONSE - }; - for (int i = 0; i < ARRAY_SIZE(types); ++i) { - EXPECT_EQ(i == 0, IsStunRequestType(types[i])); - EXPECT_EQ(i == 1, IsStunIndicationType(types[i])); - EXPECT_EQ(i == 2, IsStunSuccessResponseType(types[i])); - EXPECT_EQ(i == 3, IsStunErrorResponseType(types[i])); - EXPECT_EQ(1, types[i] & 0xFEEF); - } -} - -TEST_F(StunTest, ReadMessageWithIPv4AddressAttribute) { - StunMessage msg; - size_t size = ReadStunMessage(&msg, kStunMessageWithIPv4MappedAddress); - CheckStunHeader(msg, STUN_BINDING_RESPONSE, size); - CheckStunTransactionID(msg, kTestTransactionId1, kStunTransactionIdLength); - - const StunAddressAttribute* addr = msg.GetAddress(STUN_ATTR_MAPPED_ADDRESS); - rtc::IPAddress test_address(kIPv4TestAddress1); - CheckStunAddressAttribute(addr, STUN_ADDRESS_IPV4, - kTestMessagePort4, test_address); -} - -TEST_F(StunTest, ReadMessageWithIPv4XorAddressAttribute) { - StunMessage msg; - StunMessage msg2; - size_t size = ReadStunMessage(&msg, kStunMessageWithIPv4XorMappedAddress); - CheckStunHeader(msg, STUN_BINDING_RESPONSE, size); - CheckStunTransactionID(msg, kTestTransactionId1, kStunTransactionIdLength); - - const StunAddressAttribute* addr = - msg.GetAddress(STUN_ATTR_XOR_MAPPED_ADDRESS); - rtc::IPAddress test_address(kIPv4TestAddress1); - CheckStunAddressAttribute(addr, STUN_ADDRESS_IPV4, - kTestMessagePort3, test_address); -} - -TEST_F(StunTest, ReadMessageWithIPv6AddressAttribute) { - StunMessage msg; - size_t size = ReadStunMessage(&msg, kStunMessageWithIPv6MappedAddress); - CheckStunHeader(msg, STUN_BINDING_REQUEST, size); - CheckStunTransactionID(msg, kTestTransactionId1, kStunTransactionIdLength); - - rtc::IPAddress test_address(kIPv6TestAddress1); - - const StunAddressAttribute* addr = msg.GetAddress(STUN_ATTR_MAPPED_ADDRESS); - CheckStunAddressAttribute(addr, STUN_ADDRESS_IPV6, - kTestMessagePort2, test_address); -} - -TEST_F(StunTest, ReadMessageWithInvalidAddressAttribute) { - StunMessage msg; - size_t size = ReadStunMessage(&msg, kStunMessageWithIPv6MappedAddress); - CheckStunHeader(msg, STUN_BINDING_REQUEST, size); - CheckStunTransactionID(msg, kTestTransactionId1, kStunTransactionIdLength); - - rtc::IPAddress test_address(kIPv6TestAddress1); - - const StunAddressAttribute* addr = msg.GetAddress(STUN_ATTR_MAPPED_ADDRESS); - CheckStunAddressAttribute(addr, STUN_ADDRESS_IPV6, - kTestMessagePort2, test_address); -} - -TEST_F(StunTest, ReadMessageWithIPv6XorAddressAttribute) { - StunMessage msg; - size_t size = ReadStunMessage(&msg, kStunMessageWithIPv6XorMappedAddress); - - rtc::IPAddress test_address(kIPv6TestAddress1); - - CheckStunHeader(msg, STUN_BINDING_RESPONSE, size); - CheckStunTransactionID(msg, kTestTransactionId2, kStunTransactionIdLength); - - const StunAddressAttribute* addr = - msg.GetAddress(STUN_ATTR_XOR_MAPPED_ADDRESS); - CheckStunAddressAttribute(addr, STUN_ADDRESS_IPV6, - kTestMessagePort1, test_address); -} - -// Read the RFC5389 fields from the RFC5769 sample STUN request. -TEST_F(StunTest, ReadRfc5769RequestMessage) { - StunMessage msg; - size_t size = ReadStunMessage(&msg, kRfc5769SampleRequest); - CheckStunHeader(msg, STUN_BINDING_REQUEST, size); - CheckStunTransactionID(msg, kRfc5769SampleMsgTransactionId, - kStunTransactionIdLength); - - const StunByteStringAttribute* software = - msg.GetByteString(STUN_ATTR_SOFTWARE); - ASSERT_TRUE(software != NULL); - EXPECT_EQ(kRfc5769SampleMsgClientSoftware, software->GetString()); - - const StunByteStringAttribute* username = - msg.GetByteString(STUN_ATTR_USERNAME); - ASSERT_TRUE(username != NULL); - EXPECT_EQ(kRfc5769SampleMsgUsername, username->GetString()); - - // Actual M-I value checked in a later test. - ASSERT_TRUE(msg.GetByteString(STUN_ATTR_MESSAGE_INTEGRITY) != NULL); - - // Fingerprint checked in a later test, but double-check the value here. - const StunUInt32Attribute* fingerprint = - msg.GetUInt32(STUN_ATTR_FINGERPRINT); - ASSERT_TRUE(fingerprint != NULL); - EXPECT_EQ(0xe57a3bcf, fingerprint->value()); -} - -// Read the RFC5389 fields from the RFC5769 sample STUN response. -TEST_F(StunTest, ReadRfc5769ResponseMessage) { - StunMessage msg; - size_t size = ReadStunMessage(&msg, kRfc5769SampleResponse); - CheckStunHeader(msg, STUN_BINDING_RESPONSE, size); - CheckStunTransactionID(msg, kRfc5769SampleMsgTransactionId, - kStunTransactionIdLength); - - const StunByteStringAttribute* software = - msg.GetByteString(STUN_ATTR_SOFTWARE); - ASSERT_TRUE(software != NULL); - EXPECT_EQ(kRfc5769SampleMsgServerSoftware, software->GetString()); - - const StunAddressAttribute* mapped_address = - msg.GetAddress(STUN_ATTR_XOR_MAPPED_ADDRESS); - ASSERT_TRUE(mapped_address != NULL); - EXPECT_EQ(kRfc5769SampleMsgMappedAddress, mapped_address->GetAddress()); - - // Actual M-I and fingerprint checked in later tests. - ASSERT_TRUE(msg.GetByteString(STUN_ATTR_MESSAGE_INTEGRITY) != NULL); - ASSERT_TRUE(msg.GetUInt32(STUN_ATTR_FINGERPRINT) != NULL); -} - -// Read the RFC5389 fields from the RFC5769 sample STUN response for IPv6. -TEST_F(StunTest, ReadRfc5769ResponseMessageIPv6) { - StunMessage msg; - size_t size = ReadStunMessage(&msg, kRfc5769SampleResponseIPv6); - CheckStunHeader(msg, STUN_BINDING_RESPONSE, size); - CheckStunTransactionID(msg, kRfc5769SampleMsgTransactionId, - kStunTransactionIdLength); - - const StunByteStringAttribute* software = - msg.GetByteString(STUN_ATTR_SOFTWARE); - ASSERT_TRUE(software != NULL); - EXPECT_EQ(kRfc5769SampleMsgServerSoftware, software->GetString()); - - const StunAddressAttribute* mapped_address = - msg.GetAddress(STUN_ATTR_XOR_MAPPED_ADDRESS); - ASSERT_TRUE(mapped_address != NULL); - EXPECT_EQ(kRfc5769SampleMsgIPv6MappedAddress, mapped_address->GetAddress()); - - // Actual M-I and fingerprint checked in later tests. - ASSERT_TRUE(msg.GetByteString(STUN_ATTR_MESSAGE_INTEGRITY) != NULL); - ASSERT_TRUE(msg.GetUInt32(STUN_ATTR_FINGERPRINT) != NULL); -} - -// Read the RFC5389 fields from the RFC5769 sample STUN response with auth. -TEST_F(StunTest, ReadRfc5769RequestMessageLongTermAuth) { - StunMessage msg; - size_t size = ReadStunMessage(&msg, kRfc5769SampleRequestLongTermAuth); - CheckStunHeader(msg, STUN_BINDING_REQUEST, size); - CheckStunTransactionID(msg, kRfc5769SampleMsgWithAuthTransactionId, - kStunTransactionIdLength); - - const StunByteStringAttribute* username = - msg.GetByteString(STUN_ATTR_USERNAME); - ASSERT_TRUE(username != NULL); - EXPECT_EQ(kRfc5769SampleMsgWithAuthUsername, username->GetString()); - - const StunByteStringAttribute* nonce = - msg.GetByteString(STUN_ATTR_NONCE); - ASSERT_TRUE(nonce != NULL); - EXPECT_EQ(kRfc5769SampleMsgWithAuthNonce, nonce->GetString()); - - const StunByteStringAttribute* realm = - msg.GetByteString(STUN_ATTR_REALM); - ASSERT_TRUE(realm != NULL); - EXPECT_EQ(kRfc5769SampleMsgWithAuthRealm, realm->GetString()); - - // No fingerprint, actual M-I checked in later tests. - ASSERT_TRUE(msg.GetByteString(STUN_ATTR_MESSAGE_INTEGRITY) != NULL); - ASSERT_TRUE(msg.GetUInt32(STUN_ATTR_FINGERPRINT) == NULL); -} - -// The RFC3489 packet in this test is the same as -// kStunMessageWithIPv4MappedAddress, but with a different value where the -// magic cookie was. -TEST_F(StunTest, ReadLegacyMessage) { - unsigned char rfc3489_packet[sizeof(kStunMessageWithIPv4MappedAddress)]; - memcpy(rfc3489_packet, kStunMessageWithIPv4MappedAddress, - sizeof(kStunMessageWithIPv4MappedAddress)); - // Overwrite the magic cookie here. - memcpy(&rfc3489_packet[4], "ABCD", 4); - - StunMessage msg; - size_t size = ReadStunMessage(&msg, rfc3489_packet); - CheckStunHeader(msg, STUN_BINDING_RESPONSE, size); - CheckStunTransactionID(msg, &rfc3489_packet[4], kStunTransactionIdLength + 4); - - const StunAddressAttribute* addr = msg.GetAddress(STUN_ATTR_MAPPED_ADDRESS); - rtc::IPAddress test_address(kIPv4TestAddress1); - CheckStunAddressAttribute(addr, STUN_ADDRESS_IPV4, - kTestMessagePort4, test_address); -} - -TEST_F(StunTest, SetIPv6XorAddressAttributeOwner) { - StunMessage msg; - StunMessage msg2; - size_t size = ReadStunMessage(&msg, kStunMessageWithIPv6XorMappedAddress); - - rtc::IPAddress test_address(kIPv6TestAddress1); - - CheckStunHeader(msg, STUN_BINDING_RESPONSE, size); - CheckStunTransactionID(msg, kTestTransactionId2, kStunTransactionIdLength); - - const StunAddressAttribute* addr = - msg.GetAddress(STUN_ATTR_XOR_MAPPED_ADDRESS); - CheckStunAddressAttribute(addr, STUN_ADDRESS_IPV6, - kTestMessagePort1, test_address); - - // Owner with a different transaction ID. - msg2.SetTransactionID("ABCDABCDABCD"); - StunXorAddressAttribute addr2(STUN_ATTR_XOR_MAPPED_ADDRESS, 20, NULL); - addr2.SetIP(addr->ipaddr()); - addr2.SetPort(addr->port()); - addr2.SetOwner(&msg2); - // The internal IP address shouldn't change. - ASSERT_EQ(addr2.ipaddr(), addr->ipaddr()); - - rtc::ByteBuffer correct_buf; - rtc::ByteBuffer wrong_buf; - EXPECT_TRUE(addr->Write(&correct_buf)); - EXPECT_TRUE(addr2.Write(&wrong_buf)); - // But when written out, the buffers should look different. - ASSERT_NE(0, - memcmp(correct_buf.Data(), wrong_buf.Data(), wrong_buf.Length())); - // And when reading a known good value, the address should be wrong. - addr2.Read(&correct_buf); - ASSERT_NE(addr->ipaddr(), addr2.ipaddr()); - addr2.SetIP(addr->ipaddr()); - addr2.SetPort(addr->port()); - // Try writing with no owner at all, should fail and write nothing. - addr2.SetOwner(NULL); - ASSERT_EQ(addr2.ipaddr(), addr->ipaddr()); - wrong_buf.Consume(wrong_buf.Length()); - EXPECT_FALSE(addr2.Write(&wrong_buf)); - ASSERT_EQ(0U, wrong_buf.Length()); -} - -TEST_F(StunTest, SetIPv4XorAddressAttributeOwner) { - // Unlike the IPv6XorAddressAttributeOwner test, IPv4 XOR address attributes - // should _not_ be affected by a change in owner. IPv4 XOR address uses the - // magic cookie value which is fixed. - StunMessage msg; - StunMessage msg2; - size_t size = ReadStunMessage(&msg, kStunMessageWithIPv4XorMappedAddress); - - rtc::IPAddress test_address(kIPv4TestAddress1); - - CheckStunHeader(msg, STUN_BINDING_RESPONSE, size); - CheckStunTransactionID(msg, kTestTransactionId1, kStunTransactionIdLength); - - const StunAddressAttribute* addr = - msg.GetAddress(STUN_ATTR_XOR_MAPPED_ADDRESS); - CheckStunAddressAttribute(addr, STUN_ADDRESS_IPV4, - kTestMessagePort3, test_address); - - // Owner with a different transaction ID. - msg2.SetTransactionID("ABCDABCDABCD"); - StunXorAddressAttribute addr2(STUN_ATTR_XOR_MAPPED_ADDRESS, 20, NULL); - addr2.SetIP(addr->ipaddr()); - addr2.SetPort(addr->port()); - addr2.SetOwner(&msg2); - // The internal IP address shouldn't change. - ASSERT_EQ(addr2.ipaddr(), addr->ipaddr()); - - rtc::ByteBuffer correct_buf; - rtc::ByteBuffer wrong_buf; - EXPECT_TRUE(addr->Write(&correct_buf)); - EXPECT_TRUE(addr2.Write(&wrong_buf)); - // The same address data should be written. - ASSERT_EQ(0, - memcmp(correct_buf.Data(), wrong_buf.Data(), wrong_buf.Length())); - // And an attribute should be able to un-XOR an address belonging to a message - // with a different transaction ID. - EXPECT_TRUE(addr2.Read(&correct_buf)); - ASSERT_EQ(addr->ipaddr(), addr2.ipaddr()); - - // However, no owner is still an error, should fail and write nothing. - addr2.SetOwner(NULL); - ASSERT_EQ(addr2.ipaddr(), addr->ipaddr()); - wrong_buf.Consume(wrong_buf.Length()); - EXPECT_FALSE(addr2.Write(&wrong_buf)); -} - -TEST_F(StunTest, CreateIPv6AddressAttribute) { - rtc::IPAddress test_ip(kIPv6TestAddress2); - - StunAddressAttribute* addr = - StunAttribute::CreateAddress(STUN_ATTR_MAPPED_ADDRESS); - rtc::SocketAddress test_addr(test_ip, kTestMessagePort2); - addr->SetAddress(test_addr); - - CheckStunAddressAttribute(addr, STUN_ADDRESS_IPV6, - kTestMessagePort2, test_ip); - delete addr; -} - -TEST_F(StunTest, CreateIPv4AddressAttribute) { - struct in_addr test_in_addr; - test_in_addr.s_addr = 0xBEB0B0BE; - rtc::IPAddress test_ip(test_in_addr); - - StunAddressAttribute* addr = - StunAttribute::CreateAddress(STUN_ATTR_MAPPED_ADDRESS); - rtc::SocketAddress test_addr(test_ip, kTestMessagePort2); - addr->SetAddress(test_addr); - - CheckStunAddressAttribute(addr, STUN_ADDRESS_IPV4, - kTestMessagePort2, test_ip); - delete addr; -} - -// Test that we don't care what order we set the parts of an address -TEST_F(StunTest, CreateAddressInArbitraryOrder) { - StunAddressAttribute* addr = - StunAttribute::CreateAddress(STUN_ATTR_DESTINATION_ADDRESS); - // Port first - addr->SetPort(kTestMessagePort1); - addr->SetIP(rtc::IPAddress(kIPv4TestAddress1)); - ASSERT_EQ(kTestMessagePort1, addr->port()); - ASSERT_EQ(rtc::IPAddress(kIPv4TestAddress1), addr->ipaddr()); - - StunAddressAttribute* addr2 = - StunAttribute::CreateAddress(STUN_ATTR_DESTINATION_ADDRESS); - // IP first - addr2->SetIP(rtc::IPAddress(kIPv4TestAddress1)); - addr2->SetPort(kTestMessagePort2); - ASSERT_EQ(kTestMessagePort2, addr2->port()); - ASSERT_EQ(rtc::IPAddress(kIPv4TestAddress1), addr2->ipaddr()); - - delete addr; - delete addr2; -} - -TEST_F(StunTest, WriteMessageWithIPv6AddressAttribute) { - StunMessage msg; - size_t size = sizeof(kStunMessageWithIPv6MappedAddress); - - rtc::IPAddress test_ip(kIPv6TestAddress1); - - msg.SetType(STUN_BINDING_REQUEST); - msg.SetTransactionID( - std::string(reinterpret_cast<const char*>(kTestTransactionId1), - kStunTransactionIdLength)); - CheckStunTransactionID(msg, kTestTransactionId1, kStunTransactionIdLength); - - StunAddressAttribute* addr = - StunAttribute::CreateAddress(STUN_ATTR_MAPPED_ADDRESS); - rtc::SocketAddress test_addr(test_ip, kTestMessagePort2); - addr->SetAddress(test_addr); - EXPECT_TRUE(msg.AddAttribute(addr)); - - CheckStunHeader(msg, STUN_BINDING_REQUEST, (size - 20)); - - rtc::ByteBuffer out; - EXPECT_TRUE(msg.Write(&out)); - ASSERT_EQ(out.Length(), sizeof(kStunMessageWithIPv6MappedAddress)); - int len1 = static_cast<int>(out.Length()); - std::string bytes; - out.ReadString(&bytes, len1); - ASSERT_EQ(0, memcmp(bytes.c_str(), kStunMessageWithIPv6MappedAddress, len1)); -} - -TEST_F(StunTest, WriteMessageWithIPv4AddressAttribute) { - StunMessage msg; - size_t size = sizeof(kStunMessageWithIPv4MappedAddress); - - rtc::IPAddress test_ip(kIPv4TestAddress1); - - msg.SetType(STUN_BINDING_RESPONSE); - msg.SetTransactionID( - std::string(reinterpret_cast<const char*>(kTestTransactionId1), - kStunTransactionIdLength)); - CheckStunTransactionID(msg, kTestTransactionId1, kStunTransactionIdLength); - - StunAddressAttribute* addr = - StunAttribute::CreateAddress(STUN_ATTR_MAPPED_ADDRESS); - rtc::SocketAddress test_addr(test_ip, kTestMessagePort4); - addr->SetAddress(test_addr); - EXPECT_TRUE(msg.AddAttribute(addr)); - - CheckStunHeader(msg, STUN_BINDING_RESPONSE, (size - 20)); - - rtc::ByteBuffer out; - EXPECT_TRUE(msg.Write(&out)); - ASSERT_EQ(out.Length(), sizeof(kStunMessageWithIPv4MappedAddress)); - int len1 = static_cast<int>(out.Length()); - std::string bytes; - out.ReadString(&bytes, len1); - ASSERT_EQ(0, memcmp(bytes.c_str(), kStunMessageWithIPv4MappedAddress, len1)); -} - -TEST_F(StunTest, WriteMessageWithIPv6XorAddressAttribute) { - StunMessage msg; - size_t size = sizeof(kStunMessageWithIPv6XorMappedAddress); - - rtc::IPAddress test_ip(kIPv6TestAddress1); - - msg.SetType(STUN_BINDING_RESPONSE); - msg.SetTransactionID( - std::string(reinterpret_cast<const char*>(kTestTransactionId2), - kStunTransactionIdLength)); - CheckStunTransactionID(msg, kTestTransactionId2, kStunTransactionIdLength); - - StunAddressAttribute* addr = - StunAttribute::CreateXorAddress(STUN_ATTR_XOR_MAPPED_ADDRESS); - rtc::SocketAddress test_addr(test_ip, kTestMessagePort1); - addr->SetAddress(test_addr); - EXPECT_TRUE(msg.AddAttribute(addr)); - - CheckStunHeader(msg, STUN_BINDING_RESPONSE, (size - 20)); - - rtc::ByteBuffer out; - EXPECT_TRUE(msg.Write(&out)); - ASSERT_EQ(out.Length(), sizeof(kStunMessageWithIPv6XorMappedAddress)); - int len1 = static_cast<int>(out.Length()); - std::string bytes; - out.ReadString(&bytes, len1); - ASSERT_EQ(0, - memcmp(bytes.c_str(), kStunMessageWithIPv6XorMappedAddress, len1)); -} - -TEST_F(StunTest, WriteMessageWithIPv4XoreAddressAttribute) { - StunMessage msg; - size_t size = sizeof(kStunMessageWithIPv4XorMappedAddress); - - rtc::IPAddress test_ip(kIPv4TestAddress1); - - msg.SetType(STUN_BINDING_RESPONSE); - msg.SetTransactionID( - std::string(reinterpret_cast<const char*>(kTestTransactionId1), - kStunTransactionIdLength)); - CheckStunTransactionID(msg, kTestTransactionId1, kStunTransactionIdLength); - - StunAddressAttribute* addr = - StunAttribute::CreateXorAddress(STUN_ATTR_XOR_MAPPED_ADDRESS); - rtc::SocketAddress test_addr(test_ip, kTestMessagePort3); - addr->SetAddress(test_addr); - EXPECT_TRUE(msg.AddAttribute(addr)); - - CheckStunHeader(msg, STUN_BINDING_RESPONSE, (size - 20)); - - rtc::ByteBuffer out; - EXPECT_TRUE(msg.Write(&out)); - ASSERT_EQ(out.Length(), sizeof(kStunMessageWithIPv4XorMappedAddress)); - int len1 = static_cast<int>(out.Length()); - std::string bytes; - out.ReadString(&bytes, len1); - ASSERT_EQ(0, - memcmp(bytes.c_str(), kStunMessageWithIPv4XorMappedAddress, len1)); -} - -TEST_F(StunTest, ReadByteStringAttribute) { - StunMessage msg; - size_t size = ReadStunMessage(&msg, kStunMessageWithByteStringAttribute); - - CheckStunHeader(msg, STUN_BINDING_REQUEST, size); - CheckStunTransactionID(msg, kTestTransactionId2, kStunTransactionIdLength); - const StunByteStringAttribute* username = - msg.GetByteString(STUN_ATTR_USERNAME); - ASSERT_TRUE(username != NULL); - EXPECT_EQ(kTestUserName1, username->GetString()); -} - -TEST_F(StunTest, ReadPaddedByteStringAttribute) { - StunMessage msg; - size_t size = ReadStunMessage(&msg, - kStunMessageWithPaddedByteStringAttribute); - ASSERT_NE(0U, size); - CheckStunHeader(msg, STUN_BINDING_REQUEST, size); - CheckStunTransactionID(msg, kTestTransactionId2, kStunTransactionIdLength); - const StunByteStringAttribute* username = - msg.GetByteString(STUN_ATTR_USERNAME); - ASSERT_TRUE(username != NULL); - EXPECT_EQ(kTestUserName2, username->GetString()); -} - -TEST_F(StunTest, ReadErrorCodeAttribute) { - StunMessage msg; - size_t size = ReadStunMessage(&msg, kStunMessageWithErrorAttribute); - - CheckStunHeader(msg, STUN_BINDING_ERROR_RESPONSE, size); - CheckStunTransactionID(msg, kTestTransactionId1, kStunTransactionIdLength); - const StunErrorCodeAttribute* errorcode = msg.GetErrorCode(); - ASSERT_TRUE(errorcode != NULL); - EXPECT_EQ(kTestErrorClass, errorcode->eclass()); - EXPECT_EQ(kTestErrorNumber, errorcode->number()); - EXPECT_EQ(kTestErrorReason, errorcode->reason()); - EXPECT_EQ(kTestErrorCode, errorcode->code()); -} - -TEST_F(StunTest, ReadMessageWithAUInt16ListAttribute) { - StunMessage msg; - size_t size = ReadStunMessage(&msg, kStunMessageWithUInt16ListAttribute); - CheckStunHeader(msg, STUN_BINDING_REQUEST, size); - const StunUInt16ListAttribute* types = msg.GetUnknownAttributes(); - ASSERT_TRUE(types != NULL); - EXPECT_EQ(3U, types->Size()); - EXPECT_EQ(0x1U, types->GetType(0)); - EXPECT_EQ(0x1000U, types->GetType(1)); - EXPECT_EQ(0xAB0CU, types->GetType(2)); -} - -TEST_F(StunTest, ReadMessageWithAnUnknownAttribute) { - StunMessage msg; - size_t size = ReadStunMessage(&msg, kStunMessageWithUnknownAttribute); - CheckStunHeader(msg, STUN_BINDING_REQUEST, size); - - // Parsing should have succeeded and there should be a USERNAME attribute - const StunByteStringAttribute* username = - msg.GetByteString(STUN_ATTR_USERNAME); - ASSERT_TRUE(username != NULL); - EXPECT_EQ(kTestUserName2, username->GetString()); -} - -TEST_F(StunTest, WriteMessageWithAnErrorCodeAttribute) { - StunMessage msg; - size_t size = sizeof(kStunMessageWithErrorAttribute); - - msg.SetType(STUN_BINDING_ERROR_RESPONSE); - msg.SetTransactionID( - std::string(reinterpret_cast<const char*>(kTestTransactionId1), - kStunTransactionIdLength)); - CheckStunTransactionID(msg, kTestTransactionId1, kStunTransactionIdLength); - StunErrorCodeAttribute* errorcode = StunAttribute::CreateErrorCode(); - errorcode->SetCode(kTestErrorCode); - errorcode->SetReason(kTestErrorReason); - EXPECT_TRUE(msg.AddAttribute(errorcode)); - CheckStunHeader(msg, STUN_BINDING_ERROR_RESPONSE, (size - 20)); - - rtc::ByteBuffer out; - EXPECT_TRUE(msg.Write(&out)); - ASSERT_EQ(size, out.Length()); - // No padding. - ASSERT_EQ(0, memcmp(out.Data(), kStunMessageWithErrorAttribute, size)); -} - -TEST_F(StunTest, WriteMessageWithAUInt16ListAttribute) { - StunMessage msg; - size_t size = sizeof(kStunMessageWithUInt16ListAttribute); - - msg.SetType(STUN_BINDING_REQUEST); - msg.SetTransactionID( - std::string(reinterpret_cast<const char*>(kTestTransactionId2), - kStunTransactionIdLength)); - CheckStunTransactionID(msg, kTestTransactionId2, kStunTransactionIdLength); - StunUInt16ListAttribute* list = StunAttribute::CreateUnknownAttributes(); - list->AddType(0x1U); - list->AddType(0x1000U); - list->AddType(0xAB0CU); - EXPECT_TRUE(msg.AddAttribute(list)); - CheckStunHeader(msg, STUN_BINDING_REQUEST, (size - 20)); - - rtc::ByteBuffer out; - EXPECT_TRUE(msg.Write(&out)); - ASSERT_EQ(size, out.Length()); - // Check everything up to the padding. - ASSERT_EQ(0, - memcmp(out.Data(), kStunMessageWithUInt16ListAttribute, size - 2)); -} - -// Test that we fail to read messages with invalid lengths. -void CheckFailureToRead(const unsigned char* testcase, size_t length) { - StunMessage msg; - const char* input = reinterpret_cast<const char*>(testcase); - rtc::ByteBuffer buf(input, length); - ASSERT_FALSE(msg.Read(&buf)); -} - -TEST_F(StunTest, FailToReadInvalidMessages) { - CheckFailureToRead(kStunMessageWithZeroLength, - kRealLengthOfInvalidLengthTestCases); - CheckFailureToRead(kStunMessageWithSmallLength, - kRealLengthOfInvalidLengthTestCases); - CheckFailureToRead(kStunMessageWithExcessLength, - kRealLengthOfInvalidLengthTestCases); -} - -// Test that we properly fail to read a non-STUN message. -TEST_F(StunTest, FailToReadRtcpPacket) { - CheckFailureToRead(kRtcpPacket, sizeof(kRtcpPacket)); -} - -// Check our STUN message validation code against the RFC5769 test messages. -TEST_F(StunTest, ValidateMessageIntegrity) { - // Try the messages from RFC 5769. - EXPECT_TRUE(StunMessage::ValidateMessageIntegrity( - reinterpret_cast<const char*>(kRfc5769SampleRequest), - sizeof(kRfc5769SampleRequest), - kRfc5769SampleMsgPassword)); - EXPECT_FALSE(StunMessage::ValidateMessageIntegrity( - reinterpret_cast<const char*>(kRfc5769SampleRequest), - sizeof(kRfc5769SampleRequest), - "InvalidPassword")); - - EXPECT_TRUE(StunMessage::ValidateMessageIntegrity( - reinterpret_cast<const char*>(kRfc5769SampleResponse), - sizeof(kRfc5769SampleResponse), - kRfc5769SampleMsgPassword)); - EXPECT_FALSE(StunMessage::ValidateMessageIntegrity( - reinterpret_cast<const char*>(kRfc5769SampleResponse), - sizeof(kRfc5769SampleResponse), - "InvalidPassword")); - - EXPECT_TRUE(StunMessage::ValidateMessageIntegrity( - reinterpret_cast<const char*>(kRfc5769SampleResponseIPv6), - sizeof(kRfc5769SampleResponseIPv6), - kRfc5769SampleMsgPassword)); - EXPECT_FALSE(StunMessage::ValidateMessageIntegrity( - reinterpret_cast<const char*>(kRfc5769SampleResponseIPv6), - sizeof(kRfc5769SampleResponseIPv6), - "InvalidPassword")); - - // We first need to compute the key for the long-term authentication HMAC. - std::string key; - ComputeStunCredentialHash(kRfc5769SampleMsgWithAuthUsername, - kRfc5769SampleMsgWithAuthRealm, kRfc5769SampleMsgWithAuthPassword, &key); - EXPECT_TRUE(StunMessage::ValidateMessageIntegrity( - reinterpret_cast<const char*>(kRfc5769SampleRequestLongTermAuth), - sizeof(kRfc5769SampleRequestLongTermAuth), key)); - EXPECT_FALSE(StunMessage::ValidateMessageIntegrity( - reinterpret_cast<const char*>(kRfc5769SampleRequestLongTermAuth), - sizeof(kRfc5769SampleRequestLongTermAuth), - "InvalidPassword")); - - // Try some edge cases. - EXPECT_FALSE(StunMessage::ValidateMessageIntegrity( - reinterpret_cast<const char*>(kStunMessageWithZeroLength), - sizeof(kStunMessageWithZeroLength), - kRfc5769SampleMsgPassword)); - EXPECT_FALSE(StunMessage::ValidateMessageIntegrity( - reinterpret_cast<const char*>(kStunMessageWithExcessLength), - sizeof(kStunMessageWithExcessLength), - kRfc5769SampleMsgPassword)); - EXPECT_FALSE(StunMessage::ValidateMessageIntegrity( - reinterpret_cast<const char*>(kStunMessageWithSmallLength), - sizeof(kStunMessageWithSmallLength), - kRfc5769SampleMsgPassword)); - - // Test that munging a single bit anywhere in the message causes the - // message-integrity check to fail, unless it is after the M-I attribute. - char buf[sizeof(kRfc5769SampleRequest)]; - memcpy(buf, kRfc5769SampleRequest, sizeof(kRfc5769SampleRequest)); - for (size_t i = 0; i < sizeof(buf); ++i) { - buf[i] ^= 0x01; - if (i > 0) - buf[i - 1] ^= 0x01; - EXPECT_EQ(i >= sizeof(buf) - 8, StunMessage::ValidateMessageIntegrity( - buf, sizeof(buf), kRfc5769SampleMsgPassword)); - } -} - -// Validate that we generate correct MESSAGE-INTEGRITY attributes. -// Note the use of IceMessage instead of StunMessage; this is necessary because -// the RFC5769 test messages used include attributes not found in basic STUN. -TEST_F(StunTest, AddMessageIntegrity) { - IceMessage msg; - rtc::ByteBuffer buf( - reinterpret_cast<const char*>(kRfc5769SampleRequestWithoutMI), - sizeof(kRfc5769SampleRequestWithoutMI)); - EXPECT_TRUE(msg.Read(&buf)); - EXPECT_TRUE(msg.AddMessageIntegrity(kRfc5769SampleMsgPassword)); - const StunByteStringAttribute* mi_attr = - msg.GetByteString(STUN_ATTR_MESSAGE_INTEGRITY); - EXPECT_EQ(20U, mi_attr->length()); - EXPECT_EQ(0, memcmp( - mi_attr->bytes(), kCalculatedHmac1, sizeof(kCalculatedHmac1))); - - rtc::ByteBuffer buf1; - EXPECT_TRUE(msg.Write(&buf1)); - EXPECT_TRUE(StunMessage::ValidateMessageIntegrity( - reinterpret_cast<const char*>(buf1.Data()), buf1.Length(), - kRfc5769SampleMsgPassword)); - - IceMessage msg2; - rtc::ByteBuffer buf2( - reinterpret_cast<const char*>(kRfc5769SampleResponseWithoutMI), - sizeof(kRfc5769SampleResponseWithoutMI)); - EXPECT_TRUE(msg2.Read(&buf2)); - EXPECT_TRUE(msg2.AddMessageIntegrity(kRfc5769SampleMsgPassword)); - const StunByteStringAttribute* mi_attr2 = - msg2.GetByteString(STUN_ATTR_MESSAGE_INTEGRITY); - EXPECT_EQ(20U, mi_attr2->length()); - EXPECT_EQ( - 0, memcmp(mi_attr2->bytes(), kCalculatedHmac2, sizeof(kCalculatedHmac2))); - - rtc::ByteBuffer buf3; - EXPECT_TRUE(msg2.Write(&buf3)); - EXPECT_TRUE(StunMessage::ValidateMessageIntegrity( - reinterpret_cast<const char*>(buf3.Data()), buf3.Length(), - kRfc5769SampleMsgPassword)); -} - -// Check our STUN message validation code against the RFC5769 test messages. -TEST_F(StunTest, ValidateFingerprint) { - EXPECT_TRUE(StunMessage::ValidateFingerprint( - reinterpret_cast<const char*>(kRfc5769SampleRequest), - sizeof(kRfc5769SampleRequest))); - EXPECT_TRUE(StunMessage::ValidateFingerprint( - reinterpret_cast<const char*>(kRfc5769SampleResponse), - sizeof(kRfc5769SampleResponse))); - EXPECT_TRUE(StunMessage::ValidateFingerprint( - reinterpret_cast<const char*>(kRfc5769SampleResponseIPv6), - sizeof(kRfc5769SampleResponseIPv6))); - - EXPECT_FALSE(StunMessage::ValidateFingerprint( - reinterpret_cast<const char*>(kStunMessageWithZeroLength), - sizeof(kStunMessageWithZeroLength))); - EXPECT_FALSE(StunMessage::ValidateFingerprint( - reinterpret_cast<const char*>(kStunMessageWithExcessLength), - sizeof(kStunMessageWithExcessLength))); - EXPECT_FALSE(StunMessage::ValidateFingerprint( - reinterpret_cast<const char*>(kStunMessageWithSmallLength), - sizeof(kStunMessageWithSmallLength))); - - // Test that munging a single bit anywhere in the message causes the - // fingerprint check to fail. - char buf[sizeof(kRfc5769SampleRequest)]; - memcpy(buf, kRfc5769SampleRequest, sizeof(kRfc5769SampleRequest)); - for (size_t i = 0; i < sizeof(buf); ++i) { - buf[i] ^= 0x01; - if (i > 0) - buf[i - 1] ^= 0x01; - EXPECT_FALSE(StunMessage::ValidateFingerprint(buf, sizeof(buf))); - } - // Put them all back to normal and the check should pass again. - buf[sizeof(buf) - 1] ^= 0x01; - EXPECT_TRUE(StunMessage::ValidateFingerprint(buf, sizeof(buf))); -} - -TEST_F(StunTest, AddFingerprint) { - IceMessage msg; - rtc::ByteBuffer buf( - reinterpret_cast<const char*>(kRfc5769SampleRequestWithoutMI), - sizeof(kRfc5769SampleRequestWithoutMI)); - EXPECT_TRUE(msg.Read(&buf)); - EXPECT_TRUE(msg.AddFingerprint()); - - rtc::ByteBuffer buf1; - EXPECT_TRUE(msg.Write(&buf1)); - EXPECT_TRUE(StunMessage::ValidateFingerprint( - reinterpret_cast<const char*>(buf1.Data()), buf1.Length())); -} - -// Sample "GTURN" relay message. -static const unsigned char kRelayMessage[] = { - 0x00, 0x01, 0x00, 88, // message header - 0x21, 0x12, 0xA4, 0x42, // magic cookie - '0', '1', '2', '3', // transaction id - '4', '5', '6', '7', - '8', '9', 'a', 'b', - 0x00, 0x01, 0x00, 8, // mapped address - 0x00, 0x01, 0x00, 13, - 0x00, 0x00, 0x00, 17, - 0x00, 0x06, 0x00, 12, // username - 'a', 'b', 'c', 'd', - 'e', 'f', 'g', 'h', - 'i', 'j', 'k', 'l', - 0x00, 0x0d, 0x00, 4, // lifetime - 0x00, 0x00, 0x00, 11, - 0x00, 0x0f, 0x00, 4, // magic cookie - 0x72, 0xc6, 0x4b, 0xc6, - 0x00, 0x10, 0x00, 4, // bandwidth - 0x00, 0x00, 0x00, 6, - 0x00, 0x11, 0x00, 8, // destination address - 0x00, 0x01, 0x00, 13, - 0x00, 0x00, 0x00, 17, - 0x00, 0x12, 0x00, 8, // source address 2 - 0x00, 0x01, 0x00, 13, - 0x00, 0x00, 0x00, 17, - 0x00, 0x13, 0x00, 7, // data - 'a', 'b', 'c', 'd', - 'e', 'f', 'g', 0 // DATA must be padded per rfc5766. -}; - -// Test that we can read the GTURN-specific fields. -TEST_F(StunTest, ReadRelayMessage) { - RelayMessage msg, msg2; - - const char* input = reinterpret_cast<const char*>(kRelayMessage); - size_t size = sizeof(kRelayMessage); - rtc::ByteBuffer buf(input, size); - EXPECT_TRUE(msg.Read(&buf)); - - EXPECT_EQ(STUN_BINDING_REQUEST, msg.type()); - EXPECT_EQ(size - 20, msg.length()); - EXPECT_EQ("0123456789ab", msg.transaction_id()); - - msg2.SetType(STUN_BINDING_REQUEST); - msg2.SetTransactionID("0123456789ab"); - - in_addr legacy_in_addr; - legacy_in_addr.s_addr = htonl(17U); - rtc::IPAddress legacy_ip(legacy_in_addr); - - const StunAddressAttribute* addr = msg.GetAddress(STUN_ATTR_MAPPED_ADDRESS); - ASSERT_TRUE(addr != NULL); - EXPECT_EQ(1, addr->family()); - EXPECT_EQ(13, addr->port()); - EXPECT_EQ(legacy_ip, addr->ipaddr()); - - StunAddressAttribute* addr2 = - StunAttribute::CreateAddress(STUN_ATTR_MAPPED_ADDRESS); - addr2->SetPort(13); - addr2->SetIP(legacy_ip); - EXPECT_TRUE(msg2.AddAttribute(addr2)); - - const StunByteStringAttribute* bytes = msg.GetByteString(STUN_ATTR_USERNAME); - ASSERT_TRUE(bytes != NULL); - EXPECT_EQ(12U, bytes->length()); - EXPECT_EQ("abcdefghijkl", bytes->GetString()); - - StunByteStringAttribute* bytes2 = - StunAttribute::CreateByteString(STUN_ATTR_USERNAME); - bytes2->CopyBytes("abcdefghijkl"); - EXPECT_TRUE(msg2.AddAttribute(bytes2)); - - const StunUInt32Attribute* uval = msg.GetUInt32(STUN_ATTR_LIFETIME); - ASSERT_TRUE(uval != NULL); - EXPECT_EQ(11U, uval->value()); - - StunUInt32Attribute* uval2 = StunAttribute::CreateUInt32(STUN_ATTR_LIFETIME); - uval2->SetValue(11); - EXPECT_TRUE(msg2.AddAttribute(uval2)); - - bytes = msg.GetByteString(STUN_ATTR_MAGIC_COOKIE); - ASSERT_TRUE(bytes != NULL); - EXPECT_EQ(4U, bytes->length()); - EXPECT_EQ(0, - memcmp(bytes->bytes(), - TURN_MAGIC_COOKIE_VALUE, - sizeof(TURN_MAGIC_COOKIE_VALUE))); - - bytes2 = StunAttribute::CreateByteString(STUN_ATTR_MAGIC_COOKIE); - bytes2->CopyBytes(reinterpret_cast<const char*>(TURN_MAGIC_COOKIE_VALUE), - sizeof(TURN_MAGIC_COOKIE_VALUE)); - EXPECT_TRUE(msg2.AddAttribute(bytes2)); - - uval = msg.GetUInt32(STUN_ATTR_BANDWIDTH); - ASSERT_TRUE(uval != NULL); - EXPECT_EQ(6U, uval->value()); - - uval2 = StunAttribute::CreateUInt32(STUN_ATTR_BANDWIDTH); - uval2->SetValue(6); - EXPECT_TRUE(msg2.AddAttribute(uval2)); - - addr = msg.GetAddress(STUN_ATTR_DESTINATION_ADDRESS); - ASSERT_TRUE(addr != NULL); - EXPECT_EQ(1, addr->family()); - EXPECT_EQ(13, addr->port()); - EXPECT_EQ(legacy_ip, addr->ipaddr()); - - addr2 = StunAttribute::CreateAddress(STUN_ATTR_DESTINATION_ADDRESS); - addr2->SetPort(13); - addr2->SetIP(legacy_ip); - EXPECT_TRUE(msg2.AddAttribute(addr2)); - - addr = msg.GetAddress(STUN_ATTR_SOURCE_ADDRESS2); - ASSERT_TRUE(addr != NULL); - EXPECT_EQ(1, addr->family()); - EXPECT_EQ(13, addr->port()); - EXPECT_EQ(legacy_ip, addr->ipaddr()); - - addr2 = StunAttribute::CreateAddress(STUN_ATTR_SOURCE_ADDRESS2); - addr2->SetPort(13); - addr2->SetIP(legacy_ip); - EXPECT_TRUE(msg2.AddAttribute(addr2)); - - bytes = msg.GetByteString(STUN_ATTR_DATA); - ASSERT_TRUE(bytes != NULL); - EXPECT_EQ(7U, bytes->length()); - EXPECT_EQ("abcdefg", bytes->GetString()); - - bytes2 = StunAttribute::CreateByteString(STUN_ATTR_DATA); - bytes2->CopyBytes("abcdefg"); - EXPECT_TRUE(msg2.AddAttribute(bytes2)); - - rtc::ByteBuffer out; - EXPECT_TRUE(msg.Write(&out)); - EXPECT_EQ(size, out.Length()); - size_t len1 = out.Length(); - std::string outstring; - out.ReadString(&outstring, len1); - EXPECT_EQ(0, memcmp(outstring.c_str(), input, len1)); - - rtc::ByteBuffer out2; - EXPECT_TRUE(msg2.Write(&out2)); - EXPECT_EQ(size, out2.Length()); - size_t len2 = out2.Length(); - std::string outstring2; - out2.ReadString(&outstring2, len2); - EXPECT_EQ(0, memcmp(outstring2.c_str(), input, len2)); -} - -} // namespace cricket diff --git a/talk/p2p/base/stunport.cc b/talk/p2p/base/stunport.cc deleted file mode 100644 index 0602c5a5d..000000000 --- a/talk/p2p/base/stunport.cc +++ /dev/null @@ -1,468 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "webrtc/p2p/base/stunport.h" - -#include "webrtc/p2p/base/common.h" -#include "webrtc/p2p/base/portallocator.h" -#include "webrtc/p2p/base/stun.h" -#include "webrtc/base/common.h" -#include "webrtc/base/helpers.h" -#include "webrtc/base/logging.h" -#include "webrtc/base/nethelpers.h" - -namespace cricket { - -// TODO: Move these to a common place (used in relayport too) -const int KEEPALIVE_DELAY = 10 * 1000; // 10 seconds - sort timeouts -const int RETRY_DELAY = 50; // 50ms, from ICE spec -const int RETRY_TIMEOUT = 50 * 1000; // ICE says 50 secs - -// Handles a binding request sent to the STUN server. -class StunBindingRequest : public StunRequest { - public: - StunBindingRequest(UDPPort* port, bool keep_alive, - const rtc::SocketAddress& addr) - : port_(port), keep_alive_(keep_alive), server_addr_(addr) { - start_time_ = rtc::Time(); - } - - virtual ~StunBindingRequest() { - } - - const rtc::SocketAddress& server_addr() const { return server_addr_; } - - virtual void Prepare(StunMessage* request) { - request->SetType(STUN_BINDING_REQUEST); - } - - virtual void OnResponse(StunMessage* response) { - const StunAddressAttribute* addr_attr = - response->GetAddress(STUN_ATTR_MAPPED_ADDRESS); - if (!addr_attr) { - LOG(LS_ERROR) << "Binding response missing mapped address."; - } else if (addr_attr->family() != STUN_ADDRESS_IPV4 && - addr_attr->family() != STUN_ADDRESS_IPV6) { - LOG(LS_ERROR) << "Binding address has bad family"; - } else { - rtc::SocketAddress addr(addr_attr->ipaddr(), addr_attr->port()); - port_->OnStunBindingRequestSucceeded(server_addr_, addr); - } - - // We will do a keep-alive regardless of whether this request succeeds. - // This should have almost no impact on network usage. - if (keep_alive_) { - port_->requests_.SendDelayed( - new StunBindingRequest(port_, true, server_addr_), - port_->stun_keepalive_delay()); - } - } - - virtual void OnErrorResponse(StunMessage* response) { - const StunErrorCodeAttribute* attr = response->GetErrorCode(); - if (!attr) { - LOG(LS_ERROR) << "Bad allocate response error code"; - } else { - LOG(LS_ERROR) << "Binding error response:" - << " class=" << attr->eclass() - << " number=" << attr->number() - << " reason='" << attr->reason() << "'"; - } - - port_->OnStunBindingOrResolveRequestFailed(server_addr_); - - if (keep_alive_ - && (rtc::TimeSince(start_time_) <= RETRY_TIMEOUT)) { - port_->requests_.SendDelayed( - new StunBindingRequest(port_, true, server_addr_), - port_->stun_keepalive_delay()); - } - } - - virtual void OnTimeout() { - LOG(LS_ERROR) << "Binding request timed out from " - << port_->GetLocalAddress().ToSensitiveString() - << " (" << port_->Network()->name() << ")"; - - port_->OnStunBindingOrResolveRequestFailed(server_addr_); - - if (keep_alive_ - && (rtc::TimeSince(start_time_) <= RETRY_TIMEOUT)) { - port_->requests_.SendDelayed( - new StunBindingRequest(port_, true, server_addr_), - RETRY_DELAY); - } - } - - private: - UDPPort* port_; - bool keep_alive_; - const rtc::SocketAddress server_addr_; - uint32 start_time_; -}; - -UDPPort::AddressResolver::AddressResolver( - rtc::PacketSocketFactory* factory) - : socket_factory_(factory) {} - -UDPPort::AddressResolver::~AddressResolver() { - for (ResolverMap::iterator it = resolvers_.begin(); - it != resolvers_.end(); ++it) { - it->second->Destroy(true); - } -} - -void UDPPort::AddressResolver::Resolve( - const rtc::SocketAddress& address) { - if (resolvers_.find(address) != resolvers_.end()) - return; - - rtc::AsyncResolverInterface* resolver = - socket_factory_->CreateAsyncResolver(); - resolvers_.insert( - std::pair<rtc::SocketAddress, rtc::AsyncResolverInterface*>( - address, resolver)); - - resolver->SignalDone.connect(this, - &UDPPort::AddressResolver::OnResolveResult); - - resolver->Start(address); -} - -bool UDPPort::AddressResolver::GetResolvedAddress( - const rtc::SocketAddress& input, - int family, - rtc::SocketAddress* output) const { - ResolverMap::const_iterator it = resolvers_.find(input); - if (it == resolvers_.end()) - return false; - - return it->second->GetResolvedAddress(family, output); -} - -void UDPPort::AddressResolver::OnResolveResult( - rtc::AsyncResolverInterface* resolver) { - for (ResolverMap::iterator it = resolvers_.begin(); - it != resolvers_.end(); ++it) { - if (it->second == resolver) { - SignalDone(it->first, resolver->GetError()); - return; - } - } -} - -UDPPort::UDPPort(rtc::Thread* thread, - rtc::PacketSocketFactory* factory, - rtc::Network* network, - rtc::AsyncPacketSocket* socket, - const std::string& username, const std::string& password) - : Port(thread, factory, network, socket->GetLocalAddress().ipaddr(), - username, password), - requests_(thread), - socket_(socket), - error_(0), - ready_(false), - stun_keepalive_delay_(KEEPALIVE_DELAY) { -} - -UDPPort::UDPPort(rtc::Thread* thread, - rtc::PacketSocketFactory* factory, - rtc::Network* network, - const rtc::IPAddress& ip, int min_port, int max_port, - const std::string& username, const std::string& password) - : Port(thread, LOCAL_PORT_TYPE, factory, network, ip, min_port, max_port, - username, password), - requests_(thread), - socket_(NULL), - error_(0), - ready_(false), - stun_keepalive_delay_(KEEPALIVE_DELAY) { -} - -bool UDPPort::Init() { - if (!SharedSocket()) { - ASSERT(socket_ == NULL); - socket_ = socket_factory()->CreateUdpSocket( - rtc::SocketAddress(ip(), 0), min_port(), max_port()); - if (!socket_) { - LOG_J(LS_WARNING, this) << "UDP socket creation failed"; - return false; - } - socket_->SignalReadPacket.connect(this, &UDPPort::OnReadPacket); - } - socket_->SignalReadyToSend.connect(this, &UDPPort::OnReadyToSend); - socket_->SignalAddressReady.connect(this, &UDPPort::OnLocalAddressReady); - requests_.SignalSendPacket.connect(this, &UDPPort::OnSendPacket); - return true; -} - -UDPPort::~UDPPort() { - if (!SharedSocket()) - delete socket_; -} - -void UDPPort::PrepareAddress() { - ASSERT(requests_.empty()); - if (socket_->GetState() == rtc::AsyncPacketSocket::STATE_BOUND) { - OnLocalAddressReady(socket_, socket_->GetLocalAddress()); - } -} - -void UDPPort::MaybePrepareStunCandidate() { - // Sending binding request to the STUN server if address is available to - // prepare STUN candidate. - if (!server_addresses_.empty()) { - SendStunBindingRequests(); - } else { - // Port is done allocating candidates. - MaybeSetPortCompleteOrError(); - } -} - -Connection* UDPPort::CreateConnection(const Candidate& address, - CandidateOrigin origin) { - if (address.protocol() != "udp") - return NULL; - - if (!IsCompatibleAddress(address.address())) { - return NULL; - } - - if (SharedSocket() && Candidates()[0].type() != LOCAL_PORT_TYPE) { - ASSERT(false); - return NULL; - } - - Connection* conn = new ProxyConnection(this, 0, address); - AddConnection(conn); - return conn; -} - -int UDPPort::SendTo(const void* data, size_t size, - const rtc::SocketAddress& addr, - const rtc::PacketOptions& options, - bool payload) { - int sent = socket_->SendTo(data, size, addr, options); - if (sent < 0) { - error_ = socket_->GetError(); - LOG_J(LS_ERROR, this) << "UDP send of " << size - << " bytes failed with error " << error_; - } - return sent; -} - -int UDPPort::SetOption(rtc::Socket::Option opt, int value) { - return socket_->SetOption(opt, value); -} - -int UDPPort::GetOption(rtc::Socket::Option opt, int* value) { - return socket_->GetOption(opt, value); -} - -int UDPPort::GetError() { - return error_; -} - -void UDPPort::OnLocalAddressReady(rtc::AsyncPacketSocket* socket, - const rtc::SocketAddress& address) { - AddAddress(address, address, rtc::SocketAddress(), - UDP_PROTOCOL_NAME, "", LOCAL_PORT_TYPE, - ICE_TYPE_PREFERENCE_HOST, 0, false); - MaybePrepareStunCandidate(); -} - -void UDPPort::OnReadPacket( - rtc::AsyncPacketSocket* socket, const char* data, size_t size, - const rtc::SocketAddress& remote_addr, - const rtc::PacketTime& packet_time) { - ASSERT(socket == socket_); - ASSERT(!remote_addr.IsUnresolved()); - - // Look for a response from the STUN server. - // Even if the response doesn't match one of our outstanding requests, we - // will eat it because it might be a response to a retransmitted packet, and - // we already cleared the request when we got the first response. - if (server_addresses_.find(remote_addr) != server_addresses_.end()) { - requests_.CheckResponse(data, size); - return; - } - - if (Connection* conn = GetConnection(remote_addr)) { - conn->OnReadPacket(data, size, packet_time); - } else { - Port::OnReadPacket(data, size, remote_addr, PROTO_UDP); - } -} - -void UDPPort::OnReadyToSend(rtc::AsyncPacketSocket* socket) { - Port::OnReadyToSend(); -} - -void UDPPort::SendStunBindingRequests() { - // We will keep pinging the stun server to make sure our NAT pin-hole stays - // open during the call. - ASSERT(requests_.empty()); - - for (ServerAddresses::const_iterator it = server_addresses_.begin(); - it != server_addresses_.end(); ++it) { - SendStunBindingRequest(*it); - } -} - -void UDPPort::ResolveStunAddress(const rtc::SocketAddress& stun_addr) { - if (!resolver_) { - resolver_.reset(new AddressResolver(socket_factory())); - resolver_->SignalDone.connect(this, &UDPPort::OnResolveResult); - } - - resolver_->Resolve(stun_addr); -} - -void UDPPort::OnResolveResult(const rtc::SocketAddress& input, - int error) { - ASSERT(resolver_.get() != NULL); - - rtc::SocketAddress resolved; - if (error != 0 || - !resolver_->GetResolvedAddress(input, ip().family(), &resolved)) { - LOG_J(LS_WARNING, this) << "StunPort: stun host lookup received error " - << error; - OnStunBindingOrResolveRequestFailed(input); - return; - } - - server_addresses_.erase(input); - - if (server_addresses_.find(resolved) == server_addresses_.end()) { - server_addresses_.insert(resolved); - SendStunBindingRequest(resolved); - } -} - -void UDPPort::SendStunBindingRequest( - const rtc::SocketAddress& stun_addr) { - if (stun_addr.IsUnresolved()) { - ResolveStunAddress(stun_addr); - - } else if (socket_->GetState() == rtc::AsyncPacketSocket::STATE_BOUND) { - // Check if |server_addr_| is compatible with the port's ip. - if (IsCompatibleAddress(stun_addr)) { - requests_.Send(new StunBindingRequest(this, true, stun_addr)); - } else { - // Since we can't send stun messages to the server, we should mark this - // port ready. - LOG(LS_WARNING) << "STUN server address is incompatible."; - OnStunBindingOrResolveRequestFailed(stun_addr); - } - } -} - -void UDPPort::OnStunBindingRequestSucceeded( - const rtc::SocketAddress& stun_server_addr, - const rtc::SocketAddress& stun_reflected_addr) { - if (bind_request_succeeded_servers_.find(stun_server_addr) != - bind_request_succeeded_servers_.end()) { - return; - } - bind_request_succeeded_servers_.insert(stun_server_addr); - - // If socket is shared and |stun_reflected_addr| is equal to local socket - // address, or if the same address has been added by another STUN server, - // then discarding the stun address. - // For STUN, related address is the local socket address. - if ((!SharedSocket() || stun_reflected_addr != socket_->GetLocalAddress()) && - !HasCandidateWithAddress(stun_reflected_addr)) { - - rtc::SocketAddress related_address = socket_->GetLocalAddress(); - if (!(candidate_filter() & CF_HOST)) { - // If candidate filter doesn't have CF_HOST specified, empty raddr to - // avoid local address leakage. - related_address = rtc::EmptySocketAddressWithFamily( - related_address.family()); - } - - AddAddress(stun_reflected_addr, socket_->GetLocalAddress(), - related_address, UDP_PROTOCOL_NAME, "", - STUN_PORT_TYPE, ICE_TYPE_PREFERENCE_SRFLX, 0, false); - } - MaybeSetPortCompleteOrError(); -} - -void UDPPort::OnStunBindingOrResolveRequestFailed( - const rtc::SocketAddress& stun_server_addr) { - if (bind_request_failed_servers_.find(stun_server_addr) != - bind_request_failed_servers_.end()) { - return; - } - bind_request_failed_servers_.insert(stun_server_addr); - MaybeSetPortCompleteOrError(); -} - -void UDPPort::MaybeSetPortCompleteOrError() { - if (ready_) - return; - - // Do not set port ready if we are still waiting for bind responses. - const size_t servers_done_bind_request = bind_request_failed_servers_.size() + - bind_request_succeeded_servers_.size(); - if (server_addresses_.size() != servers_done_bind_request) { - return; - } - - // Setting ready status. - ready_ = true; - - // The port is "completed" if there is no stun server provided, or the bind - // request succeeded for any stun server, or the socket is shared. - if (server_addresses_.empty() || - bind_request_succeeded_servers_.size() > 0 || - SharedSocket()) { - SignalPortComplete(this); - } else { - SignalPortError(this); - } -} - -// TODO: merge this with SendTo above. -void UDPPort::OnSendPacket(const void* data, size_t size, StunRequest* req) { - StunBindingRequest* sreq = static_cast<StunBindingRequest*>(req); - rtc::PacketOptions options(DefaultDscpValue()); - if (socket_->SendTo(data, size, sreq->server_addr(), options) < 0) - PLOG(LERROR, socket_->GetError()) << "sendto"; -} - -bool UDPPort::HasCandidateWithAddress(const rtc::SocketAddress& addr) const { - const std::vector<Candidate>& existing_candidates = Candidates(); - std::vector<Candidate>::const_iterator it = existing_candidates.begin(); - for (; it != existing_candidates.end(); ++it) { - if (it->address() == addr) - return true; - } - return false; -} - -} // namespace cricket diff --git a/talk/p2p/base/stunport.h b/talk/p2p/base/stunport.h deleted file mode 100644 index 976754603..000000000 --- a/talk/p2p/base/stunport.h +++ /dev/null @@ -1,255 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef WEBRTC_P2P_BASE_STUNPORT_H_ -#define WEBRTC_P2P_BASE_STUNPORT_H_ - -#include <string> - -#include "webrtc/p2p/base/port.h" -#include "webrtc/p2p/base/stunrequest.h" -#include "webrtc/base/asyncpacketsocket.h" - -// TODO(mallinath) - Rename stunport.cc|h to udpport.cc|h. -namespace rtc { -class AsyncResolver; -class SignalThread; -} - -namespace cricket { - -// Communicates using the address on the outside of a NAT. -class UDPPort : public Port { - public: - static UDPPort* Create(rtc::Thread* thread, - rtc::PacketSocketFactory* factory, - rtc::Network* network, - rtc::AsyncPacketSocket* socket, - const std::string& username, - const std::string& password) { - UDPPort* port = new UDPPort(thread, factory, network, socket, - username, password); - if (!port->Init()) { - delete port; - port = NULL; - } - return port; - } - - static UDPPort* Create(rtc::Thread* thread, - rtc::PacketSocketFactory* factory, - rtc::Network* network, - const rtc::IPAddress& ip, - int min_port, int max_port, - const std::string& username, - const std::string& password) { - UDPPort* port = new UDPPort(thread, factory, network, - ip, min_port, max_port, - username, password); - if (!port->Init()) { - delete port; - port = NULL; - } - return port; - } - virtual ~UDPPort(); - - rtc::SocketAddress GetLocalAddress() const { - return socket_->GetLocalAddress(); - } - - const ServerAddresses& server_addresses() const { - return server_addresses_; - } - void - set_server_addresses(const ServerAddresses& addresses) { - server_addresses_ = addresses; - } - - virtual void PrepareAddress(); - - virtual Connection* CreateConnection(const Candidate& address, - CandidateOrigin origin); - virtual int SetOption(rtc::Socket::Option opt, int value); - virtual int GetOption(rtc::Socket::Option opt, int* value); - virtual int GetError(); - - virtual bool HandleIncomingPacket( - rtc::AsyncPacketSocket* socket, const char* data, size_t size, - const rtc::SocketAddress& remote_addr, - const rtc::PacketTime& packet_time) { - // All packets given to UDP port will be consumed. - OnReadPacket(socket, data, size, remote_addr, packet_time); - return true; - } - - void set_stun_keepalive_delay(int delay) { - stun_keepalive_delay_ = delay; - } - int stun_keepalive_delay() const { - return stun_keepalive_delay_; - } - - protected: - UDPPort(rtc::Thread* thread, rtc::PacketSocketFactory* factory, - rtc::Network* network, const rtc::IPAddress& ip, - int min_port, int max_port, - const std::string& username, const std::string& password); - - UDPPort(rtc::Thread* thread, rtc::PacketSocketFactory* factory, - rtc::Network* network, rtc::AsyncPacketSocket* socket, - const std::string& username, const std::string& password); - - bool Init(); - - virtual int SendTo(const void* data, size_t size, - const rtc::SocketAddress& addr, - const rtc::PacketOptions& options, - bool payload); - - void OnLocalAddressReady(rtc::AsyncPacketSocket* socket, - const rtc::SocketAddress& address); - void OnReadPacket(rtc::AsyncPacketSocket* socket, - const char* data, size_t size, - const rtc::SocketAddress& remote_addr, - const rtc::PacketTime& packet_time); - - void OnReadyToSend(rtc::AsyncPacketSocket* socket); - - // This method will send STUN binding request if STUN server address is set. - void MaybePrepareStunCandidate(); - - void SendStunBindingRequests(); - - private: - // A helper class which can be called repeatedly to resolve multiple - // addresses, as opposed to rtc::AsyncResolverInterface, which can only - // resolve one address per instance. - class AddressResolver : public sigslot::has_slots<> { - public: - explicit AddressResolver(rtc::PacketSocketFactory* factory); - ~AddressResolver(); - - void Resolve(const rtc::SocketAddress& address); - bool GetResolvedAddress(const rtc::SocketAddress& input, - int family, - rtc::SocketAddress* output) const; - - // The signal is sent when resolving the specified address is finished. The - // first argument is the input address, the second argument is the error - // or 0 if it succeeded. - sigslot::signal2<const rtc::SocketAddress&, int> SignalDone; - - private: - typedef std::map<rtc::SocketAddress, - rtc::AsyncResolverInterface*> ResolverMap; - - void OnResolveResult(rtc::AsyncResolverInterface* resolver); - - rtc::PacketSocketFactory* socket_factory_; - ResolverMap resolvers_; - }; - - // DNS resolution of the STUN server. - void ResolveStunAddress(const rtc::SocketAddress& stun_addr); - void OnResolveResult(const rtc::SocketAddress& input, int error); - - void SendStunBindingRequest(const rtc::SocketAddress& stun_addr); - - // Below methods handles binding request responses. - void OnStunBindingRequestSucceeded( - const rtc::SocketAddress& stun_server_addr, - const rtc::SocketAddress& stun_reflected_addr); - void OnStunBindingOrResolveRequestFailed( - const rtc::SocketAddress& stun_server_addr); - - // Sends STUN requests to the server. - void OnSendPacket(const void* data, size_t size, StunRequest* req); - - // TODO(mallinaht) - Move this up to cricket::Port when SignalAddressReady is - // changed to SignalPortReady. - void MaybeSetPortCompleteOrError(); - - bool HasCandidateWithAddress(const rtc::SocketAddress& addr) const; - - ServerAddresses server_addresses_; - ServerAddresses bind_request_succeeded_servers_; - ServerAddresses bind_request_failed_servers_; - StunRequestManager requests_; - rtc::AsyncPacketSocket* socket_; - int error_; - rtc::scoped_ptr<AddressResolver> resolver_; - bool ready_; - int stun_keepalive_delay_; - - friend class StunBindingRequest; -}; - -class StunPort : public UDPPort { - public: - static StunPort* Create( - rtc::Thread* thread, - rtc::PacketSocketFactory* factory, - rtc::Network* network, - const rtc::IPAddress& ip, - int min_port, int max_port, - const std::string& username, - const std::string& password, - const ServerAddresses& servers) { - StunPort* port = new StunPort(thread, factory, network, - ip, min_port, max_port, - username, password, servers); - if (!port->Init()) { - delete port; - port = NULL; - } - return port; - } - - virtual ~StunPort() {} - - virtual void PrepareAddress() { - SendStunBindingRequests(); - } - - protected: - StunPort(rtc::Thread* thread, rtc::PacketSocketFactory* factory, - rtc::Network* network, const rtc::IPAddress& ip, - int min_port, int max_port, - const std::string& username, const std::string& password, - const ServerAddresses& servers) - : UDPPort(thread, factory, network, ip, min_port, max_port, username, - password) { - // UDPPort will set these to local udp, updating these to STUN. - set_type(STUN_PORT_TYPE); - set_server_addresses(servers); - } -}; - -} // namespace cricket - -#endif // WEBRTC_P2P_BASE_STUNPORT_H_ diff --git a/talk/p2p/base/stunport_unittest.cc b/talk/p2p/base/stunport_unittest.cc deleted file mode 100644 index 7b289ea08..000000000 --- a/talk/p2p/base/stunport_unittest.cc +++ /dev/null @@ -1,300 +0,0 @@ -/* - * libjingle - * Copyright 2009 Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "webrtc/p2p/base/basicpacketsocketfactory.h" -#include "webrtc/p2p/base/stunport.h" -#include "webrtc/p2p/base/teststunserver.h" -#include "webrtc/base/gunit.h" -#include "webrtc/base/helpers.h" -#include "webrtc/base/physicalsocketserver.h" -#include "webrtc/base/scoped_ptr.h" -#include "webrtc/base/socketaddress.h" -#include "webrtc/base/ssladapter.h" -#include "webrtc/base/virtualsocketserver.h" - -using cricket::ServerAddresses; -using rtc::SocketAddress; - -static const SocketAddress kLocalAddr("127.0.0.1", 0); -static const SocketAddress kStunAddr1("127.0.0.1", 5000); -static const SocketAddress kStunAddr2("127.0.0.1", 4000); -static const SocketAddress kBadAddr("0.0.0.1", 5000); -static const SocketAddress kStunHostnameAddr("localhost", 5000); -static const SocketAddress kBadHostnameAddr("not-a-real-hostname", 5000); -static const int kTimeoutMs = 10000; -// stun prio = 100 << 24 | 30 (IPV4) << 8 | 256 - 0 -static const uint32 kStunCandidatePriority = 1677729535; - -// Tests connecting a StunPort to a fake STUN server (cricket::StunServer) -// TODO: Use a VirtualSocketServer here. We have to use a -// PhysicalSocketServer right now since DNS is not part of SocketServer yet. -class StunPortTest : public testing::Test, - public sigslot::has_slots<> { - public: - StunPortTest() - : pss_(new rtc::PhysicalSocketServer), - ss_(new rtc::VirtualSocketServer(pss_.get())), - ss_scope_(ss_.get()), - network_("unittest", "unittest", rtc::IPAddress(INADDR_ANY), 32), - socket_factory_(rtc::Thread::Current()), - stun_server_1_(cricket::TestStunServer::Create( - rtc::Thread::Current(), kStunAddr1)), - stun_server_2_(cricket::TestStunServer::Create( - rtc::Thread::Current(), kStunAddr2)), - done_(false), error_(false), stun_keepalive_delay_(0) { - } - - const cricket::Port* port() const { return stun_port_.get(); } - bool done() const { return done_; } - bool error() const { return error_; } - - void CreateStunPort(const rtc::SocketAddress& server_addr) { - ServerAddresses stun_servers; - stun_servers.insert(server_addr); - CreateStunPort(stun_servers); - } - - void CreateStunPort(const ServerAddresses& stun_servers) { - stun_port_.reset(cricket::StunPort::Create( - rtc::Thread::Current(), &socket_factory_, &network_, - kLocalAddr.ipaddr(), 0, 0, rtc::CreateRandomString(16), - rtc::CreateRandomString(22), stun_servers)); - stun_port_->set_stun_keepalive_delay(stun_keepalive_delay_); - stun_port_->SignalPortComplete.connect(this, - &StunPortTest::OnPortComplete); - stun_port_->SignalPortError.connect(this, - &StunPortTest::OnPortError); - } - - void CreateSharedStunPort(const rtc::SocketAddress& server_addr) { - socket_.reset(socket_factory_.CreateUdpSocket( - rtc::SocketAddress(kLocalAddr.ipaddr(), 0), 0, 0)); - ASSERT_TRUE(socket_ != NULL); - socket_->SignalReadPacket.connect(this, &StunPortTest::OnReadPacket); - stun_port_.reset(cricket::UDPPort::Create( - rtc::Thread::Current(), &socket_factory_, - &network_, socket_.get(), - rtc::CreateRandomString(16), rtc::CreateRandomString(22))); - ASSERT_TRUE(stun_port_ != NULL); - ServerAddresses stun_servers; - stun_servers.insert(server_addr); - stun_port_->set_server_addresses(stun_servers); - stun_port_->SignalPortComplete.connect(this, - &StunPortTest::OnPortComplete); - stun_port_->SignalPortError.connect(this, - &StunPortTest::OnPortError); - } - - void PrepareAddress() { - stun_port_->PrepareAddress(); - } - - void OnReadPacket(rtc::AsyncPacketSocket* socket, const char* data, - size_t size, const rtc::SocketAddress& remote_addr, - const rtc::PacketTime& packet_time) { - stun_port_->HandleIncomingPacket( - socket, data, size, remote_addr, rtc::PacketTime()); - } - - void SendData(const char* data, size_t len) { - stun_port_->HandleIncomingPacket( - socket_.get(), data, len, rtc::SocketAddress("22.22.22.22", 0), - rtc::PacketTime()); - } - - protected: - static void SetUpTestCase() { - // Ensure the RNG is inited. - rtc::InitRandom(NULL, 0); - - } - - void OnPortComplete(cricket::Port* port) { - ASSERT_FALSE(done_); - done_ = true; - error_ = false; - } - void OnPortError(cricket::Port* port) { - done_ = true; - error_ = true; - } - void SetKeepaliveDelay(int delay) { - stun_keepalive_delay_ = delay; - } - - cricket::TestStunServer* stun_server_1() { - return stun_server_1_.get(); - } - cricket::TestStunServer* stun_server_2() { - return stun_server_2_.get(); - } - - private: - rtc::scoped_ptr<rtc::PhysicalSocketServer> pss_; - rtc::scoped_ptr<rtc::VirtualSocketServer> ss_; - rtc::SocketServerScope ss_scope_; - rtc::Network network_; - rtc::BasicPacketSocketFactory socket_factory_; - rtc::scoped_ptr<cricket::UDPPort> stun_port_; - rtc::scoped_ptr<cricket::TestStunServer> stun_server_1_; - rtc::scoped_ptr<cricket::TestStunServer> stun_server_2_; - rtc::scoped_ptr<rtc::AsyncPacketSocket> socket_; - bool done_; - bool error_; - int stun_keepalive_delay_; -}; - -// Test that we can create a STUN port -TEST_F(StunPortTest, TestBasic) { - CreateStunPort(kStunAddr1); - EXPECT_EQ("stun", port()->Type()); - EXPECT_EQ(0U, port()->Candidates().size()); -} - -// Test that we can get an address from a STUN server. -TEST_F(StunPortTest, TestPrepareAddress) { - CreateStunPort(kStunAddr1); - PrepareAddress(); - EXPECT_TRUE_WAIT(done(), kTimeoutMs); - ASSERT_EQ(1U, port()->Candidates().size()); - EXPECT_TRUE(kLocalAddr.EqualIPs(port()->Candidates()[0].address())); - - // TODO: Add IPv6 tests here, once either physicalsocketserver supports - // IPv6, or this test is changed to use VirtualSocketServer. -} - -// Test that we fail properly if we can't get an address. -TEST_F(StunPortTest, TestPrepareAddressFail) { - CreateStunPort(kBadAddr); - PrepareAddress(); - EXPECT_TRUE_WAIT(done(), kTimeoutMs); - EXPECT_TRUE(error()); - EXPECT_EQ(0U, port()->Candidates().size()); -} - -// Test that we can get an address from a STUN server specified by a hostname. -TEST_F(StunPortTest, TestPrepareAddressHostname) { - CreateStunPort(kStunHostnameAddr); - PrepareAddress(); - EXPECT_TRUE_WAIT(done(), kTimeoutMs); - ASSERT_EQ(1U, port()->Candidates().size()); - EXPECT_TRUE(kLocalAddr.EqualIPs(port()->Candidates()[0].address())); - EXPECT_EQ(kStunCandidatePriority, port()->Candidates()[0].priority()); -} - -// Test that we handle hostname lookup failures properly. -TEST_F(StunPortTest, TestPrepareAddressHostnameFail) { - CreateStunPort(kBadHostnameAddr); - PrepareAddress(); - EXPECT_TRUE_WAIT(done(), kTimeoutMs); - EXPECT_TRUE(error()); - EXPECT_EQ(0U, port()->Candidates().size()); -} - -// This test verifies keepalive response messages don't result in -// additional candidate generation. -TEST_F(StunPortTest, TestKeepAliveResponse) { - SetKeepaliveDelay(500); // 500ms of keepalive delay. - CreateStunPort(kStunHostnameAddr); - PrepareAddress(); - EXPECT_TRUE_WAIT(done(), kTimeoutMs); - ASSERT_EQ(1U, port()->Candidates().size()); - EXPECT_TRUE(kLocalAddr.EqualIPs(port()->Candidates()[0].address())); - // Waiting for 1 seond, which will allow us to process - // response for keepalive binding request. 500 ms is the keepalive delay. - rtc::Thread::Current()->ProcessMessages(1000); - ASSERT_EQ(1U, port()->Candidates().size()); -} - -// Test that a local candidate can be generated using a shared socket. -TEST_F(StunPortTest, TestSharedSocketPrepareAddress) { - CreateSharedStunPort(kStunAddr1); - PrepareAddress(); - EXPECT_TRUE_WAIT(done(), kTimeoutMs); - ASSERT_EQ(1U, port()->Candidates().size()); - EXPECT_TRUE(kLocalAddr.EqualIPs(port()->Candidates()[0].address())); -} - -// Test that we still a get a local candidate with invalid stun server hostname. -// Also verifing that UDPPort can receive packets when stun address can't be -// resolved. -TEST_F(StunPortTest, TestSharedSocketPrepareAddressInvalidHostname) { - CreateSharedStunPort(kBadHostnameAddr); - PrepareAddress(); - EXPECT_TRUE_WAIT(done(), kTimeoutMs); - ASSERT_EQ(1U, port()->Candidates().size()); - EXPECT_TRUE(kLocalAddr.EqualIPs(port()->Candidates()[0].address())); - - // Send data to port after it's ready. This is to make sure, UDP port can - // handle data with unresolved stun server address. - std::string data = "some random data, sending to cricket::Port."; - SendData(data.c_str(), data.length()); - // No crash is success. -} - -// Test that the same address is added only once if two STUN servers are in use. -TEST_F(StunPortTest, TestNoDuplicatedAddressWithTwoStunServers) { - ServerAddresses stun_servers; - stun_servers.insert(kStunAddr1); - stun_servers.insert(kStunAddr2); - CreateStunPort(stun_servers); - EXPECT_EQ("stun", port()->Type()); - PrepareAddress(); - EXPECT_TRUE_WAIT(done(), kTimeoutMs); - EXPECT_EQ(1U, port()->Candidates().size()); -} - -// Test that candidates can be allocated for multiple STUN servers, one of which -// is not reachable. -TEST_F(StunPortTest, TestMultipleStunServersWithBadServer) { - ServerAddresses stun_servers; - stun_servers.insert(kStunAddr1); - stun_servers.insert(kBadAddr); - CreateStunPort(stun_servers); - EXPECT_EQ("stun", port()->Type()); - PrepareAddress(); - EXPECT_TRUE_WAIT(done(), kTimeoutMs); - EXPECT_EQ(1U, port()->Candidates().size()); -} - -// Test that two candidates are allocated if the two STUN servers return -// different mapped addresses. -TEST_F(StunPortTest, TestTwoCandidatesWithTwoStunServersAcrossNat) { - const SocketAddress kStunMappedAddr1("77.77.77.77", 0); - const SocketAddress kStunMappedAddr2("88.77.77.77", 0); - stun_server_1()->set_fake_stun_addr(kStunMappedAddr1); - stun_server_2()->set_fake_stun_addr(kStunMappedAddr2); - - ServerAddresses stun_servers; - stun_servers.insert(kStunAddr1); - stun_servers.insert(kStunAddr2); - CreateStunPort(stun_servers); - EXPECT_EQ("stun", port()->Type()); - PrepareAddress(); - EXPECT_TRUE_WAIT(done(), kTimeoutMs); - EXPECT_EQ(2U, port()->Candidates().size()); -} diff --git a/talk/p2p/base/stunrequest.cc b/talk/p2p/base/stunrequest.cc deleted file mode 100644 index 55d270e2b..000000000 --- a/talk/p2p/base/stunrequest.cc +++ /dev/null @@ -1,210 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "webrtc/p2p/base/stunrequest.h" - -#include "webrtc/base/common.h" -#include "webrtc/base/helpers.h" -#include "webrtc/base/logging.h" - -namespace cricket { - -const uint32 MSG_STUN_SEND = 1; - -const int MAX_SENDS = 9; -const int DELAY_UNIT = 100; // 100 milliseconds -const int DELAY_MAX_FACTOR = 16; - -StunRequestManager::StunRequestManager(rtc::Thread* thread) - : thread_(thread) { -} - -StunRequestManager::~StunRequestManager() { - while (requests_.begin() != requests_.end()) { - StunRequest *request = requests_.begin()->second; - requests_.erase(requests_.begin()); - delete request; - } -} - -void StunRequestManager::Send(StunRequest* request) { - SendDelayed(request, 0); -} - -void StunRequestManager::SendDelayed(StunRequest* request, int delay) { - request->set_manager(this); - ASSERT(requests_.find(request->id()) == requests_.end()); - request->Construct(); - requests_[request->id()] = request; - thread_->PostDelayed(delay, request, MSG_STUN_SEND, NULL); -} - -void StunRequestManager::Remove(StunRequest* request) { - ASSERT(request->manager() == this); - RequestMap::iterator iter = requests_.find(request->id()); - if (iter != requests_.end()) { - ASSERT(iter->second == request); - requests_.erase(iter); - thread_->Clear(request); - } -} - -void StunRequestManager::Clear() { - std::vector<StunRequest*> requests; - for (RequestMap::iterator i = requests_.begin(); i != requests_.end(); ++i) - requests.push_back(i->second); - - for (uint32 i = 0; i < requests.size(); ++i) { - // StunRequest destructor calls Remove() which deletes requests - // from |requests_|. - delete requests[i]; - } -} - -bool StunRequestManager::CheckResponse(StunMessage* msg) { - RequestMap::iterator iter = requests_.find(msg->transaction_id()); - if (iter == requests_.end()) - return false; - - StunRequest* request = iter->second; - if (msg->type() == GetStunSuccessResponseType(request->type())) { - request->OnResponse(msg); - } else if (msg->type() == GetStunErrorResponseType(request->type())) { - request->OnErrorResponse(msg); - } else { - LOG(LERROR) << "Received response with wrong type: " << msg->type() - << " (expecting " - << GetStunSuccessResponseType(request->type()) << ")"; - return false; - } - - delete request; - return true; -} - -bool StunRequestManager::CheckResponse(const char* data, size_t size) { - // Check the appropriate bytes of the stream to see if they match the - // transaction ID of a response we are expecting. - - if (size < 20) - return false; - - std::string id; - id.append(data + kStunTransactionIdOffset, kStunTransactionIdLength); - - RequestMap::iterator iter = requests_.find(id); - if (iter == requests_.end()) - return false; - - // Parse the STUN message and continue processing as usual. - - rtc::ByteBuffer buf(data, size); - rtc::scoped_ptr<StunMessage> response(iter->second->msg_->CreateNew()); - if (!response->Read(&buf)) - return false; - - return CheckResponse(response.get()); -} - -StunRequest::StunRequest() - : count_(0), timeout_(false), manager_(0), - msg_(new StunMessage()), tstamp_(0) { - msg_->SetTransactionID( - rtc::CreateRandomString(kStunTransactionIdLength)); -} - -StunRequest::StunRequest(StunMessage* request) - : count_(0), timeout_(false), manager_(0), - msg_(request), tstamp_(0) { - msg_->SetTransactionID( - rtc::CreateRandomString(kStunTransactionIdLength)); -} - -StunRequest::~StunRequest() { - ASSERT(manager_ != NULL); - if (manager_) { - manager_->Remove(this); - manager_->thread_->Clear(this); - } - delete msg_; -} - -void StunRequest::Construct() { - if (msg_->type() == 0) { - Prepare(msg_); - ASSERT(msg_->type() != 0); - } -} - -int StunRequest::type() { - ASSERT(msg_ != NULL); - return msg_->type(); -} - -const StunMessage* StunRequest::msg() const { - return msg_; -} - -uint32 StunRequest::Elapsed() const { - return rtc::TimeSince(tstamp_); -} - - -void StunRequest::set_manager(StunRequestManager* manager) { - ASSERT(!manager_); - manager_ = manager; -} - -void StunRequest::OnMessage(rtc::Message* pmsg) { - ASSERT(manager_ != NULL); - ASSERT(pmsg->message_id == MSG_STUN_SEND); - - if (timeout_) { - OnTimeout(); - delete this; - return; - } - - tstamp_ = rtc::Time(); - - rtc::ByteBuffer buf; - msg_->Write(&buf); - manager_->SignalSendPacket(buf.Data(), buf.Length(), this); - - int delay = GetNextDelay(); - manager_->thread_->PostDelayed(delay, this, MSG_STUN_SEND, NULL); -} - -int StunRequest::GetNextDelay() { - int delay = DELAY_UNIT * rtc::_min(1 << count_, DELAY_MAX_FACTOR); - count_ += 1; - if (count_ == MAX_SENDS) - timeout_ = true; - return delay; -} - -} // namespace cricket diff --git a/talk/p2p/base/stunrequest.h b/talk/p2p/base/stunrequest.h deleted file mode 100644 index be7344576..000000000 --- a/talk/p2p/base/stunrequest.h +++ /dev/null @@ -1,133 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef WEBRTC_P2P_BASE_STUNREQUEST_H_ -#define WEBRTC_P2P_BASE_STUNREQUEST_H_ - -#include <map> -#include <string> -#include "webrtc/p2p/base/stun.h" -#include "webrtc/base/sigslot.h" -#include "webrtc/base/thread.h" - -namespace cricket { - -class StunRequest; - -// Manages a set of STUN requests, sending and resending until we receive a -// response or determine that the request has timed out. -class StunRequestManager { -public: - StunRequestManager(rtc::Thread* thread); - ~StunRequestManager(); - - // Starts sending the given request (perhaps after a delay). - void Send(StunRequest* request); - void SendDelayed(StunRequest* request, int delay); - - // Removes a stun request that was added previously. This will happen - // automatically when a request succeeds, fails, or times out. - void Remove(StunRequest* request); - - // Removes all stun requests that were added previously. - void Clear(); - - // Determines whether the given message is a response to one of the - // outstanding requests, and if so, processes it appropriately. - bool CheckResponse(StunMessage* msg); - bool CheckResponse(const char* data, size_t size); - - bool empty() { return requests_.empty(); } - - // Raised when there are bytes to be sent. - sigslot::signal3<const void*, size_t, StunRequest*> SignalSendPacket; - -private: - typedef std::map<std::string, StunRequest*> RequestMap; - - rtc::Thread* thread_; - RequestMap requests_; - - friend class StunRequest; -}; - -// Represents an individual request to be sent. The STUN message can either be -// constructed beforehand or built on demand. -class StunRequest : public rtc::MessageHandler { -public: - StunRequest(); - StunRequest(StunMessage* request); - virtual ~StunRequest(); - - // Causes our wrapped StunMessage to be Prepared - void Construct(); - - // The manager handling this request (if it has been scheduled for sending). - StunRequestManager* manager() { return manager_; } - - // Returns the transaction ID of this request. - const std::string& id() { return msg_->transaction_id(); } - - // Returns the STUN type of the request message. - int type(); - - // Returns a const pointer to |msg_|. - const StunMessage* msg() const; - - // Time elapsed since last send (in ms) - uint32 Elapsed() const; - -protected: - int count_; - bool timeout_; - - // Fills in a request object to be sent. Note that request's transaction ID - // will already be set and cannot be changed. - virtual void Prepare(StunMessage* request) {} - - // Called when the message receives a response or times out. - virtual void OnResponse(StunMessage* response) {} - virtual void OnErrorResponse(StunMessage* response) {} - virtual void OnTimeout() {} - virtual int GetNextDelay(); - -private: - void set_manager(StunRequestManager* manager); - - // Handles messages for sending and timeout. - void OnMessage(rtc::Message* pmsg); - - StunRequestManager* manager_; - StunMessage* msg_; - uint32 tstamp_; - - friend class StunRequestManager; -}; - -} // namespace cricket - -#endif // WEBRTC_P2P_BASE_STUNREQUEST_H_ diff --git a/talk/p2p/base/stunrequest_unittest.cc b/talk/p2p/base/stunrequest_unittest.cc deleted file mode 100644 index 5c7b97bae..000000000 --- a/talk/p2p/base/stunrequest_unittest.cc +++ /dev/null @@ -1,220 +0,0 @@ -/* - * libjingle - * Copyright 2004 Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "webrtc/p2p/base/stunrequest.h" -#include "webrtc/base/gunit.h" -#include "webrtc/base/helpers.h" -#include "webrtc/base/logging.h" -#include "webrtc/base/ssladapter.h" -#include "webrtc/base/timeutils.h" - -using namespace cricket; - -class StunRequestTest : public testing::Test, - public sigslot::has_slots<> { - public: - StunRequestTest() - : manager_(rtc::Thread::Current()), - request_count_(0), response_(NULL), - success_(false), failure_(false), timeout_(false) { - manager_.SignalSendPacket.connect(this, &StunRequestTest::OnSendPacket); - } - - void OnSendPacket(const void* data, size_t size, StunRequest* req) { - request_count_++; - } - - void OnResponse(StunMessage* res) { - response_ = res; - success_ = true; - } - void OnErrorResponse(StunMessage* res) { - response_ = res; - failure_ = true; - } - void OnTimeout() { - timeout_ = true; - } - - protected: - static StunMessage* CreateStunMessage(StunMessageType type, - StunMessage* req) { - StunMessage* msg = new StunMessage(); - msg->SetType(type); - if (req) { - msg->SetTransactionID(req->transaction_id()); - } - return msg; - } - static int TotalDelay(int sends) { - int total = 0; - for (int i = 0; i < sends; i++) { - if (i < 4) - total += 100 << i; - else - total += 1600; - } - return total; - } - - StunRequestManager manager_; - int request_count_; - StunMessage* response_; - bool success_; - bool failure_; - bool timeout_; -}; - -// Forwards results to the test class. -class StunRequestThunker : public StunRequest { - public: - StunRequestThunker(StunMessage* msg, StunRequestTest* test) - : StunRequest(msg), test_(test) {} - explicit StunRequestThunker(StunRequestTest* test) : test_(test) {} - private: - virtual void OnResponse(StunMessage* res) { - test_->OnResponse(res); - } - virtual void OnErrorResponse(StunMessage* res) { - test_->OnErrorResponse(res); - } - virtual void OnTimeout() { - test_->OnTimeout(); - } - - virtual void Prepare(StunMessage* request) { - request->SetType(STUN_BINDING_REQUEST); - } - - StunRequestTest* test_; -}; - -// Test handling of a normal binding response. -TEST_F(StunRequestTest, TestSuccess) { - StunMessage* req = CreateStunMessage(STUN_BINDING_REQUEST, NULL); - - manager_.Send(new StunRequestThunker(req, this)); - StunMessage* res = CreateStunMessage(STUN_BINDING_RESPONSE, req); - EXPECT_TRUE(manager_.CheckResponse(res)); - - EXPECT_TRUE(response_ == res); - EXPECT_TRUE(success_); - EXPECT_FALSE(failure_); - EXPECT_FALSE(timeout_); - delete res; -} - -// Test handling of an error binding response. -TEST_F(StunRequestTest, TestError) { - StunMessage* req = CreateStunMessage(STUN_BINDING_REQUEST, NULL); - - manager_.Send(new StunRequestThunker(req, this)); - StunMessage* res = CreateStunMessage(STUN_BINDING_ERROR_RESPONSE, req); - EXPECT_TRUE(manager_.CheckResponse(res)); - - EXPECT_TRUE(response_ == res); - EXPECT_FALSE(success_); - EXPECT_TRUE(failure_); - EXPECT_FALSE(timeout_); - delete res; -} - -// Test handling of a binding response with the wrong transaction id. -TEST_F(StunRequestTest, TestUnexpected) { - StunMessage* req = CreateStunMessage(STUN_BINDING_REQUEST, NULL); - - manager_.Send(new StunRequestThunker(req, this)); - StunMessage* res = CreateStunMessage(STUN_BINDING_RESPONSE, NULL); - EXPECT_FALSE(manager_.CheckResponse(res)); - - EXPECT_TRUE(response_ == NULL); - EXPECT_FALSE(success_); - EXPECT_FALSE(failure_); - EXPECT_FALSE(timeout_); - delete res; -} - -// Test that requests are sent at the right times, and that the 9th request -// (sent at 7900 ms) can be properly replied to. -TEST_F(StunRequestTest, TestBackoff) { - StunMessage* req = CreateStunMessage(STUN_BINDING_REQUEST, NULL); - - uint32 start = rtc::Time(); - manager_.Send(new StunRequestThunker(req, this)); - StunMessage* res = CreateStunMessage(STUN_BINDING_RESPONSE, req); - for (int i = 0; i < 9; ++i) { - while (request_count_ == i) - rtc::Thread::Current()->ProcessMessages(1); - int32 elapsed = rtc::TimeSince(start); - LOG(LS_INFO) << "STUN request #" << (i + 1) - << " sent at " << elapsed << " ms"; - EXPECT_GE(TotalDelay(i + 1), elapsed); - } - EXPECT_TRUE(manager_.CheckResponse(res)); - - EXPECT_TRUE(response_ == res); - EXPECT_TRUE(success_); - EXPECT_FALSE(failure_); - EXPECT_FALSE(timeout_); - delete res; -} - -// Test that we timeout properly if no response is received in 9500 ms. -TEST_F(StunRequestTest, TestTimeout) { - StunMessage* req = CreateStunMessage(STUN_BINDING_REQUEST, NULL); - StunMessage* res = CreateStunMessage(STUN_BINDING_RESPONSE, req); - - manager_.Send(new StunRequestThunker(req, this)); - rtc::Thread::Current()->ProcessMessages(10000); // > STUN timeout - EXPECT_FALSE(manager_.CheckResponse(res)); - - EXPECT_TRUE(response_ == NULL); - EXPECT_FALSE(success_); - EXPECT_FALSE(failure_); - EXPECT_TRUE(timeout_); - delete res; -} - -// Regression test for specific crash where we receive a response with the -// same id as a request that doesn't have an underlying StunMessage yet. -TEST_F(StunRequestTest, TestNoEmptyRequest) { - StunRequestThunker* request = new StunRequestThunker(this); - - manager_.SendDelayed(request, 100); - - StunMessage dummy_req; - dummy_req.SetTransactionID(request->id()); - StunMessage* res = CreateStunMessage(STUN_BINDING_RESPONSE, &dummy_req); - - EXPECT_TRUE(manager_.CheckResponse(res)); - - EXPECT_TRUE(response_ == res); - EXPECT_TRUE(success_); - EXPECT_FALSE(failure_); - EXPECT_FALSE(timeout_); - delete res; -} diff --git a/talk/p2p/base/stunserver.cc b/talk/p2p/base/stunserver.cc deleted file mode 100644 index a4beca433..000000000 --- a/talk/p2p/base/stunserver.cc +++ /dev/null @@ -1,116 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "webrtc/p2p/base/stunserver.h" - -#include "webrtc/base/bytebuffer.h" -#include "webrtc/base/logging.h" - -namespace cricket { - -StunServer::StunServer(rtc::AsyncUDPSocket* socket) : socket_(socket) { - socket_->SignalReadPacket.connect(this, &StunServer::OnPacket); -} - -StunServer::~StunServer() { - socket_->SignalReadPacket.disconnect(this); -} - -void StunServer::OnPacket( - rtc::AsyncPacketSocket* socket, const char* buf, size_t size, - const rtc::SocketAddress& remote_addr, - const rtc::PacketTime& packet_time) { - // Parse the STUN message; eat any messages that fail to parse. - rtc::ByteBuffer bbuf(buf, size); - StunMessage msg; - if (!msg.Read(&bbuf)) { - return; - } - - // TODO: If unknown non-optional (<= 0x7fff) attributes are found, send a - // 420 "Unknown Attribute" response. - - // Send the message to the appropriate handler function. - switch (msg.type()) { - case STUN_BINDING_REQUEST: - OnBindingRequest(&msg, remote_addr); - break; - - default: - SendErrorResponse(msg, remote_addr, 600, "Operation Not Supported"); - } -} - -void StunServer::OnBindingRequest( - StunMessage* msg, const rtc::SocketAddress& remote_addr) { - StunMessage response; - GetStunBindReqponse(msg, remote_addr, &response); - SendResponse(response, remote_addr); -} - -void StunServer::SendErrorResponse( - const StunMessage& msg, const rtc::SocketAddress& addr, - int error_code, const char* error_desc) { - StunMessage err_msg; - err_msg.SetType(GetStunErrorResponseType(msg.type())); - err_msg.SetTransactionID(msg.transaction_id()); - - StunErrorCodeAttribute* err_code = StunAttribute::CreateErrorCode(); - err_code->SetCode(error_code); - err_code->SetReason(error_desc); - err_msg.AddAttribute(err_code); - - SendResponse(err_msg, addr); -} - -void StunServer::SendResponse( - const StunMessage& msg, const rtc::SocketAddress& addr) { - rtc::ByteBuffer buf; - msg.Write(&buf); - rtc::PacketOptions options; - if (socket_->SendTo(buf.Data(), buf.Length(), addr, options) < 0) - LOG_ERR(LS_ERROR) << "sendto"; -} - -void StunServer::GetStunBindReqponse(StunMessage* request, - const rtc::SocketAddress& remote_addr, - StunMessage* response) const { - response->SetType(STUN_BINDING_RESPONSE); - response->SetTransactionID(request->transaction_id()); - - // Tell the user the address that we received their request from. - StunAddressAttribute* mapped_addr; - if (!request->IsLegacy()) { - mapped_addr = StunAttribute::CreateAddress(STUN_ATTR_MAPPED_ADDRESS); - } else { - mapped_addr = StunAttribute::CreateXorAddress(STUN_ATTR_XOR_MAPPED_ADDRESS); - } - mapped_addr->SetAddress(remote_addr); - response->AddAttribute(mapped_addr); -} - -} // namespace cricket diff --git a/talk/p2p/base/stunserver.h b/talk/p2p/base/stunserver.h deleted file mode 100644 index 5bbe258c4..000000000 --- a/talk/p2p/base/stunserver.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef WEBRTC_P2P_BASE_STUNSERVER_H_ -#define WEBRTC_P2P_BASE_STUNSERVER_H_ - -#include "webrtc/p2p/base/stun.h" -#include "webrtc/base/asyncudpsocket.h" -#include "webrtc/base/scoped_ptr.h" - -namespace cricket { - -const int STUN_SERVER_PORT = 3478; - -class StunServer : public sigslot::has_slots<> { - public: - // Creates a STUN server, which will listen on the given socket. - explicit StunServer(rtc::AsyncUDPSocket* socket); - // Removes the STUN server from the socket and deletes the socket. - ~StunServer(); - - protected: - // Slot for AsyncSocket.PacketRead: - void OnPacket( - rtc::AsyncPacketSocket* socket, const char* buf, size_t size, - const rtc::SocketAddress& remote_addr, - const rtc::PacketTime& packet_time); - - // Handlers for the different types of STUN/TURN requests: - virtual void OnBindingRequest(StunMessage* msg, - const rtc::SocketAddress& addr); - void OnAllocateRequest(StunMessage* msg, - const rtc::SocketAddress& addr); - void OnSharedSecretRequest(StunMessage* msg, - const rtc::SocketAddress& addr); - void OnSendRequest(StunMessage* msg, - const rtc::SocketAddress& addr); - - // Sends an error response to the given message back to the user. - void SendErrorResponse( - const StunMessage& msg, const rtc::SocketAddress& addr, - int error_code, const char* error_desc); - - // Sends the given message to the appropriate destination. - void SendResponse(const StunMessage& msg, - const rtc::SocketAddress& addr); - - // A helper method to compose a STUN binding response. - void GetStunBindReqponse(StunMessage* request, - const rtc::SocketAddress& remote_addr, - StunMessage* response) const; - - private: - rtc::scoped_ptr<rtc::AsyncUDPSocket> socket_; -}; - -} // namespace cricket - -#endif // WEBRTC_P2P_BASE_STUNSERVER_H_ diff --git a/talk/p2p/base/stunserver_unittest.cc b/talk/p2p/base/stunserver_unittest.cc deleted file mode 100644 index 4cf3c3303..000000000 --- a/talk/p2p/base/stunserver_unittest.cc +++ /dev/null @@ -1,126 +0,0 @@ -/* - * libjingle - * Copyright 2004 Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <string> - -#include "webrtc/p2p/base/stunserver.h" -#include "webrtc/base/gunit.h" -#include "webrtc/base/logging.h" -#include "webrtc/base/physicalsocketserver.h" -#include "webrtc/base/testclient.h" -#include "webrtc/base/thread.h" -#include "webrtc/base/virtualsocketserver.h" - -using namespace cricket; - -static const rtc::SocketAddress server_addr("99.99.99.1", 3478); -static const rtc::SocketAddress client_addr("1.2.3.4", 1234); - -class StunServerTest : public testing::Test { - public: - StunServerTest() - : pss_(new rtc::PhysicalSocketServer), - ss_(new rtc::VirtualSocketServer(pss_.get())), - worker_(ss_.get()) { - } - virtual void SetUp() { - server_.reset(new StunServer( - rtc::AsyncUDPSocket::Create(ss_.get(), server_addr))); - client_.reset(new rtc::TestClient( - rtc::AsyncUDPSocket::Create(ss_.get(), client_addr))); - - worker_.Start(); - } - void Send(const StunMessage& msg) { - rtc::ByteBuffer buf; - msg.Write(&buf); - Send(buf.Data(), static_cast<int>(buf.Length())); - } - void Send(const char* buf, int len) { - client_->SendTo(buf, len, server_addr); - } - StunMessage* Receive() { - StunMessage* msg = NULL; - rtc::TestClient::Packet* packet = client_->NextPacket(); - if (packet) { - rtc::ByteBuffer buf(packet->buf, packet->size); - msg = new StunMessage(); - msg->Read(&buf); - delete packet; - } - return msg; - } - private: - rtc::scoped_ptr<rtc::PhysicalSocketServer> pss_; - rtc::scoped_ptr<rtc::VirtualSocketServer> ss_; - rtc::Thread worker_; - rtc::scoped_ptr<StunServer> server_; - rtc::scoped_ptr<rtc::TestClient> client_; -}; - -// Disable for TSan v2, see -// https://code.google.com/p/webrtc/issues/detail?id=2517 for details. -#if !defined(THREAD_SANITIZER) - -TEST_F(StunServerTest, TestGood) { - StunMessage req; - std::string transaction_id = "0123456789ab"; - req.SetType(STUN_BINDING_REQUEST); - req.SetTransactionID(transaction_id); - Send(req); - - StunMessage* msg = Receive(); - ASSERT_TRUE(msg != NULL); - EXPECT_EQ(STUN_BINDING_RESPONSE, msg->type()); - EXPECT_EQ(req.transaction_id(), msg->transaction_id()); - - const StunAddressAttribute* mapped_addr = - msg->GetAddress(STUN_ATTR_MAPPED_ADDRESS); - EXPECT_TRUE(mapped_addr != NULL); - EXPECT_EQ(1, mapped_addr->family()); - EXPECT_EQ(client_addr.port(), mapped_addr->port()); - if (mapped_addr->ipaddr() != client_addr.ipaddr()) { - LOG(LS_WARNING) << "Warning: mapped IP (" - << mapped_addr->ipaddr() - << ") != local IP (" << client_addr.ipaddr() - << ")"; - } - - delete msg; -} - -#endif // if !defined(THREAD_SANITIZER) - -TEST_F(StunServerTest, TestBad) { - const char* bad = "this is a completely nonsensical message whose only " - "purpose is to make the parser go 'ack'. it doesn't " - "look anything like a normal stun message"; - Send(bad, static_cast<int>(strlen(bad))); - - StunMessage* msg = Receive(); - ASSERT_TRUE(msg == NULL); -} diff --git a/talk/p2p/base/tcpport.cc b/talk/p2p/base/tcpport.cc deleted file mode 100644 index aa08a9272..000000000 --- a/talk/p2p/base/tcpport.cc +++ /dev/null @@ -1,341 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "webrtc/p2p/base/tcpport.h" - -#include "webrtc/p2p/base/common.h" -#include "webrtc/base/common.h" -#include "webrtc/base/logging.h" - -namespace cricket { - -TCPPort::TCPPort(rtc::Thread* thread, - rtc::PacketSocketFactory* factory, - rtc::Network* network, const rtc::IPAddress& ip, - int min_port, int max_port, const std::string& username, - const std::string& password, bool allow_listen) - : Port(thread, LOCAL_PORT_TYPE, factory, network, ip, min_port, max_port, - username, password), - incoming_only_(false), - allow_listen_(allow_listen), - socket_(NULL), - error_(0) { - // TODO(mallinath) - Set preference value as per RFC 6544. - // http://b/issue?id=7141794 -} - -bool TCPPort::Init() { - if (allow_listen_) { - // Treat failure to create or bind a TCP socket as fatal. This - // should never happen. - socket_ = socket_factory()->CreateServerTcpSocket( - rtc::SocketAddress(ip(), 0), min_port(), max_port(), - false /* ssl */); - if (!socket_) { - LOG_J(LS_ERROR, this) << "TCP socket creation failed."; - return false; - } - socket_->SignalNewConnection.connect(this, &TCPPort::OnNewConnection); - socket_->SignalAddressReady.connect(this, &TCPPort::OnAddressReady); - } - return true; -} - -TCPPort::~TCPPort() { - delete socket_; - std::list<Incoming>::iterator it; - for (it = incoming_.begin(); it != incoming_.end(); ++it) - delete it->socket; - incoming_.clear(); -} - -Connection* TCPPort::CreateConnection(const Candidate& address, - CandidateOrigin origin) { - // We only support TCP protocols - if ((address.protocol() != TCP_PROTOCOL_NAME) && - (address.protocol() != SSLTCP_PROTOCOL_NAME)) { - return NULL; - } - - if (address.tcptype() == TCPTYPE_ACTIVE_STR || - (address.tcptype().empty() && address.address().port() == 0)) { - // It's active only candidate, we should not try to create connections - // for these candidates. - return NULL; - } - - // We can't accept TCP connections incoming on other ports - if (origin == ORIGIN_OTHER_PORT) - return NULL; - - // Check if we are allowed to make outgoing TCP connections - if (incoming_only_ && (origin == ORIGIN_MESSAGE)) - return NULL; - - // We don't know how to act as an ssl server yet - if ((address.protocol() == SSLTCP_PROTOCOL_NAME) && - (origin == ORIGIN_THIS_PORT)) { - return NULL; - } - - if (!IsCompatibleAddress(address.address())) { - return NULL; - } - - TCPConnection* conn = NULL; - if (rtc::AsyncPacketSocket* socket = - GetIncoming(address.address(), true)) { - socket->SignalReadPacket.disconnect(this); - conn = new TCPConnection(this, address, socket); - } else { - conn = new TCPConnection(this, address); - } - AddConnection(conn); - return conn; -} - -void TCPPort::PrepareAddress() { - if (socket_) { - // If socket isn't bound yet the address will be added in - // OnAddressReady(). Socket may be in the CLOSED state if Listen() - // failed, we still want to add the socket address. - LOG(LS_VERBOSE) << "Preparing TCP address, current state: " - << socket_->GetState(); - if (socket_->GetState() == rtc::AsyncPacketSocket::STATE_BOUND || - socket_->GetState() == rtc::AsyncPacketSocket::STATE_CLOSED) - AddAddress(socket_->GetLocalAddress(), socket_->GetLocalAddress(), - rtc::SocketAddress(), - TCP_PROTOCOL_NAME, TCPTYPE_PASSIVE_STR, LOCAL_PORT_TYPE, - ICE_TYPE_PREFERENCE_HOST_TCP, 0, true); - } else { - LOG_J(LS_INFO, this) << "Not listening due to firewall restrictions."; - // Note: We still add the address, since otherwise the remote side won't - // recognize our incoming TCP connections. - AddAddress(rtc::SocketAddress(ip(), 0), - rtc::SocketAddress(ip(), 0), rtc::SocketAddress(), - TCP_PROTOCOL_NAME, TCPTYPE_ACTIVE_STR, LOCAL_PORT_TYPE, - ICE_TYPE_PREFERENCE_HOST_TCP, 0, true); - } -} - -int TCPPort::SendTo(const void* data, size_t size, - const rtc::SocketAddress& addr, - const rtc::PacketOptions& options, - bool payload) { - rtc::AsyncPacketSocket * socket = NULL; - if (TCPConnection * conn = static_cast<TCPConnection*>(GetConnection(addr))) { - socket = conn->socket(); - } else { - socket = GetIncoming(addr); - } - if (!socket) { - LOG_J(LS_ERROR, this) << "Attempted to send to an unknown destination, " - << addr.ToSensitiveString(); - return -1; // TODO: Set error_ - } - - int sent = socket->Send(data, size, options); - if (sent < 0) { - error_ = socket->GetError(); - LOG_J(LS_ERROR, this) << "TCP send of " << size - << " bytes failed with error " << error_; - } - return sent; -} - -int TCPPort::GetOption(rtc::Socket::Option opt, int* value) { - if (socket_) { - return socket_->GetOption(opt, value); - } else { - return SOCKET_ERROR; - } -} - -int TCPPort::SetOption(rtc::Socket::Option opt, int value) { - if (socket_) { - return socket_->SetOption(opt, value); - } else { - return SOCKET_ERROR; - } -} - -int TCPPort::GetError() { - return error_; -} - -void TCPPort::OnNewConnection(rtc::AsyncPacketSocket* socket, - rtc::AsyncPacketSocket* new_socket) { - ASSERT(socket == socket_); - - Incoming incoming; - incoming.addr = new_socket->GetRemoteAddress(); - incoming.socket = new_socket; - incoming.socket->SignalReadPacket.connect(this, &TCPPort::OnReadPacket); - incoming.socket->SignalReadyToSend.connect(this, &TCPPort::OnReadyToSend); - - LOG_J(LS_VERBOSE, this) << "Accepted connection from " - << incoming.addr.ToSensitiveString(); - incoming_.push_back(incoming); -} - -rtc::AsyncPacketSocket* TCPPort::GetIncoming( - const rtc::SocketAddress& addr, bool remove) { - rtc::AsyncPacketSocket* socket = NULL; - for (std::list<Incoming>::iterator it = incoming_.begin(); - it != incoming_.end(); ++it) { - if (it->addr == addr) { - socket = it->socket; - if (remove) - incoming_.erase(it); - break; - } - } - return socket; -} - -void TCPPort::OnReadPacket(rtc::AsyncPacketSocket* socket, - const char* data, size_t size, - const rtc::SocketAddress& remote_addr, - const rtc::PacketTime& packet_time) { - Port::OnReadPacket(data, size, remote_addr, PROTO_TCP); -} - -void TCPPort::OnReadyToSend(rtc::AsyncPacketSocket* socket) { - Port::OnReadyToSend(); -} - -void TCPPort::OnAddressReady(rtc::AsyncPacketSocket* socket, - const rtc::SocketAddress& address) { - AddAddress(address, address, rtc::SocketAddress(), - TCP_PROTOCOL_NAME, TCPTYPE_PASSIVE_STR, LOCAL_PORT_TYPE, - ICE_TYPE_PREFERENCE_HOST_TCP, 0, true); -} - -TCPConnection::TCPConnection(TCPPort* port, const Candidate& candidate, - rtc::AsyncPacketSocket* socket) - : Connection(port, 0, candidate), socket_(socket), error_(0) { - bool outgoing = (socket_ == NULL); - if (outgoing) { - // TODO: Handle failures here (unlikely since TCP). - int opts = (candidate.protocol() == SSLTCP_PROTOCOL_NAME) ? - rtc::PacketSocketFactory::OPT_SSLTCP : 0; - socket_ = port->socket_factory()->CreateClientTcpSocket( - rtc::SocketAddress(port->ip(), 0), - candidate.address(), port->proxy(), port->user_agent(), opts); - if (socket_) { - LOG_J(LS_VERBOSE, this) << "Connecting from " - << socket_->GetLocalAddress().ToSensitiveString() - << " to " - << candidate.address().ToSensitiveString(); - set_connected(false); - socket_->SignalConnect.connect(this, &TCPConnection::OnConnect); - } else { - LOG_J(LS_WARNING, this) << "Failed to create connection to " - << candidate.address().ToSensitiveString(); - } - } else { - // Incoming connections should match the network address. - ASSERT(socket_->GetLocalAddress().ipaddr() == port->ip()); - } - - if (socket_) { - socket_->SignalReadPacket.connect(this, &TCPConnection::OnReadPacket); - socket_->SignalReadyToSend.connect(this, &TCPConnection::OnReadyToSend); - socket_->SignalClose.connect(this, &TCPConnection::OnClose); - } -} - -TCPConnection::~TCPConnection() { - delete socket_; -} - -int TCPConnection::Send(const void* data, size_t size, - const rtc::PacketOptions& options) { - if (!socket_) { - error_ = ENOTCONN; - return SOCKET_ERROR; - } - - if (write_state() != STATE_WRITABLE) { - // TODO: Should STATE_WRITE_TIMEOUT return a non-blocking error? - error_ = EWOULDBLOCK; - return SOCKET_ERROR; - } - int sent = socket_->Send(data, size, options); - if (sent < 0) { - error_ = socket_->GetError(); - } else { - send_rate_tracker_.Update(sent); - } - return sent; -} - -int TCPConnection::GetError() { - return error_; -} - -void TCPConnection::OnConnect(rtc::AsyncPacketSocket* socket) { - ASSERT(socket == socket_); - // Do not use this connection if the socket bound to a different address than - // the one we asked for. This is seen in Chrome, where TCP sockets cannot be - // given a binding address, and the platform is expected to pick the - // correct local address. - const rtc::IPAddress& socket_ip = socket->GetLocalAddress().ipaddr(); - if (socket_ip == port()->ip()) { - LOG_J(LS_VERBOSE, this) << "Connection established to " - << socket->GetRemoteAddress().ToSensitiveString(); - set_connected(true); - } else { - LOG_J(LS_WARNING, this) << "Dropping connection as TCP socket bound to IP " - << socket_ip.ToSensitiveString() - << ", different from the local candidate IP " - << port()->ip().ToSensitiveString(); - socket_->Close(); - } -} - -void TCPConnection::OnClose(rtc::AsyncPacketSocket* socket, int error) { - ASSERT(socket == socket_); - LOG_J(LS_INFO, this) << "Connection closed with error " << error; - set_connected(false); - set_write_state(STATE_WRITE_TIMEOUT); -} - -void TCPConnection::OnReadPacket( - rtc::AsyncPacketSocket* socket, const char* data, size_t size, - const rtc::SocketAddress& remote_addr, - const rtc::PacketTime& packet_time) { - ASSERT(socket == socket_); - Connection::OnReadPacket(data, size, packet_time); -} - -void TCPConnection::OnReadyToSend(rtc::AsyncPacketSocket* socket) { - ASSERT(socket == socket_); - Connection::OnReadyToSend(); -} - -} // namespace cricket diff --git a/talk/p2p/base/tcpport.h b/talk/p2p/base/tcpport.h deleted file mode 100644 index c331f6be3..000000000 --- a/talk/p2p/base/tcpport.h +++ /dev/null @@ -1,153 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef WEBRTC_P2P_BASE_TCPPORT_H_ -#define WEBRTC_P2P_BASE_TCPPORT_H_ - -#include <list> -#include <string> -#include "webrtc/p2p/base/port.h" -#include "webrtc/base/asyncpacketsocket.h" - -namespace cricket { - -class TCPConnection; - -// Communicates using a local TCP port. -// -// This class is designed to allow subclasses to take advantage of the -// connection management provided by this class. A subclass should take of all -// packet sending and preparation, but when a packet is received, it should -// call this TCPPort::OnReadPacket (3 arg) to dispatch to a connection. -class TCPPort : public Port { - public: - static TCPPort* Create(rtc::Thread* thread, - rtc::PacketSocketFactory* factory, - rtc::Network* network, - const rtc::IPAddress& ip, - int min_port, int max_port, - const std::string& username, - const std::string& password, - bool allow_listen) { - TCPPort* port = new TCPPort(thread, factory, network, - ip, min_port, max_port, - username, password, allow_listen); - if (!port->Init()) { - delete port; - port = NULL; - } - return port; - } - virtual ~TCPPort(); - - virtual Connection* CreateConnection(const Candidate& address, - CandidateOrigin origin); - - virtual void PrepareAddress(); - - virtual int GetOption(rtc::Socket::Option opt, int* value); - virtual int SetOption(rtc::Socket::Option opt, int value); - virtual int GetError(); - - protected: - TCPPort(rtc::Thread* thread, rtc::PacketSocketFactory* factory, - rtc::Network* network, const rtc::IPAddress& ip, - int min_port, int max_port, const std::string& username, - const std::string& password, bool allow_listen); - bool Init(); - - // Handles sending using the local TCP socket. - virtual int SendTo(const void* data, size_t size, - const rtc::SocketAddress& addr, - const rtc::PacketOptions& options, - bool payload); - - // Accepts incoming TCP connection. - void OnNewConnection(rtc::AsyncPacketSocket* socket, - rtc::AsyncPacketSocket* new_socket); - - private: - struct Incoming { - rtc::SocketAddress addr; - rtc::AsyncPacketSocket* socket; - }; - - rtc::AsyncPacketSocket* GetIncoming( - const rtc::SocketAddress& addr, bool remove = false); - - // Receives packet signal from the local TCP Socket. - void OnReadPacket(rtc::AsyncPacketSocket* socket, - const char* data, size_t size, - const rtc::SocketAddress& remote_addr, - const rtc::PacketTime& packet_time); - - void OnReadyToSend(rtc::AsyncPacketSocket* socket); - - void OnAddressReady(rtc::AsyncPacketSocket* socket, - const rtc::SocketAddress& address); - - // TODO: Is this still needed? - bool incoming_only_; - bool allow_listen_; - rtc::AsyncPacketSocket* socket_; - int error_; - std::list<Incoming> incoming_; - - friend class TCPConnection; -}; - -class TCPConnection : public Connection { - public: - // Connection is outgoing unless socket is specified - TCPConnection(TCPPort* port, const Candidate& candidate, - rtc::AsyncPacketSocket* socket = 0); - virtual ~TCPConnection(); - - virtual int Send(const void* data, size_t size, - const rtc::PacketOptions& options); - virtual int GetError(); - - rtc::AsyncPacketSocket* socket() { return socket_; } - - private: - void OnConnect(rtc::AsyncPacketSocket* socket); - void OnClose(rtc::AsyncPacketSocket* socket, int error); - void OnReadPacket(rtc::AsyncPacketSocket* socket, - const char* data, size_t size, - const rtc::SocketAddress& remote_addr, - const rtc::PacketTime& packet_time); - void OnReadyToSend(rtc::AsyncPacketSocket* socket); - - rtc::AsyncPacketSocket* socket_; - int error_; - - friend class TCPPort; -}; - -} // namespace cricket - -#endif // WEBRTC_P2P_BASE_TCPPORT_H_ diff --git a/talk/p2p/base/testrelayserver.h b/talk/p2p/base/testrelayserver.h deleted file mode 100644 index 003b42c0f..000000000 --- a/talk/p2p/base/testrelayserver.h +++ /dev/null @@ -1,118 +0,0 @@ -/* - * libjingle - * Copyright 2008 Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef WEBRTC_P2P_BASE_TESTRELAYSERVER_H_ -#define WEBRTC_P2P_BASE_TESTRELAYSERVER_H_ - -#include "webrtc/p2p/base/relayserver.h" -#include "webrtc/base/asynctcpsocket.h" -#include "webrtc/base/scoped_ptr.h" -#include "webrtc/base/sigslot.h" -#include "webrtc/base/socketadapters.h" -#include "webrtc/base/thread.h" - -namespace cricket { - -// A test relay server. Useful for unit tests. -class TestRelayServer : public sigslot::has_slots<> { - public: - TestRelayServer(rtc::Thread* thread, - const rtc::SocketAddress& udp_int_addr, - const rtc::SocketAddress& udp_ext_addr, - const rtc::SocketAddress& tcp_int_addr, - const rtc::SocketAddress& tcp_ext_addr, - const rtc::SocketAddress& ssl_int_addr, - const rtc::SocketAddress& ssl_ext_addr) - : server_(thread) { - server_.AddInternalSocket(rtc::AsyncUDPSocket::Create( - thread->socketserver(), udp_int_addr)); - server_.AddExternalSocket(rtc::AsyncUDPSocket::Create( - thread->socketserver(), udp_ext_addr)); - - tcp_int_socket_.reset(CreateListenSocket(thread, tcp_int_addr)); - tcp_ext_socket_.reset(CreateListenSocket(thread, tcp_ext_addr)); - ssl_int_socket_.reset(CreateListenSocket(thread, ssl_int_addr)); - ssl_ext_socket_.reset(CreateListenSocket(thread, ssl_ext_addr)); - } - int GetConnectionCount() const { - return server_.GetConnectionCount(); - } - rtc::SocketAddressPair GetConnection(int connection) const { - return server_.GetConnection(connection); - } - bool HasConnection(const rtc::SocketAddress& address) const { - return server_.HasConnection(address); - } - - private: - rtc::AsyncSocket* CreateListenSocket(rtc::Thread* thread, - const rtc::SocketAddress& addr) { - rtc::AsyncSocket* socket = - thread->socketserver()->CreateAsyncSocket(addr.family(), SOCK_STREAM); - socket->Bind(addr); - socket->Listen(5); - socket->SignalReadEvent.connect(this, &TestRelayServer::OnAccept); - return socket; - } - void OnAccept(rtc::AsyncSocket* socket) { - bool external = (socket == tcp_ext_socket_.get() || - socket == ssl_ext_socket_.get()); - bool ssl = (socket == ssl_int_socket_.get() || - socket == ssl_ext_socket_.get()); - rtc::AsyncSocket* raw_socket = socket->Accept(NULL); - if (raw_socket) { - rtc::AsyncTCPSocket* packet_socket = new rtc::AsyncTCPSocket( - (!ssl) ? raw_socket : - new rtc::AsyncSSLServerSocket(raw_socket), false); - if (!external) { - packet_socket->SignalClose.connect(this, - &TestRelayServer::OnInternalClose); - server_.AddInternalSocket(packet_socket); - } else { - packet_socket->SignalClose.connect(this, - &TestRelayServer::OnExternalClose); - server_.AddExternalSocket(packet_socket); - } - } - } - void OnInternalClose(rtc::AsyncPacketSocket* socket, int error) { - server_.RemoveInternalSocket(socket); - } - void OnExternalClose(rtc::AsyncPacketSocket* socket, int error) { - server_.RemoveExternalSocket(socket); - } - private: - cricket::RelayServer server_; - rtc::scoped_ptr<rtc::AsyncSocket> tcp_int_socket_; - rtc::scoped_ptr<rtc::AsyncSocket> tcp_ext_socket_; - rtc::scoped_ptr<rtc::AsyncSocket> ssl_int_socket_; - rtc::scoped_ptr<rtc::AsyncSocket> ssl_ext_socket_; -}; - -} // namespace cricket - -#endif // WEBRTC_P2P_BASE_TESTRELAYSERVER_H_ diff --git a/talk/p2p/base/teststunserver.h b/talk/p2p/base/teststunserver.h deleted file mode 100644 index eef15d798..000000000 --- a/talk/p2p/base/teststunserver.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - * libjingle - * Copyright 2008 Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef WEBRTC_P2P_BASE_TESTSTUNSERVER_H_ -#define WEBRTC_P2P_BASE_TESTSTUNSERVER_H_ - -#include "webrtc/p2p/base/stunserver.h" -#include "webrtc/base/socketaddress.h" -#include "webrtc/base/thread.h" - -namespace cricket { - -// A test STUN server. Useful for unit tests. -class TestStunServer : StunServer { - public: - static TestStunServer* Create(rtc::Thread* thread, - const rtc::SocketAddress& addr) { - rtc::AsyncSocket* socket = - thread->socketserver()->CreateAsyncSocket(addr.family(), SOCK_DGRAM); - rtc::AsyncUDPSocket* udp_socket = - rtc::AsyncUDPSocket::Create(socket, addr); - - return new TestStunServer(udp_socket); - } - - // Set a fake STUN address to return to the client. - void set_fake_stun_addr(const rtc::SocketAddress& addr) { - fake_stun_addr_ = addr; - } - - private: - explicit TestStunServer(rtc::AsyncUDPSocket* socket) : StunServer(socket) {} - - void OnBindingRequest(StunMessage* msg, - const rtc::SocketAddress& remote_addr) OVERRIDE { - if (fake_stun_addr_.IsNil()) { - StunServer::OnBindingRequest(msg, remote_addr); - } else { - StunMessage response; - GetStunBindReqponse(msg, fake_stun_addr_, &response); - SendResponse(response, remote_addr); - } - } - - private: - rtc::SocketAddress fake_stun_addr_; -}; - -} // namespace cricket - -#endif // WEBRTC_P2P_BASE_TESTSTUNSERVER_H_ diff --git a/talk/p2p/base/testturnserver.h b/talk/p2p/base/testturnserver.h deleted file mode 100644 index 64da87783..000000000 --- a/talk/p2p/base/testturnserver.h +++ /dev/null @@ -1,120 +0,0 @@ -/* - * libjingle - * Copyright 2012, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef WEBRTC_P2P_BASE_TESTTURNSERVER_H_ -#define WEBRTC_P2P_BASE_TESTTURNSERVER_H_ - -#include <string> -#include <vector> - -#include "webrtc/p2p/base/basicpacketsocketfactory.h" -#include "webrtc/p2p/base/stun.h" -#include "webrtc/p2p/base/turnserver.h" -#include "webrtc/base/asyncudpsocket.h" -#include "webrtc/base/thread.h" - -namespace cricket { - -static const char kTestRealm[] = "example.org"; -static const char kTestSoftware[] = "TestTurnServer"; - -class TestTurnRedirector : public TurnRedirectInterface { - public: - explicit TestTurnRedirector(const std::vector<rtc::SocketAddress>& addresses) - : alternate_server_addresses_(addresses), - iter_(alternate_server_addresses_.begin()) { - } - - virtual bool ShouldRedirect(const rtc::SocketAddress&, - rtc::SocketAddress* out) { - if (!out || iter_ == alternate_server_addresses_.end()) { - return false; - } - *out = *iter_++; - return true; - } - - private: - const std::vector<rtc::SocketAddress>& alternate_server_addresses_; - std::vector<rtc::SocketAddress>::const_iterator iter_; -}; - -class TestTurnServer : public TurnAuthInterface { - public: - TestTurnServer(rtc::Thread* thread, - const rtc::SocketAddress& udp_int_addr, - const rtc::SocketAddress& udp_ext_addr) - : server_(thread) { - AddInternalSocket(udp_int_addr, cricket::PROTO_UDP); - server_.SetExternalSocketFactory(new rtc::BasicPacketSocketFactory(), - udp_ext_addr); - server_.set_realm(kTestRealm); - server_.set_software(kTestSoftware); - server_.set_auth_hook(this); - } - - void set_enable_otu_nonce(bool enable) { - server_.set_enable_otu_nonce(enable); - } - - TurnServer* server() { return &server_; } - - void set_redirect_hook(TurnRedirectInterface* redirect_hook) { - server_.set_redirect_hook(redirect_hook); - } - - void AddInternalSocket(const rtc::SocketAddress& int_addr, - ProtocolType proto) { - rtc::Thread* thread = rtc::Thread::Current(); - if (proto == cricket::PROTO_UDP) { - server_.AddInternalSocket(rtc::AsyncUDPSocket::Create( - thread->socketserver(), int_addr), proto); - } else if (proto == cricket::PROTO_TCP) { - // For TCP we need to create a server socket which can listen for incoming - // new connections. - rtc::AsyncSocket* socket = - thread->socketserver()->CreateAsyncSocket(SOCK_STREAM); - socket->Bind(int_addr); - socket->Listen(5); - server_.AddInternalServerSocket(socket, proto); - } - } - - private: - // For this test server, succeed if the password is the same as the username. - // Obviously, do not use this in a production environment. - virtual bool GetKey(const std::string& username, const std::string& realm, - std::string* key) { - return ComputeStunCredentialHash(username, realm, username, key); - } - - TurnServer server_; -}; - -} // namespace cricket - -#endif // WEBRTC_P2P_BASE_TESTTURNSERVER_H_ diff --git a/talk/p2p/base/transport.cc b/talk/p2p/base/transport.cc deleted file mode 100644 index f33f942c9..000000000 --- a/talk/p2p/base/transport.cc +++ /dev/null @@ -1,977 +0,0 @@ -/* - * libjingle - * Copyright 2004, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "webrtc/p2p/base/transport.h" - -#include "webrtc/p2p/base/candidate.h" -#include "webrtc/p2p/base/constants.h" -#include "webrtc/p2p/base/parsing.h" -#include "webrtc/p2p/base/port.h" -#include "webrtc/p2p/base/sessionmanager.h" -#include "webrtc/p2p/base/transportchannelimpl.h" -#include "webrtc/libjingle/xmllite/xmlelement.h" -#include "webrtc/libjingle/xmpp/constants.h" -#include "webrtc/base/bind.h" -#include "webrtc/base/common.h" -#include "webrtc/base/logging.h" - -namespace cricket { - -using rtc::Bind; - -enum { - MSG_ONSIGNALINGREADY = 1, - MSG_ONREMOTECANDIDATE, - MSG_READSTATE, - MSG_WRITESTATE, - MSG_REQUESTSIGNALING, - MSG_CANDIDATEREADY, - MSG_ROUTECHANGE, - MSG_CONNECTING, - MSG_CANDIDATEALLOCATIONCOMPLETE, - MSG_ROLECONFLICT, - MSG_COMPLETED, - MSG_FAILED, -}; - -struct ChannelParams : public rtc::MessageData { - ChannelParams() : channel(NULL), candidate(NULL) {} - explicit ChannelParams(int component) - : component(component), channel(NULL), candidate(NULL) {} - explicit ChannelParams(Candidate* candidate) - : channel(NULL), candidate(candidate) { - } - - ~ChannelParams() { - delete candidate; - } - - std::string name; - int component; - TransportChannelImpl* channel; - Candidate* candidate; -}; - -static std::string IceProtoToString(TransportProtocol proto) { - std::string proto_str; - switch (proto) { - case ICEPROTO_GOOGLE: - proto_str = "gice"; - break; - case ICEPROTO_HYBRID: - proto_str = "hybrid"; - break; - case ICEPROTO_RFC5245: - proto_str = "ice"; - break; - default: - ASSERT(false); - break; - } - return proto_str; -} - -static bool VerifyIceParams(const TransportDescription& desc) { - // For legacy protocols. - if (desc.ice_ufrag.empty() && desc.ice_pwd.empty()) - return true; - - if (desc.ice_ufrag.length() < ICE_UFRAG_MIN_LENGTH || - desc.ice_ufrag.length() > ICE_UFRAG_MAX_LENGTH) { - return false; - } - if (desc.ice_pwd.length() < ICE_PWD_MIN_LENGTH || - desc.ice_pwd.length() > ICE_PWD_MAX_LENGTH) { - return false; - } - return true; -} - -bool BadTransportDescription(const std::string& desc, std::string* err_desc) { - if (err_desc) { - *err_desc = desc; - } - LOG(LS_ERROR) << desc; - return false; -} - -bool IceCredentialsChanged(const std::string& old_ufrag, - const std::string& old_pwd, - const std::string& new_ufrag, - const std::string& new_pwd) { - // TODO(jiayl): The standard (RFC 5245 Section 9.1.1.1) says that ICE should - // restart when both the ufrag and password are changed, but we do restart - // when either ufrag or passwrod is changed to keep compatible with GICE. We - // should clean this up when GICE is no longer used. - return (old_ufrag != new_ufrag) || (old_pwd != new_pwd); -} - -static bool IceCredentialsChanged(const TransportDescription& old_desc, - const TransportDescription& new_desc) { - return IceCredentialsChanged(old_desc.ice_ufrag, old_desc.ice_pwd, - new_desc.ice_ufrag, new_desc.ice_pwd); -} - -Transport::Transport(rtc::Thread* signaling_thread, - rtc::Thread* worker_thread, - const std::string& content_name, - const std::string& type, - PortAllocator* allocator) - : signaling_thread_(signaling_thread), - worker_thread_(worker_thread), - content_name_(content_name), - type_(type), - allocator_(allocator), - destroyed_(false), - readable_(TRANSPORT_STATE_NONE), - writable_(TRANSPORT_STATE_NONE), - was_writable_(false), - connect_requested_(false), - ice_role_(ICEROLE_UNKNOWN), - tiebreaker_(0), - protocol_(ICEPROTO_HYBRID), - remote_ice_mode_(ICEMODE_FULL) { -} - -Transport::~Transport() { - ASSERT(signaling_thread_->IsCurrent()); - ASSERT(destroyed_); -} - -void Transport::SetIceRole(IceRole role) { - worker_thread_->Invoke<void>(Bind(&Transport::SetIceRole_w, this, role)); -} - -void Transport::SetIdentity(rtc::SSLIdentity* identity) { - worker_thread_->Invoke<void>(Bind(&Transport::SetIdentity_w, this, identity)); -} - -bool Transport::GetIdentity(rtc::SSLIdentity** identity) { - // The identity is set on the worker thread, so for safety it must also be - // acquired on the worker thread. - return worker_thread_->Invoke<bool>( - Bind(&Transport::GetIdentity_w, this, identity)); -} - -bool Transport::GetRemoteCertificate(rtc::SSLCertificate** cert) { - // Channels can be deleted on the worker thread, so for safety the remote - // certificate is acquired on the worker thread. - return worker_thread_->Invoke<bool>( - Bind(&Transport::GetRemoteCertificate_w, this, cert)); -} - -bool Transport::GetRemoteCertificate_w(rtc::SSLCertificate** cert) { - ASSERT(worker_thread()->IsCurrent()); - if (channels_.empty()) - return false; - - ChannelMap::iterator iter = channels_.begin(); - return iter->second->GetRemoteCertificate(cert); -} - -bool Transport::SetLocalTransportDescription( - const TransportDescription& description, - ContentAction action, - std::string* error_desc) { - return worker_thread_->Invoke<bool>(Bind( - &Transport::SetLocalTransportDescription_w, this, - description, action, error_desc)); -} - -bool Transport::SetRemoteTransportDescription( - const TransportDescription& description, - ContentAction action, - std::string* error_desc) { - return worker_thread_->Invoke<bool>(Bind( - &Transport::SetRemoteTransportDescription_w, this, - description, action, error_desc)); -} - -TransportChannelImpl* Transport::CreateChannel(int component) { - return worker_thread_->Invoke<TransportChannelImpl*>(Bind( - &Transport::CreateChannel_w, this, component)); -} - -TransportChannelImpl* Transport::CreateChannel_w(int component) { - ASSERT(worker_thread()->IsCurrent()); - TransportChannelImpl *impl; - rtc::CritScope cs(&crit_); - - // Create the entry if it does not exist. - bool impl_exists = false; - if (channels_.find(component) == channels_.end()) { - impl = CreateTransportChannel(component); - channels_[component] = ChannelMapEntry(impl); - } else { - impl = channels_[component].get(); - impl_exists = true; - } - - // Increase the ref count. - channels_[component].AddRef(); - destroyed_ = false; - - if (impl_exists) { - // If this is an existing channel, we should just return it without - // connecting to all the signal again. - return impl; - } - - // Push down our transport state to the new channel. - impl->SetIceRole(ice_role_); - impl->SetIceTiebreaker(tiebreaker_); - // TODO(ronghuawu): Change CreateChannel_w to be able to return error since - // below Apply**Description_w calls can fail. - if (local_description_) - ApplyLocalTransportDescription_w(impl, NULL); - if (remote_description_) - ApplyRemoteTransportDescription_w(impl, NULL); - if (local_description_ && remote_description_) - ApplyNegotiatedTransportDescription_w(impl, NULL); - - impl->SignalReadableState.connect(this, &Transport::OnChannelReadableState); - impl->SignalWritableState.connect(this, &Transport::OnChannelWritableState); - impl->SignalRequestSignaling.connect( - this, &Transport::OnChannelRequestSignaling); - impl->SignalCandidateReady.connect(this, &Transport::OnChannelCandidateReady); - impl->SignalRouteChange.connect(this, &Transport::OnChannelRouteChange); - impl->SignalCandidatesAllocationDone.connect( - this, &Transport::OnChannelCandidatesAllocationDone); - impl->SignalRoleConflict.connect(this, &Transport::OnRoleConflict); - impl->SignalConnectionRemoved.connect( - this, &Transport::OnChannelConnectionRemoved); - - if (connect_requested_) { - impl->Connect(); - if (channels_.size() == 1) { - // If this is the first channel, then indicate that we have started - // connecting. - signaling_thread()->Post(this, MSG_CONNECTING, NULL); - } - } - return impl; -} - -TransportChannelImpl* Transport::GetChannel(int component) { - rtc::CritScope cs(&crit_); - ChannelMap::iterator iter = channels_.find(component); - return (iter != channels_.end()) ? iter->second.get() : NULL; -} - -bool Transport::HasChannels() { - rtc::CritScope cs(&crit_); - return !channels_.empty(); -} - -void Transport::DestroyChannel(int component) { - worker_thread_->Invoke<void>(Bind( - &Transport::DestroyChannel_w, this, component)); -} - -void Transport::DestroyChannel_w(int component) { - ASSERT(worker_thread()->IsCurrent()); - - TransportChannelImpl* impl = NULL; - { - rtc::CritScope cs(&crit_); - ChannelMap::iterator iter = channels_.find(component); - if (iter == channels_.end()) - return; - - iter->second.DecRef(); - if (!iter->second.ref()) { - impl = iter->second.get(); - channels_.erase(iter); - } - } - - if (connect_requested_ && channels_.empty()) { - // We're no longer attempting to connect. - signaling_thread()->Post(this, MSG_CONNECTING, NULL); - } - - if (impl) { - // Check in case the deleted channel was the only non-writable channel. - OnChannelWritableState(impl); - DestroyTransportChannel(impl); - } -} - -void Transport::ConnectChannels() { - ASSERT(signaling_thread()->IsCurrent()); - worker_thread_->Invoke<void>(Bind(&Transport::ConnectChannels_w, this)); -} - -void Transport::ConnectChannels_w() { - ASSERT(worker_thread()->IsCurrent()); - if (connect_requested_ || channels_.empty()) - return; - connect_requested_ = true; - signaling_thread()->Post( - this, MSG_CANDIDATEREADY, NULL); - - if (!local_description_) { - // TOOD(mallinath) : TransportDescription(TD) shouldn't be generated here. - // As Transport must know TD is offer or answer and cricket::Transport - // doesn't have the capability to decide it. This should be set by the - // Session. - // Session must generate local TD before remote candidates pushed when - // initiate request initiated by the remote. - LOG(LS_INFO) << "Transport::ConnectChannels_w: No local description has " - << "been set. Will generate one."; - TransportDescription desc(NS_GINGLE_P2P, std::vector<std::string>(), - rtc::CreateRandomString(ICE_UFRAG_LENGTH), - rtc::CreateRandomString(ICE_PWD_LENGTH), - ICEMODE_FULL, CONNECTIONROLE_NONE, NULL, - Candidates()); - SetLocalTransportDescription_w(desc, CA_OFFER, NULL); - } - - CallChannels_w(&TransportChannelImpl::Connect); - if (!channels_.empty()) { - signaling_thread()->Post(this, MSG_CONNECTING, NULL); - } -} - -void Transport::OnConnecting_s() { - ASSERT(signaling_thread()->IsCurrent()); - SignalConnecting(this); -} - -void Transport::DestroyAllChannels() { - ASSERT(signaling_thread()->IsCurrent()); - worker_thread_->Invoke<void>( - Bind(&Transport::DestroyAllChannels_w, this)); - worker_thread()->Clear(this); - signaling_thread()->Clear(this); - destroyed_ = true; -} - -void Transport::DestroyAllChannels_w() { - ASSERT(worker_thread()->IsCurrent()); - std::vector<TransportChannelImpl*> impls; - { - rtc::CritScope cs(&crit_); - for (ChannelMap::iterator iter = channels_.begin(); - iter != channels_.end(); - ++iter) { - iter->second.DecRef(); - if (!iter->second.ref()) - impls.push_back(iter->second.get()); - } - } - channels_.clear(); - - - for (size_t i = 0; i < impls.size(); ++i) - DestroyTransportChannel(impls[i]); -} - -void Transport::ResetChannels() { - ASSERT(signaling_thread()->IsCurrent()); - worker_thread_->Invoke<void>(Bind(&Transport::ResetChannels_w, this)); -} - -void Transport::ResetChannels_w() { - ASSERT(worker_thread()->IsCurrent()); - - // We are no longer attempting to connect - connect_requested_ = false; - - // Clear out the old messages, they aren't relevant - rtc::CritScope cs(&crit_); - ready_candidates_.clear(); - - // Reset all of the channels - CallChannels_w(&TransportChannelImpl::Reset); -} - -void Transport::OnSignalingReady() { - ASSERT(signaling_thread()->IsCurrent()); - if (destroyed_) return; - - worker_thread()->Post(this, MSG_ONSIGNALINGREADY, NULL); - - // Notify the subclass. - OnTransportSignalingReady(); -} - -void Transport::CallChannels_w(TransportChannelFunc func) { - ASSERT(worker_thread()->IsCurrent()); - rtc::CritScope cs(&crit_); - for (ChannelMap::iterator iter = channels_.begin(); - iter != channels_.end(); - ++iter) { - ((iter->second.get())->*func)(); - } -} - -bool Transport::VerifyCandidate(const Candidate& cand, std::string* error) { - // No address zero. - if (cand.address().IsNil() || cand.address().IsAny()) { - *error = "candidate has address of zero"; - return false; - } - - // Disallow all ports below 1024, except for 80 and 443 on public addresses. - int port = cand.address().port(); - if (cand.protocol() == TCP_PROTOCOL_NAME && - (cand.tcptype() == TCPTYPE_ACTIVE_STR || port == 0)) { - // Expected for active-only candidates per - // http://tools.ietf.org/html/rfc6544#section-4.5 so no error. - // Libjingle clients emit port 0, in "active" mode. - return true; - } - if (port < 1024) { - if ((port != 80) && (port != 443)) { - *error = "candidate has port below 1024, but not 80 or 443"; - return false; - } - - if (cand.address().IsPrivateIP()) { - *error = "candidate has port of 80 or 443 with private IP address"; - return false; - } - } - - return true; -} - - -bool Transport::GetStats(TransportStats* stats) { - ASSERT(signaling_thread()->IsCurrent()); - return worker_thread_->Invoke<bool>(Bind( - &Transport::GetStats_w, this, stats)); -} - -bool Transport::GetStats_w(TransportStats* stats) { - ASSERT(worker_thread()->IsCurrent()); - stats->content_name = content_name(); - stats->channel_stats.clear(); - for (ChannelMap::iterator iter = channels_.begin(); - iter != channels_.end(); - ++iter) { - TransportChannelStats substats; - substats.component = iter->second->component(); - if (!iter->second->GetStats(&substats.connection_infos)) { - return false; - } - stats->channel_stats.push_back(substats); - } - return true; -} - -bool Transport::GetSslRole(rtc::SSLRole* ssl_role) const { - return worker_thread_->Invoke<bool>(Bind( - &Transport::GetSslRole_w, this, ssl_role)); -} - -void Transport::OnRemoteCandidates(const std::vector<Candidate>& candidates) { - for (std::vector<Candidate>::const_iterator iter = candidates.begin(); - iter != candidates.end(); - ++iter) { - OnRemoteCandidate(*iter); - } -} - -void Transport::OnRemoteCandidate(const Candidate& candidate) { - ASSERT(signaling_thread()->IsCurrent()); - if (destroyed_) return; - - if (!HasChannel(candidate.component())) { - LOG(LS_WARNING) << "Ignoring candidate for unknown component " - << candidate.component(); - return; - } - - ChannelParams* params = new ChannelParams(new Candidate(candidate)); - worker_thread()->Post(this, MSG_ONREMOTECANDIDATE, params); -} - -void Transport::OnRemoteCandidate_w(const Candidate& candidate) { - ASSERT(worker_thread()->IsCurrent()); - ChannelMap::iterator iter = channels_.find(candidate.component()); - // It's ok for a channel to go away while this message is in transit. - if (iter != channels_.end()) { - iter->second->OnCandidate(candidate); - } -} - -void Transport::OnChannelReadableState(TransportChannel* channel) { - ASSERT(worker_thread()->IsCurrent()); - signaling_thread()->Post(this, MSG_READSTATE, NULL); -} - -void Transport::OnChannelReadableState_s() { - ASSERT(signaling_thread()->IsCurrent()); - TransportState readable = GetTransportState_s(true); - if (readable_ != readable) { - readable_ = readable; - SignalReadableState(this); - } -} - -void Transport::OnChannelWritableState(TransportChannel* channel) { - ASSERT(worker_thread()->IsCurrent()); - signaling_thread()->Post(this, MSG_WRITESTATE, NULL); - - MaybeCompleted_w(); -} - -void Transport::OnChannelWritableState_s() { - ASSERT(signaling_thread()->IsCurrent()); - TransportState writable = GetTransportState_s(false); - if (writable_ != writable) { - was_writable_ = (writable_ == TRANSPORT_STATE_ALL); - writable_ = writable; - SignalWritableState(this); - } -} - -TransportState Transport::GetTransportState_s(bool read) { - ASSERT(signaling_thread()->IsCurrent()); - rtc::CritScope cs(&crit_); - bool any = false; - bool all = !channels_.empty(); - for (ChannelMap::iterator iter = channels_.begin(); - iter != channels_.end(); - ++iter) { - bool b = (read ? iter->second->readable() : - iter->second->writable()); - any = any || b; - all = all && b; - } - if (all) { - return TRANSPORT_STATE_ALL; - } else if (any) { - return TRANSPORT_STATE_SOME; - } else { - return TRANSPORT_STATE_NONE; - } -} - -void Transport::OnChannelRequestSignaling(TransportChannelImpl* channel) { - ASSERT(worker_thread()->IsCurrent()); - ChannelParams* params = new ChannelParams(channel->component()); - signaling_thread()->Post(this, MSG_REQUESTSIGNALING, params); -} - -void Transport::OnChannelRequestSignaling_s(int component) { - ASSERT(signaling_thread()->IsCurrent()); - LOG(LS_INFO) << "Transport: " << content_name_ << ", allocating candidates"; - // Resetting ICE state for the channel. - { - rtc::CritScope cs(&crit_); - ChannelMap::iterator iter = channels_.find(component); - if (iter != channels_.end()) - iter->second.set_candidates_allocated(false); - } - SignalRequestSignaling(this); -} - -void Transport::OnChannelCandidateReady(TransportChannelImpl* channel, - const Candidate& candidate) { - ASSERT(worker_thread()->IsCurrent()); - rtc::CritScope cs(&crit_); - ready_candidates_.push_back(candidate); - - // We hold any messages until the client lets us connect. - if (connect_requested_) { - signaling_thread()->Post( - this, MSG_CANDIDATEREADY, NULL); - } -} - -void Transport::OnChannelCandidateReady_s() { - ASSERT(signaling_thread()->IsCurrent()); - ASSERT(connect_requested_); - - std::vector<Candidate> candidates; - { - rtc::CritScope cs(&crit_); - candidates.swap(ready_candidates_); - } - - // we do the deleting of Candidate* here to keep the new above and - // delete below close to each other - if (!candidates.empty()) { - SignalCandidatesReady(this, candidates); - } -} - -void Transport::OnChannelRouteChange(TransportChannel* channel, - const Candidate& remote_candidate) { - ASSERT(worker_thread()->IsCurrent()); - ChannelParams* params = new ChannelParams(new Candidate(remote_candidate)); - params->channel = static_cast<cricket::TransportChannelImpl*>(channel); - signaling_thread()->Post(this, MSG_ROUTECHANGE, params); -} - -void Transport::OnChannelRouteChange_s(const TransportChannel* channel, - const Candidate& remote_candidate) { - ASSERT(signaling_thread()->IsCurrent()); - SignalRouteChange(this, remote_candidate.component(), remote_candidate); -} - -void Transport::OnChannelCandidatesAllocationDone( - TransportChannelImpl* channel) { - ASSERT(worker_thread()->IsCurrent()); - rtc::CritScope cs(&crit_); - ChannelMap::iterator iter = channels_.find(channel->component()); - ASSERT(iter != channels_.end()); - LOG(LS_INFO) << "Transport: " << content_name_ << ", component " - << channel->component() << " allocation complete"; - iter->second.set_candidates_allocated(true); - - // If all channels belonging to this Transport got signal, then - // forward this signal to upper layer. - // Can this signal arrive before all transport channels are created? - for (iter = channels_.begin(); iter != channels_.end(); ++iter) { - if (!iter->second.candidates_allocated()) - return; - } - signaling_thread_->Post(this, MSG_CANDIDATEALLOCATIONCOMPLETE); - - MaybeCompleted_w(); -} - -void Transport::OnChannelCandidatesAllocationDone_s() { - ASSERT(signaling_thread()->IsCurrent()); - LOG(LS_INFO) << "Transport: " << content_name_ << " allocation complete"; - SignalCandidatesAllocationDone(this); -} - -void Transport::OnRoleConflict(TransportChannelImpl* channel) { - signaling_thread_->Post(this, MSG_ROLECONFLICT); -} - -void Transport::OnChannelConnectionRemoved(TransportChannelImpl* channel) { - ASSERT(worker_thread()->IsCurrent()); - MaybeCompleted_w(); - - // Check if the state is now Failed. - // Failed is only available in the Controlling ICE role. - if (channel->GetIceRole() != ICEROLE_CONTROLLING) { - return; - } - - ChannelMap::iterator iter = channels_.find(channel->component()); - ASSERT(iter != channels_.end()); - // Failed can only occur after candidate allocation has stopped. - if (!iter->second.candidates_allocated()) { - return; - } - - size_t connections = channel->GetConnectionCount(); - if (connections == 0) { - // A Transport has failed if any of its channels have no remaining - // connections. - signaling_thread_->Post(this, MSG_FAILED); - } -} - -void Transport::MaybeCompleted_w() { - ASSERT(worker_thread()->IsCurrent()); - - // A Transport's ICE process is completed if all of its channels are writable, - // have finished allocating candidates, and have pruned all but one of their - // connections. - ChannelMap::const_iterator iter; - for (iter = channels_.begin(); iter != channels_.end(); ++iter) { - const TransportChannelImpl* channel = iter->second.get(); - if (!(channel->writable() && - channel->GetConnectionCount() == 1 && - channel->GetIceRole() == ICEROLE_CONTROLLING && - iter->second.candidates_allocated())) { - return; - } - } - - signaling_thread_->Post(this, MSG_COMPLETED); -} - -void Transport::SetIceRole_w(IceRole role) { - rtc::CritScope cs(&crit_); - ice_role_ = role; - for (ChannelMap::iterator iter = channels_.begin(); - iter != channels_.end(); ++iter) { - iter->second->SetIceRole(ice_role_); - } -} - -void Transport::SetRemoteIceMode_w(IceMode mode) { - rtc::CritScope cs(&crit_); - remote_ice_mode_ = mode; - // Shouldn't channels be created after this method executed? - for (ChannelMap::iterator iter = channels_.begin(); - iter != channels_.end(); ++iter) { - iter->second->SetRemoteIceMode(remote_ice_mode_); - } -} - -bool Transport::SetLocalTransportDescription_w( - const TransportDescription& desc, - ContentAction action, - std::string* error_desc) { - bool ret = true; - rtc::CritScope cs(&crit_); - - if (!VerifyIceParams(desc)) { - return BadTransportDescription("Invalid ice-ufrag or ice-pwd length", - error_desc); - } - - if (local_description_ && IceCredentialsChanged(*local_description_, desc)) { - IceRole new_ice_role = (action == CA_OFFER) ? ICEROLE_CONTROLLING - : ICEROLE_CONTROLLED; - - // It must be called before ApplyLocalTransportDescription_w, which may - // trigger an ICE restart and depends on the new ICE role. - SetIceRole_w(new_ice_role); - } - - local_description_.reset(new TransportDescription(desc)); - - for (ChannelMap::iterator iter = channels_.begin(); - iter != channels_.end(); ++iter) { - ret &= ApplyLocalTransportDescription_w(iter->second.get(), error_desc); - } - if (!ret) - return false; - - // If PRANSWER/ANSWER is set, we should decide transport protocol type. - if (action == CA_PRANSWER || action == CA_ANSWER) { - ret &= NegotiateTransportDescription_w(action, error_desc); - } - return ret; -} - -bool Transport::SetRemoteTransportDescription_w( - const TransportDescription& desc, - ContentAction action, - std::string* error_desc) { - bool ret = true; - rtc::CritScope cs(&crit_); - - if (!VerifyIceParams(desc)) { - return BadTransportDescription("Invalid ice-ufrag or ice-pwd length", - error_desc); - } - - remote_description_.reset(new TransportDescription(desc)); - for (ChannelMap::iterator iter = channels_.begin(); - iter != channels_.end(); ++iter) { - ret &= ApplyRemoteTransportDescription_w(iter->second.get(), error_desc); - } - - // If PRANSWER/ANSWER is set, we should decide transport protocol type. - if (action == CA_PRANSWER || action == CA_ANSWER) { - ret = NegotiateTransportDescription_w(CA_OFFER, error_desc); - } - return ret; -} - -bool Transport::ApplyLocalTransportDescription_w(TransportChannelImpl* ch, - std::string* error_desc) { - // If existing protocol_type is HYBRID, we may have not chosen the final - // protocol type, so update the channel protocol type from the - // local description. Otherwise, skip updating the protocol type. - // We check for HYBRID to avoid accidental changes; in the case of a - // session renegotiation, the new offer will have the google-ice ICE option, - // so we need to make sure we don't switch back from ICE mode to HYBRID - // when this happens. - // There are some other ways we could have solved this, but this is the - // simplest. The ultimate solution will be to get rid of GICE altogether. - IceProtocolType protocol_type; - if (ch->GetIceProtocolType(&protocol_type) && - protocol_type == ICEPROTO_HYBRID) { - ch->SetIceProtocolType( - TransportProtocolFromDescription(local_description())); - } - ch->SetIceCredentials(local_description_->ice_ufrag, - local_description_->ice_pwd); - return true; -} - -bool Transport::ApplyRemoteTransportDescription_w(TransportChannelImpl* ch, - std::string* error_desc) { - ch->SetRemoteIceCredentials(remote_description_->ice_ufrag, - remote_description_->ice_pwd); - return true; -} - -bool Transport::ApplyNegotiatedTransportDescription_w( - TransportChannelImpl* channel, std::string* error_desc) { - channel->SetIceProtocolType(protocol_); - channel->SetRemoteIceMode(remote_ice_mode_); - return true; -} - -bool Transport::NegotiateTransportDescription_w(ContentAction local_role, - std::string* error_desc) { - // TODO(ekr@rtfm.com): This is ICE-specific stuff. Refactor into - // P2PTransport. - const TransportDescription* offer; - const TransportDescription* answer; - - if (local_role == CA_OFFER) { - offer = local_description_.get(); - answer = remote_description_.get(); - } else { - offer = remote_description_.get(); - answer = local_description_.get(); - } - - TransportProtocol offer_proto = TransportProtocolFromDescription(offer); - TransportProtocol answer_proto = TransportProtocolFromDescription(answer); - - // If offered protocol is gice/ice, then we expect to receive matching - // protocol in answer, anything else is treated as an error. - // HYBRID is not an option when offered specific protocol. - // If offered protocol is HYBRID and answered protocol is HYBRID then - // gice is preferred protocol. - // TODO(mallinath) - Answer from local or remote should't have both ice - // and gice support. It should always pick which protocol it wants to use. - // Once WebRTC stops supporting gice (for backward compatibility), HYBRID in - // answer must be treated as error. - if ((offer_proto == ICEPROTO_GOOGLE || offer_proto == ICEPROTO_RFC5245) && - (offer_proto != answer_proto)) { - std::ostringstream desc; - desc << "Offer and answer protocol mismatch: " - << IceProtoToString(offer_proto) - << " vs " - << IceProtoToString(answer_proto); - return BadTransportDescription(desc.str(), error_desc); - } - protocol_ = answer_proto == ICEPROTO_HYBRID ? ICEPROTO_GOOGLE : answer_proto; - - // If transport is in ICEROLE_CONTROLLED and remote end point supports only - // ice_lite, this local end point should take CONTROLLING role. - if (ice_role_ == ICEROLE_CONTROLLED && - remote_description_->ice_mode == ICEMODE_LITE) { - SetIceRole_w(ICEROLE_CONTROLLING); - } - - // Update remote ice_mode to all existing channels. - remote_ice_mode_ = remote_description_->ice_mode; - - // Now that we have negotiated everything, push it downward. - // Note that we cache the result so that if we have race conditions - // between future SetRemote/SetLocal invocations and new channel - // creation, we have the negotiation state saved until a new - // negotiation happens. - for (ChannelMap::iterator iter = channels_.begin(); - iter != channels_.end(); - ++iter) { - if (!ApplyNegotiatedTransportDescription_w(iter->second.get(), error_desc)) - return false; - } - return true; -} - -void Transport::OnMessage(rtc::Message* msg) { - switch (msg->message_id) { - case MSG_ONSIGNALINGREADY: - CallChannels_w(&TransportChannelImpl::OnSignalingReady); - break; - case MSG_ONREMOTECANDIDATE: { - ChannelParams* params = static_cast<ChannelParams*>(msg->pdata); - OnRemoteCandidate_w(*params->candidate); - delete params; - } - break; - case MSG_CONNECTING: - OnConnecting_s(); - break; - case MSG_READSTATE: - OnChannelReadableState_s(); - break; - case MSG_WRITESTATE: - OnChannelWritableState_s(); - break; - case MSG_REQUESTSIGNALING: { - ChannelParams* params = static_cast<ChannelParams*>(msg->pdata); - OnChannelRequestSignaling_s(params->component); - delete params; - } - break; - case MSG_CANDIDATEREADY: - OnChannelCandidateReady_s(); - break; - case MSG_ROUTECHANGE: { - ChannelParams* params = static_cast<ChannelParams*>(msg->pdata); - OnChannelRouteChange_s(params->channel, *params->candidate); - delete params; - } - break; - case MSG_CANDIDATEALLOCATIONCOMPLETE: - OnChannelCandidatesAllocationDone_s(); - break; - case MSG_ROLECONFLICT: - SignalRoleConflict(); - break; - case MSG_COMPLETED: - SignalCompleted(this); - break; - case MSG_FAILED: - SignalFailed(this); - break; - } -} - -bool TransportParser::ParseAddress(const buzz::XmlElement* elem, - const buzz::QName& address_name, - const buzz::QName& port_name, - rtc::SocketAddress* address, - ParseError* error) { - if (!elem->HasAttr(address_name)) - return BadParse("address does not have " + address_name.LocalPart(), error); - if (!elem->HasAttr(port_name)) - return BadParse("address does not have " + port_name.LocalPart(), error); - - address->SetIP(elem->Attr(address_name)); - std::istringstream ist(elem->Attr(port_name)); - int port = 0; - ist >> port; - address->SetPort(port); - - return true; -} - -// We're GICE if the namespace is NS_GOOGLE_P2P, or if NS_JINGLE_ICE_UDP is -// used and the GICE ice-option is set. -TransportProtocol TransportProtocolFromDescription( - const TransportDescription* desc) { - ASSERT(desc != NULL); - if (desc->transport_type == NS_JINGLE_ICE_UDP) { - return (desc->HasOption(ICE_OPTION_GICE)) ? - ICEPROTO_HYBRID : ICEPROTO_RFC5245; - } - return ICEPROTO_GOOGLE; -} - -} // namespace cricket diff --git a/talk/p2p/base/transport.h b/talk/p2p/base/transport.h deleted file mode 100644 index fbc7f6f44..000000000 --- a/talk/p2p/base/transport.h +++ /dev/null @@ -1,530 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -// A Transport manages a set of named channels of the same type. -// -// Subclasses choose the appropriate class to instantiate for each channel; -// however, this base class keeps track of the channels by name, watches their -// state changes (in order to update the manager's state), and forwards -// requests to begin connecting or to reset to each of the channels. -// -// On Threading: Transport performs work on both the signaling and worker -// threads. For subclasses, the rule is that all signaling related calls will -// be made on the signaling thread and all channel related calls (including -// signaling for a channel) will be made on the worker thread. When -// information needs to be sent between the two threads, this class should do -// the work (e.g., OnRemoteCandidate). -// -// Note: Subclasses must call DestroyChannels() in their own constructors. -// It is not possible to do so here because the subclass constructor will -// already have run. - -#ifndef WEBRTC_P2P_BASE_TRANSPORT_H_ -#define WEBRTC_P2P_BASE_TRANSPORT_H_ - -#include <map> -#include <string> -#include <vector> -#include "webrtc/p2p/base/candidate.h" -#include "webrtc/p2p/base/constants.h" -#include "webrtc/p2p/base/sessiondescription.h" -#include "webrtc/p2p/base/transportinfo.h" -#include "webrtc/base/criticalsection.h" -#include "webrtc/base/messagequeue.h" -#include "webrtc/base/sigslot.h" -#include "webrtc/base/sslstreamadapter.h" - -namespace rtc { -class Thread; -} - -namespace buzz { -class QName; -class XmlElement; -} - -namespace cricket { - -struct ParseError; -struct WriteError; -class CandidateTranslator; -class PortAllocator; -class SessionManager; -class Session; -class TransportChannel; -class TransportChannelImpl; - -typedef std::vector<buzz::XmlElement*> XmlElements; -typedef std::vector<Candidate> Candidates; - -// Used to parse and serialize (write) transport candidates. For -// convenience of old code, Transports will implement TransportParser. -// Parse/Write seems better than Serialize/Deserialize or -// Create/Translate. -class TransportParser { - public: - // The incoming Translator value may be null, in which case - // ParseCandidates should return false if there are candidates to - // parse (indicating a failure to parse). If the Translator is null - // and there are no candidates to parse, then return true, - // indicating a successful parse of 0 candidates. - - // Parse or write a transport description, including ICE credentials and - // any DTLS fingerprint. Since only Jingle has transport descriptions, these - // functions are only used when serializing to Jingle. - virtual bool ParseTransportDescription(const buzz::XmlElement* elem, - const CandidateTranslator* translator, - TransportDescription* tdesc, - ParseError* error) = 0; - virtual bool WriteTransportDescription(const TransportDescription& tdesc, - const CandidateTranslator* translator, - buzz::XmlElement** tdesc_elem, - WriteError* error) = 0; - - - // Parse a single candidate. This must be used when parsing Gingle - // candidates, since there is no enclosing transport description. - virtual bool ParseGingleCandidate(const buzz::XmlElement* elem, - const CandidateTranslator* translator, - Candidate* candidates, - ParseError* error) = 0; - virtual bool WriteGingleCandidate(const Candidate& candidate, - const CandidateTranslator* translator, - buzz::XmlElement** candidate_elem, - WriteError* error) = 0; - - // Helper function to parse an element describing an address. This - // retrieves the IP and port from the given element and verifies - // that they look like plausible values. - bool ParseAddress(const buzz::XmlElement* elem, - const buzz::QName& address_name, - const buzz::QName& port_name, - rtc::SocketAddress* address, - ParseError* error); - - virtual ~TransportParser() {} -}; - -// For "writable" and "readable", we need to differentiate between -// none, all, and some. -enum TransportState { - TRANSPORT_STATE_NONE = 0, - TRANSPORT_STATE_SOME, - TRANSPORT_STATE_ALL -}; - -// Stats that we can return about the connections for a transport channel. -// TODO(hta): Rename to ConnectionStats -struct ConnectionInfo { - ConnectionInfo() - : best_connection(false), - writable(false), - readable(false), - timeout(false), - new_connection(false), - rtt(0), - sent_total_bytes(0), - sent_bytes_second(0), - recv_total_bytes(0), - recv_bytes_second(0), - key(NULL) {} - - bool best_connection; // Is this the best connection we have? - bool writable; // Has this connection received a STUN response? - bool readable; // Has this connection received a STUN request? - bool timeout; // Has this connection timed out? - bool new_connection; // Is this a newly created connection? - size_t rtt; // The STUN RTT for this connection. - size_t sent_total_bytes; // Total bytes sent on this connection. - size_t sent_bytes_second; // Bps over the last measurement interval. - size_t recv_total_bytes; // Total bytes received on this connection. - size_t recv_bytes_second; // Bps over the last measurement interval. - Candidate local_candidate; // The local candidate for this connection. - Candidate remote_candidate; // The remote candidate for this connection. - void* key; // A static value that identifies this conn. -}; - -// Information about all the connections of a channel. -typedef std::vector<ConnectionInfo> ConnectionInfos; - -// Information about a specific channel -struct TransportChannelStats { - int component; - ConnectionInfos connection_infos; -}; - -// Information about all the channels of a transport. -// TODO(hta): Consider if a simple vector is as good as a map. -typedef std::vector<TransportChannelStats> TransportChannelStatsList; - -// Information about the stats of a transport. -struct TransportStats { - std::string content_name; - TransportChannelStatsList channel_stats; -}; - -bool BadTransportDescription(const std::string& desc, std::string* err_desc); - -bool IceCredentialsChanged(const std::string& old_ufrag, - const std::string& old_pwd, - const std::string& new_ufrag, - const std::string& new_pwd); - -class Transport : public rtc::MessageHandler, - public sigslot::has_slots<> { - public: - Transport(rtc::Thread* signaling_thread, - rtc::Thread* worker_thread, - const std::string& content_name, - const std::string& type, - PortAllocator* allocator); - virtual ~Transport(); - - // Returns the signaling thread. The app talks to Transport on this thread. - rtc::Thread* signaling_thread() { return signaling_thread_; } - // Returns the worker thread. The actual networking is done on this thread. - rtc::Thread* worker_thread() { return worker_thread_; } - - // Returns the content_name of this transport. - const std::string& content_name() const { return content_name_; } - // Returns the type of this transport. - const std::string& type() const { return type_; } - - // Returns the port allocator object for this transport. - PortAllocator* port_allocator() { return allocator_; } - - // Returns the readable and states of this manager. These bits are the ORs - // of the corresponding bits on the managed channels. Each time one of these - // states changes, a signal is raised. - // TODO: Replace uses of readable() and writable() with - // any_channels_readable() and any_channels_writable(). - bool readable() const { return any_channels_readable(); } - bool writable() const { return any_channels_writable(); } - bool was_writable() const { return was_writable_; } - bool any_channels_readable() const { - return (readable_ == TRANSPORT_STATE_SOME || - readable_ == TRANSPORT_STATE_ALL); - } - bool any_channels_writable() const { - return (writable_ == TRANSPORT_STATE_SOME || - writable_ == TRANSPORT_STATE_ALL); - } - bool all_channels_readable() const { - return (readable_ == TRANSPORT_STATE_ALL); - } - bool all_channels_writable() const { - return (writable_ == TRANSPORT_STATE_ALL); - } - sigslot::signal1<Transport*> SignalReadableState; - sigslot::signal1<Transport*> SignalWritableState; - sigslot::signal1<Transport*> SignalCompleted; - sigslot::signal1<Transport*> SignalFailed; - - // Returns whether the client has requested the channels to connect. - bool connect_requested() const { return connect_requested_; } - - void SetIceRole(IceRole role); - IceRole ice_role() const { return ice_role_; } - - void SetIceTiebreaker(uint64 IceTiebreaker) { tiebreaker_ = IceTiebreaker; } - uint64 IceTiebreaker() { return tiebreaker_; } - - // Must be called before applying local session description. - void SetIdentity(rtc::SSLIdentity* identity); - - // Get a copy of the local identity provided by SetIdentity. - bool GetIdentity(rtc::SSLIdentity** identity); - - // Get a copy of the remote certificate in use by the specified channel. - bool GetRemoteCertificate(rtc::SSLCertificate** cert); - - TransportProtocol protocol() const { return protocol_; } - - // Create, destroy, and lookup the channels of this type by their components. - TransportChannelImpl* CreateChannel(int component); - // Note: GetChannel may lead to race conditions, since the mutex is not held - // after the pointer is returned. - TransportChannelImpl* GetChannel(int component); - // Note: HasChannel does not lead to race conditions, unlike GetChannel. - bool HasChannel(int component) { - return (NULL != GetChannel(component)); - } - bool HasChannels(); - void DestroyChannel(int component); - - // Set the local TransportDescription to be used by TransportChannels. - // This should be called before ConnectChannels(). - bool SetLocalTransportDescription(const TransportDescription& description, - ContentAction action, - std::string* error_desc); - - // Set the remote TransportDescription to be used by TransportChannels. - bool SetRemoteTransportDescription(const TransportDescription& description, - ContentAction action, - std::string* error_desc); - - // Tells all current and future channels to start connecting. When the first - // channel begins connecting, the following signal is raised. - void ConnectChannels(); - sigslot::signal1<Transport*> SignalConnecting; - - // Resets all of the channels back to their initial state. They are no - // longer connecting. - void ResetChannels(); - - // Destroys every channel created so far. - void DestroyAllChannels(); - - bool GetStats(TransportStats* stats); - - // Before any stanza is sent, the manager will request signaling. Once - // signaling is available, the client should call OnSignalingReady. Once - // this occurs, the transport (or its channels) can send any waiting stanzas. - // OnSignalingReady invokes OnTransportSignalingReady and then forwards this - // signal to each channel. - sigslot::signal1<Transport*> SignalRequestSignaling; - void OnSignalingReady(); - - // Handles sending of ready candidates and receiving of remote candidates. - sigslot::signal2<Transport*, - const std::vector<Candidate>&> SignalCandidatesReady; - - sigslot::signal1<Transport*> SignalCandidatesAllocationDone; - void OnRemoteCandidates(const std::vector<Candidate>& candidates); - - // If candidate is not acceptable, returns false and sets error. - // Call this before calling OnRemoteCandidates. - virtual bool VerifyCandidate(const Candidate& candidate, - std::string* error); - - // Signals when the best connection for a channel changes. - sigslot::signal3<Transport*, - int, // component - const Candidate&> SignalRouteChange; - - // A transport message has generated an transport-specific error. The - // stanza that caused the error is available in session_msg. If false is - // returned, the error is considered unrecoverable, and the session is - // terminated. - // TODO(juberti): Remove these obsolete functions once Session no longer - // references them. - virtual void OnTransportError(const buzz::XmlElement* error) {} - sigslot::signal6<Transport*, const buzz::XmlElement*, const buzz::QName&, - const std::string&, const std::string&, - const buzz::XmlElement*> - SignalTransportError; - - // Forwards the signal from TransportChannel to BaseSession. - sigslot::signal0<> SignalRoleConflict; - - virtual bool GetSslRole(rtc::SSLRole* ssl_role) const; - - protected: - // These are called by Create/DestroyChannel above in order to create or - // destroy the appropriate type of channel. - virtual TransportChannelImpl* CreateTransportChannel(int component) = 0; - virtual void DestroyTransportChannel(TransportChannelImpl* channel) = 0; - - // Informs the subclass that we received the signaling ready message. - virtual void OnTransportSignalingReady() {} - - // The current local transport description, for use by derived classes - // when performing transport description negotiation. - const TransportDescription* local_description() const { - return local_description_.get(); - } - - // The current remote transport description, for use by derived classes - // when performing transport description negotiation. - const TransportDescription* remote_description() const { - return remote_description_.get(); - } - - virtual void SetIdentity_w(rtc::SSLIdentity* identity) {} - - virtual bool GetIdentity_w(rtc::SSLIdentity** identity) { - return false; - } - - // Pushes down the transport parameters from the local description, such - // as the ICE ufrag and pwd. - // Derived classes can override, but must call the base as well. - virtual bool ApplyLocalTransportDescription_w(TransportChannelImpl* channel, - std::string* error_desc); - - // Pushes down remote ice credentials from the remote description to the - // transport channel. - virtual bool ApplyRemoteTransportDescription_w(TransportChannelImpl* ch, - std::string* error_desc); - - // Negotiates the transport parameters based on the current local and remote - // transport description, such at the version of ICE to use, and whether DTLS - // should be activated. - // Derived classes can negotiate their specific parameters here, but must call - // the base as well. - virtual bool NegotiateTransportDescription_w(ContentAction local_role, - std::string* error_desc); - - // Pushes down the transport parameters obtained via negotiation. - // Derived classes can set their specific parameters here, but must call the - // base as well. - virtual bool ApplyNegotiatedTransportDescription_w( - TransportChannelImpl* channel, std::string* error_desc); - - virtual bool GetSslRole_w(rtc::SSLRole* ssl_role) const { - return false; - } - - private: - struct ChannelMapEntry { - ChannelMapEntry() : impl_(NULL), candidates_allocated_(false), ref_(0) {} - explicit ChannelMapEntry(TransportChannelImpl *impl) - : impl_(impl), - candidates_allocated_(false), - ref_(0) { - } - - void AddRef() { ++ref_; } - void DecRef() { - ASSERT(ref_ > 0); - --ref_; - } - int ref() const { return ref_; } - - TransportChannelImpl* get() const { return impl_; } - TransportChannelImpl* operator->() const { return impl_; } - void set_candidates_allocated(bool status) { - candidates_allocated_ = status; - } - bool candidates_allocated() const { return candidates_allocated_; } - - private: - TransportChannelImpl *impl_; - bool candidates_allocated_; - int ref_; - }; - - // Candidate component => ChannelMapEntry - typedef std::map<int, ChannelMapEntry> ChannelMap; - - // Called when the state of a channel changes. - void OnChannelReadableState(TransportChannel* channel); - void OnChannelWritableState(TransportChannel* channel); - - // Called when a channel requests signaling. - void OnChannelRequestSignaling(TransportChannelImpl* channel); - - // Called when a candidate is ready from remote peer. - void OnRemoteCandidate(const Candidate& candidate); - // Called when a candidate is ready from channel. - void OnChannelCandidateReady(TransportChannelImpl* channel, - const Candidate& candidate); - void OnChannelRouteChange(TransportChannel* channel, - const Candidate& remote_candidate); - void OnChannelCandidatesAllocationDone(TransportChannelImpl* channel); - // Called when there is ICE role change. - void OnRoleConflict(TransportChannelImpl* channel); - // Called when the channel removes a connection. - void OnChannelConnectionRemoved(TransportChannelImpl* channel); - - // Dispatches messages to the appropriate handler (below). - void OnMessage(rtc::Message* msg); - - // These are versions of the above methods that are called only on a - // particular thread (s = signaling, w = worker). The above methods post or - // send a message to invoke this version. - TransportChannelImpl* CreateChannel_w(int component); - void DestroyChannel_w(int component); - void ConnectChannels_w(); - void ResetChannels_w(); - void DestroyAllChannels_w(); - void OnRemoteCandidate_w(const Candidate& candidate); - void OnChannelReadableState_s(); - void OnChannelWritableState_s(); - void OnChannelRequestSignaling_s(int component); - void OnConnecting_s(); - void OnChannelRouteChange_s(const TransportChannel* channel, - const Candidate& remote_candidate); - void OnChannelCandidatesAllocationDone_s(); - - // Helper function that invokes the given function on every channel. - typedef void (TransportChannelImpl::* TransportChannelFunc)(); - void CallChannels_w(TransportChannelFunc func); - - // Computes the OR of the channel's read or write state (argument picks). - TransportState GetTransportState_s(bool read); - - void OnChannelCandidateReady_s(); - - void SetIceRole_w(IceRole role); - void SetRemoteIceMode_w(IceMode mode); - bool SetLocalTransportDescription_w(const TransportDescription& desc, - ContentAction action, - std::string* error_desc); - bool SetRemoteTransportDescription_w(const TransportDescription& desc, - ContentAction action, - std::string* error_desc); - bool GetStats_w(TransportStats* infos); - bool GetRemoteCertificate_w(rtc::SSLCertificate** cert); - - // Sends SignalCompleted if we are now in that state. - void MaybeCompleted_w(); - - rtc::Thread* signaling_thread_; - rtc::Thread* worker_thread_; - std::string content_name_; - std::string type_; - PortAllocator* allocator_; - bool destroyed_; - TransportState readable_; - TransportState writable_; - bool was_writable_; - bool connect_requested_; - IceRole ice_role_; - uint64 tiebreaker_; - TransportProtocol protocol_; - IceMode remote_ice_mode_; - rtc::scoped_ptr<TransportDescription> local_description_; - rtc::scoped_ptr<TransportDescription> remote_description_; - - ChannelMap channels_; - // Buffers the ready_candidates so that SignalCanidatesReady can - // provide them in multiples. - std::vector<Candidate> ready_candidates_; - // Protects changes to channels and messages - rtc::CriticalSection crit_; - - DISALLOW_EVIL_CONSTRUCTORS(Transport); -}; - -// Extract a TransportProtocol from a TransportDescription. -TransportProtocol TransportProtocolFromDescription( - const TransportDescription* desc); - -} // namespace cricket - -#endif // WEBRTC_P2P_BASE_TRANSPORT_H_ diff --git a/talk/p2p/base/transport_unittest.cc b/talk/p2p/base/transport_unittest.cc deleted file mode 100644 index 9ef7d60ef..000000000 --- a/talk/p2p/base/transport_unittest.cc +++ /dev/null @@ -1,455 +0,0 @@ -/* - * libjingle - * Copyright 2011 Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "webrtc/p2p/base/constants.h" -#include "webrtc/p2p/base/fakesession.h" -#include "webrtc/p2p/base/p2ptransport.h" -#include "webrtc/p2p/base/parsing.h" -#include "webrtc/p2p/base/rawtransport.h" -#include "webrtc/p2p/base/sessionmessages.h" -#include "webrtc/libjingle/xmllite/xmlelement.h" -#include "webrtc/libjingle/xmpp/constants.h" -#include "webrtc/base/fakesslidentity.h" -#include "webrtc/base/gunit.h" -#include "webrtc/base/thread.h" - -using cricket::Candidate; -using cricket::Candidates; -using cricket::Transport; -using cricket::FakeTransport; -using cricket::TransportChannel; -using cricket::FakeTransportChannel; -using cricket::IceRole; -using cricket::TransportDescription; -using cricket::WriteError; -using cricket::ParseError; -using rtc::SocketAddress; - -static const char kIceUfrag1[] = "TESTICEUFRAG0001"; -static const char kIcePwd1[] = "TESTICEPWD00000000000001"; - -static const char kIceUfrag2[] = "TESTICEUFRAG0002"; -static const char kIcePwd2[] = "TESTICEPWD00000000000002"; - -class TransportTest : public testing::Test, - public sigslot::has_slots<> { - public: - TransportTest() - : thread_(rtc::Thread::Current()), - transport_(new FakeTransport( - thread_, thread_, "test content name", NULL)), - channel_(NULL), - connecting_signalled_(false), - completed_(false), - failed_(false) { - transport_->SignalConnecting.connect(this, &TransportTest::OnConnecting); - transport_->SignalCompleted.connect(this, &TransportTest::OnCompleted); - transport_->SignalFailed.connect(this, &TransportTest::OnFailed); - } - ~TransportTest() { - transport_->DestroyAllChannels(); - } - bool SetupChannel() { - channel_ = CreateChannel(1); - return (channel_ != NULL); - } - FakeTransportChannel* CreateChannel(int component) { - return static_cast<FakeTransportChannel*>( - transport_->CreateChannel(component)); - } - void DestroyChannel() { - transport_->DestroyChannel(1); - channel_ = NULL; - } - - protected: - void OnConnecting(Transport* transport) { - connecting_signalled_ = true; - } - void OnCompleted(Transport* transport) { - completed_ = true; - } - void OnFailed(Transport* transport) { - failed_ = true; - } - - rtc::Thread* thread_; - rtc::scoped_ptr<FakeTransport> transport_; - FakeTransportChannel* channel_; - bool connecting_signalled_; - bool completed_; - bool failed_; -}; - -class FakeCandidateTranslator : public cricket::CandidateTranslator { - public: - void AddMapping(int component, const std::string& channel_name) { - name_to_component[channel_name] = component; - component_to_name[component] = channel_name; - } - - bool GetChannelNameFromComponent( - int component, std::string* channel_name) const { - if (component_to_name.find(component) == component_to_name.end()) { - return false; - } - *channel_name = component_to_name.find(component)->second; - return true; - } - bool GetComponentFromChannelName( - const std::string& channel_name, int* component) const { - if (name_to_component.find(channel_name) == name_to_component.end()) { - return false; - } - *component = name_to_component.find(channel_name)->second; - return true; - } - - std::map<std::string, int> name_to_component; - std::map<int, std::string> component_to_name; -}; - -// Test that calling ConnectChannels triggers an OnConnecting signal. -TEST_F(TransportTest, TestConnectChannelsDoesSignal) { - EXPECT_TRUE(SetupChannel()); - transport_->ConnectChannels(); - EXPECT_FALSE(connecting_signalled_); - - EXPECT_TRUE_WAIT(connecting_signalled_, 100); -} - -// Test that DestroyAllChannels kills any pending OnConnecting signals. -TEST_F(TransportTest, TestDestroyAllClearsPosts) { - EXPECT_TRUE(transport_->CreateChannel(1) != NULL); - - transport_->ConnectChannels(); - transport_->DestroyAllChannels(); - - thread_->ProcessMessages(0); - EXPECT_FALSE(connecting_signalled_); -} - -// This test verifies channels are created with proper ICE -// role, tiebreaker and remote ice mode and credentials after offer and -// answer negotiations. -TEST_F(TransportTest, TestChannelIceParameters) { - transport_->SetIceRole(cricket::ICEROLE_CONTROLLING); - transport_->SetIceTiebreaker(99U); - cricket::TransportDescription local_desc( - cricket::NS_JINGLE_ICE_UDP, kIceUfrag1, kIcePwd1); - ASSERT_TRUE(transport_->SetLocalTransportDescription(local_desc, - cricket::CA_OFFER, - NULL)); - EXPECT_EQ(cricket::ICEROLE_CONTROLLING, transport_->ice_role()); - EXPECT_TRUE(SetupChannel()); - EXPECT_EQ(cricket::ICEROLE_CONTROLLING, channel_->GetIceRole()); - EXPECT_EQ(cricket::ICEMODE_FULL, channel_->remote_ice_mode()); - EXPECT_EQ(kIceUfrag1, channel_->ice_ufrag()); - EXPECT_EQ(kIcePwd1, channel_->ice_pwd()); - - cricket::TransportDescription remote_desc( - cricket::NS_JINGLE_ICE_UDP, kIceUfrag1, kIcePwd1); - ASSERT_TRUE(transport_->SetRemoteTransportDescription(remote_desc, - cricket::CA_ANSWER, - NULL)); - EXPECT_EQ(cricket::ICEROLE_CONTROLLING, channel_->GetIceRole()); - EXPECT_EQ(99U, channel_->IceTiebreaker()); - EXPECT_EQ(cricket::ICEMODE_FULL, channel_->remote_ice_mode()); - // Changing the transport role from CONTROLLING to CONTROLLED. - transport_->SetIceRole(cricket::ICEROLE_CONTROLLED); - EXPECT_EQ(cricket::ICEROLE_CONTROLLED, channel_->GetIceRole()); - EXPECT_EQ(cricket::ICEMODE_FULL, channel_->remote_ice_mode()); - EXPECT_EQ(kIceUfrag1, channel_->remote_ice_ufrag()); - EXPECT_EQ(kIcePwd1, channel_->remote_ice_pwd()); -} - -// Verifies that IceCredentialsChanged returns true when either ufrag or pwd -// changed, and false in other cases. -TEST_F(TransportTest, TestIceCredentialsChanged) { - EXPECT_TRUE(cricket::IceCredentialsChanged("u1", "p1", "u2", "p2")); - EXPECT_TRUE(cricket::IceCredentialsChanged("u1", "p1", "u2", "p1")); - EXPECT_TRUE(cricket::IceCredentialsChanged("u1", "p1", "u1", "p2")); - EXPECT_FALSE(cricket::IceCredentialsChanged("u1", "p1", "u1", "p1")); -} - -// This test verifies that the callee's ICE role changes from controlled to -// controlling when the callee triggers an ICE restart. -TEST_F(TransportTest, TestIceControlledToControllingOnIceRestart) { - EXPECT_TRUE(SetupChannel()); - transport_->SetIceRole(cricket::ICEROLE_CONTROLLED); - - cricket::TransportDescription desc( - cricket::NS_JINGLE_ICE_UDP, kIceUfrag1, kIcePwd1); - ASSERT_TRUE(transport_->SetRemoteTransportDescription(desc, - cricket::CA_OFFER, - NULL)); - ASSERT_TRUE(transport_->SetLocalTransportDescription(desc, - cricket::CA_ANSWER, - NULL)); - EXPECT_EQ(cricket::ICEROLE_CONTROLLED, transport_->ice_role()); - - cricket::TransportDescription new_local_desc( - cricket::NS_JINGLE_ICE_UDP, kIceUfrag2, kIcePwd2); - ASSERT_TRUE(transport_->SetLocalTransportDescription(new_local_desc, - cricket::CA_OFFER, - NULL)); - EXPECT_EQ(cricket::ICEROLE_CONTROLLING, transport_->ice_role()); - EXPECT_EQ(cricket::ICEROLE_CONTROLLING, channel_->GetIceRole()); -} - -// This test verifies that the caller's ICE role changes from controlling to -// controlled when the callee triggers an ICE restart. -TEST_F(TransportTest, TestIceControllingToControlledOnIceRestart) { - EXPECT_TRUE(SetupChannel()); - transport_->SetIceRole(cricket::ICEROLE_CONTROLLING); - - cricket::TransportDescription desc( - cricket::NS_JINGLE_ICE_UDP, kIceUfrag1, kIcePwd1); - ASSERT_TRUE(transport_->SetLocalTransportDescription(desc, - cricket::CA_OFFER, - NULL)); - ASSERT_TRUE(transport_->SetRemoteTransportDescription(desc, - cricket::CA_ANSWER, - NULL)); - EXPECT_EQ(cricket::ICEROLE_CONTROLLING, transport_->ice_role()); - - cricket::TransportDescription new_local_desc( - cricket::NS_JINGLE_ICE_UDP, kIceUfrag2, kIcePwd2); - ASSERT_TRUE(transport_->SetLocalTransportDescription(new_local_desc, - cricket::CA_ANSWER, - NULL)); - EXPECT_EQ(cricket::ICEROLE_CONTROLLED, transport_->ice_role()); - EXPECT_EQ(cricket::ICEROLE_CONTROLLED, channel_->GetIceRole()); -} - -// This test verifies that the caller's ICE role is still controlling after the -// callee triggers ICE restart if the callee's ICE mode is LITE. -TEST_F(TransportTest, TestIceControllingOnIceRestartIfRemoteIsIceLite) { - EXPECT_TRUE(SetupChannel()); - transport_->SetIceRole(cricket::ICEROLE_CONTROLLING); - - cricket::TransportDescription desc( - cricket::NS_JINGLE_ICE_UDP, kIceUfrag1, kIcePwd1); - ASSERT_TRUE(transport_->SetLocalTransportDescription(desc, - cricket::CA_OFFER, - NULL)); - - cricket::TransportDescription remote_desc( - cricket::NS_JINGLE_ICE_UDP, std::vector<std::string>(), - kIceUfrag1, kIcePwd1, cricket::ICEMODE_LITE, - cricket::CONNECTIONROLE_NONE, NULL, cricket::Candidates()); - ASSERT_TRUE(transport_->SetRemoteTransportDescription(remote_desc, - cricket::CA_ANSWER, - NULL)); - - EXPECT_EQ(cricket::ICEROLE_CONTROLLING, transport_->ice_role()); - - cricket::TransportDescription new_local_desc( - cricket::NS_JINGLE_ICE_UDP, kIceUfrag2, kIcePwd2); - ASSERT_TRUE(transport_->SetLocalTransportDescription(new_local_desc, - cricket::CA_ANSWER, - NULL)); - EXPECT_EQ(cricket::ICEROLE_CONTROLLING, transport_->ice_role()); - EXPECT_EQ(cricket::ICEROLE_CONTROLLING, channel_->GetIceRole()); -} - -// This test verifies that the Completed and Failed states can be reached. -TEST_F(TransportTest, TestChannelCompletedAndFailed) { - transport_->SetIceRole(cricket::ICEROLE_CONTROLLING); - cricket::TransportDescription local_desc( - cricket::NS_JINGLE_ICE_UDP, kIceUfrag1, kIcePwd1); - ASSERT_TRUE(transport_->SetLocalTransportDescription(local_desc, - cricket::CA_OFFER, - NULL)); - EXPECT_TRUE(SetupChannel()); - - cricket::TransportDescription remote_desc( - cricket::NS_JINGLE_ICE_UDP, kIceUfrag1, kIcePwd1); - ASSERT_TRUE(transport_->SetRemoteTransportDescription(remote_desc, - cricket::CA_ANSWER, - NULL)); - - channel_->SetConnectionCount(2); - channel_->SignalCandidatesAllocationDone(channel_); - channel_->SetWritable(true); - EXPECT_TRUE_WAIT(transport_->all_channels_writable(), 100); - // ICE is not yet completed because there is still more than one connection. - EXPECT_FALSE(completed_); - EXPECT_FALSE(failed_); - - // When the connection count drops to 1, SignalCompleted should be emitted, - // and completed() should be true. - channel_->SetConnectionCount(1); - EXPECT_TRUE_WAIT(completed_, 100); - completed_ = false; - - // When the connection count drops to 0, SignalFailed should be emitted, and - // completed() should be false. - channel_->SetConnectionCount(0); - EXPECT_TRUE_WAIT(failed_, 100); - EXPECT_FALSE(completed_); -} - -// Tests channel role is reversed after receiving ice-lite from remote. -TEST_F(TransportTest, TestSetRemoteIceLiteInOffer) { - transport_->SetIceRole(cricket::ICEROLE_CONTROLLED); - cricket::TransportDescription remote_desc( - cricket::NS_JINGLE_ICE_UDP, std::vector<std::string>(), - kIceUfrag1, kIcePwd1, cricket::ICEMODE_LITE, - cricket::CONNECTIONROLE_ACTPASS, NULL, cricket::Candidates()); - ASSERT_TRUE(transport_->SetRemoteTransportDescription(remote_desc, - cricket::CA_OFFER, - NULL)); - cricket::TransportDescription local_desc( - cricket::NS_JINGLE_ICE_UDP, kIceUfrag1, kIcePwd1); - ASSERT_TRUE(transport_->SetLocalTransportDescription(local_desc, - cricket::CA_ANSWER, - NULL)); - EXPECT_EQ(cricket::ICEROLE_CONTROLLING, transport_->ice_role()); - EXPECT_TRUE(SetupChannel()); - EXPECT_EQ(cricket::ICEROLE_CONTROLLING, channel_->GetIceRole()); - EXPECT_EQ(cricket::ICEMODE_LITE, channel_->remote_ice_mode()); -} - -// Tests ice-lite in remote answer. -TEST_F(TransportTest, TestSetRemoteIceLiteInAnswer) { - transport_->SetIceRole(cricket::ICEROLE_CONTROLLING); - cricket::TransportDescription local_desc( - cricket::NS_JINGLE_ICE_UDP, kIceUfrag1, kIcePwd1); - ASSERT_TRUE(transport_->SetLocalTransportDescription(local_desc, - cricket::CA_OFFER, - NULL)); - EXPECT_EQ(cricket::ICEROLE_CONTROLLING, transport_->ice_role()); - EXPECT_TRUE(SetupChannel()); - EXPECT_EQ(cricket::ICEROLE_CONTROLLING, channel_->GetIceRole()); - // Channels will be created in ICEFULL_MODE. - EXPECT_EQ(cricket::ICEMODE_FULL, channel_->remote_ice_mode()); - cricket::TransportDescription remote_desc( - cricket::NS_JINGLE_ICE_UDP, std::vector<std::string>(), - kIceUfrag1, kIcePwd1, cricket::ICEMODE_LITE, - cricket::CONNECTIONROLE_NONE, NULL, cricket::Candidates()); - ASSERT_TRUE(transport_->SetRemoteTransportDescription(remote_desc, - cricket::CA_ANSWER, - NULL)); - EXPECT_EQ(cricket::ICEROLE_CONTROLLING, channel_->GetIceRole()); - // After receiving remote description with ICEMODE_LITE, channel should - // have mode set to ICEMODE_LITE. - EXPECT_EQ(cricket::ICEMODE_LITE, channel_->remote_ice_mode()); -} - -// Tests that we can properly serialize/deserialize candidates. -TEST_F(TransportTest, TestP2PTransportWriteAndParseCandidate) { - Candidate test_candidate( - "", 1, "udp", - rtc::SocketAddress("2001:db8:fefe::1", 9999), - 738197504, "abcdef", "ghijkl", "foo", "testnet", 50, ""); - Candidate test_candidate2( - "", 2, "tcp", - rtc::SocketAddress("192.168.7.1", 9999), - 1107296256, "mnopqr", "stuvwx", "bar", "testnet2", 100, ""); - rtc::SocketAddress host_address("www.google.com", 24601); - host_address.SetResolvedIP(rtc::IPAddress(0x0A000001)); - Candidate test_candidate3( - "", 3, "spdy", host_address, 1476395008, "yzabcd", - "efghij", "baz", "testnet3", 150, ""); - WriteError write_error; - ParseError parse_error; - rtc::scoped_ptr<buzz::XmlElement> elem; - cricket::Candidate parsed_candidate; - cricket::P2PTransportParser parser; - - FakeCandidateTranslator translator; - translator.AddMapping(1, "test"); - translator.AddMapping(2, "test2"); - translator.AddMapping(3, "test3"); - - EXPECT_TRUE(parser.WriteGingleCandidate(test_candidate, &translator, - elem.accept(), &write_error)); - EXPECT_EQ("", write_error.text); - EXPECT_EQ("test", elem->Attr(buzz::QN_NAME)); - EXPECT_EQ("udp", elem->Attr(cricket::QN_PROTOCOL)); - EXPECT_EQ("2001:db8:fefe::1", elem->Attr(cricket::QN_ADDRESS)); - EXPECT_EQ("9999", elem->Attr(cricket::QN_PORT)); - EXPECT_EQ("0.34", elem->Attr(cricket::QN_PREFERENCE)); - EXPECT_EQ("abcdef", elem->Attr(cricket::QN_USERNAME)); - EXPECT_EQ("ghijkl", elem->Attr(cricket::QN_PASSWORD)); - EXPECT_EQ("foo", elem->Attr(cricket::QN_TYPE)); - EXPECT_EQ("testnet", elem->Attr(cricket::QN_NETWORK)); - EXPECT_EQ("50", elem->Attr(cricket::QN_GENERATION)); - - EXPECT_TRUE(parser.ParseGingleCandidate(elem.get(), &translator, - &parsed_candidate, &parse_error)); - EXPECT_TRUE(test_candidate.IsEquivalent(parsed_candidate)); - - EXPECT_TRUE(parser.WriteGingleCandidate(test_candidate2, &translator, - elem.accept(), &write_error)); - EXPECT_EQ("test2", elem->Attr(buzz::QN_NAME)); - EXPECT_EQ("tcp", elem->Attr(cricket::QN_PROTOCOL)); - EXPECT_EQ("192.168.7.1", elem->Attr(cricket::QN_ADDRESS)); - EXPECT_EQ("9999", elem->Attr(cricket::QN_PORT)); - EXPECT_EQ("0.51", elem->Attr(cricket::QN_PREFERENCE)); - EXPECT_EQ("mnopqr", elem->Attr(cricket::QN_USERNAME)); - EXPECT_EQ("stuvwx", elem->Attr(cricket::QN_PASSWORD)); - EXPECT_EQ("bar", elem->Attr(cricket::QN_TYPE)); - EXPECT_EQ("testnet2", elem->Attr(cricket::QN_NETWORK)); - EXPECT_EQ("100", elem->Attr(cricket::QN_GENERATION)); - - EXPECT_TRUE(parser.ParseGingleCandidate(elem.get(), &translator, - &parsed_candidate, &parse_error)); - EXPECT_TRUE(test_candidate2.IsEquivalent(parsed_candidate)); - - // Check that an ip is preferred over hostname. - EXPECT_TRUE(parser.WriteGingleCandidate(test_candidate3, &translator, - elem.accept(), &write_error)); - EXPECT_EQ("test3", elem->Attr(cricket::QN_NAME)); - EXPECT_EQ("spdy", elem->Attr(cricket::QN_PROTOCOL)); - EXPECT_EQ("10.0.0.1", elem->Attr(cricket::QN_ADDRESS)); - EXPECT_EQ("24601", elem->Attr(cricket::QN_PORT)); - EXPECT_EQ("0.69", elem->Attr(cricket::QN_PREFERENCE)); - EXPECT_EQ("yzabcd", elem->Attr(cricket::QN_USERNAME)); - EXPECT_EQ("efghij", elem->Attr(cricket::QN_PASSWORD)); - EXPECT_EQ("baz", elem->Attr(cricket::QN_TYPE)); - EXPECT_EQ("testnet3", elem->Attr(cricket::QN_NETWORK)); - EXPECT_EQ("150", elem->Attr(cricket::QN_GENERATION)); - - EXPECT_TRUE(parser.ParseGingleCandidate(elem.get(), &translator, - &parsed_candidate, &parse_error)); - EXPECT_TRUE(test_candidate3.IsEquivalent(parsed_candidate)); -} - -TEST_F(TransportTest, TestGetStats) { - EXPECT_TRUE(SetupChannel()); - cricket::TransportStats stats; - EXPECT_TRUE(transport_->GetStats(&stats)); - // Note that this tests the behavior of a FakeTransportChannel. - ASSERT_EQ(1U, stats.channel_stats.size()); - EXPECT_EQ(1, stats.channel_stats[0].component); - transport_->ConnectChannels(); - EXPECT_TRUE(transport_->GetStats(&stats)); - ASSERT_EQ(1U, stats.channel_stats.size()); - EXPECT_EQ(1, stats.channel_stats[0].component); -} diff --git a/talk/p2p/base/transportchannel.cc b/talk/p2p/base/transportchannel.cc deleted file mode 100644 index 13048ed08..000000000 --- a/talk/p2p/base/transportchannel.cc +++ /dev/null @@ -1,60 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <sstream> -#include "webrtc/p2p/base/transportchannel.h" - -namespace cricket { - -std::string TransportChannel::ToString() const { - const char READABLE_ABBREV[2] = { '_', 'R' }; - const char WRITABLE_ABBREV[2] = { '_', 'W' }; - std::stringstream ss; - ss << "Channel[" << content_name_ - << "|" << component_ - << "|" << READABLE_ABBREV[readable_] << WRITABLE_ABBREV[writable_] << "]"; - return ss.str(); -} - -void TransportChannel::set_readable(bool readable) { - if (readable_ != readable) { - readable_ = readable; - SignalReadableState(this); - } -} - -void TransportChannel::set_writable(bool writable) { - if (writable_ != writable) { - writable_ = writable; - if (writable_) { - SignalReadyToSend(this); - } - SignalWritableState(this); - } -} - -} // namespace cricket diff --git a/talk/p2p/base/transportchannel.h b/talk/p2p/base/transportchannel.h deleted file mode 100644 index 56d9467ff..000000000 --- a/talk/p2p/base/transportchannel.h +++ /dev/null @@ -1,160 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef WEBRTC_P2P_BASE_TRANSPORTCHANNEL_H_ -#define WEBRTC_P2P_BASE_TRANSPORTCHANNEL_H_ - -#include <string> -#include <vector> - -#include "webrtc/p2p/base/candidate.h" -#include "webrtc/p2p/base/transport.h" -#include "webrtc/p2p/base/transportdescription.h" -#include "webrtc/base/asyncpacketsocket.h" -#include "webrtc/base/basictypes.h" -#include "webrtc/base/dscp.h" -#include "webrtc/base/sigslot.h" -#include "webrtc/base/socket.h" -#include "webrtc/base/sslidentity.h" -#include "webrtc/base/sslstreamadapter.h" - -namespace cricket { - -class Candidate; - -// Flags for SendPacket/SignalReadPacket. -enum PacketFlags { - PF_NORMAL = 0x00, // A normal packet. - PF_SRTP_BYPASS = 0x01, // An encrypted SRTP packet; bypass any additional - // crypto provided by the transport (e.g. DTLS) -}; - -// A TransportChannel represents one logical stream of packets that are sent -// between the two sides of a session. -class TransportChannel : public sigslot::has_slots<> { - public: - explicit TransportChannel(const std::string& content_name, int component) - : content_name_(content_name), - component_(component), - readable_(false), writable_(false) {} - virtual ~TransportChannel() {} - - // TODO(mallinath) - Remove this API, as it's no longer useful. - // Returns the session id of this channel. - virtual const std::string SessionId() const { return std::string(); } - - const std::string& content_name() const { return content_name_; } - int component() const { return component_; } - - // Returns the readable and states of this channel. Each time one of these - // states changes, a signal is raised. These states are aggregated by the - // TransportManager. - bool readable() const { return readable_; } - bool writable() const { return writable_; } - sigslot::signal1<TransportChannel*> SignalReadableState; - sigslot::signal1<TransportChannel*> SignalWritableState; - // Emitted when the TransportChannel's ability to send has changed. - sigslot::signal1<TransportChannel*> SignalReadyToSend; - - // Attempts to send the given packet. The return value is < 0 on failure. - // TODO: Remove the default argument once channel code is updated. - virtual int SendPacket(const char* data, size_t len, - const rtc::PacketOptions& options, - int flags = 0) = 0; - - // Sets a socket option on this channel. Note that not all options are - // supported by all transport types. - virtual int SetOption(rtc::Socket::Option opt, int value) = 0; - - // Returns the most recent error that occurred on this channel. - virtual int GetError() = 0; - - // Returns the current stats for this connection. - virtual bool GetStats(ConnectionInfos* infos) = 0; - - // Is DTLS active? - virtual bool IsDtlsActive() const = 0; - - // Default implementation. - virtual bool GetSslRole(rtc::SSLRole* role) const = 0; - - // Sets up the ciphers to use for DTLS-SRTP. - virtual bool SetSrtpCiphers(const std::vector<std::string>& ciphers) = 0; - - // Finds out which DTLS-SRTP cipher was negotiated - virtual bool GetSrtpCipher(std::string* cipher) = 0; - - // Gets a copy of the local SSL identity, owned by the caller. - virtual bool GetLocalIdentity(rtc::SSLIdentity** identity) const = 0; - - // Gets a copy of the remote side's SSL certificate, owned by the caller. - virtual bool GetRemoteCertificate(rtc::SSLCertificate** cert) const = 0; - - // Allows key material to be extracted for external encryption. - virtual bool ExportKeyingMaterial(const std::string& label, - const uint8* context, - size_t context_len, - bool use_context, - uint8* result, - size_t result_len) = 0; - - // Signalled each time a packet is received on this channel. - sigslot::signal5<TransportChannel*, const char*, - size_t, const rtc::PacketTime&, int> SignalReadPacket; - - // This signal occurs when there is a change in the way that packets are - // being routed, i.e. to a different remote location. The candidate - // indicates where and how we are currently sending media. - sigslot::signal2<TransportChannel*, const Candidate&> SignalRouteChange; - - // Invoked when the channel is being destroyed. - sigslot::signal1<TransportChannel*> SignalDestroyed; - - // Debugging description of this transport channel. - std::string ToString() const; - - protected: - // Sets the readable state, signaling if necessary. - void set_readable(bool readable); - - // Sets the writable state, signaling if necessary. - void set_writable(bool writable); - - - private: - // Used mostly for debugging. - std::string content_name_; - int component_; - bool readable_; - bool writable_; - - DISALLOW_EVIL_CONSTRUCTORS(TransportChannel); -}; - -} // namespace cricket - -#endif // WEBRTC_P2P_BASE_TRANSPORTCHANNEL_H_ diff --git a/talk/p2p/base/transportchannelimpl.h b/talk/p2p/base/transportchannelimpl.h deleted file mode 100644 index 73afdee23..000000000 --- a/talk/p2p/base/transportchannelimpl.h +++ /dev/null @@ -1,128 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef WEBRTC_P2P_BASE_TRANSPORTCHANNELIMPL_H_ -#define WEBRTC_P2P_BASE_TRANSPORTCHANNELIMPL_H_ - -#include <string> -#include "webrtc/p2p/base/transport.h" -#include "webrtc/p2p/base/transportchannel.h" - -namespace buzz { class XmlElement; } - -namespace cricket { - -class Candidate; - -// Base class for real implementations of TransportChannel. This includes some -// methods called only by Transport, which do not need to be exposed to the -// client. -class TransportChannelImpl : public TransportChannel { - public: - explicit TransportChannelImpl(const std::string& content_name, int component) - : TransportChannel(content_name, component) {} - - // Returns the transport that created this channel. - virtual Transport* GetTransport() = 0; - - // For ICE channels. - virtual IceRole GetIceRole() const = 0; - virtual void SetIceRole(IceRole role) = 0; - virtual void SetIceTiebreaker(uint64 tiebreaker) = 0; - virtual size_t GetConnectionCount() const = 0; - // To toggle G-ICE/ICE. - virtual bool GetIceProtocolType(IceProtocolType* type) const = 0; - virtual void SetIceProtocolType(IceProtocolType type) = 0; - // SetIceCredentials only need to be implemented by the ICE - // transport channels. Non-ICE transport channels can just ignore. - // The ufrag and pwd should be set before the Connect() is called. - virtual void SetIceCredentials(const std::string& ice_ufrag, - const std::string& ice_pwd) = 0; - // SetRemoteIceCredentials only need to be implemented by the ICE - // transport channels. Non-ICE transport channels can just ignore. - virtual void SetRemoteIceCredentials(const std::string& ice_ufrag, - const std::string& ice_pwd) = 0; - - // SetRemoteIceMode must be implemented only by the ICE transport channels. - virtual void SetRemoteIceMode(IceMode mode) = 0; - - // Begins the process of attempting to make a connection to the other client. - virtual void Connect() = 0; - - // Resets this channel back to the initial state (i.e., not connecting). - virtual void Reset() = 0; - - // Allows an individual channel to request signaling and be notified when it - // is ready. This is useful if the individual named channels have need to - // send their own transport-info stanzas. - sigslot::signal1<TransportChannelImpl*> SignalRequestSignaling; - virtual void OnSignalingReady() = 0; - - // Handles sending and receiving of candidates. The Transport - // receives the candidates and may forward them to the relevant - // channel. - // - // Note: Since candidates are delivered asynchronously to the - // channel, they cannot return an error if the message is invalid. - // It is assumed that the Transport will have checked validity - // before forwarding. - sigslot::signal2<TransportChannelImpl*, - const Candidate&> SignalCandidateReady; - virtual void OnCandidate(const Candidate& candidate) = 0; - - // DTLS methods - // Set DTLS local identity. The identity object is not copied, but the caller - // retains ownership and must delete it after this TransportChannelImpl is - // destroyed. - // TODO(bemasc): Fix the ownership semantics of this method. - virtual bool SetLocalIdentity(rtc::SSLIdentity* identity) = 0; - - // Set DTLS Remote fingerprint. Must be after local identity set. - virtual bool SetRemoteFingerprint(const std::string& digest_alg, - const uint8* digest, - size_t digest_len) = 0; - - virtual bool SetSslRole(rtc::SSLRole role) = 0; - - // TransportChannel is forwarding this signal from PortAllocatorSession. - sigslot::signal1<TransportChannelImpl*> SignalCandidatesAllocationDone; - - // Invoked when there is conflict in the ICE role between local and remote - // agents. - sigslot::signal1<TransportChannelImpl*> SignalRoleConflict; - - // Emitted whenever the number of connections available to the transport - // channel decreases. - sigslot::signal1<TransportChannelImpl*> SignalConnectionRemoved; - - private: - DISALLOW_EVIL_CONSTRUCTORS(TransportChannelImpl); -}; - -} // namespace cricket - -#endif // WEBRTC_P2P_BASE_TRANSPORTCHANNELIMPL_H_ diff --git a/talk/p2p/base/transportchannelproxy.cc b/talk/p2p/base/transportchannelproxy.cc deleted file mode 100644 index 259b8ddc6..000000000 --- a/talk/p2p/base/transportchannelproxy.cc +++ /dev/null @@ -1,266 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "webrtc/p2p/base/transport.h" -#include "webrtc/p2p/base/transportchannelimpl.h" -#include "webrtc/p2p/base/transportchannelproxy.h" -#include "webrtc/base/common.h" -#include "webrtc/base/logging.h" -#include "webrtc/base/thread.h" - -namespace cricket { - -enum { - MSG_UPDATESTATE, -}; - -TransportChannelProxy::TransportChannelProxy(const std::string& content_name, - const std::string& name, - int component) - : TransportChannel(content_name, component), - name_(name), - impl_(NULL) { - worker_thread_ = rtc::Thread::Current(); -} - -TransportChannelProxy::~TransportChannelProxy() { - // Clearing any pending signal. - worker_thread_->Clear(this); - if (impl_) - impl_->GetTransport()->DestroyChannel(impl_->component()); -} - -void TransportChannelProxy::SetImplementation(TransportChannelImpl* impl) { - ASSERT(rtc::Thread::Current() == worker_thread_); - - if (impl == impl_) { - // Ignore if the |impl| has already been set. - LOG(LS_WARNING) << "Ignored TransportChannelProxy::SetImplementation call " - << "with a same impl as the existing one."; - return; - } - - // Destroy any existing impl_. - if (impl_) { - impl_->GetTransport()->DestroyChannel(impl_->component()); - } - - // Adopt the supplied impl, and connect to its signals. - impl_ = impl; - - if (impl_) { - impl_->SignalReadableState.connect( - this, &TransportChannelProxy::OnReadableState); - impl_->SignalWritableState.connect( - this, &TransportChannelProxy::OnWritableState); - impl_->SignalReadPacket.connect( - this, &TransportChannelProxy::OnReadPacket); - impl_->SignalReadyToSend.connect( - this, &TransportChannelProxy::OnReadyToSend); - impl_->SignalRouteChange.connect( - this, &TransportChannelProxy::OnRouteChange); - for (OptionList::iterator it = pending_options_.begin(); - it != pending_options_.end(); - ++it) { - impl_->SetOption(it->first, it->second); - } - - // Push down the SRTP ciphers, if any were set. - if (!pending_srtp_ciphers_.empty()) { - impl_->SetSrtpCiphers(pending_srtp_ciphers_); - } - pending_options_.clear(); - } - - // Post ourselves a message to see if we need to fire state callbacks. - worker_thread_->Post(this, MSG_UPDATESTATE); -} - -int TransportChannelProxy::SendPacket(const char* data, size_t len, - const rtc::PacketOptions& options, - int flags) { - ASSERT(rtc::Thread::Current() == worker_thread_); - // Fail if we don't have an impl yet. - if (!impl_) { - return -1; - } - return impl_->SendPacket(data, len, options, flags); -} - -int TransportChannelProxy::SetOption(rtc::Socket::Option opt, int value) { - ASSERT(rtc::Thread::Current() == worker_thread_); - if (!impl_) { - pending_options_.push_back(OptionPair(opt, value)); - return 0; - } - return impl_->SetOption(opt, value); -} - -int TransportChannelProxy::GetError() { - ASSERT(rtc::Thread::Current() == worker_thread_); - if (!impl_) { - return 0; - } - return impl_->GetError(); -} - -bool TransportChannelProxy::GetStats(ConnectionInfos* infos) { - ASSERT(rtc::Thread::Current() == worker_thread_); - if (!impl_) { - return false; - } - return impl_->GetStats(infos); -} - -bool TransportChannelProxy::IsDtlsActive() const { - ASSERT(rtc::Thread::Current() == worker_thread_); - if (!impl_) { - return false; - } - return impl_->IsDtlsActive(); -} - -bool TransportChannelProxy::GetSslRole(rtc::SSLRole* role) const { - ASSERT(rtc::Thread::Current() == worker_thread_); - if (!impl_) { - return false; - } - return impl_->GetSslRole(role); -} - -bool TransportChannelProxy::SetSslRole(rtc::SSLRole role) { - ASSERT(rtc::Thread::Current() == worker_thread_); - if (!impl_) { - return false; - } - return impl_->SetSslRole(role); -} - -bool TransportChannelProxy::SetSrtpCiphers(const std::vector<std::string>& - ciphers) { - ASSERT(rtc::Thread::Current() == worker_thread_); - pending_srtp_ciphers_ = ciphers; // Cache so we can send later, but always - // set so it stays consistent. - if (impl_) { - return impl_->SetSrtpCiphers(ciphers); - } - return true; -} - -bool TransportChannelProxy::GetSrtpCipher(std::string* cipher) { - ASSERT(rtc::Thread::Current() == worker_thread_); - if (!impl_) { - return false; - } - return impl_->GetSrtpCipher(cipher); -} - -bool TransportChannelProxy::GetLocalIdentity( - rtc::SSLIdentity** identity) const { - ASSERT(rtc::Thread::Current() == worker_thread_); - if (!impl_) { - return false; - } - return impl_->GetLocalIdentity(identity); -} - -bool TransportChannelProxy::GetRemoteCertificate( - rtc::SSLCertificate** cert) const { - ASSERT(rtc::Thread::Current() == worker_thread_); - if (!impl_) { - return false; - } - return impl_->GetRemoteCertificate(cert); -} - -bool TransportChannelProxy::ExportKeyingMaterial(const std::string& label, - const uint8* context, - size_t context_len, - bool use_context, - uint8* result, - size_t result_len) { - ASSERT(rtc::Thread::Current() == worker_thread_); - if (!impl_) { - return false; - } - return impl_->ExportKeyingMaterial(label, context, context_len, use_context, - result, result_len); -} - -IceRole TransportChannelProxy::GetIceRole() const { - ASSERT(rtc::Thread::Current() == worker_thread_); - if (!impl_) { - return ICEROLE_UNKNOWN; - } - return impl_->GetIceRole(); -} - -void TransportChannelProxy::OnReadableState(TransportChannel* channel) { - ASSERT(rtc::Thread::Current() == worker_thread_); - ASSERT(channel == impl_); - set_readable(impl_->readable()); - // Note: SignalReadableState fired by set_readable. -} - -void TransportChannelProxy::OnWritableState(TransportChannel* channel) { - ASSERT(rtc::Thread::Current() == worker_thread_); - ASSERT(channel == impl_); - set_writable(impl_->writable()); - // Note: SignalWritableState fired by set_readable. -} - -void TransportChannelProxy::OnReadPacket( - TransportChannel* channel, const char* data, size_t size, - const rtc::PacketTime& packet_time, int flags) { - ASSERT(rtc::Thread::Current() == worker_thread_); - ASSERT(channel == impl_); - SignalReadPacket(this, data, size, packet_time, flags); -} - -void TransportChannelProxy::OnReadyToSend(TransportChannel* channel) { - ASSERT(rtc::Thread::Current() == worker_thread_); - ASSERT(channel == impl_); - SignalReadyToSend(this); -} - -void TransportChannelProxy::OnRouteChange(TransportChannel* channel, - const Candidate& candidate) { - ASSERT(rtc::Thread::Current() == worker_thread_); - ASSERT(channel == impl_); - SignalRouteChange(this, candidate); -} - -void TransportChannelProxy::OnMessage(rtc::Message* msg) { - ASSERT(rtc::Thread::Current() == worker_thread_); - if (msg->message_id == MSG_UPDATESTATE) { - // If impl_ is already readable or writable, push up those signals. - set_readable(impl_ ? impl_->readable() : false); - set_writable(impl_ ? impl_->writable() : false); - } -} - -} // namespace cricket diff --git a/talk/p2p/base/transportchannelproxy.h b/talk/p2p/base/transportchannelproxy.h deleted file mode 100644 index dee4313c4..000000000 --- a/talk/p2p/base/transportchannelproxy.h +++ /dev/null @@ -1,112 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef WEBRTC_P2P_BASE_TRANSPORTCHANNELPROXY_H_ -#define WEBRTC_P2P_BASE_TRANSPORTCHANNELPROXY_H_ - -#include <string> -#include <utility> -#include <vector> - -#include "webrtc/p2p/base/transportchannel.h" -#include "webrtc/base/messagehandler.h" - -namespace rtc { -class Thread; -} - -namespace cricket { - -class TransportChannelImpl; - -// Proxies calls between the client and the transport channel implementation. -// This is needed because clients are allowed to create channels before the -// network negotiation is complete. Hence, we create a proxy up front, and -// when negotiation completes, connect the proxy to the implementaiton. -class TransportChannelProxy : public TransportChannel, - public rtc::MessageHandler { - public: - TransportChannelProxy(const std::string& content_name, - const std::string& name, - int component); - virtual ~TransportChannelProxy(); - - const std::string& name() const { return name_; } - TransportChannelImpl* impl() { return impl_; } - - // Sets the implementation to which we will proxy. - void SetImplementation(TransportChannelImpl* impl); - - // Implementation of the TransportChannel interface. These simply forward to - // the implementation. - virtual int SendPacket(const char* data, size_t len, - const rtc::PacketOptions& options, - int flags); - virtual int SetOption(rtc::Socket::Option opt, int value); - virtual int GetError(); - virtual IceRole GetIceRole() const; - virtual bool GetStats(ConnectionInfos* infos); - virtual bool IsDtlsActive() const; - virtual bool GetSslRole(rtc::SSLRole* role) const; - virtual bool SetSslRole(rtc::SSLRole role); - virtual bool SetSrtpCiphers(const std::vector<std::string>& ciphers); - virtual bool GetSrtpCipher(std::string* cipher); - virtual bool GetLocalIdentity(rtc::SSLIdentity** identity) const; - virtual bool GetRemoteCertificate(rtc::SSLCertificate** cert) const; - virtual bool ExportKeyingMaterial(const std::string& label, - const uint8* context, - size_t context_len, - bool use_context, - uint8* result, - size_t result_len); - - private: - // Catch signals from the implementation channel. These just forward to the - // client (after updating our state to match). - void OnReadableState(TransportChannel* channel); - void OnWritableState(TransportChannel* channel); - void OnReadPacket(TransportChannel* channel, const char* data, size_t size, - const rtc::PacketTime& packet_time, int flags); - void OnReadyToSend(TransportChannel* channel); - void OnRouteChange(TransportChannel* channel, const Candidate& candidate); - - void OnMessage(rtc::Message* message); - - typedef std::pair<rtc::Socket::Option, int> OptionPair; - typedef std::vector<OptionPair> OptionList; - std::string name_; - rtc::Thread* worker_thread_; - TransportChannelImpl* impl_; - OptionList pending_options_; - std::vector<std::string> pending_srtp_ciphers_; - - DISALLOW_EVIL_CONSTRUCTORS(TransportChannelProxy); -}; - -} // namespace cricket - -#endif // WEBRTC_P2P_BASE_TRANSPORTCHANNELPROXY_H_ diff --git a/talk/p2p/base/transportdescription.cc b/talk/p2p/base/transportdescription.cc deleted file mode 100644 index 8bdcbb368..000000000 --- a/talk/p2p/base/transportdescription.cc +++ /dev/null @@ -1,72 +0,0 @@ -/* - * libjingle - * Copyright 2013 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "webrtc/p2p/base/transportdescription.h" - -#include "webrtc/p2p/base/constants.h" -#include "webrtc/base/stringutils.h" - -namespace cricket { - -bool StringToConnectionRole(const std::string& role_str, ConnectionRole* role) { - const char* const roles[] = { - CONNECTIONROLE_ACTIVE_STR, - CONNECTIONROLE_PASSIVE_STR, - CONNECTIONROLE_ACTPASS_STR, - CONNECTIONROLE_HOLDCONN_STR - }; - - for (size_t i = 0; i < ARRAY_SIZE(roles); ++i) { - if (_stricmp(roles[i], role_str.c_str()) == 0) { - *role = static_cast<ConnectionRole>(CONNECTIONROLE_ACTIVE + i); - return true; - } - } - return false; -} - -bool ConnectionRoleToString(const ConnectionRole& role, std::string* role_str) { - switch (role) { - case cricket::CONNECTIONROLE_ACTIVE: - *role_str = cricket::CONNECTIONROLE_ACTIVE_STR; - break; - case cricket::CONNECTIONROLE_ACTPASS: - *role_str = cricket::CONNECTIONROLE_ACTPASS_STR; - break; - case cricket::CONNECTIONROLE_PASSIVE: - *role_str = cricket::CONNECTIONROLE_PASSIVE_STR; - break; - case cricket::CONNECTIONROLE_HOLDCONN: - *role_str = cricket::CONNECTIONROLE_HOLDCONN_STR; - break; - default: - return false; - } - return true; -} - -} // namespace cricket diff --git a/talk/p2p/base/transportdescription.h b/talk/p2p/base/transportdescription.h deleted file mode 100644 index 5763d23e6..000000000 --- a/talk/p2p/base/transportdescription.h +++ /dev/null @@ -1,188 +0,0 @@ -/* - * libjingle - * Copyright 2012, The Libjingle Authors. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef WEBRTC_P2P_BASE_TRANSPORTDESCRIPTION_H_ -#define WEBRTC_P2P_BASE_TRANSPORTDESCRIPTION_H_ - -#include <algorithm> -#include <string> -#include <vector> - -#include "webrtc/p2p/base/candidate.h" -#include "webrtc/p2p/base/constants.h" -#include "webrtc/base/scoped_ptr.h" -#include "webrtc/base/sslfingerprint.h" - -namespace cricket { - -// SEC_ENABLED and SEC_REQUIRED should only be used if the session -// was negotiated over TLS, to protect the inline crypto material -// exchange. -// SEC_DISABLED: No crypto in outgoing offer, ignore any supplied crypto. -// SEC_ENABLED: Crypto in outgoing offer and answer (if supplied in offer). -// SEC_REQUIRED: Crypto in outgoing offer and answer. Fail any offer with absent -// or unsupported crypto. -enum SecurePolicy { - SEC_DISABLED, - SEC_ENABLED, - SEC_REQUIRED -}; - -// The transport protocol we've elected to use. -enum TransportProtocol { - ICEPROTO_GOOGLE, // Google version of ICE protocol. - ICEPROTO_HYBRID, // ICE, but can fall back to the Google version. - ICEPROTO_RFC5245 // Standard RFC 5245 version of ICE. -}; -// The old name for TransportProtocol. -// TODO(juberti): remove this. -typedef TransportProtocol IceProtocolType; - -// Whether our side of the call is driving the negotiation, or the other side. -enum IceRole { - ICEROLE_CONTROLLING = 0, - ICEROLE_CONTROLLED, - ICEROLE_UNKNOWN -}; - -// ICE RFC 5245 implementation type. -enum IceMode { - ICEMODE_FULL, // As defined in http://tools.ietf.org/html/rfc5245#section-4.1 - ICEMODE_LITE // As defined in http://tools.ietf.org/html/rfc5245#section-4.2 -}; - -// RFC 4145 - http://tools.ietf.org/html/rfc4145#section-4 -// 'active': The endpoint will initiate an outgoing connection. -// 'passive': The endpoint will accept an incoming connection. -// 'actpass': The endpoint is willing to accept an incoming -// connection or to initiate an outgoing connection. -enum ConnectionRole { - CONNECTIONROLE_NONE = 0, - CONNECTIONROLE_ACTIVE, - CONNECTIONROLE_PASSIVE, - CONNECTIONROLE_ACTPASS, - CONNECTIONROLE_HOLDCONN, -}; - -extern const char CONNECTIONROLE_ACTIVE_STR[]; -extern const char CONNECTIONROLE_PASSIVE_STR[]; -extern const char CONNECTIONROLE_ACTPASS_STR[]; -extern const char CONNECTIONROLE_HOLDCONN_STR[]; - -bool StringToConnectionRole(const std::string& role_str, ConnectionRole* role); -bool ConnectionRoleToString(const ConnectionRole& role, std::string* role_str); - -typedef std::vector<Candidate> Candidates; - -struct TransportDescription { - TransportDescription() - : ice_mode(ICEMODE_FULL), - connection_role(CONNECTIONROLE_NONE) {} - - TransportDescription(const std::string& transport_type, - const std::vector<std::string>& transport_options, - const std::string& ice_ufrag, - const std::string& ice_pwd, - IceMode ice_mode, - ConnectionRole role, - const rtc::SSLFingerprint* identity_fingerprint, - const Candidates& candidates) - : transport_type(transport_type), - transport_options(transport_options), - ice_ufrag(ice_ufrag), - ice_pwd(ice_pwd), - ice_mode(ice_mode), - connection_role(role), - identity_fingerprint(CopyFingerprint(identity_fingerprint)), - candidates(candidates) {} - TransportDescription(const std::string& transport_type, - const std::string& ice_ufrag, - const std::string& ice_pwd) - : transport_type(transport_type), - ice_ufrag(ice_ufrag), - ice_pwd(ice_pwd), - ice_mode(ICEMODE_FULL), - connection_role(CONNECTIONROLE_NONE) {} - TransportDescription(const TransportDescription& from) - : transport_type(from.transport_type), - transport_options(from.transport_options), - ice_ufrag(from.ice_ufrag), - ice_pwd(from.ice_pwd), - ice_mode(from.ice_mode), - connection_role(from.connection_role), - identity_fingerprint(CopyFingerprint(from.identity_fingerprint.get())), - candidates(from.candidates) {} - - TransportDescription& operator=(const TransportDescription& from) { - // Self-assignment - if (this == &from) - return *this; - - transport_type = from.transport_type; - transport_options = from.transport_options; - ice_ufrag = from.ice_ufrag; - ice_pwd = from.ice_pwd; - ice_mode = from.ice_mode; - connection_role = from.connection_role; - - identity_fingerprint.reset(CopyFingerprint( - from.identity_fingerprint.get())); - candidates = from.candidates; - return *this; - } - - bool HasOption(const std::string& option) const { - return (std::find(transport_options.begin(), transport_options.end(), - option) != transport_options.end()); - } - void AddOption(const std::string& option) { - transport_options.push_back(option); - } - bool secure() const { return identity_fingerprint != NULL; } - - static rtc::SSLFingerprint* CopyFingerprint( - const rtc::SSLFingerprint* from) { - if (!from) - return NULL; - - return new rtc::SSLFingerprint(*from); - } - - std::string transport_type; // xmlns of <transport> - std::vector<std::string> transport_options; - std::string ice_ufrag; - std::string ice_pwd; - IceMode ice_mode; - ConnectionRole connection_role; - - rtc::scoped_ptr<rtc::SSLFingerprint> identity_fingerprint; - Candidates candidates; -}; - -} // namespace cricket - -#endif // WEBRTC_P2P_BASE_TRANSPORTDESCRIPTION_H_ diff --git a/talk/p2p/base/transportdescriptionfactory.cc b/talk/p2p/base/transportdescriptionfactory.cc deleted file mode 100644 index 7260b9c8e..000000000 --- a/talk/p2p/base/transportdescriptionfactory.cc +++ /dev/null @@ -1,177 +0,0 @@ -/* - * libjingle - * Copyright 2012 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "webrtc/p2p/base/transportdescriptionfactory.h" - -#include "webrtc/p2p/base/transportdescription.h" -#include "webrtc/base/helpers.h" -#include "webrtc/base/logging.h" -#include "webrtc/base/messagedigest.h" -#include "webrtc/base/scoped_ptr.h" -#include "webrtc/base/sslfingerprint.h" - -namespace cricket { - -static TransportProtocol kDefaultProtocol = ICEPROTO_GOOGLE; - -TransportDescriptionFactory::TransportDescriptionFactory() - : protocol_(kDefaultProtocol), - secure_(SEC_DISABLED), - identity_(NULL) { -} - -TransportDescription* TransportDescriptionFactory::CreateOffer( - const TransportOptions& options, - const TransportDescription* current_description) const { - rtc::scoped_ptr<TransportDescription> desc(new TransportDescription()); - - // Set the transport type depending on the selected protocol. - if (protocol_ == ICEPROTO_RFC5245) { - desc->transport_type = NS_JINGLE_ICE_UDP; - } else if (protocol_ == ICEPROTO_HYBRID) { - desc->transport_type = NS_JINGLE_ICE_UDP; - desc->AddOption(ICE_OPTION_GICE); - } else if (protocol_ == ICEPROTO_GOOGLE) { - desc->transport_type = NS_GINGLE_P2P; - } - - // Generate the ICE credentials if we don't already have them. - if (!current_description || options.ice_restart) { - desc->ice_ufrag = rtc::CreateRandomString(ICE_UFRAG_LENGTH); - desc->ice_pwd = rtc::CreateRandomString(ICE_PWD_LENGTH); - } else { - desc->ice_ufrag = current_description->ice_ufrag; - desc->ice_pwd = current_description->ice_pwd; - } - - // If we are trying to establish a secure transport, add a fingerprint. - if (secure_ == SEC_ENABLED || secure_ == SEC_REQUIRED) { - // Fail if we can't create the fingerprint. - // If we are the initiator set role to "actpass". - if (!SetSecurityInfo(desc.get(), CONNECTIONROLE_ACTPASS)) { - return NULL; - } - } - - return desc.release(); -} - -TransportDescription* TransportDescriptionFactory::CreateAnswer( - const TransportDescription* offer, - const TransportOptions& options, - const TransportDescription* current_description) const { - // A NULL offer is treated as a GICE transport description. - // TODO(juberti): Figure out why we get NULL offers, and fix this upstream. - rtc::scoped_ptr<TransportDescription> desc(new TransportDescription()); - - // Figure out which ICE variant to negotiate; prefer RFC 5245 ICE, but fall - // back to G-ICE if needed. Note that we never create a hybrid answer, since - // we know what the other side can support already. - if (offer && offer->transport_type == NS_JINGLE_ICE_UDP && - (protocol_ == ICEPROTO_RFC5245 || protocol_ == ICEPROTO_HYBRID)) { - // Offer is ICE or hybrid, we support ICE or hybrid: use ICE. - desc->transport_type = NS_JINGLE_ICE_UDP; - } else if (offer && offer->transport_type == NS_JINGLE_ICE_UDP && - offer->HasOption(ICE_OPTION_GICE) && - protocol_ == ICEPROTO_GOOGLE) { - desc->transport_type = NS_GINGLE_P2P; - // Offer is hybrid, we support GICE: use GICE. - } else if ((!offer || offer->transport_type == NS_GINGLE_P2P) && - (protocol_ == ICEPROTO_HYBRID || protocol_ == ICEPROTO_GOOGLE)) { - // Offer is GICE, we support hybrid or GICE: use GICE. - desc->transport_type = NS_GINGLE_P2P; - } else { - // Mismatch. - LOG(LS_WARNING) << "Failed to create TransportDescription answer " - "because of incompatible transport types"; - return NULL; - } - - // Generate the ICE credentials if we don't already have them or ice is - // being restarted. - if (!current_description || options.ice_restart) { - desc->ice_ufrag = rtc::CreateRandomString(ICE_UFRAG_LENGTH); - desc->ice_pwd = rtc::CreateRandomString(ICE_PWD_LENGTH); - } else { - desc->ice_ufrag = current_description->ice_ufrag; - desc->ice_pwd = current_description->ice_pwd; - } - - // Negotiate security params. - if (offer && offer->identity_fingerprint.get()) { - // The offer supports DTLS, so answer with DTLS, as long as we support it. - if (secure_ == SEC_ENABLED || secure_ == SEC_REQUIRED) { - // Fail if we can't create the fingerprint. - // Setting DTLS role to active. - ConnectionRole role = (options.prefer_passive_role) ? - CONNECTIONROLE_PASSIVE : CONNECTIONROLE_ACTIVE; - - if (!SetSecurityInfo(desc.get(), role)) { - return NULL; - } - } - } else if (secure_ == SEC_REQUIRED) { - // We require DTLS, but the other side didn't offer it. Fail. - LOG(LS_WARNING) << "Failed to create TransportDescription answer " - "because of incompatible security settings"; - return NULL; - } - - return desc.release(); -} - -bool TransportDescriptionFactory::SetSecurityInfo( - TransportDescription* desc, ConnectionRole role) const { - if (!identity_) { - LOG(LS_ERROR) << "Cannot create identity digest with no identity"; - return false; - } - - // This digest algorithm is used to produce the a=fingerprint lines in SDP. - // RFC 4572 Section 5 requires that those lines use the same hash function as - // the certificate's signature. - std::string digest_alg; - if (!identity_->certificate().GetSignatureDigestAlgorithm(&digest_alg)) { - LOG(LS_ERROR) << "Failed to retrieve the certificate's digest algorithm"; - return false; - } - - desc->identity_fingerprint.reset( - rtc::SSLFingerprint::Create(digest_alg, identity_)); - if (!desc->identity_fingerprint.get()) { - LOG(LS_ERROR) << "Failed to create identity fingerprint, alg=" - << digest_alg; - return false; - } - - // Assign security role. - desc->connection_role = role; - return true; -} - -} // namespace cricket - diff --git a/talk/p2p/base/transportdescriptionfactory.h b/talk/p2p/base/transportdescriptionfactory.h deleted file mode 100644 index bcd14c648..000000000 --- a/talk/p2p/base/transportdescriptionfactory.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - * libjingle - * Copyright 2012 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef WEBRTC_P2P_BASE_TRANSPORTDESCRIPTIONFACTORY_H_ -#define WEBRTC_P2P_BASE_TRANSPORTDESCRIPTIONFACTORY_H_ - -#include "webrtc/p2p/base/transportdescription.h" - -namespace rtc { -class SSLIdentity; -} - -namespace cricket { - -struct TransportOptions { - TransportOptions() : ice_restart(false), prefer_passive_role(false) {} - bool ice_restart; - bool prefer_passive_role; -}; - -// Creates transport descriptions according to the supplied configuration. -// When creating answers, performs the appropriate negotiation -// of the various fields to determine the proper result. -class TransportDescriptionFactory { - public: - // Default ctor; use methods below to set configuration. - TransportDescriptionFactory(); - SecurePolicy secure() const { return secure_; } - // The identity to use when setting up DTLS. - rtc::SSLIdentity* identity() const { return identity_; } - - // Specifies the transport protocol to be use. - void set_protocol(TransportProtocol protocol) { protocol_ = protocol; } - // Specifies the transport security policy to use. - void set_secure(SecurePolicy s) { secure_ = s; } - // Specifies the identity to use (only used when secure is not SEC_DISABLED). - void set_identity(rtc::SSLIdentity* identity) { identity_ = identity; } - - // Creates a transport description suitable for use in an offer. - TransportDescription* CreateOffer(const TransportOptions& options, - const TransportDescription* current_description) const; - // Create a transport description that is a response to an offer. - TransportDescription* CreateAnswer( - const TransportDescription* offer, - const TransportOptions& options, - const TransportDescription* current_description) const; - - private: - bool SetSecurityInfo(TransportDescription* description, - ConnectionRole role) const; - - TransportProtocol protocol_; - SecurePolicy secure_; - rtc::SSLIdentity* identity_; -}; - -} // namespace cricket - -#endif // WEBRTC_P2P_BASE_TRANSPORTDESCRIPTIONFACTORY_H_ diff --git a/talk/p2p/base/transportdescriptionfactory_unittest.cc b/talk/p2p/base/transportdescriptionfactory_unittest.cc deleted file mode 100644 index a7938532f..000000000 --- a/talk/p2p/base/transportdescriptionfactory_unittest.cc +++ /dev/null @@ -1,382 +0,0 @@ -/* - * libjingle - * Copyright 2012, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <string> -#include <vector> - -#include "webrtc/p2p/base/constants.h" -#include "webrtc/p2p/base/transportdescription.h" -#include "webrtc/p2p/base/transportdescriptionfactory.h" -#include "webrtc/base/fakesslidentity.h" -#include "webrtc/base/gunit.h" -#include "webrtc/base/ssladapter.h" - -using rtc::scoped_ptr; -using cricket::TransportDescriptionFactory; -using cricket::TransportDescription; -using cricket::TransportOptions; - -class TransportDescriptionFactoryTest : public testing::Test { - public: - TransportDescriptionFactoryTest() - : id1_(new rtc::FakeSSLIdentity("User1")), - id2_(new rtc::FakeSSLIdentity("User2")) { - } - - void CheckDesc(const TransportDescription* desc, const std::string& type, - const std::string& opt, const std::string& ice_ufrag, - const std::string& ice_pwd, const std::string& dtls_alg) { - ASSERT_TRUE(desc != NULL); - EXPECT_EQ(type, desc->transport_type); - EXPECT_EQ(!opt.empty(), desc->HasOption(opt)); - if (ice_ufrag.empty() && ice_pwd.empty()) { - EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH), - desc->ice_ufrag.size()); - EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH), - desc->ice_pwd.size()); - } else { - EXPECT_EQ(ice_ufrag, desc->ice_ufrag); - EXPECT_EQ(ice_pwd, desc->ice_pwd); - } - if (dtls_alg.empty()) { - EXPECT_TRUE(desc->identity_fingerprint.get() == NULL); - } else { - ASSERT_TRUE(desc->identity_fingerprint.get() != NULL); - EXPECT_EQ(desc->identity_fingerprint->algorithm, dtls_alg); - EXPECT_GT(desc->identity_fingerprint->digest.length(), 0U); - } - } - - // This test ice restart by doing two offer answer exchanges. On the second - // exchange ice is restarted. The test verifies that the ufrag and password - // in the offer and answer is changed. - // If |dtls| is true, the test verifies that the finger print is not changed. - void TestIceRestart(bool dtls) { - if (dtls) { - f1_.set_secure(cricket::SEC_ENABLED); - f2_.set_secure(cricket::SEC_ENABLED); - f1_.set_identity(id1_.get()); - f2_.set_identity(id2_.get()); - } else { - f1_.set_secure(cricket::SEC_DISABLED); - f2_.set_secure(cricket::SEC_DISABLED); - } - - cricket::TransportOptions options; - // The initial offer / answer exchange. - rtc::scoped_ptr<TransportDescription> offer(f1_.CreateOffer( - options, NULL)); - rtc::scoped_ptr<TransportDescription> answer( - f2_.CreateAnswer(offer.get(), - options, NULL)); - - // Create an updated offer where we restart ice. - options.ice_restart = true; - rtc::scoped_ptr<TransportDescription> restart_offer(f1_.CreateOffer( - options, offer.get())); - - VerifyUfragAndPasswordChanged(dtls, offer.get(), restart_offer.get()); - - // Create a new answer. The transport ufrag and password is changed since - // |options.ice_restart == true| - rtc::scoped_ptr<TransportDescription> restart_answer( - f2_.CreateAnswer(restart_offer.get(), options, answer.get())); - ASSERT_TRUE(restart_answer.get() != NULL); - - VerifyUfragAndPasswordChanged(dtls, answer.get(), restart_answer.get()); - } - - void VerifyUfragAndPasswordChanged(bool dtls, - const TransportDescription* org_desc, - const TransportDescription* restart_desc) { - EXPECT_NE(org_desc->ice_pwd, restart_desc->ice_pwd); - EXPECT_NE(org_desc->ice_ufrag, restart_desc->ice_ufrag); - EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH), - restart_desc->ice_ufrag.size()); - EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH), - restart_desc->ice_pwd.size()); - // If DTLS is enabled, make sure the finger print is unchanged. - if (dtls) { - EXPECT_FALSE( - org_desc->identity_fingerprint->GetRfc4572Fingerprint().empty()); - EXPECT_EQ(org_desc->identity_fingerprint->GetRfc4572Fingerprint(), - restart_desc->identity_fingerprint->GetRfc4572Fingerprint()); - } - } - - protected: - TransportDescriptionFactory f1_; - TransportDescriptionFactory f2_; - scoped_ptr<rtc::SSLIdentity> id1_; - scoped_ptr<rtc::SSLIdentity> id2_; -}; - -// Test that in the default case, we generate the expected G-ICE offer. -TEST_F(TransportDescriptionFactoryTest, TestOfferGice) { - f1_.set_protocol(cricket::ICEPROTO_GOOGLE); - scoped_ptr<TransportDescription> desc(f1_.CreateOffer( - TransportOptions(), NULL)); - CheckDesc(desc.get(), cricket::NS_GINGLE_P2P, "", "", "", ""); -} - -// Test generating a hybrid offer. -TEST_F(TransportDescriptionFactoryTest, TestOfferHybrid) { - f1_.set_protocol(cricket::ICEPROTO_HYBRID); - scoped_ptr<TransportDescription> desc(f1_.CreateOffer( - TransportOptions(), NULL)); - CheckDesc(desc.get(), cricket::NS_JINGLE_ICE_UDP, "google-ice", "", "", ""); -} - -// Test generating an ICE-only offer. -TEST_F(TransportDescriptionFactoryTest, TestOfferIce) { - f1_.set_protocol(cricket::ICEPROTO_RFC5245); - scoped_ptr<TransportDescription> desc(f1_.CreateOffer( - TransportOptions(), NULL)); - CheckDesc(desc.get(), cricket::NS_JINGLE_ICE_UDP, "", "", "", ""); -} - -// Test generating a hybrid offer with DTLS. -TEST_F(TransportDescriptionFactoryTest, TestOfferHybridDtls) { - f1_.set_protocol(cricket::ICEPROTO_HYBRID); - f1_.set_secure(cricket::SEC_ENABLED); - f1_.set_identity(id1_.get()); - std::string digest_alg; - ASSERT_TRUE(id1_->certificate().GetSignatureDigestAlgorithm(&digest_alg)); - scoped_ptr<TransportDescription> desc(f1_.CreateOffer( - TransportOptions(), NULL)); - CheckDesc(desc.get(), cricket::NS_JINGLE_ICE_UDP, "google-ice", "", "", - digest_alg); - // Ensure it also works with SEC_REQUIRED. - f1_.set_secure(cricket::SEC_REQUIRED); - desc.reset(f1_.CreateOffer(TransportOptions(), NULL)); - CheckDesc(desc.get(), cricket::NS_JINGLE_ICE_UDP, "google-ice", "", "", - digest_alg); -} - -// Test generating a hybrid offer with DTLS fails with no identity. -TEST_F(TransportDescriptionFactoryTest, TestOfferHybridDtlsWithNoIdentity) { - f1_.set_protocol(cricket::ICEPROTO_HYBRID); - f1_.set_secure(cricket::SEC_ENABLED); - scoped_ptr<TransportDescription> desc(f1_.CreateOffer( - TransportOptions(), NULL)); - ASSERT_TRUE(desc.get() == NULL); -} - -// Test updating a hybrid offer with DTLS to pick ICE. -// The ICE credentials should stay the same in the new offer. -TEST_F(TransportDescriptionFactoryTest, TestOfferHybridDtlsReofferIceDtls) { - f1_.set_protocol(cricket::ICEPROTO_HYBRID); - f1_.set_secure(cricket::SEC_ENABLED); - f1_.set_identity(id1_.get()); - std::string digest_alg; - ASSERT_TRUE(id1_->certificate().GetSignatureDigestAlgorithm(&digest_alg)); - scoped_ptr<TransportDescription> old_desc(f1_.CreateOffer( - TransportOptions(), NULL)); - ASSERT_TRUE(old_desc.get() != NULL); - f1_.set_protocol(cricket::ICEPROTO_RFC5245); - scoped_ptr<TransportDescription> desc( - f1_.CreateOffer(TransportOptions(), old_desc.get())); - CheckDesc(desc.get(), cricket::NS_JINGLE_ICE_UDP, "", - old_desc->ice_ufrag, old_desc->ice_pwd, digest_alg); -} - -// Test that we can answer a GICE offer with GICE. -TEST_F(TransportDescriptionFactoryTest, TestAnswerGiceToGice) { - f1_.set_protocol(cricket::ICEPROTO_GOOGLE); - f2_.set_protocol(cricket::ICEPROTO_GOOGLE); - scoped_ptr<TransportDescription> offer(f1_.CreateOffer( - TransportOptions(), NULL)); - ASSERT_TRUE(offer.get() != NULL); - scoped_ptr<TransportDescription> desc(f2_.CreateAnswer( - offer.get(), TransportOptions(), NULL)); - CheckDesc(desc.get(), cricket::NS_GINGLE_P2P, "", "", "", ""); - // Should get the same result when answering as hybrid. - f2_.set_protocol(cricket::ICEPROTO_HYBRID); - desc.reset(f2_.CreateAnswer(offer.get(), TransportOptions(), - NULL)); - CheckDesc(desc.get(), cricket::NS_GINGLE_P2P, "", "", "", ""); -} - -// Test that we can answer a hybrid offer with GICE. -TEST_F(TransportDescriptionFactoryTest, TestAnswerGiceToHybrid) { - f1_.set_protocol(cricket::ICEPROTO_HYBRID); - f2_.set_protocol(cricket::ICEPROTO_GOOGLE); - scoped_ptr<TransportDescription> offer(f1_.CreateOffer( - TransportOptions(), NULL)); - ASSERT_TRUE(offer.get() != NULL); - scoped_ptr<TransportDescription> desc( - f2_.CreateAnswer(offer.get(), TransportOptions(), NULL)); - CheckDesc(desc.get(), cricket::NS_GINGLE_P2P, "", "", "", ""); -} - -// Test that we can answer a hybrid offer with ICE. -TEST_F(TransportDescriptionFactoryTest, TestAnswerIceToHybrid) { - f1_.set_protocol(cricket::ICEPROTO_HYBRID); - f2_.set_protocol(cricket::ICEPROTO_RFC5245); - scoped_ptr<TransportDescription> offer(f1_.CreateOffer( - TransportOptions(), NULL)); - ASSERT_TRUE(offer.get() != NULL); - scoped_ptr<TransportDescription> desc( - f2_.CreateAnswer(offer.get(), TransportOptions(), NULL)); - CheckDesc(desc.get(), cricket::NS_JINGLE_ICE_UDP, "", "", "", ""); - // Should get the same result when answering as hybrid. - f2_.set_protocol(cricket::ICEPROTO_HYBRID); - desc.reset(f2_.CreateAnswer(offer.get(), TransportOptions(), - NULL)); - CheckDesc(desc.get(), cricket::NS_JINGLE_ICE_UDP, "", "", "", ""); -} - -// Test that we can answer an ICE offer with ICE. -TEST_F(TransportDescriptionFactoryTest, TestAnswerIceToIce) { - f1_.set_protocol(cricket::ICEPROTO_RFC5245); - f2_.set_protocol(cricket::ICEPROTO_RFC5245); - scoped_ptr<TransportDescription> offer(f1_.CreateOffer( - TransportOptions(), NULL)); - ASSERT_TRUE(offer.get() != NULL); - scoped_ptr<TransportDescription> desc(f2_.CreateAnswer( - offer.get(), TransportOptions(), NULL)); - CheckDesc(desc.get(), cricket::NS_JINGLE_ICE_UDP, "", "", "", ""); - // Should get the same result when answering as hybrid. - f2_.set_protocol(cricket::ICEPROTO_HYBRID); - desc.reset(f2_.CreateAnswer(offer.get(), TransportOptions(), - NULL)); - CheckDesc(desc.get(), cricket::NS_JINGLE_ICE_UDP, "", "", "", ""); -} - -// Test that we can't answer a GICE offer with ICE. -TEST_F(TransportDescriptionFactoryTest, TestAnswerIceToGice) { - f1_.set_protocol(cricket::ICEPROTO_GOOGLE); - f2_.set_protocol(cricket::ICEPROTO_RFC5245); - scoped_ptr<TransportDescription> offer( - f1_.CreateOffer(TransportOptions(), NULL)); - ASSERT_TRUE(offer.get() != NULL); - scoped_ptr<TransportDescription> desc( - f2_.CreateAnswer(offer.get(), TransportOptions(), NULL)); - ASSERT_TRUE(desc.get() == NULL); -} - -// Test that we can't answer an ICE offer with GICE. -TEST_F(TransportDescriptionFactoryTest, TestAnswerGiceToIce) { - f1_.set_protocol(cricket::ICEPROTO_RFC5245); - f2_.set_protocol(cricket::ICEPROTO_GOOGLE); - scoped_ptr<TransportDescription> offer( - f1_.CreateOffer(TransportOptions(), NULL)); - ASSERT_TRUE(offer.get() != NULL); - scoped_ptr<TransportDescription> desc(f2_.CreateAnswer( - offer.get(), TransportOptions(), NULL)); - ASSERT_TRUE(desc.get() == NULL); -} - -// Test that we can update an answer properly; ICE credentials shouldn't change. -TEST_F(TransportDescriptionFactoryTest, TestAnswerIceToIceReanswer) { - f1_.set_protocol(cricket::ICEPROTO_RFC5245); - f2_.set_protocol(cricket::ICEPROTO_RFC5245); - scoped_ptr<TransportDescription> offer( - f1_.CreateOffer(TransportOptions(), NULL)); - ASSERT_TRUE(offer.get() != NULL); - scoped_ptr<TransportDescription> old_desc( - f2_.CreateAnswer(offer.get(), TransportOptions(), NULL)); - ASSERT_TRUE(old_desc.get() != NULL); - scoped_ptr<TransportDescription> desc( - f2_.CreateAnswer(offer.get(), TransportOptions(), - old_desc.get())); - ASSERT_TRUE(desc.get() != NULL); - CheckDesc(desc.get(), cricket::NS_JINGLE_ICE_UDP, "", - old_desc->ice_ufrag, old_desc->ice_pwd, ""); -} - -// Test that we handle answering an offer with DTLS with no DTLS. -TEST_F(TransportDescriptionFactoryTest, TestAnswerHybridToHybridDtls) { - f1_.set_protocol(cricket::ICEPROTO_HYBRID); - f1_.set_secure(cricket::SEC_ENABLED); - f1_.set_identity(id1_.get()); - f2_.set_protocol(cricket::ICEPROTO_HYBRID); - scoped_ptr<TransportDescription> offer( - f1_.CreateOffer(TransportOptions(), NULL)); - ASSERT_TRUE(offer.get() != NULL); - scoped_ptr<TransportDescription> desc( - f2_.CreateAnswer(offer.get(), TransportOptions(), NULL)); - CheckDesc(desc.get(), cricket::NS_JINGLE_ICE_UDP, "", "", "", ""); -} - -// Test that we handle answering an offer without DTLS if we have DTLS enabled, -// but fail if we require DTLS. -TEST_F(TransportDescriptionFactoryTest, TestAnswerHybridDtlsToHybrid) { - f1_.set_protocol(cricket::ICEPROTO_HYBRID); - f2_.set_protocol(cricket::ICEPROTO_HYBRID); - f2_.set_secure(cricket::SEC_ENABLED); - f2_.set_identity(id2_.get()); - scoped_ptr<TransportDescription> offer( - f1_.CreateOffer(TransportOptions(), NULL)); - ASSERT_TRUE(offer.get() != NULL); - scoped_ptr<TransportDescription> desc( - f2_.CreateAnswer(offer.get(), TransportOptions(), NULL)); - CheckDesc(desc.get(), cricket::NS_JINGLE_ICE_UDP, "", "", "", ""); - f2_.set_secure(cricket::SEC_REQUIRED); - desc.reset(f2_.CreateAnswer(offer.get(), TransportOptions(), - NULL)); - ASSERT_TRUE(desc.get() == NULL); -} - -// Test that we handle answering an DTLS offer with DTLS, both if we have -// DTLS enabled and required. -TEST_F(TransportDescriptionFactoryTest, TestAnswerHybridDtlsToHybridDtls) { - f1_.set_protocol(cricket::ICEPROTO_HYBRID); - f1_.set_secure(cricket::SEC_ENABLED); - f1_.set_identity(id1_.get()); - - f2_.set_protocol(cricket::ICEPROTO_HYBRID); - f2_.set_secure(cricket::SEC_ENABLED); - f2_.set_identity(id2_.get()); - // f2_ produces the answer that is being checked in this test, so the - // answer must contain fingerprint lines with id2_'s digest algorithm. - std::string digest_alg2; - ASSERT_TRUE(id2_->certificate().GetSignatureDigestAlgorithm(&digest_alg2)); - - scoped_ptr<TransportDescription> offer( - f1_.CreateOffer(TransportOptions(), NULL)); - ASSERT_TRUE(offer.get() != NULL); - scoped_ptr<TransportDescription> desc( - f2_.CreateAnswer(offer.get(), TransportOptions(), NULL)); - CheckDesc(desc.get(), cricket::NS_JINGLE_ICE_UDP, "", "", "", digest_alg2); - f2_.set_secure(cricket::SEC_REQUIRED); - desc.reset(f2_.CreateAnswer(offer.get(), TransportOptions(), - NULL)); - CheckDesc(desc.get(), cricket::NS_JINGLE_ICE_UDP, "", "", "", digest_alg2); -} - -// Test that ice ufrag and password is changed in an updated offer and answer -// if |TransportDescriptionOptions::ice_restart| is true. -TEST_F(TransportDescriptionFactoryTest, TestIceRestart) { - TestIceRestart(false); -} - -// Test that ice ufrag and password is changed in an updated offer and answer -// if |TransportDescriptionOptions::ice_restart| is true and DTLS is enabled. -TEST_F(TransportDescriptionFactoryTest, TestIceRestartWithDtls) { - TestIceRestart(true); -} diff --git a/talk/p2p/base/transportinfo.h b/talk/p2p/base/transportinfo.h deleted file mode 100644 index 414b6caf6..000000000 --- a/talk/p2p/base/transportinfo.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * libjingle - * Copyright 2012, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef WEBRTC_P2P_BASE_TRANSPORTINFO_H_ -#define WEBRTC_P2P_BASE_TRANSPORTINFO_H_ - -#include <string> -#include <vector> - -#include "webrtc/p2p/base/candidate.h" -#include "webrtc/p2p/base/constants.h" -#include "webrtc/p2p/base/transportdescription.h" -#include "webrtc/base/helpers.h" - -namespace cricket { - -// A TransportInfo is NOT a transport-info message. It is comparable -// to a "ContentInfo". A transport-infos message is basically just a -// collection of TransportInfos. -struct TransportInfo { - TransportInfo() {} - - TransportInfo(const std::string& content_name, - const TransportDescription& description) - : content_name(content_name), - description(description) {} - - std::string content_name; - TransportDescription description; -}; - -typedef std::vector<TransportInfo> TransportInfos; - -} // namespace cricket - -#endif // WEBRTC_P2P_BASE_TRANSPORTINFO_H_ diff --git a/talk/p2p/base/turnport.cc b/talk/p2p/base/turnport.cc deleted file mode 100644 index b38317b81..000000000 --- a/talk/p2p/base/turnport.cc +++ /dev/null @@ -1,1213 +0,0 @@ -/* - * libjingle - * Copyright 2012, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "webrtc/p2p/base/turnport.h" - -#include <functional> - -#include "webrtc/p2p/base/common.h" -#include "webrtc/p2p/base/stun.h" -#include "webrtc/base/asyncpacketsocket.h" -#include "webrtc/base/byteorder.h" -#include "webrtc/base/common.h" -#include "webrtc/base/logging.h" -#include "webrtc/base/nethelpers.h" -#include "webrtc/base/socketaddress.h" -#include "webrtc/base/stringencode.h" - -namespace cricket { - -// TODO(juberti): Move to stun.h when relay messages have been renamed. -static const int TURN_ALLOCATE_REQUEST = STUN_ALLOCATE_REQUEST; - -// TODO(juberti): Extract to turnmessage.h -static const int TURN_DEFAULT_PORT = 3478; -static const int TURN_CHANNEL_NUMBER_START = 0x4000; -static const int TURN_PERMISSION_TIMEOUT = 5 * 60 * 1000; // 5 minutes - -static const size_t TURN_CHANNEL_HEADER_SIZE = 4U; - -// Retry at most twice (i.e. three different ALLOCATE requests) on -// STUN_ERROR_ALLOCATION_MISMATCH error per rfc5766. -static const size_t MAX_ALLOCATE_MISMATCH_RETRIES = 2; - -inline bool IsTurnChannelData(uint16 msg_type) { - return ((msg_type & 0xC000) == 0x4000); // MSB are 0b01 -} - -static int GetRelayPreference(cricket::ProtocolType proto, bool secure) { - int relay_preference = ICE_TYPE_PREFERENCE_RELAY; - if (proto == cricket::PROTO_TCP) { - relay_preference -= 1; - if (secure) - relay_preference -= 1; - } - - ASSERT(relay_preference >= 0); - return relay_preference; -} - -class TurnAllocateRequest : public StunRequest { - public: - explicit TurnAllocateRequest(TurnPort* port); - virtual void Prepare(StunMessage* request); - virtual void OnResponse(StunMessage* response); - virtual void OnErrorResponse(StunMessage* response); - virtual void OnTimeout(); - - private: - // Handles authentication challenge from the server. - void OnAuthChallenge(StunMessage* response, int code); - void OnTryAlternate(StunMessage* response, int code); - void OnUnknownAttribute(StunMessage* response); - - TurnPort* port_; -}; - -class TurnRefreshRequest : public StunRequest { - public: - explicit TurnRefreshRequest(TurnPort* port); - virtual void Prepare(StunMessage* request); - virtual void OnResponse(StunMessage* response); - virtual void OnErrorResponse(StunMessage* response); - virtual void OnTimeout(); - - private: - TurnPort* port_; -}; - -class TurnCreatePermissionRequest : public StunRequest, - public sigslot::has_slots<> { - public: - TurnCreatePermissionRequest(TurnPort* port, TurnEntry* entry, - const rtc::SocketAddress& ext_addr); - virtual void Prepare(StunMessage* request); - virtual void OnResponse(StunMessage* response); - virtual void OnErrorResponse(StunMessage* response); - virtual void OnTimeout(); - - private: - void OnEntryDestroyed(TurnEntry* entry); - - TurnPort* port_; - TurnEntry* entry_; - rtc::SocketAddress ext_addr_; -}; - -class TurnChannelBindRequest : public StunRequest, - public sigslot::has_slots<> { - public: - TurnChannelBindRequest(TurnPort* port, TurnEntry* entry, int channel_id, - const rtc::SocketAddress& ext_addr); - virtual void Prepare(StunMessage* request); - virtual void OnResponse(StunMessage* response); - virtual void OnErrorResponse(StunMessage* response); - virtual void OnTimeout(); - - private: - void OnEntryDestroyed(TurnEntry* entry); - - TurnPort* port_; - TurnEntry* entry_; - int channel_id_; - rtc::SocketAddress ext_addr_; -}; - -// Manages a "connection" to a remote destination. We will attempt to bring up -// a channel for this remote destination to reduce the overhead of sending data. -class TurnEntry : public sigslot::has_slots<> { - public: - enum BindState { STATE_UNBOUND, STATE_BINDING, STATE_BOUND }; - TurnEntry(TurnPort* port, int channel_id, - const rtc::SocketAddress& ext_addr); - - TurnPort* port() { return port_; } - - int channel_id() const { return channel_id_; } - const rtc::SocketAddress& address() const { return ext_addr_; } - BindState state() const { return state_; } - - // Helper methods to send permission and channel bind requests. - void SendCreatePermissionRequest(); - void SendChannelBindRequest(int delay); - // Sends a packet to the given destination address. - // This will wrap the packet in STUN if necessary. - int Send(const void* data, size_t size, bool payload, - const rtc::PacketOptions& options); - - void OnCreatePermissionSuccess(); - void OnCreatePermissionError(StunMessage* response, int code); - void OnChannelBindSuccess(); - void OnChannelBindError(StunMessage* response, int code); - // Signal sent when TurnEntry is destroyed. - sigslot::signal1<TurnEntry*> SignalDestroyed; - - private: - TurnPort* port_; - int channel_id_; - rtc::SocketAddress ext_addr_; - BindState state_; -}; - -TurnPort::TurnPort(rtc::Thread* thread, - rtc::PacketSocketFactory* factory, - rtc::Network* network, - rtc::AsyncPacketSocket* socket, - const std::string& username, - const std::string& password, - const ProtocolAddress& server_address, - const RelayCredentials& credentials, - int server_priority) - : Port(thread, factory, network, socket->GetLocalAddress().ipaddr(), - username, password), - server_address_(server_address), - credentials_(credentials), - socket_(socket), - resolver_(NULL), - error_(0), - request_manager_(thread), - next_channel_number_(TURN_CHANNEL_NUMBER_START), - connected_(false), - server_priority_(server_priority), - allocate_mismatch_retries_(0) { - request_manager_.SignalSendPacket.connect(this, &TurnPort::OnSendStunPacket); -} - -TurnPort::TurnPort(rtc::Thread* thread, - rtc::PacketSocketFactory* factory, - rtc::Network* network, - const rtc::IPAddress& ip, - int min_port, int max_port, - const std::string& username, - const std::string& password, - const ProtocolAddress& server_address, - const RelayCredentials& credentials, - int server_priority) - : Port(thread, RELAY_PORT_TYPE, factory, network, ip, min_port, max_port, - username, password), - server_address_(server_address), - credentials_(credentials), - socket_(NULL), - resolver_(NULL), - error_(0), - request_manager_(thread), - next_channel_number_(TURN_CHANNEL_NUMBER_START), - connected_(false), - server_priority_(server_priority), - allocate_mismatch_retries_(0) { - request_manager_.SignalSendPacket.connect(this, &TurnPort::OnSendStunPacket); -} - -TurnPort::~TurnPort() { - // TODO(juberti): Should this even be necessary? - while (!entries_.empty()) { - DestroyEntry(entries_.front()->address()); - } - if (resolver_) { - resolver_->Destroy(false); - } - if (!SharedSocket()) { - delete socket_; - } -} - -void TurnPort::PrepareAddress() { - if (credentials_.username.empty() || - credentials_.password.empty()) { - LOG(LS_ERROR) << "Allocation can't be started without setting the" - << " TURN server credentials for the user."; - OnAllocateError(); - return; - } - - if (!server_address_.address.port()) { - // We will set default TURN port, if no port is set in the address. - server_address_.address.SetPort(TURN_DEFAULT_PORT); - } - - if (server_address_.address.IsUnresolved()) { - ResolveTurnAddress(server_address_.address); - } else { - // If protocol family of server address doesn't match with local, return. - if (!IsCompatibleAddress(server_address_.address)) { - LOG(LS_ERROR) << "Server IP address family does not match with " - << "local host address family type"; - OnAllocateError(); - return; - } - - // Insert the current address to prevent redirection pingpong. - attempted_server_addresses_.insert(server_address_.address); - - LOG_J(LS_INFO, this) << "Trying to connect to TURN server via " - << ProtoToString(server_address_.proto) << " @ " - << server_address_.address.ToSensitiveString(); - if (!CreateTurnClientSocket()) { - OnAllocateError(); - } else if (server_address_.proto == PROTO_UDP) { - // If its UDP, send AllocateRequest now. - // For TCP and TLS AllcateRequest will be sent by OnSocketConnect. - SendRequest(new TurnAllocateRequest(this), 0); - } - } -} - -bool TurnPort::CreateTurnClientSocket() { - ASSERT(!socket_ || SharedSocket()); - - if (server_address_.proto == PROTO_UDP && !SharedSocket()) { - socket_ = socket_factory()->CreateUdpSocket( - rtc::SocketAddress(ip(), 0), min_port(), max_port()); - } else if (server_address_.proto == PROTO_TCP) { - ASSERT(!SharedSocket()); - int opts = rtc::PacketSocketFactory::OPT_STUN; - // If secure bit is enabled in server address, use TLS over TCP. - if (server_address_.secure) { - opts |= rtc::PacketSocketFactory::OPT_TLS; - } - socket_ = socket_factory()->CreateClientTcpSocket( - rtc::SocketAddress(ip(), 0), server_address_.address, - proxy(), user_agent(), opts); - } - - if (!socket_) { - error_ = SOCKET_ERROR; - return false; - } - - // Apply options if any. - for (SocketOptionsMap::iterator iter = socket_options_.begin(); - iter != socket_options_.end(); ++iter) { - socket_->SetOption(iter->first, iter->second); - } - - if (!SharedSocket()) { - // If socket is shared, AllocationSequence will receive the packet. - socket_->SignalReadPacket.connect(this, &TurnPort::OnReadPacket); - } - - socket_->SignalReadyToSend.connect(this, &TurnPort::OnReadyToSend); - - if (server_address_.proto == PROTO_TCP) { - socket_->SignalConnect.connect(this, &TurnPort::OnSocketConnect); - socket_->SignalClose.connect(this, &TurnPort::OnSocketClose); - } - return true; -} - -void TurnPort::OnSocketConnect(rtc::AsyncPacketSocket* socket) { - ASSERT(server_address_.proto == PROTO_TCP); - // Do not use this port if the socket bound to a different address than - // the one we asked for. This is seen in Chrome, where TCP sockets cannot be - // given a binding address, and the platform is expected to pick the - // correct local address. - if (socket->GetLocalAddress().ipaddr() != ip()) { - LOG(LS_WARNING) << "Socket is bound to a different address then the " - << "local port. Discarding TURN port."; - OnAllocateError(); - return; - } - - if (server_address_.address.IsUnresolved()) { - server_address_.address = socket_->GetRemoteAddress(); - } - - LOG(LS_INFO) << "TurnPort connected to " << socket->GetRemoteAddress() - << " using tcp."; - SendRequest(new TurnAllocateRequest(this), 0); -} - -void TurnPort::OnSocketClose(rtc::AsyncPacketSocket* socket, int error) { - LOG_J(LS_WARNING, this) << "Connection with server failed, error=" << error; - if (!connected_) { - OnAllocateError(); - } -} - -void TurnPort::OnAllocateMismatch() { - if (allocate_mismatch_retries_ >= MAX_ALLOCATE_MISMATCH_RETRIES) { - LOG_J(LS_WARNING, this) << "Giving up on the port after " - << allocate_mismatch_retries_ - << " retries for STUN_ERROR_ALLOCATION_MISMATCH"; - OnAllocateError(); - return; - } - - LOG_J(LS_INFO, this) << "Allocating a new socket after " - << "STUN_ERROR_ALLOCATION_MISMATCH, retry = " - << allocate_mismatch_retries_ + 1; - if (SharedSocket()) { - ResetSharedSocket(); - } else { - delete socket_; - } - socket_ = NULL; - - PrepareAddress(); - ++allocate_mismatch_retries_; -} - -Connection* TurnPort::CreateConnection(const Candidate& address, - CandidateOrigin origin) { - // TURN-UDP can only connect to UDP candidates. - if (address.protocol() != UDP_PROTOCOL_NAME) { - return NULL; - } - - if (!IsCompatibleAddress(address.address())) { - return NULL; - } - - // Create an entry, if needed, so we can get our permissions set up correctly. - CreateEntry(address.address()); - - // A TURN port will have two candiates, STUN and TURN. STUN may not - // present in all cases. If present stun candidate will be added first - // and TURN candidate later. - for (size_t index = 0; index < Candidates().size(); ++index) { - if (Candidates()[index].type() == RELAY_PORT_TYPE) { - ProxyConnection* conn = new ProxyConnection(this, index, address); - conn->SignalDestroyed.connect(this, &TurnPort::OnConnectionDestroyed); - AddConnection(conn); - return conn; - } - } - return NULL; -} - -int TurnPort::SetOption(rtc::Socket::Option opt, int value) { - if (!socket_) { - // If socket is not created yet, these options will be applied during socket - // creation. - socket_options_[opt] = value; - return 0; - } - return socket_->SetOption(opt, value); -} - -int TurnPort::GetOption(rtc::Socket::Option opt, int* value) { - if (!socket_) { - SocketOptionsMap::const_iterator it = socket_options_.find(opt); - if (it == socket_options_.end()) { - return -1; - } - *value = it->second; - return 0; - } - - return socket_->GetOption(opt, value); -} - -int TurnPort::GetError() { - return error_; -} - -int TurnPort::SendTo(const void* data, size_t size, - const rtc::SocketAddress& addr, - const rtc::PacketOptions& options, - bool payload) { - // Try to find an entry for this specific address; we should have one. - TurnEntry* entry = FindEntry(addr); - ASSERT(entry != NULL); - if (!entry) { - return 0; - } - - if (!connected()) { - error_ = EWOULDBLOCK; - return SOCKET_ERROR; - } - - // Send the actual contents to the server using the usual mechanism. - int sent = entry->Send(data, size, payload, options); - if (sent <= 0) { - return SOCKET_ERROR; - } - - // The caller of the function is expecting the number of user data bytes, - // rather than the size of the packet. - return static_cast<int>(size); -} - -void TurnPort::OnReadPacket( - rtc::AsyncPacketSocket* socket, const char* data, size_t size, - const rtc::SocketAddress& remote_addr, - const rtc::PacketTime& packet_time) { - ASSERT(socket == socket_); - ASSERT(remote_addr == server_address_.address); - - // The message must be at least the size of a channel header. - if (size < TURN_CHANNEL_HEADER_SIZE) { - LOG_J(LS_WARNING, this) << "Received TURN message that was too short"; - return; - } - - // Check the message type, to see if is a Channel Data message. - // The message will either be channel data, a TURN data indication, or - // a response to a previous request. - uint16 msg_type = rtc::GetBE16(data); - if (IsTurnChannelData(msg_type)) { - HandleChannelData(msg_type, data, size, packet_time); - } else if (msg_type == TURN_DATA_INDICATION) { - HandleDataIndication(data, size, packet_time); - } else { - // This must be a response for one of our requests. - // Check success responses, but not errors, for MESSAGE-INTEGRITY. - if (IsStunSuccessResponseType(msg_type) && - !StunMessage::ValidateMessageIntegrity(data, size, hash())) { - LOG_J(LS_WARNING, this) << "Received TURN message with invalid " - << "message integrity, msg_type=" << msg_type; - return; - } - request_manager_.CheckResponse(data, size); - } -} - -void TurnPort::OnReadyToSend(rtc::AsyncPacketSocket* socket) { - if (connected_) { - Port::OnReadyToSend(); - } -} - - -// Update current server address port with the alternate server address port. -bool TurnPort::SetAlternateServer(const rtc::SocketAddress& address) { - // Check if we have seen this address before and reject if we did. - AttemptedServerSet::iterator iter = attempted_server_addresses_.find(address); - if (iter != attempted_server_addresses_.end()) { - LOG_J(LS_WARNING, this) << "Redirection to [" - << address.ToSensitiveString() - << "] ignored, allocation failed."; - return false; - } - - // If protocol family of server address doesn't match with local, return. - if (!IsCompatibleAddress(address)) { - LOG(LS_WARNING) << "Server IP address family does not match with " - << "local host address family type"; - return false; - } - - LOG_J(LS_INFO, this) << "Redirecting from TURN server [" - << server_address_.address.ToSensitiveString() - << "] to TURN server [" - << address.ToSensitiveString() - << "]"; - server_address_ = ProtocolAddress(address, server_address_.proto, - server_address_.secure); - - // Insert the current address to prevent redirection pingpong. - attempted_server_addresses_.insert(server_address_.address); - return true; -} - -void TurnPort::ResolveTurnAddress(const rtc::SocketAddress& address) { - if (resolver_) - return; - - resolver_ = socket_factory()->CreateAsyncResolver(); - resolver_->SignalDone.connect(this, &TurnPort::OnResolveResult); - resolver_->Start(address); -} - -void TurnPort::OnResolveResult(rtc::AsyncResolverInterface* resolver) { - ASSERT(resolver == resolver_); - // If DNS resolve is failed when trying to connect to the server using TCP, - // one of the reason could be due to DNS queries blocked by firewall. - // In such cases we will try to connect to the server with hostname, assuming - // socket layer will resolve the hostname through a HTTP proxy (if any). - if (resolver_->GetError() != 0 && server_address_.proto == PROTO_TCP) { - if (!CreateTurnClientSocket()) { - OnAllocateError(); - } - return; - } - - // Copy the original server address in |resolved_address|. For TLS based - // sockets we need hostname along with resolved address. - rtc::SocketAddress resolved_address = server_address_.address; - if (resolver_->GetError() != 0 || - !resolver_->GetResolvedAddress(ip().family(), &resolved_address)) { - LOG_J(LS_WARNING, this) << "TURN host lookup received error " - << resolver_->GetError(); - error_ = resolver_->GetError(); - OnAllocateError(); - return; - } - // Signal needs both resolved and unresolved address. After signal is sent - // we can copy resolved address back into |server_address_|. - SignalResolvedServerAddress(this, server_address_.address, - resolved_address); - server_address_.address = resolved_address; - PrepareAddress(); -} - -void TurnPort::OnSendStunPacket(const void* data, size_t size, - StunRequest* request) { - rtc::PacketOptions options(DefaultDscpValue()); - if (Send(data, size, options) < 0) { - LOG_J(LS_ERROR, this) << "Failed to send TURN message, err=" - << socket_->GetError(); - } -} - -void TurnPort::OnStunAddress(const rtc::SocketAddress& address) { - // STUN Port will discover STUN candidate, as it's supplied with first TURN - // server address. - // Why not using this address? - P2PTransportChannel will start creating - // connections after first candidate, which means it could start creating the - // connections before TURN candidate added. For that to handle, we need to - // supply STUN candidate from this port to UDPPort, and TurnPort should have - // handle to UDPPort to pass back the address. -} - -void TurnPort::OnAllocateSuccess(const rtc::SocketAddress& address, - const rtc::SocketAddress& stun_address) { - connected_ = true; - - rtc::SocketAddress related_address = stun_address; - if (!(candidate_filter() & CF_REFLEXIVE)) { - // If candidate filter only allows relay type of address, empty raddr to - // avoid local address leakage. - related_address = rtc::EmptySocketAddressWithFamily(stun_address.family()); - } - - // For relayed candidate, Base is the candidate itself. - AddAddress(address, // Candidate address. - address, // Base address. - related_address, // Related address. - UDP_PROTOCOL_NAME, - "", // TCP canddiate type, empty for turn candidates. - RELAY_PORT_TYPE, - GetRelayPreference(server_address_.proto, server_address_.secure), - server_priority_, - true); -} - -void TurnPort::OnAllocateError() { - // We will send SignalPortError asynchronously as this can be sent during - // port initialization. This way it will not be blocking other port - // creation. - thread()->Post(this, MSG_ERROR); -} - -void TurnPort::OnMessage(rtc::Message* message) { - if (message->message_id == MSG_ERROR) { - SignalPortError(this); - return; - } else if (message->message_id == MSG_ALLOCATE_MISMATCH) { - OnAllocateMismatch(); - return; - } - - Port::OnMessage(message); -} - -void TurnPort::OnAllocateRequestTimeout() { - OnAllocateError(); -} - -void TurnPort::HandleDataIndication(const char* data, size_t size, - const rtc::PacketTime& packet_time) { - // Read in the message, and process according to RFC5766, Section 10.4. - rtc::ByteBuffer buf(data, size); - TurnMessage msg; - if (!msg.Read(&buf)) { - LOG_J(LS_WARNING, this) << "Received invalid TURN data indication"; - return; - } - - // Check mandatory attributes. - const StunAddressAttribute* addr_attr = - msg.GetAddress(STUN_ATTR_XOR_PEER_ADDRESS); - if (!addr_attr) { - LOG_J(LS_WARNING, this) << "Missing STUN_ATTR_XOR_PEER_ADDRESS attribute " - << "in data indication."; - return; - } - - const StunByteStringAttribute* data_attr = - msg.GetByteString(STUN_ATTR_DATA); - if (!data_attr) { - LOG_J(LS_WARNING, this) << "Missing STUN_ATTR_DATA attribute in " - << "data indication."; - return; - } - - // Verify that the data came from somewhere we think we have a permission for. - rtc::SocketAddress ext_addr(addr_attr->GetAddress()); - if (!HasPermission(ext_addr.ipaddr())) { - LOG_J(LS_WARNING, this) << "Received TURN data indication with invalid " - << "peer address, addr=" - << ext_addr.ToSensitiveString(); - return; - } - - DispatchPacket(data_attr->bytes(), data_attr->length(), ext_addr, - PROTO_UDP, packet_time); -} - -void TurnPort::HandleChannelData(int channel_id, const char* data, - size_t size, - const rtc::PacketTime& packet_time) { - // Read the message, and process according to RFC5766, Section 11.6. - // 0 1 2 3 - // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - // | Channel Number | Length | - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - // | | - // / Application Data / - // / / - // | | - // | +-------------------------------+ - // | | - // +-------------------------------+ - - // Extract header fields from the message. - uint16 len = rtc::GetBE16(data + 2); - if (len > size - TURN_CHANNEL_HEADER_SIZE) { - LOG_J(LS_WARNING, this) << "Received TURN channel data message with " - << "incorrect length, len=" << len; - return; - } - // Allowing messages larger than |len|, as ChannelData can be padded. - - TurnEntry* entry = FindEntry(channel_id); - if (!entry) { - LOG_J(LS_WARNING, this) << "Received TURN channel data message for invalid " - << "channel, channel_id=" << channel_id; - return; - } - - DispatchPacket(data + TURN_CHANNEL_HEADER_SIZE, len, entry->address(), - PROTO_UDP, packet_time); -} - -void TurnPort::DispatchPacket(const char* data, size_t size, - const rtc::SocketAddress& remote_addr, - ProtocolType proto, const rtc::PacketTime& packet_time) { - if (Connection* conn = GetConnection(remote_addr)) { - conn->OnReadPacket(data, size, packet_time); - } else { - Port::OnReadPacket(data, size, remote_addr, proto); - } -} - -bool TurnPort::ScheduleRefresh(int lifetime) { - // Lifetime is in seconds; we schedule a refresh for one minute less. - if (lifetime < 2 * 60) { - LOG_J(LS_WARNING, this) << "Received response with lifetime that was " - << "too short, lifetime=" << lifetime; - return false; - } - - SendRequest(new TurnRefreshRequest(this), (lifetime - 60) * 1000); - return true; -} - -void TurnPort::SendRequest(StunRequest* req, int delay) { - request_manager_.SendDelayed(req, delay); -} - -void TurnPort::AddRequestAuthInfo(StunMessage* msg) { - // If we've gotten the necessary data from the server, add it to our request. - VERIFY(!hash_.empty()); - VERIFY(msg->AddAttribute(new StunByteStringAttribute( - STUN_ATTR_USERNAME, credentials_.username))); - VERIFY(msg->AddAttribute(new StunByteStringAttribute( - STUN_ATTR_REALM, realm_))); - VERIFY(msg->AddAttribute(new StunByteStringAttribute( - STUN_ATTR_NONCE, nonce_))); - VERIFY(msg->AddMessageIntegrity(hash())); -} - -int TurnPort::Send(const void* data, size_t len, - const rtc::PacketOptions& options) { - return socket_->SendTo(data, len, server_address_.address, options); -} - -void TurnPort::UpdateHash() { - VERIFY(ComputeStunCredentialHash(credentials_.username, realm_, - credentials_.password, &hash_)); -} - -bool TurnPort::UpdateNonce(StunMessage* response) { - // When stale nonce error received, we should update - // hash and store realm and nonce. - // Check the mandatory attributes. - const StunByteStringAttribute* realm_attr = - response->GetByteString(STUN_ATTR_REALM); - if (!realm_attr) { - LOG(LS_ERROR) << "Missing STUN_ATTR_REALM attribute in " - << "stale nonce error response."; - return false; - } - set_realm(realm_attr->GetString()); - - const StunByteStringAttribute* nonce_attr = - response->GetByteString(STUN_ATTR_NONCE); - if (!nonce_attr) { - LOG(LS_ERROR) << "Missing STUN_ATTR_NONCE attribute in " - << "stale nonce error response."; - return false; - } - set_nonce(nonce_attr->GetString()); - return true; -} - -static bool MatchesIP(TurnEntry* e, rtc::IPAddress ipaddr) { - return e->address().ipaddr() == ipaddr; -} -bool TurnPort::HasPermission(const rtc::IPAddress& ipaddr) const { - return (std::find_if(entries_.begin(), entries_.end(), - std::bind2nd(std::ptr_fun(MatchesIP), ipaddr)) != entries_.end()); -} - -static bool MatchesAddress(TurnEntry* e, rtc::SocketAddress addr) { - return e->address() == addr; -} -TurnEntry* TurnPort::FindEntry(const rtc::SocketAddress& addr) const { - EntryList::const_iterator it = std::find_if(entries_.begin(), entries_.end(), - std::bind2nd(std::ptr_fun(MatchesAddress), addr)); - return (it != entries_.end()) ? *it : NULL; -} - -static bool MatchesChannelId(TurnEntry* e, int id) { - return e->channel_id() == id; -} -TurnEntry* TurnPort::FindEntry(int channel_id) const { - EntryList::const_iterator it = std::find_if(entries_.begin(), entries_.end(), - std::bind2nd(std::ptr_fun(MatchesChannelId), channel_id)); - return (it != entries_.end()) ? *it : NULL; -} - -TurnEntry* TurnPort::CreateEntry(const rtc::SocketAddress& addr) { - ASSERT(FindEntry(addr) == NULL); - TurnEntry* entry = new TurnEntry(this, next_channel_number_++, addr); - entries_.push_back(entry); - return entry; -} - -void TurnPort::DestroyEntry(const rtc::SocketAddress& addr) { - TurnEntry* entry = FindEntry(addr); - ASSERT(entry != NULL); - entry->SignalDestroyed(entry); - entries_.remove(entry); - delete entry; -} - -void TurnPort::OnConnectionDestroyed(Connection* conn) { - // Destroying TurnEntry for the connection, which is already destroyed. - DestroyEntry(conn->remote_candidate().address()); -} - -TurnAllocateRequest::TurnAllocateRequest(TurnPort* port) - : StunRequest(new TurnMessage()), - port_(port) { -} - -void TurnAllocateRequest::Prepare(StunMessage* request) { - // Create the request as indicated in RFC 5766, Section 6.1. - request->SetType(TURN_ALLOCATE_REQUEST); - StunUInt32Attribute* transport_attr = StunAttribute::CreateUInt32( - STUN_ATTR_REQUESTED_TRANSPORT); - transport_attr->SetValue(IPPROTO_UDP << 24); - VERIFY(request->AddAttribute(transport_attr)); - if (!port_->hash().empty()) { - port_->AddRequestAuthInfo(request); - } -} - -void TurnAllocateRequest::OnResponse(StunMessage* response) { - // Check mandatory attributes as indicated in RFC5766, Section 6.3. - const StunAddressAttribute* mapped_attr = - response->GetAddress(STUN_ATTR_XOR_MAPPED_ADDRESS); - if (!mapped_attr) { - LOG_J(LS_WARNING, port_) << "Missing STUN_ATTR_XOR_MAPPED_ADDRESS " - << "attribute in allocate success response"; - return; - } - // Using XOR-Mapped-Address for stun. - port_->OnStunAddress(mapped_attr->GetAddress()); - - const StunAddressAttribute* relayed_attr = - response->GetAddress(STUN_ATTR_XOR_RELAYED_ADDRESS); - if (!relayed_attr) { - LOG_J(LS_WARNING, port_) << "Missing STUN_ATTR_XOR_RELAYED_ADDRESS " - << "attribute in allocate success response"; - return; - } - - const StunUInt32Attribute* lifetime_attr = - response->GetUInt32(STUN_ATTR_TURN_LIFETIME); - if (!lifetime_attr) { - LOG_J(LS_WARNING, port_) << "Missing STUN_ATTR_TURN_LIFETIME attribute in " - << "allocate success response"; - return; - } - // Notify the port the allocate succeeded, and schedule a refresh request. - port_->OnAllocateSuccess(relayed_attr->GetAddress(), - mapped_attr->GetAddress()); - port_->ScheduleRefresh(lifetime_attr->value()); -} - -void TurnAllocateRequest::OnErrorResponse(StunMessage* response) { - // Process error response according to RFC5766, Section 6.4. - const StunErrorCodeAttribute* error_code = response->GetErrorCode(); - switch (error_code->code()) { - case STUN_ERROR_UNAUTHORIZED: // Unauthrorized. - OnAuthChallenge(response, error_code->code()); - break; - case STUN_ERROR_TRY_ALTERNATE: - OnTryAlternate(response, error_code->code()); - break; - case STUN_ERROR_ALLOCATION_MISMATCH: - // We must handle this error async because trying to delete the socket in - // OnErrorResponse will cause a deadlock on the socket. - port_->thread()->Post(port_, TurnPort::MSG_ALLOCATE_MISMATCH); - break; - default: - LOG_J(LS_WARNING, port_) << "Allocate response error, code=" - << error_code->code(); - port_->OnAllocateError(); - } -} - -void TurnAllocateRequest::OnTimeout() { - LOG_J(LS_WARNING, port_) << "Allocate request timeout"; - port_->OnAllocateRequestTimeout(); -} - -void TurnAllocateRequest::OnAuthChallenge(StunMessage* response, int code) { - // If we failed to authenticate even after we sent our credentials, fail hard. - if (code == STUN_ERROR_UNAUTHORIZED && !port_->hash().empty()) { - LOG_J(LS_WARNING, port_) << "Failed to authenticate with the server " - << "after challenge."; - port_->OnAllocateError(); - return; - } - - // Check the mandatory attributes. - const StunByteStringAttribute* realm_attr = - response->GetByteString(STUN_ATTR_REALM); - if (!realm_attr) { - LOG_J(LS_WARNING, port_) << "Missing STUN_ATTR_REALM attribute in " - << "allocate unauthorized response."; - return; - } - port_->set_realm(realm_attr->GetString()); - - const StunByteStringAttribute* nonce_attr = - response->GetByteString(STUN_ATTR_NONCE); - if (!nonce_attr) { - LOG_J(LS_WARNING, port_) << "Missing STUN_ATTR_NONCE attribute in " - << "allocate unauthorized response."; - return; - } - port_->set_nonce(nonce_attr->GetString()); - - // Send another allocate request, with the received realm and nonce values. - port_->SendRequest(new TurnAllocateRequest(port_), 0); -} - -void TurnAllocateRequest::OnTryAlternate(StunMessage* response, int code) { - // TODO(guoweis): Currently, we only support UDP redirect - if (port_->server_address().proto != PROTO_UDP) { - LOG_J(LS_WARNING, port_) << "Receiving 300 Alternate Server on non-UDP " - << "allocating request from [" - << port_->server_address().address.ToSensitiveString() - << "], failed as currently not supported"; - port_->OnAllocateError(); - return; - } - - // According to RFC 5389 section 11, there are use cases where - // authentication of response is not possible, we're not validating - // message integrity. - - // Get the alternate server address attribute value. - const StunAddressAttribute* alternate_server_attr = - response->GetAddress(STUN_ATTR_ALTERNATE_SERVER); - if (!alternate_server_attr) { - LOG_J(LS_WARNING, port_) << "Missing STUN_ATTR_ALTERNATE_SERVER " - << "attribute in try alternate error response"; - port_->OnAllocateError(); - return; - } - if (!port_->SetAlternateServer(alternate_server_attr->GetAddress())) { - port_->OnAllocateError(); - return; - } - - // Check the attributes. - const StunByteStringAttribute* realm_attr = - response->GetByteString(STUN_ATTR_REALM); - if (realm_attr) { - LOG_J(LS_INFO, port_) << "Applying STUN_ATTR_REALM attribute in " - << "try alternate error response."; - port_->set_realm(realm_attr->GetString()); - } - - const StunByteStringAttribute* nonce_attr = - response->GetByteString(STUN_ATTR_NONCE); - if (nonce_attr) { - LOG_J(LS_INFO, port_) << "Applying STUN_ATTR_NONCE attribute in " - << "try alternate error response."; - port_->set_nonce(nonce_attr->GetString()); - } - - // Send another allocate request to alternate server, - // with the received realm and nonce values. - port_->SendRequest(new TurnAllocateRequest(port_), 0); -} - -TurnRefreshRequest::TurnRefreshRequest(TurnPort* port) - : StunRequest(new TurnMessage()), - port_(port) { -} - -void TurnRefreshRequest::Prepare(StunMessage* request) { - // Create the request as indicated in RFC 5766, Section 7.1. - // No attributes need to be included. - request->SetType(TURN_REFRESH_REQUEST); - port_->AddRequestAuthInfo(request); -} - -void TurnRefreshRequest::OnResponse(StunMessage* response) { - // Check mandatory attributes as indicated in RFC5766, Section 7.3. - const StunUInt32Attribute* lifetime_attr = - response->GetUInt32(STUN_ATTR_TURN_LIFETIME); - if (!lifetime_attr) { - LOG_J(LS_WARNING, port_) << "Missing STUN_ATTR_TURN_LIFETIME attribute in " - << "refresh success response."; - return; - } - - // Schedule a refresh based on the returned lifetime value. - port_->ScheduleRefresh(lifetime_attr->value()); -} - -void TurnRefreshRequest::OnErrorResponse(StunMessage* response) { - const StunErrorCodeAttribute* error_code = response->GetErrorCode(); - LOG_J(LS_WARNING, port_) << "Refresh response error, code=" - << error_code->code(); - - if (error_code->code() == STUN_ERROR_STALE_NONCE) { - if (port_->UpdateNonce(response)) { - // Send RefreshRequest immediately. - port_->SendRequest(new TurnRefreshRequest(port_), 0); - } - } -} - -void TurnRefreshRequest::OnTimeout() { -} - -TurnCreatePermissionRequest::TurnCreatePermissionRequest( - TurnPort* port, TurnEntry* entry, - const rtc::SocketAddress& ext_addr) - : StunRequest(new TurnMessage()), - port_(port), - entry_(entry), - ext_addr_(ext_addr) { - entry_->SignalDestroyed.connect( - this, &TurnCreatePermissionRequest::OnEntryDestroyed); -} - -void TurnCreatePermissionRequest::Prepare(StunMessage* request) { - // Create the request as indicated in RFC5766, Section 9.1. - request->SetType(TURN_CREATE_PERMISSION_REQUEST); - VERIFY(request->AddAttribute(new StunXorAddressAttribute( - STUN_ATTR_XOR_PEER_ADDRESS, ext_addr_))); - port_->AddRequestAuthInfo(request); -} - -void TurnCreatePermissionRequest::OnResponse(StunMessage* response) { - if (entry_) { - entry_->OnCreatePermissionSuccess(); - } -} - -void TurnCreatePermissionRequest::OnErrorResponse(StunMessage* response) { - if (entry_) { - const StunErrorCodeAttribute* error_code = response->GetErrorCode(); - entry_->OnCreatePermissionError(response, error_code->code()); - } -} - -void TurnCreatePermissionRequest::OnTimeout() { - LOG_J(LS_WARNING, port_) << "Create permission timeout"; -} - -void TurnCreatePermissionRequest::OnEntryDestroyed(TurnEntry* entry) { - ASSERT(entry_ == entry); - entry_ = NULL; -} - -TurnChannelBindRequest::TurnChannelBindRequest( - TurnPort* port, TurnEntry* entry, - int channel_id, const rtc::SocketAddress& ext_addr) - : StunRequest(new TurnMessage()), - port_(port), - entry_(entry), - channel_id_(channel_id), - ext_addr_(ext_addr) { - entry_->SignalDestroyed.connect( - this, &TurnChannelBindRequest::OnEntryDestroyed); -} - -void TurnChannelBindRequest::Prepare(StunMessage* request) { - // Create the request as indicated in RFC5766, Section 11.1. - request->SetType(TURN_CHANNEL_BIND_REQUEST); - VERIFY(request->AddAttribute(new StunUInt32Attribute( - STUN_ATTR_CHANNEL_NUMBER, channel_id_ << 16))); - VERIFY(request->AddAttribute(new StunXorAddressAttribute( - STUN_ATTR_XOR_PEER_ADDRESS, ext_addr_))); - port_->AddRequestAuthInfo(request); -} - -void TurnChannelBindRequest::OnResponse(StunMessage* response) { - if (entry_) { - entry_->OnChannelBindSuccess(); - // Refresh the channel binding just under the permission timeout - // threshold. The channel binding has a longer lifetime, but - // this is the easiest way to keep both the channel and the - // permission from expiring. - entry_->SendChannelBindRequest(TURN_PERMISSION_TIMEOUT - 60 * 1000); - } -} - -void TurnChannelBindRequest::OnErrorResponse(StunMessage* response) { - if (entry_) { - const StunErrorCodeAttribute* error_code = response->GetErrorCode(); - entry_->OnChannelBindError(response, error_code->code()); - } -} - -void TurnChannelBindRequest::OnTimeout() { - LOG_J(LS_WARNING, port_) << "Channel bind timeout"; -} - -void TurnChannelBindRequest::OnEntryDestroyed(TurnEntry* entry) { - ASSERT(entry_ == entry); - entry_ = NULL; -} - -TurnEntry::TurnEntry(TurnPort* port, int channel_id, - const rtc::SocketAddress& ext_addr) - : port_(port), - channel_id_(channel_id), - ext_addr_(ext_addr), - state_(STATE_UNBOUND) { - // Creating permission for |ext_addr_|. - SendCreatePermissionRequest(); -} - -void TurnEntry::SendCreatePermissionRequest() { - port_->SendRequest(new TurnCreatePermissionRequest( - port_, this, ext_addr_), 0); -} - -void TurnEntry::SendChannelBindRequest(int delay) { - port_->SendRequest(new TurnChannelBindRequest( - port_, this, channel_id_, ext_addr_), delay); -} - -int TurnEntry::Send(const void* data, size_t size, bool payload, - const rtc::PacketOptions& options) { - rtc::ByteBuffer buf; - if (state_ != STATE_BOUND) { - // If we haven't bound the channel yet, we have to use a Send Indication. - TurnMessage msg; - msg.SetType(TURN_SEND_INDICATION); - msg.SetTransactionID( - rtc::CreateRandomString(kStunTransactionIdLength)); - VERIFY(msg.AddAttribute(new StunXorAddressAttribute( - STUN_ATTR_XOR_PEER_ADDRESS, ext_addr_))); - VERIFY(msg.AddAttribute(new StunByteStringAttribute( - STUN_ATTR_DATA, data, size))); - VERIFY(msg.Write(&buf)); - - // If we're sending real data, request a channel bind that we can use later. - if (state_ == STATE_UNBOUND && payload) { - SendChannelBindRequest(0); - state_ = STATE_BINDING; - } - } else { - // If the channel is bound, we can send the data as a Channel Message. - buf.WriteUInt16(channel_id_); - buf.WriteUInt16(static_cast<uint16>(size)); - buf.WriteBytes(reinterpret_cast<const char*>(data), size); - } - return port_->Send(buf.Data(), buf.Length(), options); -} - -void TurnEntry::OnCreatePermissionSuccess() { - LOG_J(LS_INFO, port_) << "Create permission for " - << ext_addr_.ToSensitiveString() - << " succeeded"; - // For success result code will be 0. - port_->SignalCreatePermissionResult(port_, ext_addr_, 0); -} - -void TurnEntry::OnCreatePermissionError(StunMessage* response, int code) { - LOG_J(LS_WARNING, port_) << "Create permission for " - << ext_addr_.ToSensitiveString() - << " failed, code=" << code; - if (code == STUN_ERROR_STALE_NONCE) { - if (port_->UpdateNonce(response)) { - SendCreatePermissionRequest(); - } - } else { - // Send signal with error code. - port_->SignalCreatePermissionResult(port_, ext_addr_, code); - } -} - -void TurnEntry::OnChannelBindSuccess() { - LOG_J(LS_INFO, port_) << "Channel bind for " << ext_addr_.ToSensitiveString() - << " succeeded"; - ASSERT(state_ == STATE_BINDING || state_ == STATE_BOUND); - state_ = STATE_BOUND; -} - -void TurnEntry::OnChannelBindError(StunMessage* response, int code) { - // TODO(mallinath) - Implement handling of error response for channel - // bind request as per http://tools.ietf.org/html/rfc5766#section-11.3 - LOG_J(LS_WARNING, port_) << "Channel bind for " - << ext_addr_.ToSensitiveString() - << " failed, code=" << code; - if (code == STUN_ERROR_STALE_NONCE) { - if (port_->UpdateNonce(response)) { - // Send channel bind request with fresh nonce. - SendChannelBindRequest(0); - } - } -} - -} // namespace cricket diff --git a/talk/p2p/base/turnport.h b/talk/p2p/base/turnport.h deleted file mode 100644 index 6345aea16..000000000 --- a/talk/p2p/base/turnport.h +++ /dev/null @@ -1,254 +0,0 @@ -/* - * libjingle - * Copyright 2012, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef WEBRTC_P2P_BASE_TURNPORT_H_ -#define WEBRTC_P2P_BASE_TURNPORT_H_ - -#include <stdio.h> -#include <list> -#include <set> -#include <string> - -#include "webrtc/p2p/base/port.h" -#include "webrtc/p2p/client/basicportallocator.h" -#include "webrtc/base/asyncpacketsocket.h" - -namespace rtc { -class AsyncResolver; -class SignalThread; -} - -namespace cricket { - -extern const char TURN_PORT_TYPE[]; -class TurnAllocateRequest; -class TurnEntry; - -class TurnPort : public Port { - public: - static TurnPort* Create(rtc::Thread* thread, - rtc::PacketSocketFactory* factory, - rtc::Network* network, - rtc::AsyncPacketSocket* socket, - const std::string& username, // ice username. - const std::string& password, // ice password. - const ProtocolAddress& server_address, - const RelayCredentials& credentials, - int server_priority) { - return new TurnPort(thread, factory, network, socket, - username, password, server_address, - credentials, server_priority); - } - - static TurnPort* Create(rtc::Thread* thread, - rtc::PacketSocketFactory* factory, - rtc::Network* network, - const rtc::IPAddress& ip, - int min_port, int max_port, - const std::string& username, // ice username. - const std::string& password, // ice password. - const ProtocolAddress& server_address, - const RelayCredentials& credentials, - int server_priority) { - return new TurnPort(thread, factory, network, ip, min_port, max_port, - username, password, server_address, credentials, - server_priority); - } - - virtual ~TurnPort(); - - const ProtocolAddress& server_address() const { return server_address_; } - - bool connected() const { return connected_; } - const RelayCredentials& credentials() const { return credentials_; } - - virtual void PrepareAddress(); - virtual Connection* CreateConnection( - const Candidate& c, PortInterface::CandidateOrigin origin); - virtual int SendTo(const void* data, size_t size, - const rtc::SocketAddress& addr, - const rtc::PacketOptions& options, - bool payload); - virtual int SetOption(rtc::Socket::Option opt, int value); - virtual int GetOption(rtc::Socket::Option opt, int* value); - virtual int GetError(); - - virtual bool HandleIncomingPacket( - rtc::AsyncPacketSocket* socket, const char* data, size_t size, - const rtc::SocketAddress& remote_addr, - const rtc::PacketTime& packet_time) { - OnReadPacket(socket, data, size, remote_addr, packet_time); - return true; - } - virtual void OnReadPacket(rtc::AsyncPacketSocket* socket, - const char* data, size_t size, - const rtc::SocketAddress& remote_addr, - const rtc::PacketTime& packet_time); - - virtual void OnReadyToSend(rtc::AsyncPacketSocket* socket); - - void OnSocketConnect(rtc::AsyncPacketSocket* socket); - void OnSocketClose(rtc::AsyncPacketSocket* socket, int error); - - - const std::string& hash() const { return hash_; } - const std::string& nonce() const { return nonce_; } - - int error() const { return error_; } - - void OnAllocateMismatch(); - - rtc::AsyncPacketSocket* socket() const { - return socket_; - } - - // Signal with resolved server address. - // Parameters are port, server address and resolved server address. - // This signal will be sent only if server address is resolved successfully. - sigslot::signal3<TurnPort*, - const rtc::SocketAddress&, - const rtc::SocketAddress&> SignalResolvedServerAddress; - - // This signal is only for testing purpose. - sigslot::signal3<TurnPort*, const rtc::SocketAddress&, int> - SignalCreatePermissionResult; - - protected: - TurnPort(rtc::Thread* thread, - rtc::PacketSocketFactory* factory, - rtc::Network* network, - rtc::AsyncPacketSocket* socket, - const std::string& username, - const std::string& password, - const ProtocolAddress& server_address, - const RelayCredentials& credentials, - int server_priority); - - TurnPort(rtc::Thread* thread, - rtc::PacketSocketFactory* factory, - rtc::Network* network, - const rtc::IPAddress& ip, - int min_port, int max_port, - const std::string& username, - const std::string& password, - const ProtocolAddress& server_address, - const RelayCredentials& credentials, - int server_priority); - - private: - enum { - MSG_ERROR = MSG_FIRST_AVAILABLE, - MSG_ALLOCATE_MISMATCH - }; - - typedef std::list<TurnEntry*> EntryList; - typedef std::map<rtc::Socket::Option, int> SocketOptionsMap; - typedef std::set<rtc::SocketAddress> AttemptedServerSet; - - virtual void OnMessage(rtc::Message* pmsg); - - bool CreateTurnClientSocket(); - - void set_nonce(const std::string& nonce) { nonce_ = nonce; } - void set_realm(const std::string& realm) { - if (realm != realm_) { - realm_ = realm; - UpdateHash(); - } - } - - bool SetAlternateServer(const rtc::SocketAddress& address); - void ResolveTurnAddress(const rtc::SocketAddress& address); - void OnResolveResult(rtc::AsyncResolverInterface* resolver); - - void AddRequestAuthInfo(StunMessage* msg); - void OnSendStunPacket(const void* data, size_t size, StunRequest* request); - // Stun address from allocate success response. - // Currently used only for testing. - void OnStunAddress(const rtc::SocketAddress& address); - void OnAllocateSuccess(const rtc::SocketAddress& address, - const rtc::SocketAddress& stun_address); - void OnAllocateError(); - void OnAllocateRequestTimeout(); - - void HandleDataIndication(const char* data, size_t size, - const rtc::PacketTime& packet_time); - void HandleChannelData(int channel_id, const char* data, size_t size, - const rtc::PacketTime& packet_time); - void DispatchPacket(const char* data, size_t size, - const rtc::SocketAddress& remote_addr, - ProtocolType proto, const rtc::PacketTime& packet_time); - - bool ScheduleRefresh(int lifetime); - void SendRequest(StunRequest* request, int delay); - int Send(const void* data, size_t size, - const rtc::PacketOptions& options); - void UpdateHash(); - bool UpdateNonce(StunMessage* response); - - bool HasPermission(const rtc::IPAddress& ipaddr) const; - TurnEntry* FindEntry(const rtc::SocketAddress& address) const; - TurnEntry* FindEntry(int channel_id) const; - TurnEntry* CreateEntry(const rtc::SocketAddress& address); - void DestroyEntry(const rtc::SocketAddress& address); - void OnConnectionDestroyed(Connection* conn); - - ProtocolAddress server_address_; - RelayCredentials credentials_; - AttemptedServerSet attempted_server_addresses_; - - rtc::AsyncPacketSocket* socket_; - SocketOptionsMap socket_options_; - rtc::AsyncResolverInterface* resolver_; - int error_; - - StunRequestManager request_manager_; - std::string realm_; // From 401/438 response message. - std::string nonce_; // From 401/438 response message. - std::string hash_; // Digest of username:realm:password - - int next_channel_number_; - EntryList entries_; - - bool connected_; - // By default the value will be set to 0. This value will be used in - // calculating the candidate priority. - int server_priority_; - - // The number of retries made due to allocate mismatch error. - size_t allocate_mismatch_retries_; - - friend class TurnEntry; - friend class TurnAllocateRequest; - friend class TurnRefreshRequest; - friend class TurnCreatePermissionRequest; - friend class TurnChannelBindRequest; -}; - -} // namespace cricket - -#endif // WEBRTC_P2P_BASE_TURNPORT_H_ diff --git a/talk/p2p/base/turnport_unittest.cc b/talk/p2p/base/turnport_unittest.cc deleted file mode 100644 index 95615ff1f..000000000 --- a/talk/p2p/base/turnport_unittest.cc +++ /dev/null @@ -1,685 +0,0 @@ -/* - * libjingle - * Copyright 2012, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -#if defined(POSIX) -#include <dirent.h> -#endif - -#include "webrtc/p2p/base/basicpacketsocketfactory.h" -#include "webrtc/p2p/base/constants.h" -#include "webrtc/p2p/base/tcpport.h" -#include "webrtc/p2p/base/testturnserver.h" -#include "webrtc/p2p/base/turnport.h" -#include "webrtc/p2p/base/udpport.h" -#include "webrtc/base/asynctcpsocket.h" -#include "webrtc/base/buffer.h" -#include "webrtc/base/dscp.h" -#include "webrtc/base/firewallsocketserver.h" -#include "webrtc/base/gunit.h" -#include "webrtc/base/helpers.h" -#include "webrtc/base/logging.h" -#include "webrtc/base/physicalsocketserver.h" -#include "webrtc/base/scoped_ptr.h" -#include "webrtc/base/socketaddress.h" -#include "webrtc/base/ssladapter.h" -#include "webrtc/base/thread.h" -#include "webrtc/base/virtualsocketserver.h" - -using rtc::SocketAddress; -using cricket::Connection; -using cricket::Port; -using cricket::PortInterface; -using cricket::TurnPort; -using cricket::UDPPort; - -static const SocketAddress kLocalAddr1("11.11.11.11", 0); -static const SocketAddress kLocalAddr2("22.22.22.22", 0); -static const SocketAddress kLocalIPv6Addr( - "2401:fa00:4:1000:be30:5bff:fee5:c3", 0); -static const SocketAddress kTurnUdpIntAddr("99.99.99.3", - cricket::TURN_SERVER_PORT); -static const SocketAddress kTurnTcpIntAddr("99.99.99.4", - cricket::TURN_SERVER_PORT); -static const SocketAddress kTurnUdpExtAddr("99.99.99.5", 0); -static const SocketAddress kTurnAlternateUdpIntAddr( - "99.99.99.6", cricket::TURN_SERVER_PORT); -static const SocketAddress kTurnUdpIPv6IntAddr( - "2400:4030:1:2c00:be30:abcd:efab:cdef", cricket::TURN_SERVER_PORT); -static const SocketAddress kTurnUdpIPv6ExtAddr( - "2620:0:1000:1b03:2e41:38ff:fea6:f2a4", 0); - -static const char kIceUfrag1[] = "TESTICEUFRAG0001"; -static const char kIceUfrag2[] = "TESTICEUFRAG0002"; -static const char kIcePwd1[] = "TESTICEPWD00000000000001"; -static const char kIcePwd2[] = "TESTICEPWD00000000000002"; -static const char kTurnUsername[] = "test"; -static const char kTurnPassword[] = "test"; -static const unsigned int kTimeout = 1000; - -static const cricket::ProtocolAddress kTurnUdpProtoAddr( - kTurnUdpIntAddr, cricket::PROTO_UDP); -static const cricket::ProtocolAddress kTurnTcpProtoAddr( - kTurnTcpIntAddr, cricket::PROTO_TCP); -static const cricket::ProtocolAddress kTurnUdpIPv6ProtoAddr( - kTurnUdpIPv6IntAddr, cricket::PROTO_UDP); - -static const unsigned int MSG_TESTFINISH = 0; - -#if defined(LINUX) -static int GetFDCount() { - struct dirent *dp; - int fd_count = 0; - DIR *dir = opendir("/proc/self/fd/"); - while ((dp = readdir(dir)) != NULL) { - if (dp->d_name[0] == '.') - continue; - ++fd_count; - } - closedir(dir); - return fd_count; -} -#endif - -class TurnPortTest : public testing::Test, - public sigslot::has_slots<>, - public rtc::MessageHandler { - public: - TurnPortTest() - : main_(rtc::Thread::Current()), - pss_(new rtc::PhysicalSocketServer), - ss_(new rtc::VirtualSocketServer(pss_.get())), - ss_scope_(ss_.get()), - network_("unittest", "unittest", rtc::IPAddress(INADDR_ANY), 32), - socket_factory_(rtc::Thread::Current()), - turn_server_(main_, kTurnUdpIntAddr, kTurnUdpExtAddr), - turn_ready_(false), - turn_error_(false), - turn_unknown_address_(false), - turn_create_permission_success_(false), - udp_ready_(false), - test_finish_(false) { - network_.AddIP(rtc::IPAddress(INADDR_ANY)); - } - - virtual void OnMessage(rtc::Message* msg) { - ASSERT(msg->message_id == MSG_TESTFINISH); - if (msg->message_id == MSG_TESTFINISH) - test_finish_ = true; - } - - void OnTurnPortComplete(Port* port) { - turn_ready_ = true; - } - void OnTurnPortError(Port* port) { - turn_error_ = true; - } - void OnTurnUnknownAddress(PortInterface* port, const SocketAddress& addr, - cricket::ProtocolType proto, - cricket::IceMessage* msg, const std::string& rf, - bool /*port_muxed*/) { - turn_unknown_address_ = true; - } - void OnTurnCreatePermissionResult(TurnPort* port, const SocketAddress& addr, - int code) { - // Ignoring the address. - if (code == 0) { - turn_create_permission_success_ = true; - } - } - void OnTurnReadPacket(Connection* conn, const char* data, size_t size, - const rtc::PacketTime& packet_time) { - turn_packets_.push_back(rtc::Buffer(data, size)); - } - void OnUdpPortComplete(Port* port) { - udp_ready_ = true; - } - void OnUdpReadPacket(Connection* conn, const char* data, size_t size, - const rtc::PacketTime& packet_time) { - udp_packets_.push_back(rtc::Buffer(data, size)); - } - void OnSocketReadPacket(rtc::AsyncPacketSocket* socket, - const char* data, size_t size, - const rtc::SocketAddress& remote_addr, - const rtc::PacketTime& packet_time) { - turn_port_->HandleIncomingPacket(socket, data, size, remote_addr, - packet_time); - } - rtc::AsyncSocket* CreateServerSocket(const SocketAddress addr) { - rtc::AsyncSocket* socket = ss_->CreateAsyncSocket(SOCK_STREAM); - EXPECT_GE(socket->Bind(addr), 0); - EXPECT_GE(socket->Listen(5), 0); - return socket; - } - - void CreateTurnPort(const std::string& username, - const std::string& password, - const cricket::ProtocolAddress& server_address) { - CreateTurnPort(kLocalAddr1, username, password, server_address); - } - void CreateTurnPort(const rtc::SocketAddress& local_address, - const std::string& username, - const std::string& password, - const cricket::ProtocolAddress& server_address) { - cricket::RelayCredentials credentials(username, password); - turn_port_.reset(TurnPort::Create(main_, &socket_factory_, &network_, - local_address.ipaddr(), 0, 0, - kIceUfrag1, kIcePwd1, - server_address, credentials, 0)); - // Set ICE protocol type to ICEPROTO_RFC5245, as port by default will be - // in Hybrid mode. Protocol type is necessary to send correct type STUN ping - // messages. - // This TURN port will be the controlling. - turn_port_->SetIceProtocolType(cricket::ICEPROTO_RFC5245); - turn_port_->SetIceRole(cricket::ICEROLE_CONTROLLING); - ConnectSignals(); - } - - void CreateSharedTurnPort(const std::string& username, - const std::string& password, - const cricket::ProtocolAddress& server_address) { - ASSERT(server_address.proto == cricket::PROTO_UDP); - - if (!socket_) { - socket_.reset(socket_factory_.CreateUdpSocket( - rtc::SocketAddress(kLocalAddr1.ipaddr(), 0), 0, 0)); - ASSERT_TRUE(socket_ != NULL); - socket_->SignalReadPacket.connect( - this, &TurnPortTest::OnSocketReadPacket); - } - - cricket::RelayCredentials credentials(username, password); - turn_port_.reset(cricket::TurnPort::Create( - main_, &socket_factory_, &network_, socket_.get(), - kIceUfrag1, kIcePwd1, server_address, credentials, 0)); - // Set ICE protocol type to ICEPROTO_RFC5245, as port by default will be - // in Hybrid mode. Protocol type is necessary to send correct type STUN ping - // messages. - // This TURN port will be the controlling. - turn_port_->SetIceProtocolType(cricket::ICEPROTO_RFC5245); - turn_port_->SetIceRole(cricket::ICEROLE_CONTROLLING); - ConnectSignals(); - } - - void ConnectSignals() { - turn_port_->SignalPortComplete.connect(this, - &TurnPortTest::OnTurnPortComplete); - turn_port_->SignalPortError.connect(this, - &TurnPortTest::OnTurnPortError); - turn_port_->SignalUnknownAddress.connect(this, - &TurnPortTest::OnTurnUnknownAddress); - turn_port_->SignalCreatePermissionResult.connect(this, - &TurnPortTest::OnTurnCreatePermissionResult); - } - void CreateUdpPort() { - udp_port_.reset(UDPPort::Create(main_, &socket_factory_, &network_, - kLocalAddr2.ipaddr(), 0, 0, - kIceUfrag2, kIcePwd2)); - // Set protocol type to RFC5245, as turn port is also in same mode. - // UDP port will be controlled. - udp_port_->SetIceProtocolType(cricket::ICEPROTO_RFC5245); - udp_port_->SetIceRole(cricket::ICEROLE_CONTROLLED); - udp_port_->SignalPortComplete.connect( - this, &TurnPortTest::OnUdpPortComplete); - } - - void TestTurnConnection() { - // Create ports and prepare addresses. - ASSERT_TRUE(turn_port_ != NULL); - turn_port_->PrepareAddress(); - ASSERT_TRUE_WAIT(turn_ready_, kTimeout); - CreateUdpPort(); - udp_port_->PrepareAddress(); - ASSERT_TRUE_WAIT(udp_ready_, kTimeout); - - // Send ping from UDP to TURN. - Connection* conn1 = udp_port_->CreateConnection( - turn_port_->Candidates()[0], Port::ORIGIN_MESSAGE); - ASSERT_TRUE(conn1 != NULL); - conn1->Ping(0); - WAIT(!turn_unknown_address_, kTimeout); - EXPECT_FALSE(turn_unknown_address_); - EXPECT_EQ(Connection::STATE_READ_INIT, conn1->read_state()); - EXPECT_EQ(Connection::STATE_WRITE_INIT, conn1->write_state()); - - // Send ping from TURN to UDP. - Connection* conn2 = turn_port_->CreateConnection( - udp_port_->Candidates()[0], Port::ORIGIN_MESSAGE); - ASSERT_TRUE(conn2 != NULL); - ASSERT_TRUE_WAIT(turn_create_permission_success_, kTimeout); - conn2->Ping(0); - - EXPECT_EQ_WAIT(Connection::STATE_WRITABLE, conn2->write_state(), kTimeout); - EXPECT_EQ(Connection::STATE_READABLE, conn1->read_state()); - EXPECT_EQ(Connection::STATE_READ_INIT, conn2->read_state()); - EXPECT_EQ(Connection::STATE_WRITE_INIT, conn1->write_state()); - - // Send another ping from UDP to TURN. - conn1->Ping(0); - EXPECT_EQ_WAIT(Connection::STATE_WRITABLE, conn1->write_state(), kTimeout); - EXPECT_EQ(Connection::STATE_READABLE, conn2->read_state()); - } - - void TestTurnSendData() { - turn_port_->PrepareAddress(); - EXPECT_TRUE_WAIT(turn_ready_, kTimeout); - CreateUdpPort(); - udp_port_->PrepareAddress(); - EXPECT_TRUE_WAIT(udp_ready_, kTimeout); - // Create connections and send pings. - Connection* conn1 = turn_port_->CreateConnection( - udp_port_->Candidates()[0], Port::ORIGIN_MESSAGE); - Connection* conn2 = udp_port_->CreateConnection( - turn_port_->Candidates()[0], Port::ORIGIN_MESSAGE); - ASSERT_TRUE(conn1 != NULL); - ASSERT_TRUE(conn2 != NULL); - conn1->SignalReadPacket.connect(static_cast<TurnPortTest*>(this), - &TurnPortTest::OnTurnReadPacket); - conn2->SignalReadPacket.connect(static_cast<TurnPortTest*>(this), - &TurnPortTest::OnUdpReadPacket); - conn1->Ping(0); - EXPECT_EQ_WAIT(Connection::STATE_WRITABLE, conn1->write_state(), kTimeout); - conn2->Ping(0); - EXPECT_EQ_WAIT(Connection::STATE_WRITABLE, conn2->write_state(), kTimeout); - - // Send some data. - size_t num_packets = 256; - for (size_t i = 0; i < num_packets; ++i) { - unsigned char buf[256] = { 0 }; - for (size_t j = 0; j < i + 1; ++j) { - buf[j] = 0xFF - static_cast<unsigned char>(j); - } - conn1->Send(buf, i + 1, options); - conn2->Send(buf, i + 1, options); - main_->ProcessMessages(0); - } - - // Check the data. - ASSERT_EQ_WAIT(num_packets, turn_packets_.size(), kTimeout); - ASSERT_EQ_WAIT(num_packets, udp_packets_.size(), kTimeout); - for (size_t i = 0; i < num_packets; ++i) { - EXPECT_EQ(i + 1, turn_packets_[i].length()); - EXPECT_EQ(i + 1, udp_packets_[i].length()); - EXPECT_EQ(turn_packets_[i], udp_packets_[i]); - } - } - - protected: - rtc::Thread* main_; - rtc::scoped_ptr<rtc::PhysicalSocketServer> pss_; - rtc::scoped_ptr<rtc::VirtualSocketServer> ss_; - rtc::SocketServerScope ss_scope_; - rtc::Network network_; - rtc::BasicPacketSocketFactory socket_factory_; - rtc::scoped_ptr<rtc::AsyncPacketSocket> socket_; - cricket::TestTurnServer turn_server_; - rtc::scoped_ptr<TurnPort> turn_port_; - rtc::scoped_ptr<UDPPort> udp_port_; - bool turn_ready_; - bool turn_error_; - bool turn_unknown_address_; - bool turn_create_permission_success_; - bool udp_ready_; - bool test_finish_; - std::vector<rtc::Buffer> turn_packets_; - std::vector<rtc::Buffer> udp_packets_; - rtc::PacketOptions options; -}; - -// Do a normal TURN allocation. -TEST_F(TurnPortTest, TestTurnAllocate) { - CreateTurnPort(kTurnUsername, kTurnPassword, kTurnUdpProtoAddr); - EXPECT_EQ(0, turn_port_->SetOption(rtc::Socket::OPT_SNDBUF, 10*1024)); - turn_port_->PrepareAddress(); - EXPECT_TRUE_WAIT(turn_ready_, kTimeout); - ASSERT_EQ(1U, turn_port_->Candidates().size()); - EXPECT_EQ(kTurnUdpExtAddr.ipaddr(), - turn_port_->Candidates()[0].address().ipaddr()); - EXPECT_NE(0, turn_port_->Candidates()[0].address().port()); -} - -// Testing a normal UDP allocation using TCP connection. -TEST_F(TurnPortTest, TestTurnTcpAllocate) { - turn_server_.AddInternalSocket(kTurnTcpIntAddr, cricket::PROTO_TCP); - CreateTurnPort(kTurnUsername, kTurnPassword, kTurnTcpProtoAddr); - EXPECT_EQ(0, turn_port_->SetOption(rtc::Socket::OPT_SNDBUF, 10*1024)); - turn_port_->PrepareAddress(); - EXPECT_TRUE_WAIT(turn_ready_, kTimeout); - ASSERT_EQ(1U, turn_port_->Candidates().size()); - EXPECT_EQ(kTurnUdpExtAddr.ipaddr(), - turn_port_->Candidates()[0].address().ipaddr()); - EXPECT_NE(0, turn_port_->Candidates()[0].address().port()); -} - -// Testing turn port will attempt to create TCP socket on address resolution -// failure. -TEST_F(TurnPortTest, DISABLED_TestTurnTcpOnAddressResolveFailure) { - turn_server_.AddInternalSocket(kTurnTcpIntAddr, cricket::PROTO_TCP); - CreateTurnPort(kTurnUsername, kTurnPassword, cricket::ProtocolAddress( - rtc::SocketAddress("www.webrtc-blah-blah.com", 3478), - cricket::PROTO_TCP)); - turn_port_->PrepareAddress(); - EXPECT_TRUE_WAIT(turn_error_, kTimeout); - // As VSS doesn't provide a DNS resolution, name resolve will fail. TurnPort - // will proceed in creating a TCP socket which will fail as there is no - // server on the above domain and error will be set to SOCKET_ERROR. - EXPECT_EQ(SOCKET_ERROR, turn_port_->error()); -} - -// In case of UDP on address resolve failure, TurnPort will not create socket -// and return allocate failure. -TEST_F(TurnPortTest, DISABLED_TestTurnUdpOnAdressResolveFailure) { - CreateTurnPort(kTurnUsername, kTurnPassword, cricket::ProtocolAddress( - rtc::SocketAddress("www.webrtc-blah-blah.com", 3478), - cricket::PROTO_UDP)); - turn_port_->PrepareAddress(); - EXPECT_TRUE_WAIT(turn_error_, kTimeout); - // Error from turn port will not be socket error. - EXPECT_NE(SOCKET_ERROR, turn_port_->error()); -} - -// Try to do a TURN allocation with an invalid password. -TEST_F(TurnPortTest, TestTurnAllocateBadPassword) { - CreateTurnPort(kTurnUsername, "bad", kTurnUdpProtoAddr); - turn_port_->PrepareAddress(); - EXPECT_TRUE_WAIT(turn_error_, kTimeout); - ASSERT_EQ(0U, turn_port_->Candidates().size()); -} - -// Tests that a new local address is created after -// STUN_ERROR_ALLOCATION_MISMATCH. -TEST_F(TurnPortTest, TestTurnAllocateMismatch) { - // Do a normal allocation first. - CreateTurnPort(kTurnUsername, kTurnPassword, kTurnUdpProtoAddr); - turn_port_->PrepareAddress(); - EXPECT_TRUE_WAIT(turn_ready_, kTimeout); - rtc::SocketAddress first_addr(turn_port_->socket()->GetLocalAddress()); - - // Forces the socket server to assign the same port. - ss_->SetNextPortForTesting(first_addr.port()); - - turn_ready_ = false; - CreateTurnPort(kTurnUsername, kTurnPassword, kTurnUdpProtoAddr); - turn_port_->PrepareAddress(); - - // Verifies that the new port has the same address. - EXPECT_EQ(first_addr, turn_port_->socket()->GetLocalAddress()); - - EXPECT_TRUE_WAIT(turn_ready_, kTimeout); - - // Verifies that the new port has a different address now. - EXPECT_NE(first_addr, turn_port_->socket()->GetLocalAddress()); -} - -// Tests that a shared-socket-TurnPort creates its own socket after -// STUN_ERROR_ALLOCATION_MISMATCH. -TEST_F(TurnPortTest, TestSharedSocketAllocateMismatch) { - // Do a normal allocation first. - CreateSharedTurnPort(kTurnUsername, kTurnPassword, kTurnUdpProtoAddr); - turn_port_->PrepareAddress(); - EXPECT_TRUE_WAIT(turn_ready_, kTimeout); - rtc::SocketAddress first_addr(turn_port_->socket()->GetLocalAddress()); - - turn_ready_ = false; - CreateSharedTurnPort(kTurnUsername, kTurnPassword, kTurnUdpProtoAddr); - - // Verifies that the new port has the same address. - EXPECT_EQ(first_addr, turn_port_->socket()->GetLocalAddress()); - EXPECT_TRUE(turn_port_->SharedSocket()); - - turn_port_->PrepareAddress(); - EXPECT_TRUE_WAIT(turn_ready_, kTimeout); - - // Verifies that the new port has a different address now. - EXPECT_NE(first_addr, turn_port_->socket()->GetLocalAddress()); - EXPECT_FALSE(turn_port_->SharedSocket()); -} - -TEST_F(TurnPortTest, TestTurnTcpAllocateMismatch) { - turn_server_.AddInternalSocket(kTurnTcpIntAddr, cricket::PROTO_TCP); - CreateTurnPort(kTurnUsername, kTurnPassword, kTurnTcpProtoAddr); - - // Do a normal allocation first. - turn_port_->PrepareAddress(); - EXPECT_TRUE_WAIT(turn_ready_, kTimeout); - rtc::SocketAddress first_addr(turn_port_->socket()->GetLocalAddress()); - - // Forces the socket server to assign the same port. - ss_->SetNextPortForTesting(first_addr.port()); - - turn_ready_ = false; - CreateTurnPort(kTurnUsername, kTurnPassword, kTurnTcpProtoAddr); - turn_port_->PrepareAddress(); - - // Verifies that the new port has the same address. - EXPECT_EQ(first_addr, turn_port_->socket()->GetLocalAddress()); - - EXPECT_TRUE_WAIT(turn_ready_, kTimeout); - - // Verifies that the new port has a different address now. - EXPECT_NE(first_addr, turn_port_->socket()->GetLocalAddress()); -} - -// Do a TURN allocation and try to send a packet to it from the outside. -// The packet should be dropped. Then, try to send a packet from TURN to the -// outside. It should reach its destination. Finally, try again from the -// outside. It should now work as well. -TEST_F(TurnPortTest, TestTurnConnection) { - CreateTurnPort(kTurnUsername, kTurnPassword, kTurnUdpProtoAddr); - TestTurnConnection(); -} - -// Similar to above, except that this test will use the shared socket. -TEST_F(TurnPortTest, TestTurnConnectionUsingSharedSocket) { - CreateSharedTurnPort(kTurnUsername, kTurnPassword, kTurnUdpProtoAddr); - TestTurnConnection(); -} - -// Test that we can establish a TCP connection with TURN server. -TEST_F(TurnPortTest, TestTurnTcpConnection) { - turn_server_.AddInternalSocket(kTurnTcpIntAddr, cricket::PROTO_TCP); - CreateTurnPort(kTurnUsername, kTurnPassword, kTurnTcpProtoAddr); - TestTurnConnection(); -} - -// Test that we fail to create a connection when we want to use TLS over TCP. -// This test should be removed once we have TLS support. -TEST_F(TurnPortTest, TestTurnTlsTcpConnectionFails) { - cricket::ProtocolAddress secure_addr(kTurnTcpProtoAddr.address, - kTurnTcpProtoAddr.proto, - true); - CreateTurnPort(kTurnUsername, kTurnPassword, secure_addr); - turn_port_->PrepareAddress(); - EXPECT_TRUE_WAIT(turn_error_, kTimeout); - ASSERT_EQ(0U, turn_port_->Candidates().size()); -} - -// Test try-alternate-server feature. -TEST_F(TurnPortTest, TestTurnAlternateServer) { - std::vector<rtc::SocketAddress> redirect_addresses; - redirect_addresses.push_back(kTurnAlternateUdpIntAddr); - - cricket::TestTurnRedirector redirector(redirect_addresses); - turn_server_.AddInternalSocket(kTurnAlternateUdpIntAddr, - cricket::PROTO_UDP); - turn_server_.set_redirect_hook(&redirector); - CreateTurnPort(kTurnUsername, kTurnPassword, kTurnUdpProtoAddr); - - // Retrieve the address before we run the state machine. - const SocketAddress old_addr = turn_port_->server_address().address; - - turn_port_->PrepareAddress(); - EXPECT_TRUE_WAIT(turn_ready_, kTimeout); - // Retrieve the address again, the turn port's address should be - // changed. - const SocketAddress new_addr = turn_port_->server_address().address; - EXPECT_NE(old_addr, new_addr); - ASSERT_EQ(1U, turn_port_->Candidates().size()); - EXPECT_EQ(kTurnUdpExtAddr.ipaddr(), - turn_port_->Candidates()[0].address().ipaddr()); - EXPECT_NE(0, turn_port_->Candidates()[0].address().port()); -} - -// Test that we fail when we redirect to an address different from -// current IP family. -TEST_F(TurnPortTest, TestTurnAlternateServerV4toV6) { - std::vector<rtc::SocketAddress> redirect_addresses; - redirect_addresses.push_back(kTurnUdpIPv6IntAddr); - - cricket::TestTurnRedirector redirector(redirect_addresses); - turn_server_.AddInternalSocket(kTurnAlternateUdpIntAddr, - cricket::PROTO_UDP); - turn_server_.set_redirect_hook(&redirector); - CreateTurnPort(kTurnUsername, kTurnPassword, kTurnUdpProtoAddr); - turn_port_->PrepareAddress(); - EXPECT_TRUE_WAIT(turn_error_, kTimeout); -} - -// Test that we fail to handle alternate-server response over TCP protocol. -TEST_F(TurnPortTest, TestTurnAlternateServerTcp) { - std::vector<rtc::SocketAddress> redirect_addresses; - redirect_addresses.push_back(kTurnAlternateUdpIntAddr); - - cricket::TestTurnRedirector redirector(redirect_addresses); - turn_server_.set_redirect_hook(&redirector); - turn_server_.AddInternalSocket(kTurnTcpIntAddr, cricket::PROTO_TCP); - CreateTurnPort(kTurnUsername, kTurnPassword, kTurnTcpProtoAddr); - - turn_server_.AddInternalSocket(kTurnAlternateUdpIntAddr, cricket::PROTO_TCP); - turn_port_->PrepareAddress(); - EXPECT_TRUE_WAIT(turn_error_, kTimeout); -} - -// Test try-alternate-server catches the case of pingpong. -TEST_F(TurnPortTest, TestTurnAlternateServerPingPong) { - std::vector<rtc::SocketAddress> redirect_addresses; - redirect_addresses.push_back(kTurnAlternateUdpIntAddr); - redirect_addresses.push_back(kTurnUdpIntAddr); - - cricket::TestTurnRedirector redirector(redirect_addresses); - - turn_server_.AddInternalSocket(kTurnAlternateUdpIntAddr, - cricket::PROTO_UDP); - turn_server_.set_redirect_hook(&redirector); - CreateTurnPort(kTurnUsername, kTurnPassword, kTurnUdpProtoAddr); - - turn_port_->PrepareAddress(); - EXPECT_TRUE_WAIT(turn_error_, kTimeout); - ASSERT_EQ(0U, turn_port_->Candidates().size()); - rtc::SocketAddress address; - // Verify that we have exhausted all alternate servers instead of - // failure caused by other errors. - EXPECT_FALSE(redirector.ShouldRedirect(address, &address)); -} - -// Test try-alternate-server catch the case of repeated server. -TEST_F(TurnPortTest, TestTurnAlternateServerDetectRepetition) { - std::vector<rtc::SocketAddress> redirect_addresses; - redirect_addresses.push_back(kTurnAlternateUdpIntAddr); - redirect_addresses.push_back(kTurnAlternateUdpIntAddr); - - cricket::TestTurnRedirector redirector(redirect_addresses); - - turn_server_.AddInternalSocket(kTurnAlternateUdpIntAddr, - cricket::PROTO_UDP); - turn_server_.set_redirect_hook(&redirector); - CreateTurnPort(kTurnUsername, kTurnPassword, kTurnUdpProtoAddr); - - turn_port_->PrepareAddress(); - EXPECT_TRUE_WAIT(turn_error_, kTimeout); - ASSERT_EQ(0U, turn_port_->Candidates().size()); -} - - -// Run TurnConnectionTest with one-time-use nonce feature. -// Here server will send a 438 STALE_NONCE error message for -// every TURN transaction. -TEST_F(TurnPortTest, TestTurnConnectionUsingOTUNonce) { - turn_server_.set_enable_otu_nonce(true); - CreateTurnPort(kTurnUsername, kTurnPassword, kTurnUdpProtoAddr); - TestTurnConnection(); -} - -// Do a TURN allocation, establish a UDP connection, and send some data. -TEST_F(TurnPortTest, TestTurnSendDataTurnUdpToUdp) { - // Create ports and prepare addresses. - CreateTurnPort(kTurnUsername, kTurnPassword, kTurnUdpProtoAddr); - TestTurnSendData(); -} - -// Do a TURN allocation, establish a TCP connection, and send some data. -TEST_F(TurnPortTest, TestTurnSendDataTurnTcpToUdp) { - turn_server_.AddInternalSocket(kTurnTcpIntAddr, cricket::PROTO_TCP); - // Create ports and prepare addresses. - CreateTurnPort(kTurnUsername, kTurnPassword, kTurnTcpProtoAddr); - TestTurnSendData(); -} - -// Test TURN fails to make a connection from IPv6 address to a server which has -// IPv4 address. -TEST_F(TurnPortTest, TestTurnLocalIPv6AddressServerIPv4) { - turn_server_.AddInternalSocket(kTurnUdpIPv6IntAddr, cricket::PROTO_UDP); - CreateTurnPort(kLocalIPv6Addr, kTurnUsername, kTurnPassword, - kTurnUdpProtoAddr); - turn_port_->PrepareAddress(); - ASSERT_TRUE_WAIT(turn_error_, kTimeout); - EXPECT_TRUE(turn_port_->Candidates().empty()); -} - -// Test TURN make a connection from IPv6 address to a server which has -// IPv6 intenal address. But in this test external address is a IPv4 address, -// hence allocated address will be a IPv4 address. -TEST_F(TurnPortTest, TestTurnLocalIPv6AddressServerIPv6ExtenalIPv4) { - turn_server_.AddInternalSocket(kTurnUdpIPv6IntAddr, cricket::PROTO_UDP); - CreateTurnPort(kLocalIPv6Addr, kTurnUsername, kTurnPassword, - kTurnUdpIPv6ProtoAddr); - turn_port_->PrepareAddress(); - EXPECT_TRUE_WAIT(turn_ready_, kTimeout); - ASSERT_EQ(1U, turn_port_->Candidates().size()); - EXPECT_EQ(kTurnUdpExtAddr.ipaddr(), - turn_port_->Candidates()[0].address().ipaddr()); - EXPECT_NE(0, turn_port_->Candidates()[0].address().port()); -} - -// This test verifies any FD's are not leaked after TurnPort is destroyed. -// https://code.google.com/p/webrtc/issues/detail?id=2651 -#if defined(LINUX) -TEST_F(TurnPortTest, TestResolverShutdown) { - turn_server_.AddInternalSocket(kTurnUdpIPv6IntAddr, cricket::PROTO_UDP); - int last_fd_count = GetFDCount(); - // Need to supply unresolved address to kick off resolver. - CreateTurnPort(kLocalIPv6Addr, kTurnUsername, kTurnPassword, - cricket::ProtocolAddress(rtc::SocketAddress( - "stun.l.google.com", 3478), cricket::PROTO_UDP)); - turn_port_->PrepareAddress(); - ASSERT_TRUE_WAIT(turn_error_, kTimeout); - EXPECT_TRUE(turn_port_->Candidates().empty()); - turn_port_.reset(); - rtc::Thread::Current()->Post(this, MSG_TESTFINISH); - // Waiting for above message to be processed. - ASSERT_TRUE_WAIT(test_finish_, kTimeout); - EXPECT_EQ(last_fd_count, GetFDCount()); -} -#endif diff --git a/talk/p2p/base/turnserver.cc b/talk/p2p/base/turnserver.cc deleted file mode 100644 index 28096aebc..000000000 --- a/talk/p2p/base/turnserver.cc +++ /dev/null @@ -1,1028 +0,0 @@ -/* - * libjingle - * Copyright 2012, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "webrtc/p2p/base/turnserver.h" - -#include "webrtc/p2p/base/asyncstuntcpsocket.h" -#include "webrtc/p2p/base/common.h" -#include "webrtc/p2p/base/packetsocketfactory.h" -#include "webrtc/p2p/base/stun.h" -#include "webrtc/base/bytebuffer.h" -#include "webrtc/base/helpers.h" -#include "webrtc/base/logging.h" -#include "webrtc/base/messagedigest.h" -#include "webrtc/base/socketadapters.h" -#include "webrtc/base/stringencode.h" -#include "webrtc/base/thread.h" - -namespace cricket { - -// TODO(juberti): Move this all to a future turnmessage.h -//static const int IPPROTO_UDP = 17; -static const int kNonceTimeout = 60 * 60 * 1000; // 60 minutes -static const int kDefaultAllocationTimeout = 10 * 60 * 1000; // 10 minutes -static const int kPermissionTimeout = 5 * 60 * 1000; // 5 minutes -static const int kChannelTimeout = 10 * 60 * 1000; // 10 minutes - -static const int kMinChannelNumber = 0x4000; -static const int kMaxChannelNumber = 0x7FFF; - -static const size_t kNonceKeySize = 16; -static const size_t kNonceSize = 40; - -static const size_t TURN_CHANNEL_HEADER_SIZE = 4U; - -// TODO(mallinath) - Move these to a common place. -inline bool IsTurnChannelData(uint16 msg_type) { - // The first two bits of a channel data message are 0b01. - return ((msg_type & 0xC000) == 0x4000); -} - -// IDs used for posted messages for TurnServer::Allocation. -enum { - MSG_ALLOCATION_TIMEOUT, -}; - -// Encapsulates a TURN allocation. -// The object is created when an allocation request is received, and then -// handles TURN messages (via HandleTurnMessage) and channel data messages -// (via HandleChannelData) for this allocation when received by the server. -// The object self-deletes and informs the server if its lifetime timer expires. -class TurnServer::Allocation : public rtc::MessageHandler, - public sigslot::has_slots<> { - public: - Allocation(TurnServer* server_, - rtc::Thread* thread, const Connection& conn, - rtc::AsyncPacketSocket* server_socket, - const std::string& key); - virtual ~Allocation(); - - Connection* conn() { return &conn_; } - const std::string& key() const { return key_; } - const std::string& transaction_id() const { return transaction_id_; } - const std::string& username() const { return username_; } - const std::string& last_nonce() const { return last_nonce_; } - void set_last_nonce(const std::string& nonce) { last_nonce_ = nonce; } - - std::string ToString() const; - - void HandleTurnMessage(const TurnMessage* msg); - void HandleChannelData(const char* data, size_t size); - - sigslot::signal1<Allocation*> SignalDestroyed; - - private: - typedef std::list<Permission*> PermissionList; - typedef std::list<Channel*> ChannelList; - - void HandleAllocateRequest(const TurnMessage* msg); - void HandleRefreshRequest(const TurnMessage* msg); - void HandleSendIndication(const TurnMessage* msg); - void HandleCreatePermissionRequest(const TurnMessage* msg); - void HandleChannelBindRequest(const TurnMessage* msg); - - void OnExternalPacket(rtc::AsyncPacketSocket* socket, - const char* data, size_t size, - const rtc::SocketAddress& addr, - const rtc::PacketTime& packet_time); - - static int ComputeLifetime(const TurnMessage* msg); - bool HasPermission(const rtc::IPAddress& addr); - void AddPermission(const rtc::IPAddress& addr); - Permission* FindPermission(const rtc::IPAddress& addr) const; - Channel* FindChannel(int channel_id) const; - Channel* FindChannel(const rtc::SocketAddress& addr) const; - - void SendResponse(TurnMessage* msg); - void SendBadRequestResponse(const TurnMessage* req); - void SendErrorResponse(const TurnMessage* req, int code, - const std::string& reason); - void SendExternal(const void* data, size_t size, - const rtc::SocketAddress& peer); - - void OnPermissionDestroyed(Permission* perm); - void OnChannelDestroyed(Channel* channel); - virtual void OnMessage(rtc::Message* msg); - - TurnServer* server_; - rtc::Thread* thread_; - Connection conn_; - rtc::scoped_ptr<rtc::AsyncPacketSocket> external_socket_; - std::string key_; - std::string transaction_id_; - std::string username_; - std::string last_nonce_; - PermissionList perms_; - ChannelList channels_; -}; - -// Encapsulates a TURN permission. -// The object is created when a create permission request is received by an -// allocation, and self-deletes when its lifetime timer expires. -class TurnServer::Permission : public rtc::MessageHandler { - public: - Permission(rtc::Thread* thread, const rtc::IPAddress& peer); - ~Permission(); - - const rtc::IPAddress& peer() const { return peer_; } - void Refresh(); - - sigslot::signal1<Permission*> SignalDestroyed; - - private: - virtual void OnMessage(rtc::Message* msg); - - rtc::Thread* thread_; - rtc::IPAddress peer_; -}; - -// Encapsulates a TURN channel binding. -// The object is created when a channel bind request is received by an -// allocation, and self-deletes when its lifetime timer expires. -class TurnServer::Channel : public rtc::MessageHandler { - public: - Channel(rtc::Thread* thread, int id, - const rtc::SocketAddress& peer); - ~Channel(); - - int id() const { return id_; } - const rtc::SocketAddress& peer() const { return peer_; } - void Refresh(); - - sigslot::signal1<Channel*> SignalDestroyed; - - private: - virtual void OnMessage(rtc::Message* msg); - - rtc::Thread* thread_; - int id_; - rtc::SocketAddress peer_; -}; - -static bool InitResponse(const StunMessage* req, StunMessage* resp) { - int resp_type = (req) ? GetStunSuccessResponseType(req->type()) : -1; - if (resp_type == -1) - return false; - resp->SetType(resp_type); - resp->SetTransactionID(req->transaction_id()); - return true; -} - -static bool InitErrorResponse(const StunMessage* req, int code, - const std::string& reason, StunMessage* resp) { - int resp_type = (req) ? GetStunErrorResponseType(req->type()) : -1; - if (resp_type == -1) - return false; - resp->SetType(resp_type); - resp->SetTransactionID(req->transaction_id()); - VERIFY(resp->AddAttribute(new cricket::StunErrorCodeAttribute( - STUN_ATTR_ERROR_CODE, code, reason))); - return true; -} - -TurnServer::TurnServer(rtc::Thread* thread) - : thread_(thread), - nonce_key_(rtc::CreateRandomString(kNonceKeySize)), - auth_hook_(NULL), - redirect_hook_(NULL), - enable_otu_nonce_(false) { -} - -TurnServer::~TurnServer() { - for (AllocationMap::iterator it = allocations_.begin(); - it != allocations_.end(); ++it) { - delete it->second; - } - - for (InternalSocketMap::iterator it = server_sockets_.begin(); - it != server_sockets_.end(); ++it) { - rtc::AsyncPacketSocket* socket = it->first; - delete socket; - } - - for (ServerSocketMap::iterator it = server_listen_sockets_.begin(); - it != server_listen_sockets_.end(); ++it) { - rtc::AsyncSocket* socket = it->first; - delete socket; - } -} - -void TurnServer::AddInternalSocket(rtc::AsyncPacketSocket* socket, - ProtocolType proto) { - ASSERT(server_sockets_.end() == server_sockets_.find(socket)); - server_sockets_[socket] = proto; - socket->SignalReadPacket.connect(this, &TurnServer::OnInternalPacket); -} - -void TurnServer::AddInternalServerSocket(rtc::AsyncSocket* socket, - ProtocolType proto) { - ASSERT(server_listen_sockets_.end() == - server_listen_sockets_.find(socket)); - server_listen_sockets_[socket] = proto; - socket->SignalReadEvent.connect(this, &TurnServer::OnNewInternalConnection); -} - -void TurnServer::SetExternalSocketFactory( - rtc::PacketSocketFactory* factory, - const rtc::SocketAddress& external_addr) { - external_socket_factory_.reset(factory); - external_addr_ = external_addr; -} - -void TurnServer::OnNewInternalConnection(rtc::AsyncSocket* socket) { - ASSERT(server_listen_sockets_.find(socket) != server_listen_sockets_.end()); - AcceptConnection(socket); -} - -void TurnServer::AcceptConnection(rtc::AsyncSocket* server_socket) { - // Check if someone is trying to connect to us. - rtc::SocketAddress accept_addr; - rtc::AsyncSocket* accepted_socket = server_socket->Accept(&accept_addr); - if (accepted_socket != NULL) { - ProtocolType proto = server_listen_sockets_[server_socket]; - cricket::AsyncStunTCPSocket* tcp_socket = - new cricket::AsyncStunTCPSocket(accepted_socket, false); - - tcp_socket->SignalClose.connect(this, &TurnServer::OnInternalSocketClose); - // Finally add the socket so it can start communicating with the client. - AddInternalSocket(tcp_socket, proto); - } -} - -void TurnServer::OnInternalSocketClose(rtc::AsyncPacketSocket* socket, - int err) { - DestroyInternalSocket(socket); -} - -void TurnServer::OnInternalPacket(rtc::AsyncPacketSocket* socket, - const char* data, size_t size, - const rtc::SocketAddress& addr, - const rtc::PacketTime& packet_time) { - // Fail if the packet is too small to even contain a channel header. - if (size < TURN_CHANNEL_HEADER_SIZE) { - return; - } - InternalSocketMap::iterator iter = server_sockets_.find(socket); - ASSERT(iter != server_sockets_.end()); - Connection conn(addr, iter->second, socket); - uint16 msg_type = rtc::GetBE16(data); - if (!IsTurnChannelData(msg_type)) { - // This is a STUN message. - HandleStunMessage(&conn, data, size); - } else { - // This is a channel message; let the allocation handle it. - Allocation* allocation = FindAllocation(&conn); - if (allocation) { - allocation->HandleChannelData(data, size); - } - } -} - -void TurnServer::HandleStunMessage(Connection* conn, const char* data, - size_t size) { - TurnMessage msg; - rtc::ByteBuffer buf(data, size); - if (!msg.Read(&buf) || (buf.Length() > 0)) { - LOG(LS_WARNING) << "Received invalid STUN message"; - return; - } - - // If it's a STUN binding request, handle that specially. - if (msg.type() == STUN_BINDING_REQUEST) { - HandleBindingRequest(conn, &msg); - return; - } - - if (redirect_hook_ != NULL && msg.type() == STUN_ALLOCATE_REQUEST) { - rtc::SocketAddress address; - if (redirect_hook_->ShouldRedirect(conn->src(), &address)) { - SendErrorResponseWithAlternateServer( - conn, &msg, address); - return; - } - } - - // Look up the key that we'll use to validate the M-I. If we have an - // existing allocation, the key will already be cached. - Allocation* allocation = FindAllocation(conn); - std::string key; - if (!allocation) { - GetKey(&msg, &key); - } else { - key = allocation->key(); - } - - // Ensure the message is authorized; only needed for requests. - if (IsStunRequestType(msg.type())) { - if (!CheckAuthorization(conn, &msg, data, size, key)) { - return; - } - } - - if (!allocation && msg.type() == STUN_ALLOCATE_REQUEST) { - HandleAllocateRequest(conn, &msg, key); - } else if (allocation && - (msg.type() != STUN_ALLOCATE_REQUEST || - msg.transaction_id() == allocation->transaction_id())) { - // This is a non-allocate request, or a retransmit of an allocate. - // Check that the username matches the previous username used. - if (IsStunRequestType(msg.type()) && - msg.GetByteString(STUN_ATTR_USERNAME)->GetString() != - allocation->username()) { - SendErrorResponse(conn, &msg, STUN_ERROR_WRONG_CREDENTIALS, - STUN_ERROR_REASON_WRONG_CREDENTIALS); - return; - } - allocation->HandleTurnMessage(&msg); - } else { - // Allocation mismatch. - SendErrorResponse(conn, &msg, STUN_ERROR_ALLOCATION_MISMATCH, - STUN_ERROR_REASON_ALLOCATION_MISMATCH); - } -} - -bool TurnServer::GetKey(const StunMessage* msg, std::string* key) { - const StunByteStringAttribute* username_attr = - msg->GetByteString(STUN_ATTR_USERNAME); - if (!username_attr) { - return false; - } - - std::string username = username_attr->GetString(); - return (auth_hook_ != NULL && auth_hook_->GetKey(username, realm_, key)); -} - -bool TurnServer::CheckAuthorization(Connection* conn, - const StunMessage* msg, - const char* data, size_t size, - const std::string& key) { - // RFC 5389, 10.2.2. - ASSERT(IsStunRequestType(msg->type())); - const StunByteStringAttribute* mi_attr = - msg->GetByteString(STUN_ATTR_MESSAGE_INTEGRITY); - const StunByteStringAttribute* username_attr = - msg->GetByteString(STUN_ATTR_USERNAME); - const StunByteStringAttribute* realm_attr = - msg->GetByteString(STUN_ATTR_REALM); - const StunByteStringAttribute* nonce_attr = - msg->GetByteString(STUN_ATTR_NONCE); - - // Fail if no M-I. - if (!mi_attr) { - SendErrorResponseWithRealmAndNonce(conn, msg, STUN_ERROR_UNAUTHORIZED, - STUN_ERROR_REASON_UNAUTHORIZED); - return false; - } - - // Fail if there is M-I but no username, nonce, or realm. - if (!username_attr || !realm_attr || !nonce_attr) { - SendErrorResponse(conn, msg, STUN_ERROR_BAD_REQUEST, - STUN_ERROR_REASON_BAD_REQUEST); - return false; - } - - // Fail if bad nonce. - if (!ValidateNonce(nonce_attr->GetString())) { - SendErrorResponseWithRealmAndNonce(conn, msg, STUN_ERROR_STALE_NONCE, - STUN_ERROR_REASON_STALE_NONCE); - return false; - } - - // Fail if bad username or M-I. - // We need |data| and |size| for the call to ValidateMessageIntegrity. - if (key.empty() || !StunMessage::ValidateMessageIntegrity(data, size, key)) { - SendErrorResponseWithRealmAndNonce(conn, msg, STUN_ERROR_UNAUTHORIZED, - STUN_ERROR_REASON_UNAUTHORIZED); - return false; - } - - // Fail if one-time-use nonce feature is enabled. - Allocation* allocation = FindAllocation(conn); - if (enable_otu_nonce_ && allocation && - allocation->last_nonce() == nonce_attr->GetString()) { - SendErrorResponseWithRealmAndNonce(conn, msg, STUN_ERROR_STALE_NONCE, - STUN_ERROR_REASON_STALE_NONCE); - return false; - } - - if (allocation) { - allocation->set_last_nonce(nonce_attr->GetString()); - } - // Success. - return true; -} - -void TurnServer::HandleBindingRequest(Connection* conn, - const StunMessage* req) { - StunMessage response; - InitResponse(req, &response); - - // Tell the user the address that we received their request from. - StunAddressAttribute* mapped_addr_attr; - mapped_addr_attr = new StunXorAddressAttribute( - STUN_ATTR_XOR_MAPPED_ADDRESS, conn->src()); - VERIFY(response.AddAttribute(mapped_addr_attr)); - - SendStun(conn, &response); -} - -void TurnServer::HandleAllocateRequest(Connection* conn, - const TurnMessage* msg, - const std::string& key) { - // Check the parameters in the request. - const StunUInt32Attribute* transport_attr = - msg->GetUInt32(STUN_ATTR_REQUESTED_TRANSPORT); - if (!transport_attr) { - SendErrorResponse(conn, msg, STUN_ERROR_BAD_REQUEST, - STUN_ERROR_REASON_BAD_REQUEST); - return; - } - - // Only UDP is supported right now. - int proto = transport_attr->value() >> 24; - if (proto != IPPROTO_UDP) { - SendErrorResponse(conn, msg, STUN_ERROR_UNSUPPORTED_PROTOCOL, - STUN_ERROR_REASON_UNSUPPORTED_PROTOCOL); - return; - } - - // Create the allocation and let it send the success response. - // If the actual socket allocation fails, send an internal error. - Allocation* alloc = CreateAllocation(conn, proto, key); - if (alloc) { - alloc->HandleTurnMessage(msg); - } else { - SendErrorResponse(conn, msg, STUN_ERROR_SERVER_ERROR, - "Failed to allocate socket"); - } -} - -std::string TurnServer::GenerateNonce() const { - // Generate a nonce of the form hex(now + HMAC-MD5(nonce_key_, now)) - uint32 now = rtc::Time(); - std::string input(reinterpret_cast<const char*>(&now), sizeof(now)); - std::string nonce = rtc::hex_encode(input.c_str(), input.size()); - nonce += rtc::ComputeHmac(rtc::DIGEST_MD5, nonce_key_, input); - ASSERT(nonce.size() == kNonceSize); - return nonce; -} - -bool TurnServer::ValidateNonce(const std::string& nonce) const { - // Check the size. - if (nonce.size() != kNonceSize) { - return false; - } - - // Decode the timestamp. - uint32 then; - char* p = reinterpret_cast<char*>(&then); - size_t len = rtc::hex_decode(p, sizeof(then), - nonce.substr(0, sizeof(then) * 2)); - if (len != sizeof(then)) { - return false; - } - - // Verify the HMAC. - if (nonce.substr(sizeof(then) * 2) != rtc::ComputeHmac( - rtc::DIGEST_MD5, nonce_key_, std::string(p, sizeof(then)))) { - return false; - } - - // Validate the timestamp. - return rtc::TimeSince(then) < kNonceTimeout; -} - -TurnServer::Allocation* TurnServer::FindAllocation(Connection* conn) { - AllocationMap::const_iterator it = allocations_.find(*conn); - return (it != allocations_.end()) ? it->second : NULL; -} - -TurnServer::Allocation* TurnServer::CreateAllocation(Connection* conn, - int proto, - const std::string& key) { - rtc::AsyncPacketSocket* external_socket = (external_socket_factory_) ? - external_socket_factory_->CreateUdpSocket(external_addr_, 0, 0) : NULL; - if (!external_socket) { - return NULL; - } - - // The Allocation takes ownership of the socket. - Allocation* allocation = new Allocation(this, - thread_, *conn, external_socket, key); - allocation->SignalDestroyed.connect(this, &TurnServer::OnAllocationDestroyed); - allocations_[*conn] = allocation; - return allocation; -} - -void TurnServer::SendErrorResponse(Connection* conn, - const StunMessage* req, - int code, const std::string& reason) { - TurnMessage resp; - InitErrorResponse(req, code, reason, &resp); - LOG(LS_INFO) << "Sending error response, type=" << resp.type() - << ", code=" << code << ", reason=" << reason; - SendStun(conn, &resp); -} - -void TurnServer::SendErrorResponseWithRealmAndNonce( - Connection* conn, const StunMessage* msg, - int code, const std::string& reason) { - TurnMessage resp; - InitErrorResponse(msg, code, reason, &resp); - VERIFY(resp.AddAttribute(new StunByteStringAttribute( - STUN_ATTR_NONCE, GenerateNonce()))); - VERIFY(resp.AddAttribute(new StunByteStringAttribute( - STUN_ATTR_REALM, realm_))); - SendStun(conn, &resp); -} - -void TurnServer::SendErrorResponseWithAlternateServer( - Connection* conn, const StunMessage* msg, - const rtc::SocketAddress& addr) { - TurnMessage resp; - InitErrorResponse(msg, STUN_ERROR_TRY_ALTERNATE, - STUN_ERROR_REASON_TRY_ALTERNATE_SERVER, &resp); - VERIFY(resp.AddAttribute(new StunAddressAttribute( - STUN_ATTR_ALTERNATE_SERVER, addr))); - SendStun(conn, &resp); -} - -void TurnServer::SendStun(Connection* conn, StunMessage* msg) { - rtc::ByteBuffer buf; - // Add a SOFTWARE attribute if one is set. - if (!software_.empty()) { - VERIFY(msg->AddAttribute( - new StunByteStringAttribute(STUN_ATTR_SOFTWARE, software_))); - } - msg->Write(&buf); - Send(conn, buf); -} - -void TurnServer::Send(Connection* conn, - const rtc::ByteBuffer& buf) { - rtc::PacketOptions options; - conn->socket()->SendTo(buf.Data(), buf.Length(), conn->src(), options); -} - -void TurnServer::OnAllocationDestroyed(Allocation* allocation) { - // Removing the internal socket if the connection is not udp. - rtc::AsyncPacketSocket* socket = allocation->conn()->socket(); - InternalSocketMap::iterator iter = server_sockets_.find(socket); - ASSERT(iter != server_sockets_.end()); - // Skip if the socket serving this allocation is UDP, as this will be shared - // by all allocations. - if (iter->second != cricket::PROTO_UDP) { - DestroyInternalSocket(socket); - } - - AllocationMap::iterator it = allocations_.find(*(allocation->conn())); - if (it != allocations_.end()) - allocations_.erase(it); -} - -void TurnServer::DestroyInternalSocket(rtc::AsyncPacketSocket* socket) { - InternalSocketMap::iterator iter = server_sockets_.find(socket); - if (iter != server_sockets_.end()) { - rtc::AsyncPacketSocket* socket = iter->first; - // We must destroy the socket async to avoid invalidating the sigslot - // callback list iterator inside a sigslot callback. - rtc::Thread::Current()->Dispose(socket); - server_sockets_.erase(iter); - } -} - -TurnServer::Connection::Connection(const rtc::SocketAddress& src, - ProtocolType proto, - rtc::AsyncPacketSocket* socket) - : src_(src), - dst_(socket->GetRemoteAddress()), - proto_(proto), - socket_(socket) { -} - -bool TurnServer::Connection::operator==(const Connection& c) const { - return src_ == c.src_ && dst_ == c.dst_ && proto_ == c.proto_; -} - -bool TurnServer::Connection::operator<(const Connection& c) const { - return src_ < c.src_ || dst_ < c.dst_ || proto_ < c.proto_; -} - -std::string TurnServer::Connection::ToString() const { - const char* const kProtos[] = { - "unknown", "udp", "tcp", "ssltcp" - }; - std::ostringstream ost; - ost << src_.ToString() << "-" << dst_.ToString() << ":"<< kProtos[proto_]; - return ost.str(); -} - -TurnServer::Allocation::Allocation(TurnServer* server, - rtc::Thread* thread, - const Connection& conn, - rtc::AsyncPacketSocket* socket, - const std::string& key) - : server_(server), - thread_(thread), - conn_(conn), - external_socket_(socket), - key_(key) { - external_socket_->SignalReadPacket.connect( - this, &TurnServer::Allocation::OnExternalPacket); -} - -TurnServer::Allocation::~Allocation() { - for (ChannelList::iterator it = channels_.begin(); - it != channels_.end(); ++it) { - delete *it; - } - for (PermissionList::iterator it = perms_.begin(); - it != perms_.end(); ++it) { - delete *it; - } - thread_->Clear(this, MSG_ALLOCATION_TIMEOUT); - LOG_J(LS_INFO, this) << "Allocation destroyed"; -} - -std::string TurnServer::Allocation::ToString() const { - std::ostringstream ost; - ost << "Alloc[" << conn_.ToString() << "]"; - return ost.str(); -} - -void TurnServer::Allocation::HandleTurnMessage(const TurnMessage* msg) { - ASSERT(msg != NULL); - switch (msg->type()) { - case STUN_ALLOCATE_REQUEST: - HandleAllocateRequest(msg); - break; - case TURN_REFRESH_REQUEST: - HandleRefreshRequest(msg); - break; - case TURN_SEND_INDICATION: - HandleSendIndication(msg); - break; - case TURN_CREATE_PERMISSION_REQUEST: - HandleCreatePermissionRequest(msg); - break; - case TURN_CHANNEL_BIND_REQUEST: - HandleChannelBindRequest(msg); - break; - default: - // Not sure what to do with this, just eat it. - LOG_J(LS_WARNING, this) << "Invalid TURN message type received: " - << msg->type(); - } -} - -void TurnServer::Allocation::HandleAllocateRequest(const TurnMessage* msg) { - // Copy the important info from the allocate request. - transaction_id_ = msg->transaction_id(); - const StunByteStringAttribute* username_attr = - msg->GetByteString(STUN_ATTR_USERNAME); - ASSERT(username_attr != NULL); - username_ = username_attr->GetString(); - - // Figure out the lifetime and start the allocation timer. - int lifetime_secs = ComputeLifetime(msg); - thread_->PostDelayed(lifetime_secs * 1000, this, MSG_ALLOCATION_TIMEOUT); - - LOG_J(LS_INFO, this) << "Created allocation, lifetime=" << lifetime_secs; - - // We've already validated all the important bits; just send a response here. - TurnMessage response; - InitResponse(msg, &response); - - StunAddressAttribute* mapped_addr_attr = - new StunXorAddressAttribute(STUN_ATTR_XOR_MAPPED_ADDRESS, conn_.src()); - StunAddressAttribute* relayed_addr_attr = - new StunXorAddressAttribute(STUN_ATTR_XOR_RELAYED_ADDRESS, - external_socket_->GetLocalAddress()); - StunUInt32Attribute* lifetime_attr = - new StunUInt32Attribute(STUN_ATTR_LIFETIME, lifetime_secs); - VERIFY(response.AddAttribute(mapped_addr_attr)); - VERIFY(response.AddAttribute(relayed_addr_attr)); - VERIFY(response.AddAttribute(lifetime_attr)); - - SendResponse(&response); -} - -void TurnServer::Allocation::HandleRefreshRequest(const TurnMessage* msg) { - // Figure out the new lifetime. - int lifetime_secs = ComputeLifetime(msg); - - // Reset the expiration timer. - thread_->Clear(this, MSG_ALLOCATION_TIMEOUT); - thread_->PostDelayed(lifetime_secs * 1000, this, MSG_ALLOCATION_TIMEOUT); - - LOG_J(LS_INFO, this) << "Refreshed allocation, lifetime=" << lifetime_secs; - - // Send a success response with a LIFETIME attribute. - TurnMessage response; - InitResponse(msg, &response); - - StunUInt32Attribute* lifetime_attr = - new StunUInt32Attribute(STUN_ATTR_LIFETIME, lifetime_secs); - VERIFY(response.AddAttribute(lifetime_attr)); - - SendResponse(&response); -} - -void TurnServer::Allocation::HandleSendIndication(const TurnMessage* msg) { - // Check mandatory attributes. - const StunByteStringAttribute* data_attr = msg->GetByteString(STUN_ATTR_DATA); - const StunAddressAttribute* peer_attr = - msg->GetAddress(STUN_ATTR_XOR_PEER_ADDRESS); - if (!data_attr || !peer_attr) { - LOG_J(LS_WARNING, this) << "Received invalid send indication"; - return; - } - - // If a permission exists, send the data on to the peer. - if (HasPermission(peer_attr->GetAddress().ipaddr())) { - SendExternal(data_attr->bytes(), data_attr->length(), - peer_attr->GetAddress()); - } else { - LOG_J(LS_WARNING, this) << "Received send indication without permission" - << "peer=" << peer_attr->GetAddress(); - } -} - -void TurnServer::Allocation::HandleCreatePermissionRequest( - const TurnMessage* msg) { - // Check mandatory attributes. - const StunAddressAttribute* peer_attr = - msg->GetAddress(STUN_ATTR_XOR_PEER_ADDRESS); - if (!peer_attr) { - SendBadRequestResponse(msg); - return; - } - - // Add this permission. - AddPermission(peer_attr->GetAddress().ipaddr()); - - LOG_J(LS_INFO, this) << "Created permission, peer=" - << peer_attr->GetAddress(); - - // Send a success response. - TurnMessage response; - InitResponse(msg, &response); - SendResponse(&response); -} - -void TurnServer::Allocation::HandleChannelBindRequest(const TurnMessage* msg) { - // Check mandatory attributes. - const StunUInt32Attribute* channel_attr = - msg->GetUInt32(STUN_ATTR_CHANNEL_NUMBER); - const StunAddressAttribute* peer_attr = - msg->GetAddress(STUN_ATTR_XOR_PEER_ADDRESS); - if (!channel_attr || !peer_attr) { - SendBadRequestResponse(msg); - return; - } - - // Check that channel id is valid. - int channel_id = channel_attr->value() >> 16; - if (channel_id < kMinChannelNumber || channel_id > kMaxChannelNumber) { - SendBadRequestResponse(msg); - return; - } - - // Check that this channel id isn't bound to another transport address, and - // that this transport address isn't bound to another channel id. - Channel* channel1 = FindChannel(channel_id); - Channel* channel2 = FindChannel(peer_attr->GetAddress()); - if (channel1 != channel2) { - SendBadRequestResponse(msg); - return; - } - - // Add or refresh this channel. - if (!channel1) { - channel1 = new Channel(thread_, channel_id, peer_attr->GetAddress()); - channel1->SignalDestroyed.connect(this, - &TurnServer::Allocation::OnChannelDestroyed); - channels_.push_back(channel1); - } else { - channel1->Refresh(); - } - - // Channel binds also refresh permissions. - AddPermission(peer_attr->GetAddress().ipaddr()); - - LOG_J(LS_INFO, this) << "Bound channel, id=" << channel_id - << ", peer=" << peer_attr->GetAddress(); - - // Send a success response. - TurnMessage response; - InitResponse(msg, &response); - SendResponse(&response); -} - -void TurnServer::Allocation::HandleChannelData(const char* data, size_t size) { - // Extract the channel number from the data. - uint16 channel_id = rtc::GetBE16(data); - Channel* channel = FindChannel(channel_id); - if (channel) { - // Send the data to the peer address. - SendExternal(data + TURN_CHANNEL_HEADER_SIZE, - size - TURN_CHANNEL_HEADER_SIZE, channel->peer()); - } else { - LOG_J(LS_WARNING, this) << "Received channel data for invalid channel, id=" - << channel_id; - } -} - -void TurnServer::Allocation::OnExternalPacket( - rtc::AsyncPacketSocket* socket, - const char* data, size_t size, - const rtc::SocketAddress& addr, - const rtc::PacketTime& packet_time) { - ASSERT(external_socket_.get() == socket); - Channel* channel = FindChannel(addr); - if (channel) { - // There is a channel bound to this address. Send as a channel message. - rtc::ByteBuffer buf; - buf.WriteUInt16(channel->id()); - buf.WriteUInt16(static_cast<uint16>(size)); - buf.WriteBytes(data, size); - server_->Send(&conn_, buf); - } else if (HasPermission(addr.ipaddr())) { - // No channel, but a permission exists. Send as a data indication. - TurnMessage msg; - msg.SetType(TURN_DATA_INDICATION); - msg.SetTransactionID( - rtc::CreateRandomString(kStunTransactionIdLength)); - VERIFY(msg.AddAttribute(new StunXorAddressAttribute( - STUN_ATTR_XOR_PEER_ADDRESS, addr))); - VERIFY(msg.AddAttribute(new StunByteStringAttribute( - STUN_ATTR_DATA, data, size))); - server_->SendStun(&conn_, &msg); - } else { - LOG_J(LS_WARNING, this) << "Received external packet without permission, " - << "peer=" << addr; - } -} - -int TurnServer::Allocation::ComputeLifetime(const TurnMessage* msg) { - // Return the smaller of our default lifetime and the requested lifetime. - uint32 lifetime = kDefaultAllocationTimeout / 1000; // convert to seconds - const StunUInt32Attribute* lifetime_attr = msg->GetUInt32(STUN_ATTR_LIFETIME); - if (lifetime_attr && lifetime_attr->value() < lifetime) { - lifetime = lifetime_attr->value(); - } - return lifetime; -} - -bool TurnServer::Allocation::HasPermission(const rtc::IPAddress& addr) { - return (FindPermission(addr) != NULL); -} - -void TurnServer::Allocation::AddPermission(const rtc::IPAddress& addr) { - Permission* perm = FindPermission(addr); - if (!perm) { - perm = new Permission(thread_, addr); - perm->SignalDestroyed.connect( - this, &TurnServer::Allocation::OnPermissionDestroyed); - perms_.push_back(perm); - } else { - perm->Refresh(); - } -} - -TurnServer::Permission* TurnServer::Allocation::FindPermission( - const rtc::IPAddress& addr) const { - for (PermissionList::const_iterator it = perms_.begin(); - it != perms_.end(); ++it) { - if ((*it)->peer() == addr) - return *it; - } - return NULL; -} - -TurnServer::Channel* TurnServer::Allocation::FindChannel(int channel_id) const { - for (ChannelList::const_iterator it = channels_.begin(); - it != channels_.end(); ++it) { - if ((*it)->id() == channel_id) - return *it; - } - return NULL; -} - -TurnServer::Channel* TurnServer::Allocation::FindChannel( - const rtc::SocketAddress& addr) const { - for (ChannelList::const_iterator it = channels_.begin(); - it != channels_.end(); ++it) { - if ((*it)->peer() == addr) - return *it; - } - return NULL; -} - -void TurnServer::Allocation::SendResponse(TurnMessage* msg) { - // Success responses always have M-I. - msg->AddMessageIntegrity(key_); - server_->SendStun(&conn_, msg); -} - -void TurnServer::Allocation::SendBadRequestResponse(const TurnMessage* req) { - SendErrorResponse(req, STUN_ERROR_BAD_REQUEST, STUN_ERROR_REASON_BAD_REQUEST); -} - -void TurnServer::Allocation::SendErrorResponse(const TurnMessage* req, int code, - const std::string& reason) { - server_->SendErrorResponse(&conn_, req, code, reason); -} - -void TurnServer::Allocation::SendExternal(const void* data, size_t size, - const rtc::SocketAddress& peer) { - rtc::PacketOptions options; - external_socket_->SendTo(data, size, peer, options); -} - -void TurnServer::Allocation::OnMessage(rtc::Message* msg) { - ASSERT(msg->message_id == MSG_ALLOCATION_TIMEOUT); - SignalDestroyed(this); - delete this; -} - -void TurnServer::Allocation::OnPermissionDestroyed(Permission* perm) { - PermissionList::iterator it = std::find(perms_.begin(), perms_.end(), perm); - ASSERT(it != perms_.end()); - perms_.erase(it); -} - -void TurnServer::Allocation::OnChannelDestroyed(Channel* channel) { - ChannelList::iterator it = - std::find(channels_.begin(), channels_.end(), channel); - ASSERT(it != channels_.end()); - channels_.erase(it); -} - -TurnServer::Permission::Permission(rtc::Thread* thread, - const rtc::IPAddress& peer) - : thread_(thread), peer_(peer) { - Refresh(); -} - -TurnServer::Permission::~Permission() { - thread_->Clear(this, MSG_ALLOCATION_TIMEOUT); -} - -void TurnServer::Permission::Refresh() { - thread_->Clear(this, MSG_ALLOCATION_TIMEOUT); - thread_->PostDelayed(kPermissionTimeout, this, MSG_ALLOCATION_TIMEOUT); -} - -void TurnServer::Permission::OnMessage(rtc::Message* msg) { - ASSERT(msg->message_id == MSG_ALLOCATION_TIMEOUT); - SignalDestroyed(this); - delete this; -} - -TurnServer::Channel::Channel(rtc::Thread* thread, int id, - const rtc::SocketAddress& peer) - : thread_(thread), id_(id), peer_(peer) { - Refresh(); -} - -TurnServer::Channel::~Channel() { - thread_->Clear(this, MSG_ALLOCATION_TIMEOUT); -} - -void TurnServer::Channel::Refresh() { - thread_->Clear(this, MSG_ALLOCATION_TIMEOUT); - thread_->PostDelayed(kChannelTimeout, this, MSG_ALLOCATION_TIMEOUT); -} - -void TurnServer::Channel::OnMessage(rtc::Message* msg) { - ASSERT(msg->message_id == MSG_ALLOCATION_TIMEOUT); - SignalDestroyed(this); - delete this; -} - -} // namespace cricket diff --git a/talk/p2p/base/turnserver.h b/talk/p2p/base/turnserver.h deleted file mode 100644 index 44878fdc8..000000000 --- a/talk/p2p/base/turnserver.h +++ /dev/null @@ -1,207 +0,0 @@ -/* - * libjingle - * Copyright 2012, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef WEBRTC_P2P_BASE_TURNSERVER_H_ -#define WEBRTC_P2P_BASE_TURNSERVER_H_ - -#include <list> -#include <map> -#include <set> -#include <string> - -#include "webrtc/p2p/base/portinterface.h" -#include "webrtc/base/asyncpacketsocket.h" -#include "webrtc/base/messagequeue.h" -#include "webrtc/base/sigslot.h" -#include "webrtc/base/socketaddress.h" - -namespace rtc { -class ByteBuffer; -class PacketSocketFactory; -class Thread; -} - -namespace cricket { - -class StunMessage; -class TurnMessage; - -// The default server port for TURN, as specified in RFC5766. -const int TURN_SERVER_PORT = 3478; - -// An interface through which the MD5 credential hash can be retrieved. -class TurnAuthInterface { - public: - // Gets HA1 for the specified user and realm. - // HA1 = MD5(A1) = MD5(username:realm:password). - // Return true if the given username and realm are valid, or false if not. - virtual bool GetKey(const std::string& username, const std::string& realm, - std::string* key) = 0; -}; - -// An interface enables Turn Server to control redirection behavior. -class TurnRedirectInterface { - public: - virtual bool ShouldRedirect(const rtc::SocketAddress& address, - rtc::SocketAddress* out) = 0; - virtual ~TurnRedirectInterface() {} -}; - -// The core TURN server class. Give it a socket to listen on via -// AddInternalServerSocket, and a factory to create external sockets via -// SetExternalSocketFactory, and it's ready to go. -// Not yet wired up: TCP support. -class TurnServer : public sigslot::has_slots<> { - public: - explicit TurnServer(rtc::Thread* thread); - ~TurnServer(); - - // Gets/sets the realm value to use for the server. - const std::string& realm() const { return realm_; } - void set_realm(const std::string& realm) { realm_ = realm; } - - // Gets/sets the value for the SOFTWARE attribute for TURN messages. - const std::string& software() const { return software_; } - void set_software(const std::string& software) { software_ = software; } - - // Sets the authentication callback; does not take ownership. - void set_auth_hook(TurnAuthInterface* auth_hook) { auth_hook_ = auth_hook; } - - void set_redirect_hook(TurnRedirectInterface* redirect_hook) { - redirect_hook_ = redirect_hook; - } - - void set_enable_otu_nonce(bool enable) { enable_otu_nonce_ = enable; } - - // Starts listening for packets from internal clients. - void AddInternalSocket(rtc::AsyncPacketSocket* socket, - ProtocolType proto); - // Starts listening for the connections on this socket. When someone tries - // to connect, the connection will be accepted and a new internal socket - // will be added. - void AddInternalServerSocket(rtc::AsyncSocket* socket, - ProtocolType proto); - // Specifies the factory to use for creating external sockets. - void SetExternalSocketFactory(rtc::PacketSocketFactory* factory, - const rtc::SocketAddress& address); - - private: - // Encapsulates the client's connection to the server. - class Connection { - public: - Connection() : proto_(PROTO_UDP), socket_(NULL) {} - Connection(const rtc::SocketAddress& src, - ProtocolType proto, - rtc::AsyncPacketSocket* socket); - const rtc::SocketAddress& src() const { return src_; } - rtc::AsyncPacketSocket* socket() { return socket_; } - bool operator==(const Connection& t) const; - bool operator<(const Connection& t) const; - std::string ToString() const; - - private: - rtc::SocketAddress src_; - rtc::SocketAddress dst_; - cricket::ProtocolType proto_; - rtc::AsyncPacketSocket* socket_; - }; - class Allocation; - class Permission; - class Channel; - typedef std::map<Connection, Allocation*> AllocationMap; - - void OnInternalPacket(rtc::AsyncPacketSocket* socket, const char* data, - size_t size, const rtc::SocketAddress& address, - const rtc::PacketTime& packet_time); - - void OnNewInternalConnection(rtc::AsyncSocket* socket); - - // Accept connections on this server socket. - void AcceptConnection(rtc::AsyncSocket* server_socket); - void OnInternalSocketClose(rtc::AsyncPacketSocket* socket, int err); - - void HandleStunMessage(Connection* conn, const char* data, size_t size); - void HandleBindingRequest(Connection* conn, const StunMessage* msg); - void HandleAllocateRequest(Connection* conn, const TurnMessage* msg, - const std::string& key); - - bool GetKey(const StunMessage* msg, std::string* key); - bool CheckAuthorization(Connection* conn, const StunMessage* msg, - const char* data, size_t size, - const std::string& key); - std::string GenerateNonce() const; - bool ValidateNonce(const std::string& nonce) const; - - Allocation* FindAllocation(Connection* conn); - Allocation* CreateAllocation(Connection* conn, int proto, - const std::string& key); - - void SendErrorResponse(Connection* conn, const StunMessage* req, - int code, const std::string& reason); - - void SendErrorResponseWithRealmAndNonce(Connection* conn, - const StunMessage* req, - int code, - const std::string& reason); - - void SendErrorResponseWithAlternateServer(Connection* conn, - const StunMessage* req, - const rtc::SocketAddress& addr); - - void SendStun(Connection* conn, StunMessage* msg); - void Send(Connection* conn, const rtc::ByteBuffer& buf); - - void OnAllocationDestroyed(Allocation* allocation); - void DestroyInternalSocket(rtc::AsyncPacketSocket* socket); - - typedef std::map<rtc::AsyncPacketSocket*, - ProtocolType> InternalSocketMap; - typedef std::map<rtc::AsyncSocket*, - ProtocolType> ServerSocketMap; - - rtc::Thread* thread_; - std::string nonce_key_; - std::string realm_; - std::string software_; - TurnAuthInterface* auth_hook_; - TurnRedirectInterface* redirect_hook_; - // otu - one-time-use. Server will respond with 438 if it's - // sees the same nonce in next transaction. - bool enable_otu_nonce_; - - InternalSocketMap server_sockets_; - ServerSocketMap server_listen_sockets_; - rtc::scoped_ptr<rtc::PacketSocketFactory> - external_socket_factory_; - rtc::SocketAddress external_addr_; - - AllocationMap allocations_; -}; - -} // namespace cricket - -#endif // WEBRTC_P2P_BASE_TURNSERVER_H_ diff --git a/talk/p2p/base/udpport.h b/talk/p2p/base/udpport.h deleted file mode 100644 index 35be1a16b..000000000 --- a/talk/p2p/base/udpport.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef WEBRTC_P2P_BASE_UDPPORT_H_ -#define WEBRTC_P2P_BASE_UDPPORT_H_ - -// StunPort will be handling UDPPort functionality. -#include "webrtc/p2p/base/stunport.h" - -#endif // WEBRTC_P2P_BASE_UDPPORT_H_ diff --git a/talk/p2p/client/autoportallocator.h b/talk/p2p/client/autoportallocator.h deleted file mode 100644 index e7f216994..000000000 --- a/talk/p2p/client/autoportallocator.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * libjingle - * Copyright 2010, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef WEBRTC_P2P_CLIENT_AUTOPORTALLOCATOR_H_ -#define WEBRTC_P2P_CLIENT_AUTOPORTALLOCATOR_H_ - -#include <string> -#include <vector> - -#include "webrtc/p2p/client/httpportallocator.h" -#include "webrtc/libjingle/xmpp/jingleinfotask.h" -#include "webrtc/libjingle/xmpp/xmppclient.h" -#include "webrtc/base/sigslot.h" - -// This class sets the relay and stun servers using XmppClient. -// It enables the client to traverse Proxy and NAT. -class AutoPortAllocator : public cricket::HttpPortAllocator { - public: - AutoPortAllocator(rtc::NetworkManager* network_manager, - const std::string& user_agent) - : cricket::HttpPortAllocator(network_manager, user_agent) { - } - - // Creates and initiates a task to get relay token from XmppClient and set - // it appropriately. - void SetXmppClient(buzz::XmppClient* client) { - // The JingleInfoTask is freed by the task-runner. - buzz::JingleInfoTask* jit = new buzz::JingleInfoTask(client); - jit->SignalJingleInfo.connect(this, &AutoPortAllocator::OnJingleInfo); - jit->Start(); - jit->RefreshJingleInfoNow(); - } - - private: - void OnJingleInfo( - const std::string& token, - const std::vector<std::string>& relay_hosts, - const std::vector<rtc::SocketAddress>& stun_hosts) { - SetRelayToken(token); - SetStunHosts(stun_hosts); - SetRelayHosts(relay_hosts); - } -}; - -#endif // WEBRTC_P2P_CLIENT_AUTOPORTALLOCATOR_H_ diff --git a/talk/p2p/client/basicportallocator.cc b/talk/p2p/client/basicportallocator.cc deleted file mode 100644 index 27d0db2d1..000000000 --- a/talk/p2p/client/basicportallocator.cc +++ /dev/null @@ -1,1207 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "webrtc/p2p/client/basicportallocator.h" - -#include <string> -#include <vector> - -#include "webrtc/p2p/base/basicpacketsocketfactory.h" -#include "webrtc/p2p/base/common.h" -#include "webrtc/p2p/base/port.h" -#include "webrtc/p2p/base/relayport.h" -#include "webrtc/p2p/base/stunport.h" -#include "webrtc/p2p/base/tcpport.h" -#include "webrtc/p2p/base/turnport.h" -#include "webrtc/p2p/base/udpport.h" -#include "webrtc/base/common.h" -#include "webrtc/base/helpers.h" -#include "webrtc/base/logging.h" - -using rtc::CreateRandomId; -using rtc::CreateRandomString; - -namespace { - -enum { - MSG_CONFIG_START, - MSG_CONFIG_READY, - MSG_ALLOCATE, - MSG_ALLOCATION_PHASE, - MSG_SHAKE, - MSG_SEQUENCEOBJECTS_CREATED, - MSG_CONFIG_STOP, -}; - -const int PHASE_UDP = 0; -const int PHASE_RELAY = 1; -const int PHASE_TCP = 2; -const int PHASE_SSLTCP = 3; - -const int kNumPhases = 4; - -const int SHAKE_MIN_DELAY = 45 * 1000; // 45 seconds -const int SHAKE_MAX_DELAY = 90 * 1000; // 90 seconds - -int ShakeDelay() { - int range = SHAKE_MAX_DELAY - SHAKE_MIN_DELAY + 1; - return SHAKE_MIN_DELAY + CreateRandomId() % range; -} - -} // namespace - -namespace cricket { - -const uint32 DISABLE_ALL_PHASES = - PORTALLOCATOR_DISABLE_UDP - | PORTALLOCATOR_DISABLE_TCP - | PORTALLOCATOR_DISABLE_STUN - | PORTALLOCATOR_DISABLE_RELAY; - -// Performs the allocation of ports, in a sequenced (timed) manner, for a given -// network and IP address. -class AllocationSequence : public rtc::MessageHandler, - public sigslot::has_slots<> { - public: - enum State { - kInit, // Initial state. - kRunning, // Started allocating ports. - kStopped, // Stopped from running. - kCompleted, // All ports are allocated. - - // kInit --> kRunning --> {kCompleted|kStopped} - }; - - AllocationSequence(BasicPortAllocatorSession* session, - rtc::Network* network, - PortConfiguration* config, - uint32 flags); - ~AllocationSequence(); - bool Init(); - void Clear(); - - State state() const { return state_; } - - // Disables the phases for a new sequence that this one already covers for an - // equivalent network setup. - void DisableEquivalentPhases(rtc::Network* network, - PortConfiguration* config, uint32* flags); - - // Starts and stops the sequence. When started, it will continue allocating - // new ports on its own timed schedule. - void Start(); - void Stop(); - - // MessageHandler - void OnMessage(rtc::Message* msg); - - void EnableProtocol(ProtocolType proto); - bool ProtocolEnabled(ProtocolType proto) const; - - // Signal from AllocationSequence, when it's done with allocating ports. - // This signal is useful, when port allocation fails which doesn't result - // in any candidates. Using this signal BasicPortAllocatorSession can send - // its candidate discovery conclusion signal. Without this signal, - // BasicPortAllocatorSession doesn't have any event to trigger signal. This - // can also be achieved by starting timer in BPAS. - sigslot::signal1<AllocationSequence*> SignalPortAllocationComplete; - - private: - typedef std::vector<ProtocolType> ProtocolList; - - bool IsFlagSet(uint32 flag) { - return ((flags_ & flag) != 0); - } - void CreateUDPPorts(); - void CreateTCPPorts(); - void CreateStunPorts(); - void CreateRelayPorts(); - void CreateGturnPort(const RelayServerConfig& config); - void CreateTurnPort(const RelayServerConfig& config); - - void OnReadPacket(rtc::AsyncPacketSocket* socket, - const char* data, size_t size, - const rtc::SocketAddress& remote_addr, - const rtc::PacketTime& packet_time); - - void OnPortDestroyed(PortInterface* port); - - BasicPortAllocatorSession* session_; - rtc::Network* network_; - rtc::IPAddress ip_; - PortConfiguration* config_; - State state_; - uint32 flags_; - ProtocolList protocols_; - rtc::scoped_ptr<rtc::AsyncPacketSocket> udp_socket_; - // There will be only one udp port per AllocationSequence. - UDPPort* udp_port_; - std::vector<TurnPort*> turn_ports_; - int phase_; -}; - -// BasicPortAllocator -BasicPortAllocator::BasicPortAllocator( - rtc::NetworkManager* network_manager, - rtc::PacketSocketFactory* socket_factory) - : network_manager_(network_manager), - socket_factory_(socket_factory) { - ASSERT(socket_factory_ != NULL); - Construct(); -} - -BasicPortAllocator::BasicPortAllocator( - rtc::NetworkManager* network_manager) - : network_manager_(network_manager), - socket_factory_(NULL) { - Construct(); -} - -BasicPortAllocator::BasicPortAllocator( - rtc::NetworkManager* network_manager, - rtc::PacketSocketFactory* socket_factory, - const ServerAddresses& stun_servers) - : network_manager_(network_manager), - socket_factory_(socket_factory), - stun_servers_(stun_servers) { - ASSERT(socket_factory_ != NULL); - Construct(); -} - -BasicPortAllocator::BasicPortAllocator( - rtc::NetworkManager* network_manager, - const ServerAddresses& stun_servers, - const rtc::SocketAddress& relay_address_udp, - const rtc::SocketAddress& relay_address_tcp, - const rtc::SocketAddress& relay_address_ssl) - : network_manager_(network_manager), - socket_factory_(NULL), - stun_servers_(stun_servers) { - - RelayServerConfig config(RELAY_GTURN); - if (!relay_address_udp.IsNil()) - config.ports.push_back(ProtocolAddress(relay_address_udp, PROTO_UDP)); - if (!relay_address_tcp.IsNil()) - config.ports.push_back(ProtocolAddress(relay_address_tcp, PROTO_TCP)); - if (!relay_address_ssl.IsNil()) - config.ports.push_back(ProtocolAddress(relay_address_ssl, PROTO_SSLTCP)); - - if (!config.ports.empty()) - AddRelay(config); - - Construct(); -} - -void BasicPortAllocator::Construct() { - allow_tcp_listen_ = true; -} - -BasicPortAllocator::~BasicPortAllocator() { -} - -PortAllocatorSession *BasicPortAllocator::CreateSessionInternal( - const std::string& content_name, int component, - const std::string& ice_ufrag, const std::string& ice_pwd) { - return new BasicPortAllocatorSession( - this, content_name, component, ice_ufrag, ice_pwd); -} - - -// BasicPortAllocatorSession -BasicPortAllocatorSession::BasicPortAllocatorSession( - BasicPortAllocator *allocator, - const std::string& content_name, - int component, - const std::string& ice_ufrag, - const std::string& ice_pwd) - : PortAllocatorSession(content_name, component, - ice_ufrag, ice_pwd, allocator->flags()), - allocator_(allocator), network_thread_(NULL), - socket_factory_(allocator->socket_factory()), - allocation_started_(false), - network_manager_started_(false), - running_(false), - allocation_sequences_created_(false) { - allocator_->network_manager()->SignalNetworksChanged.connect( - this, &BasicPortAllocatorSession::OnNetworksChanged); - allocator_->network_manager()->StartUpdating(); -} - -BasicPortAllocatorSession::~BasicPortAllocatorSession() { - allocator_->network_manager()->StopUpdating(); - if (network_thread_ != NULL) - network_thread_->Clear(this); - - for (uint32 i = 0; i < sequences_.size(); ++i) { - // AllocationSequence should clear it's map entry for turn ports before - // ports are destroyed. - sequences_[i]->Clear(); - } - - std::vector<PortData>::iterator it; - for (it = ports_.begin(); it != ports_.end(); it++) - delete it->port(); - - for (uint32 i = 0; i < configs_.size(); ++i) - delete configs_[i]; - - for (uint32 i = 0; i < sequences_.size(); ++i) - delete sequences_[i]; -} - -void BasicPortAllocatorSession::StartGettingPorts() { - network_thread_ = rtc::Thread::Current(); - if (!socket_factory_) { - owned_socket_factory_.reset( - new rtc::BasicPacketSocketFactory(network_thread_)); - socket_factory_ = owned_socket_factory_.get(); - } - - running_ = true; - network_thread_->Post(this, MSG_CONFIG_START); - - if (flags() & PORTALLOCATOR_ENABLE_SHAKER) - network_thread_->PostDelayed(ShakeDelay(), this, MSG_SHAKE); -} - -void BasicPortAllocatorSession::StopGettingPorts() { - ASSERT(rtc::Thread::Current() == network_thread_); - running_ = false; - network_thread_->Clear(this, MSG_ALLOCATE); - for (uint32 i = 0; i < sequences_.size(); ++i) - sequences_[i]->Stop(); - network_thread_->Post(this, MSG_CONFIG_STOP); -} - -void BasicPortAllocatorSession::OnMessage(rtc::Message *message) { - switch (message->message_id) { - case MSG_CONFIG_START: - ASSERT(rtc::Thread::Current() == network_thread_); - GetPortConfigurations(); - break; - - case MSG_CONFIG_READY: - ASSERT(rtc::Thread::Current() == network_thread_); - OnConfigReady(static_cast<PortConfiguration*>(message->pdata)); - break; - - case MSG_ALLOCATE: - ASSERT(rtc::Thread::Current() == network_thread_); - OnAllocate(); - break; - - case MSG_SHAKE: - ASSERT(rtc::Thread::Current() == network_thread_); - OnShake(); - break; - case MSG_SEQUENCEOBJECTS_CREATED: - ASSERT(rtc::Thread::Current() == network_thread_); - OnAllocationSequenceObjectsCreated(); - break; - case MSG_CONFIG_STOP: - ASSERT(rtc::Thread::Current() == network_thread_); - OnConfigStop(); - break; - default: - ASSERT(false); - } -} - -void BasicPortAllocatorSession::GetPortConfigurations() { - PortConfiguration* config = new PortConfiguration(allocator_->stun_servers(), - username(), - password()); - - for (size_t i = 0; i < allocator_->relays().size(); ++i) { - config->AddRelay(allocator_->relays()[i]); - } - ConfigReady(config); -} - -void BasicPortAllocatorSession::ConfigReady(PortConfiguration* config) { - network_thread_->Post(this, MSG_CONFIG_READY, config); -} - -// Adds a configuration to the list. -void BasicPortAllocatorSession::OnConfigReady(PortConfiguration* config) { - if (config) - configs_.push_back(config); - - AllocatePorts(); -} - -void BasicPortAllocatorSession::OnConfigStop() { - ASSERT(rtc::Thread::Current() == network_thread_); - - // If any of the allocated ports have not completed the candidates allocation, - // mark those as error. Since session doesn't need any new candidates - // at this stage of the allocation, it's safe to discard any new candidates. - bool send_signal = false; - for (std::vector<PortData>::iterator it = ports_.begin(); - it != ports_.end(); ++it) { - if (!it->complete()) { - // Updating port state to error, which didn't finish allocating candidates - // yet. - it->set_error(); - send_signal = true; - } - } - - // Did we stop any running sequences? - for (std::vector<AllocationSequence*>::iterator it = sequences_.begin(); - it != sequences_.end() && !send_signal; ++it) { - if ((*it)->state() == AllocationSequence::kStopped) { - send_signal = true; - } - } - - // If we stopped anything that was running, send a done signal now. - if (send_signal) { - MaybeSignalCandidatesAllocationDone(); - } -} - -void BasicPortAllocatorSession::AllocatePorts() { - ASSERT(rtc::Thread::Current() == network_thread_); - network_thread_->Post(this, MSG_ALLOCATE); -} - -void BasicPortAllocatorSession::OnAllocate() { - if (network_manager_started_) - DoAllocate(); - - allocation_started_ = true; -} - -// For each network, see if we have a sequence that covers it already. If not, -// create a new sequence to create the appropriate ports. -void BasicPortAllocatorSession::DoAllocate() { - bool done_signal_needed = false; - std::vector<rtc::Network*> networks; - allocator_->network_manager()->GetNetworks(&networks); - if (networks.empty()) { - LOG(LS_WARNING) << "Machine has no networks; no ports will be allocated"; - done_signal_needed = true; - } else { - for (uint32 i = 0; i < networks.size(); ++i) { - PortConfiguration* config = NULL; - if (configs_.size() > 0) - config = configs_.back(); - - uint32 sequence_flags = flags(); - if ((sequence_flags & DISABLE_ALL_PHASES) == DISABLE_ALL_PHASES) { - // If all the ports are disabled we should just fire the allocation - // done event and return. - done_signal_needed = true; - break; - } - - // Disables phases that are not specified in this config. - if (!config || config->StunServers().empty()) { - // No STUN ports specified in this config. - sequence_flags |= PORTALLOCATOR_DISABLE_STUN; - } - if (!config || config->relays.empty()) { - // No relay ports specified in this config. - sequence_flags |= PORTALLOCATOR_DISABLE_RELAY; - } - - if (!(sequence_flags & PORTALLOCATOR_ENABLE_IPV6) && -#ifdef USE_WEBRTC_DEV_BRANCH - networks[i]->GetBestIP().family() == AF_INET6) { -#else // USE_WEBRTC_DEV_BRANCH - networks[i]->ip().family() == AF_INET6) { -#endif // USE_WEBRTC_DEV_BRANCH - // Skip IPv6 networks unless the flag's been set. - continue; - } - - // Disable phases that would only create ports equivalent to - // ones that we have already made. - DisableEquivalentPhases(networks[i], config, &sequence_flags); - - if ((sequence_flags & DISABLE_ALL_PHASES) == DISABLE_ALL_PHASES) { - // New AllocationSequence would have nothing to do, so don't make it. - continue; - } - - AllocationSequence* sequence = - new AllocationSequence(this, networks[i], config, sequence_flags); - if (!sequence->Init()) { - delete sequence; - continue; - } - done_signal_needed = true; - sequence->SignalPortAllocationComplete.connect( - this, &BasicPortAllocatorSession::OnPortAllocationComplete); - if (running_) - sequence->Start(); - sequences_.push_back(sequence); - } - } - if (done_signal_needed) { - network_thread_->Post(this, MSG_SEQUENCEOBJECTS_CREATED); - } -} - -void BasicPortAllocatorSession::OnNetworksChanged() { - network_manager_started_ = true; - if (allocation_started_) - DoAllocate(); -} - -void BasicPortAllocatorSession::DisableEquivalentPhases( - rtc::Network* network, PortConfiguration* config, uint32* flags) { - for (uint32 i = 0; i < sequences_.size() && - (*flags & DISABLE_ALL_PHASES) != DISABLE_ALL_PHASES; ++i) { - sequences_[i]->DisableEquivalentPhases(network, config, flags); - } -} - -void BasicPortAllocatorSession::AddAllocatedPort(Port* port, - AllocationSequence * seq, - bool prepare_address) { - if (!port) - return; - - LOG(LS_INFO) << "Adding allocated port for " << content_name(); - port->set_content_name(content_name()); - port->set_component(component_); - port->set_generation(generation()); - if (allocator_->proxy().type != rtc::PROXY_NONE) - port->set_proxy(allocator_->user_agent(), allocator_->proxy()); - port->set_send_retransmit_count_attribute((allocator_->flags() & - PORTALLOCATOR_ENABLE_STUN_RETRANSMIT_ATTRIBUTE) != 0); - - // Push down the candidate_filter to individual port. - port->set_candidate_filter(allocator_->candidate_filter()); - - PortData data(port, seq); - ports_.push_back(data); - - port->SignalCandidateReady.connect( - this, &BasicPortAllocatorSession::OnCandidateReady); - port->SignalPortComplete.connect(this, - &BasicPortAllocatorSession::OnPortComplete); - port->SignalDestroyed.connect(this, - &BasicPortAllocatorSession::OnPortDestroyed); - port->SignalPortError.connect( - this, &BasicPortAllocatorSession::OnPortError); - LOG_J(LS_INFO, port) << "Added port to allocator"; - - if (prepare_address) - port->PrepareAddress(); -} - -void BasicPortAllocatorSession::OnAllocationSequenceObjectsCreated() { - allocation_sequences_created_ = true; - // Send candidate allocation complete signal if we have no sequences. - MaybeSignalCandidatesAllocationDone(); -} - -void BasicPortAllocatorSession::OnCandidateReady( - Port* port, const Candidate& c) { - ASSERT(rtc::Thread::Current() == network_thread_); - PortData* data = FindPort(port); - ASSERT(data != NULL); - // Discarding any candidate signal if port allocation status is - // already in completed state. - if (data->complete()) - return; - - // Send candidates whose protocol is enabled. - std::vector<Candidate> candidates; - ProtocolType pvalue; - bool candidate_allowed_to_send = CheckCandidateFilter(c); - if (StringToProto(c.protocol().c_str(), &pvalue) && - data->sequence()->ProtocolEnabled(pvalue) && - candidate_allowed_to_send) { - candidates.push_back(c); - } - - if (!candidates.empty()) { - SignalCandidatesReady(this, candidates); - } - - // Moving to READY state as we have atleast one candidate from the port. - // Since this port has atleast one candidate we should forward this port - // to listners, to allow connections from this port. - // Also we should make sure that candidate gathered from this port is allowed - // to send outside. - if (!data->ready() && candidate_allowed_to_send) { - data->set_ready(); - SignalPortReady(this, port); - } -} - -void BasicPortAllocatorSession::OnPortComplete(Port* port) { - ASSERT(rtc::Thread::Current() == network_thread_); - PortData* data = FindPort(port); - ASSERT(data != NULL); - - // Ignore any late signals. - if (data->complete()) - return; - - // Moving to COMPLETE state. - data->set_complete(); - // Send candidate allocation complete signal if this was the last port. - MaybeSignalCandidatesAllocationDone(); -} - -void BasicPortAllocatorSession::OnPortError(Port* port) { - ASSERT(rtc::Thread::Current() == network_thread_); - PortData* data = FindPort(port); - ASSERT(data != NULL); - // We might have already given up on this port and stopped it. - if (data->complete()) - return; - - // SignalAddressError is currently sent from StunPort/TurnPort. - // But this signal itself is generic. - data->set_error(); - // Send candidate allocation complete signal if this was the last port. - MaybeSignalCandidatesAllocationDone(); -} - -void BasicPortAllocatorSession::OnProtocolEnabled(AllocationSequence* seq, - ProtocolType proto) { - std::vector<Candidate> candidates; - for (std::vector<PortData>::iterator it = ports_.begin(); - it != ports_.end(); ++it) { - if (it->sequence() != seq) - continue; - - const std::vector<Candidate>& potentials = it->port()->Candidates(); - for (size_t i = 0; i < potentials.size(); ++i) { - if (!CheckCandidateFilter(potentials[i])) - continue; - ProtocolType pvalue; - if (!StringToProto(potentials[i].protocol().c_str(), &pvalue)) - continue; - if (pvalue == proto) { - candidates.push_back(potentials[i]); - } - } - } - - if (!candidates.empty()) { - SignalCandidatesReady(this, candidates); - } -} - -bool BasicPortAllocatorSession::CheckCandidateFilter(const Candidate& c) { - uint32 filter = allocator_->candidate_filter(); - bool allowed = false; - if (filter & CF_RELAY) { - allowed |= (c.type() == RELAY_PORT_TYPE); - } - - if (filter & CF_REFLEXIVE) { - // We allow host candidates if the filter allows server-reflexive candidates - // and the candidate is a public IP. Because we don't generate - // server-reflexive candidates if they have the same IP as the host - // candidate (i.e. when the host candidate is a public IP), filtering to - // only server-reflexive candidates won't work right when the host - // candidates have public IPs. - allowed |= (c.type() == STUN_PORT_TYPE) || - (c.type() == LOCAL_PORT_TYPE && !c.address().IsPrivateIP()); - } - - if (filter & CF_HOST) { - allowed |= (c.type() == LOCAL_PORT_TYPE); - } - - return allowed; -} - -void BasicPortAllocatorSession::OnPortAllocationComplete( - AllocationSequence* seq) { - // Send candidate allocation complete signal if all ports are done. - MaybeSignalCandidatesAllocationDone(); -} - -void BasicPortAllocatorSession::MaybeSignalCandidatesAllocationDone() { - // Send signal only if all required AllocationSequence objects - // are created. - if (!allocation_sequences_created_) - return; - - // Check that all port allocation sequences are complete. - for (std::vector<AllocationSequence*>::iterator it = sequences_.begin(); - it != sequences_.end(); ++it) { - if ((*it)->state() == AllocationSequence::kRunning) - return; - } - - // If all allocated ports are in complete state, session must have got all - // expected candidates. Session will trigger candidates allocation complete - // signal. - for (std::vector<PortData>::iterator it = ports_.begin(); - it != ports_.end(); ++it) { - if (!it->complete()) - return; - } - LOG(LS_INFO) << "All candidates gathered for " << content_name_ << ":" - << component_ << ":" << generation(); - SignalCandidatesAllocationDone(this); -} - -void BasicPortAllocatorSession::OnPortDestroyed( - PortInterface* port) { - ASSERT(rtc::Thread::Current() == network_thread_); - for (std::vector<PortData>::iterator iter = ports_.begin(); - iter != ports_.end(); ++iter) { - if (port == iter->port()) { - ports_.erase(iter); - LOG_J(LS_INFO, port) << "Removed port from allocator (" - << static_cast<int>(ports_.size()) << " remaining)"; - return; - } - } - ASSERT(false); -} - -void BasicPortAllocatorSession::OnShake() { - LOG(INFO) << ">>>>> SHAKE <<<<< >>>>> SHAKE <<<<< >>>>> SHAKE <<<<<"; - - std::vector<Port*> ports; - std::vector<Connection*> connections; - - for (size_t i = 0; i < ports_.size(); ++i) { - if (ports_[i].ready()) - ports.push_back(ports_[i].port()); - } - - for (size_t i = 0; i < ports.size(); ++i) { - Port::AddressMap::const_iterator iter; - for (iter = ports[i]->connections().begin(); - iter != ports[i]->connections().end(); - ++iter) { - connections.push_back(iter->second); - } - } - - LOG(INFO) << ">>>>> Destroying " << ports.size() << " ports and " - << connections.size() << " connections"; - - for (size_t i = 0; i < connections.size(); ++i) - connections[i]->Destroy(); - - if (running_ || (ports.size() > 0) || (connections.size() > 0)) - network_thread_->PostDelayed(ShakeDelay(), this, MSG_SHAKE); -} - -BasicPortAllocatorSession::PortData* BasicPortAllocatorSession::FindPort( - Port* port) { - for (std::vector<PortData>::iterator it = ports_.begin(); - it != ports_.end(); ++it) { - if (it->port() == port) { - return &*it; - } - } - return NULL; -} - -// AllocationSequence - -AllocationSequence::AllocationSequence(BasicPortAllocatorSession* session, - rtc::Network* network, - PortConfiguration* config, - uint32 flags) - : session_(session), - network_(network), - -#ifdef USE_WEBRTC_DEV_BRANCH - ip_(network->GetBestIP()), -#else // USE_WEBRTC_DEV_BRANCH - ip_(network->ip()), -#endif // USE_WEBRTC_DEV_BRANCH - config_(config), - state_(kInit), - flags_(flags), - udp_socket_(), - udp_port_(NULL), - phase_(0) { -} - -bool AllocationSequence::Init() { - if (IsFlagSet(PORTALLOCATOR_ENABLE_SHARED_SOCKET) && - !IsFlagSet(PORTALLOCATOR_ENABLE_SHARED_UFRAG)) { - LOG(LS_ERROR) << "Shared socket option can't be set without " - << "shared ufrag."; - ASSERT(false); - return false; - } - - if (IsFlagSet(PORTALLOCATOR_ENABLE_SHARED_SOCKET)) { - udp_socket_.reset(session_->socket_factory()->CreateUdpSocket( - rtc::SocketAddress(ip_, 0), session_->allocator()->min_port(), - session_->allocator()->max_port())); - if (udp_socket_) { - udp_socket_->SignalReadPacket.connect( - this, &AllocationSequence::OnReadPacket); - } - // Continuing if |udp_socket_| is NULL, as local TCP and RelayPort using TCP - // are next available options to setup a communication channel. - } - return true; -} - -void AllocationSequence::Clear() { - udp_port_ = NULL; - turn_ports_.clear(); -} - -AllocationSequence::~AllocationSequence() { - session_->network_thread()->Clear(this); -} - -void AllocationSequence::DisableEquivalentPhases(rtc::Network* network, - PortConfiguration* config, uint32* flags) { -#ifdef USE_WEBRTC_DEV_BRANCH - if (!((network == network_) && (ip_ == network->GetBestIP()))) { -#else // USE_WEBRTC_DEV_BRANCH - if (!((network == network_) && (ip_ == network->ip()))) { -#endif // USE_WEBRTC_DEV_BRANCH - // Different network setup; nothing is equivalent. - return; - } - - // Else turn off the stuff that we've already got covered. - - // Every config implicitly specifies local, so turn that off right away. - *flags |= PORTALLOCATOR_DISABLE_UDP; - *flags |= PORTALLOCATOR_DISABLE_TCP; - - if (config_ && config) { - if (config_->StunServers() == config->StunServers()) { - // Already got this STUN servers covered. - *flags |= PORTALLOCATOR_DISABLE_STUN; - } - if (!config_->relays.empty()) { - // Already got relays covered. - // NOTE: This will even skip a _different_ set of relay servers if we - // were to be given one, but that never happens in our codebase. Should - // probably get rid of the list in PortConfiguration and just keep a - // single relay server in each one. - *flags |= PORTALLOCATOR_DISABLE_RELAY; - } - } -} - -void AllocationSequence::Start() { - state_ = kRunning; - session_->network_thread()->Post(this, MSG_ALLOCATION_PHASE); -} - -void AllocationSequence::Stop() { - // If the port is completed, don't set it to stopped. - if (state_ == kRunning) { - state_ = kStopped; - session_->network_thread()->Clear(this, MSG_ALLOCATION_PHASE); - } -} - -void AllocationSequence::OnMessage(rtc::Message* msg) { - ASSERT(rtc::Thread::Current() == session_->network_thread()); - ASSERT(msg->message_id == MSG_ALLOCATION_PHASE); - - const char* const PHASE_NAMES[kNumPhases] = { - "Udp", "Relay", "Tcp", "SslTcp" - }; - - // Perform all of the phases in the current step. - LOG_J(LS_INFO, network_) << "Allocation Phase=" - << PHASE_NAMES[phase_]; - - switch (phase_) { - case PHASE_UDP: - CreateUDPPorts(); - CreateStunPorts(); - EnableProtocol(PROTO_UDP); - break; - - case PHASE_RELAY: - CreateRelayPorts(); - break; - - case PHASE_TCP: - CreateTCPPorts(); - EnableProtocol(PROTO_TCP); - break; - - case PHASE_SSLTCP: - state_ = kCompleted; - EnableProtocol(PROTO_SSLTCP); - break; - - default: - ASSERT(false); - } - - if (state() == kRunning) { - ++phase_; - session_->network_thread()->PostDelayed( - session_->allocator()->step_delay(), - this, MSG_ALLOCATION_PHASE); - } else { - // If all phases in AllocationSequence are completed, no allocation - // steps needed further. Canceling pending signal. - session_->network_thread()->Clear(this, MSG_ALLOCATION_PHASE); - SignalPortAllocationComplete(this); - } -} - -void AllocationSequence::EnableProtocol(ProtocolType proto) { - if (!ProtocolEnabled(proto)) { - protocols_.push_back(proto); - session_->OnProtocolEnabled(this, proto); - } -} - -bool AllocationSequence::ProtocolEnabled(ProtocolType proto) const { - for (ProtocolList::const_iterator it = protocols_.begin(); - it != protocols_.end(); ++it) { - if (*it == proto) - return true; - } - return false; -} - -void AllocationSequence::CreateUDPPorts() { - if (IsFlagSet(PORTALLOCATOR_DISABLE_UDP)) { - LOG(LS_VERBOSE) << "AllocationSequence: UDP ports disabled, skipping."; - return; - } - - // TODO(mallinath) - Remove UDPPort creating socket after shared socket - // is enabled completely. - UDPPort* port = NULL; - if (IsFlagSet(PORTALLOCATOR_ENABLE_SHARED_SOCKET) && udp_socket_) { - port = UDPPort::Create(session_->network_thread(), - session_->socket_factory(), network_, - udp_socket_.get(), - session_->username(), session_->password()); - } else { - port = UDPPort::Create(session_->network_thread(), - session_->socket_factory(), - network_, ip_, - session_->allocator()->min_port(), - session_->allocator()->max_port(), - session_->username(), session_->password()); - } - - if (port) { - // If shared socket is enabled, STUN candidate will be allocated by the - // UDPPort. - if (IsFlagSet(PORTALLOCATOR_ENABLE_SHARED_SOCKET)) { - udp_port_ = port; - - // If STUN is not disabled, setting stun server address to port. - if (!IsFlagSet(PORTALLOCATOR_DISABLE_STUN)) { - // If config has stun_servers, use it to get server reflexive candidate - // otherwise use first TURN server which supports UDP. - if (config_ && !config_->StunServers().empty()) { - LOG(LS_INFO) << "AllocationSequence: UDPPort will be handling the " - << "STUN candidate generation."; - port->set_server_addresses(config_->StunServers()); - } else if (config_ && - config_->SupportsProtocol(RELAY_TURN, PROTO_UDP)) { - port->set_server_addresses(config_->GetRelayServerAddresses( - RELAY_TURN, PROTO_UDP)); - LOG(LS_INFO) << "AllocationSequence: TURN Server address will be " - << " used for generating STUN candidate."; - } - } - } - - session_->AddAllocatedPort(port, this, true); - port->SignalDestroyed.connect(this, &AllocationSequence::OnPortDestroyed); - } -} - -void AllocationSequence::CreateTCPPorts() { - if (IsFlagSet(PORTALLOCATOR_DISABLE_TCP)) { - LOG(LS_VERBOSE) << "AllocationSequence: TCP ports disabled, skipping."; - return; - } - - Port* port = TCPPort::Create(session_->network_thread(), - session_->socket_factory(), - network_, ip_, - session_->allocator()->min_port(), - session_->allocator()->max_port(), - session_->username(), session_->password(), - session_->allocator()->allow_tcp_listen()); - if (port) { - session_->AddAllocatedPort(port, this, true); - // Since TCPPort is not created using shared socket, |port| will not be - // added to the dequeue. - } -} - -void AllocationSequence::CreateStunPorts() { - if (IsFlagSet(PORTALLOCATOR_DISABLE_STUN)) { - LOG(LS_VERBOSE) << "AllocationSequence: STUN ports disabled, skipping."; - return; - } - - if (IsFlagSet(PORTALLOCATOR_ENABLE_SHARED_SOCKET)) { - return; - } - - // If BasicPortAllocatorSession::OnAllocate left STUN ports enabled then we - // ought to have an address for them here. - ASSERT(config_ && !config_->StunServers().empty()); - if (!(config_ && !config_->StunServers().empty())) { - LOG(LS_WARNING) - << "AllocationSequence: No STUN server configured, skipping."; - return; - } - - StunPort* port = StunPort::Create(session_->network_thread(), - session_->socket_factory(), - network_, ip_, - session_->allocator()->min_port(), - session_->allocator()->max_port(), - session_->username(), session_->password(), - config_->StunServers()); - if (port) { - session_->AddAllocatedPort(port, this, true); - // Since StunPort is not created using shared socket, |port| will not be - // added to the dequeue. - } -} - -void AllocationSequence::CreateRelayPorts() { - if (IsFlagSet(PORTALLOCATOR_DISABLE_RELAY)) { - LOG(LS_VERBOSE) << "AllocationSequence: Relay ports disabled, skipping."; - return; - } - - // If BasicPortAllocatorSession::OnAllocate left relay ports enabled then we - // ought to have a relay list for them here. - ASSERT(config_ && !config_->relays.empty()); - if (!(config_ && !config_->relays.empty())) { - LOG(LS_WARNING) - << "AllocationSequence: No relay server configured, skipping."; - return; - } - - PortConfiguration::RelayList::const_iterator relay; - for (relay = config_->relays.begin(); - relay != config_->relays.end(); ++relay) { - if (relay->type == RELAY_GTURN) { - CreateGturnPort(*relay); - } else if (relay->type == RELAY_TURN) { - CreateTurnPort(*relay); - } else { - ASSERT(false); - } - } -} - -void AllocationSequence::CreateGturnPort(const RelayServerConfig& config) { - // TODO(mallinath) - Rename RelayPort to GTurnPort. - RelayPort* port = RelayPort::Create(session_->network_thread(), - session_->socket_factory(), - network_, ip_, - session_->allocator()->min_port(), - session_->allocator()->max_port(), - config_->username, config_->password); - if (port) { - // Since RelayPort is not created using shared socket, |port| will not be - // added to the dequeue. - // Note: We must add the allocated port before we add addresses because - // the latter will create candidates that need name and preference - // settings. However, we also can't prepare the address (normally - // done by AddAllocatedPort) until we have these addresses. So we - // wait to do that until below. - session_->AddAllocatedPort(port, this, false); - - // Add the addresses of this protocol. - PortList::const_iterator relay_port; - for (relay_port = config.ports.begin(); - relay_port != config.ports.end(); - ++relay_port) { - port->AddServerAddress(*relay_port); - port->AddExternalAddress(*relay_port); - } - // Start fetching an address for this port. - port->PrepareAddress(); - } -} - -void AllocationSequence::CreateTurnPort(const RelayServerConfig& config) { - PortList::const_iterator relay_port; - for (relay_port = config.ports.begin(); - relay_port != config.ports.end(); ++relay_port) { - TurnPort* port = NULL; - // Shared socket mode must be enabled only for UDP based ports. Hence - // don't pass shared socket for ports which will create TCP sockets. - // TODO(mallinath) - Enable shared socket mode for TURN ports. Disabled - // due to webrtc bug https://code.google.com/p/webrtc/issues/detail?id=3537 - if (IsFlagSet(PORTALLOCATOR_ENABLE_SHARED_SOCKET) && - relay_port->proto == PROTO_UDP) { - port = TurnPort::Create(session_->network_thread(), - session_->socket_factory(), - network_, udp_socket_.get(), - session_->username(), session_->password(), - *relay_port, config.credentials, config.priority); - - turn_ports_.push_back(port); - // Listen to the port destroyed signal, to allow AllocationSequence to - // remove entrt from it's map. - port->SignalDestroyed.connect(this, &AllocationSequence::OnPortDestroyed); - } else { - port = TurnPort::Create(session_->network_thread(), - session_->socket_factory(), - network_, ip_, - session_->allocator()->min_port(), - session_->allocator()->max_port(), - session_->username(), - session_->password(), - *relay_port, config.credentials, config.priority); - } - ASSERT(port != NULL); - session_->AddAllocatedPort(port, this, true); - } -} - -void AllocationSequence::OnReadPacket( - rtc::AsyncPacketSocket* socket, const char* data, size_t size, - const rtc::SocketAddress& remote_addr, - const rtc::PacketTime& packet_time) { - ASSERT(socket == udp_socket_.get()); - - bool turn_port_found = false; - - // Try to find the TurnPort that matches the remote address. Note that the - // message could be a STUN binding response if the TURN server is also used as - // a STUN server. We don't want to parse every message here to check if it is - // a STUN binding response, so we pass the message to TurnPort regardless of - // the message type. The TurnPort will just ignore the message since it will - // not find any request by transaction ID. - for (std::vector<TurnPort*>::const_iterator it = turn_ports_.begin(); - it != turn_ports_.end(); ++it) { - TurnPort* port = *it; - if (port->server_address().address == remote_addr) { - port->HandleIncomingPacket(socket, data, size, remote_addr, packet_time); - turn_port_found = true; - break; - } - } - - if (udp_port_) { - const ServerAddresses& stun_servers = udp_port_->server_addresses(); - - // Pass the packet to the UdpPort if there is no matching TurnPort, or if - // the TURN server is also a STUN server. - if (!turn_port_found || - stun_servers.find(remote_addr) != stun_servers.end()) { - udp_port_->HandleIncomingPacket( - socket, data, size, remote_addr, packet_time); - } - } -} - -void AllocationSequence::OnPortDestroyed(PortInterface* port) { - if (udp_port_ == port) { - udp_port_ = NULL; - return; - } - - turn_ports_.erase(std::find(turn_ports_.begin(), turn_ports_.end(), port)); -} - -// PortConfiguration -PortConfiguration::PortConfiguration( - const rtc::SocketAddress& stun_address, - const std::string& username, - const std::string& password) - : stun_address(stun_address), username(username), password(password) { - if (!stun_address.IsNil()) - stun_servers.insert(stun_address); -} - -PortConfiguration::PortConfiguration(const ServerAddresses& stun_servers, - const std::string& username, - const std::string& password) - : stun_servers(stun_servers), - username(username), - password(password) { - if (!stun_servers.empty()) - stun_address = *(stun_servers.begin()); -} - -ServerAddresses PortConfiguration::StunServers() { - if (!stun_address.IsNil() && - stun_servers.find(stun_address) == stun_servers.end()) { - stun_servers.insert(stun_address); - } - return stun_servers; -} - -void PortConfiguration::AddRelay(const RelayServerConfig& config) { - relays.push_back(config); -} - -bool PortConfiguration::SupportsProtocol( - const RelayServerConfig& relay, ProtocolType type) const { - PortList::const_iterator relay_port; - for (relay_port = relay.ports.begin(); - relay_port != relay.ports.end(); - ++relay_port) { - if (relay_port->proto == type) - return true; - } - return false; -} - -bool PortConfiguration::SupportsProtocol(RelayType turn_type, - ProtocolType type) const { - for (size_t i = 0; i < relays.size(); ++i) { - if (relays[i].type == turn_type && - SupportsProtocol(relays[i], type)) - return true; - } - return false; -} - -ServerAddresses PortConfiguration::GetRelayServerAddresses( - RelayType turn_type, ProtocolType type) const { - ServerAddresses servers; - for (size_t i = 0; i < relays.size(); ++i) { - if (relays[i].type == turn_type && SupportsProtocol(relays[i], type)) { - servers.insert(relays[i].ports.front().address); - } - } - return servers; -} - -} // namespace cricket diff --git a/talk/p2p/client/basicportallocator.h b/talk/p2p/client/basicportallocator.h deleted file mode 100644 index e2389d3e6..000000000 --- a/talk/p2p/client/basicportallocator.h +++ /dev/null @@ -1,258 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef WEBRTC_P2P_CLIENT_BASICPORTALLOCATOR_H_ -#define WEBRTC_P2P_CLIENT_BASICPORTALLOCATOR_H_ - -#include <string> -#include <vector> - -#include "webrtc/p2p/base/port.h" -#include "webrtc/p2p/base/portallocator.h" -#include "webrtc/base/messagequeue.h" -#include "webrtc/base/network.h" -#include "webrtc/base/scoped_ptr.h" -#include "webrtc/base/thread.h" - -namespace cricket { - -struct RelayCredentials { - RelayCredentials() {} - RelayCredentials(const std::string& username, - const std::string& password) - : username(username), - password(password) { - } - - std::string username; - std::string password; -}; - -typedef std::vector<ProtocolAddress> PortList; -struct RelayServerConfig { - RelayServerConfig(RelayType type) : type(type), priority(0) {} - - RelayType type; - PortList ports; - RelayCredentials credentials; - int priority; -}; - -class BasicPortAllocator : public PortAllocator { - public: - BasicPortAllocator(rtc::NetworkManager* network_manager, - rtc::PacketSocketFactory* socket_factory); - explicit BasicPortAllocator(rtc::NetworkManager* network_manager); - BasicPortAllocator(rtc::NetworkManager* network_manager, - rtc::PacketSocketFactory* socket_factory, - const ServerAddresses& stun_servers); - BasicPortAllocator(rtc::NetworkManager* network_manager, - const ServerAddresses& stun_servers, - const rtc::SocketAddress& relay_server_udp, - const rtc::SocketAddress& relay_server_tcp, - const rtc::SocketAddress& relay_server_ssl); - virtual ~BasicPortAllocator(); - - rtc::NetworkManager* network_manager() { return network_manager_; } - - // If socket_factory() is set to NULL each PortAllocatorSession - // creates its own socket factory. - rtc::PacketSocketFactory* socket_factory() { return socket_factory_; } - - const ServerAddresses& stun_servers() const { - return stun_servers_; - } - - const std::vector<RelayServerConfig>& relays() const { - return relays_; - } - virtual void AddRelay(const RelayServerConfig& relay) { - relays_.push_back(relay); - } - - virtual PortAllocatorSession* CreateSessionInternal( - const std::string& content_name, - int component, - const std::string& ice_ufrag, - const std::string& ice_pwd); - - private: - void Construct(); - - rtc::NetworkManager* network_manager_; - rtc::PacketSocketFactory* socket_factory_; - const ServerAddresses stun_servers_; - std::vector<RelayServerConfig> relays_; - bool allow_tcp_listen_; -}; - -struct PortConfiguration; -class AllocationSequence; - -class BasicPortAllocatorSession : public PortAllocatorSession, - public rtc::MessageHandler { - public: - BasicPortAllocatorSession(BasicPortAllocator* allocator, - const std::string& content_name, - int component, - const std::string& ice_ufrag, - const std::string& ice_pwd); - ~BasicPortAllocatorSession(); - - virtual BasicPortAllocator* allocator() { return allocator_; } - rtc::Thread* network_thread() { return network_thread_; } - rtc::PacketSocketFactory* socket_factory() { return socket_factory_; } - - virtual void StartGettingPorts(); - virtual void StopGettingPorts(); - virtual bool IsGettingPorts() { return running_; } - - protected: - // Starts the process of getting the port configurations. - virtual void GetPortConfigurations(); - - // Adds a port configuration that is now ready. Once we have one for each - // network (or a timeout occurs), we will start allocating ports. - virtual void ConfigReady(PortConfiguration* config); - - // MessageHandler. Can be overriden if message IDs do not conflict. - virtual void OnMessage(rtc::Message *message); - - private: - class PortData { - public: - PortData() : port_(NULL), sequence_(NULL), state_(STATE_INIT) {} - PortData(Port* port, AllocationSequence* seq) - : port_(port), sequence_(seq), state_(STATE_INIT) { - } - - Port* port() { return port_; } - AllocationSequence* sequence() { return sequence_; } - bool ready() const { return state_ == STATE_READY; } - bool complete() const { - // Returns true if candidate allocation has completed one way or another. - return ((state_ == STATE_COMPLETE) || (state_ == STATE_ERROR)); - } - - void set_ready() { ASSERT(state_ == STATE_INIT); state_ = STATE_READY; } - void set_complete() { - state_ = STATE_COMPLETE; - } - void set_error() { - ASSERT(state_ == STATE_INIT || state_ == STATE_READY); - state_ = STATE_ERROR; - } - - private: - enum State { - STATE_INIT, // No candidates allocated yet. - STATE_READY, // At least one candidate is ready for process. - STATE_COMPLETE, // All candidates allocated and ready for process. - STATE_ERROR // Error in gathering candidates. - }; - Port* port_; - AllocationSequence* sequence_; - State state_; - }; - - void OnConfigReady(PortConfiguration* config); - void OnConfigStop(); - void AllocatePorts(); - void OnAllocate(); - void DoAllocate(); - void OnNetworksChanged(); - void OnAllocationSequenceObjectsCreated(); - void DisableEquivalentPhases(rtc::Network* network, - PortConfiguration* config, uint32* flags); - void AddAllocatedPort(Port* port, AllocationSequence* seq, - bool prepare_address); - void OnCandidateReady(Port* port, const Candidate& c); - void OnPortComplete(Port* port); - void OnPortError(Port* port); - void OnProtocolEnabled(AllocationSequence* seq, ProtocolType proto); - void OnPortDestroyed(PortInterface* port); - void OnShake(); - void MaybeSignalCandidatesAllocationDone(); - void OnPortAllocationComplete(AllocationSequence* seq); - PortData* FindPort(Port* port); - - bool CheckCandidateFilter(const Candidate& c); - - BasicPortAllocator* allocator_; - rtc::Thread* network_thread_; - rtc::scoped_ptr<rtc::PacketSocketFactory> owned_socket_factory_; - rtc::PacketSocketFactory* socket_factory_; - bool allocation_started_; - bool network_manager_started_; - bool running_; // set when StartGetAllPorts is called - bool allocation_sequences_created_; - std::vector<PortConfiguration*> configs_; - std::vector<AllocationSequence*> sequences_; - std::vector<PortData> ports_; - - friend class AllocationSequence; -}; - -// Records configuration information useful in creating ports. -struct PortConfiguration : public rtc::MessageData { - // TODO(jiayl): remove |stun_address| when Chrome is updated. - rtc::SocketAddress stun_address; - ServerAddresses stun_servers; - std::string username; - std::string password; - - typedef std::vector<RelayServerConfig> RelayList; - RelayList relays; - - // TODO(jiayl): remove this ctor when Chrome is updated. - PortConfiguration(const rtc::SocketAddress& stun_address, - const std::string& username, - const std::string& password); - - PortConfiguration(const ServerAddresses& stun_servers, - const std::string& username, - const std::string& password); - - // TODO(jiayl): remove when |stun_address| is removed. - ServerAddresses StunServers(); - - // Adds another relay server, with the given ports and modifier, to the list. - void AddRelay(const RelayServerConfig& config); - - // Determines whether the given relay server supports the given protocol. - bool SupportsProtocol(const RelayServerConfig& relay, - ProtocolType type) const; - bool SupportsProtocol(RelayType turn_type, ProtocolType type) const; - // Helper method returns the server addresses for the matching RelayType and - // Protocol type. - ServerAddresses GetRelayServerAddresses( - RelayType turn_type, ProtocolType type) const; -}; - -} // namespace cricket - -#endif // WEBRTC_P2P_CLIENT_BASICPORTALLOCATOR_H_ diff --git a/talk/p2p/client/connectivitychecker.cc b/talk/p2p/client/connectivitychecker.cc deleted file mode 100644 index 527e18a46..000000000 --- a/talk/p2p/client/connectivitychecker.cc +++ /dev/null @@ -1,584 +0,0 @@ -/* - * libjingle - * Copyright 2011, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <string> - -#include "webrtc/p2p/client/connectivitychecker.h" - -#include "webrtc/p2p/base/candidate.h" -#include "webrtc/p2p/base/common.h" -#include "webrtc/p2p/base/constants.h" -#include "webrtc/p2p/base/port.h" -#include "webrtc/p2p/base/relayport.h" -#include "webrtc/p2p/base/stunport.h" -#include "webrtc/base/asynchttprequest.h" -#include "webrtc/base/autodetectproxy.h" -#include "webrtc/base/helpers.h" -#include "webrtc/base/httpcommon-inl.h" -#include "webrtc/base/httpcommon.h" -#include "webrtc/base/logging.h" -#include "webrtc/base/proxydetect.h" -#include "webrtc/base/thread.h" - -namespace cricket { - -static const char kDefaultStunHostname[] = "stun.l.google.com"; -static const int kDefaultStunPort = 19302; - -// Default maximum time in milliseconds we will wait for connections. -static const uint32 kDefaultTimeoutMs = 3000; - -enum { - MSG_START = 1, - MSG_STOP = 2, - MSG_TIMEOUT = 3, - MSG_SIGNAL_RESULTS = 4 -}; - -class TestHttpPortAllocator : public HttpPortAllocator { - public: - TestHttpPortAllocator(rtc::NetworkManager* network_manager, - const std::string& user_agent, - const std::string& relay_token) : - HttpPortAllocator(network_manager, user_agent) { - SetRelayToken(relay_token); - } - PortAllocatorSession* CreateSessionInternal( - const std::string& content_name, - int component, - const std::string& ice_ufrag, - const std::string& ice_pwd) { - return new TestHttpPortAllocatorSession(this, content_name, component, - ice_ufrag, ice_pwd, - stun_hosts(), relay_hosts(), - relay_token(), user_agent()); - } -}; - -void TestHttpPortAllocatorSession::ConfigReady(PortConfiguration* config) { - SignalConfigReady(username(), password(), config, proxy_); - delete config; -} - -void TestHttpPortAllocatorSession::OnRequestDone( - rtc::SignalThread* data) { - rtc::AsyncHttpRequest* request = - static_cast<rtc::AsyncHttpRequest*>(data); - - // Tell the checker that the request is complete. - SignalRequestDone(request); - - // Pass on the response to super class. - HttpPortAllocatorSession::OnRequestDone(data); -} - -ConnectivityChecker::ConnectivityChecker( - rtc::Thread* worker, - const std::string& jid, - const std::string& session_id, - const std::string& user_agent, - const std::string& relay_token, - const std::string& connection) - : worker_(worker), - jid_(jid), - session_id_(session_id), - user_agent_(user_agent), - relay_token_(relay_token), - connection_(connection), - proxy_detect_(NULL), - timeout_ms_(kDefaultTimeoutMs), - stun_address_(kDefaultStunHostname, kDefaultStunPort), - started_(false) { -} - -ConnectivityChecker::~ConnectivityChecker() { - if (started_) { - // We try to clear the TIMEOUT below. But worker may still handle it and - // cause SignalCheckDone to happen on main-thread. So we finally clear any - // pending SIGNAL_RESULTS. - worker_->Clear(this, MSG_TIMEOUT); - worker_->Send(this, MSG_STOP); - nics_.clear(); - main_->Clear(this, MSG_SIGNAL_RESULTS); - } -} - -bool ConnectivityChecker::Initialize() { - network_manager_.reset(CreateNetworkManager()); - socket_factory_.reset(CreateSocketFactory(worker_)); - port_allocator_.reset(CreatePortAllocator(network_manager_.get(), - user_agent_, relay_token_)); - uint32 new_allocator_flags = port_allocator_->flags(); - new_allocator_flags |= cricket::PORTALLOCATOR_ENABLE_SHARED_UFRAG; - port_allocator_->set_flags(new_allocator_flags); - return true; -} - -void ConnectivityChecker::Start() { - main_ = rtc::Thread::Current(); - worker_->Post(this, MSG_START); - started_ = true; -} - -void ConnectivityChecker::CleanUp() { - ASSERT(worker_ == rtc::Thread::Current()); - if (proxy_detect_) { - proxy_detect_->Release(); - proxy_detect_ = NULL; - } - - for (uint32 i = 0; i < sessions_.size(); ++i) { - delete sessions_[i]; - } - sessions_.clear(); - for (uint32 i = 0; i < ports_.size(); ++i) { - delete ports_[i]; - } - ports_.clear(); -} - -bool ConnectivityChecker::AddNic(const rtc::IPAddress& ip, - const rtc::SocketAddress& proxy_addr) { - NicMap::iterator i = nics_.find(NicId(ip, proxy_addr)); - if (i != nics_.end()) { - // Already have it. - return false; - } - uint32 now = rtc::Time(); - NicInfo info; - info.ip = ip; - info.proxy_info = GetProxyInfo(); - info.stun.start_time_ms = now; - nics_.insert(std::pair<NicId, NicInfo>(NicId(ip, proxy_addr), info)); - return true; -} - -void ConnectivityChecker::SetProxyInfo(const rtc::ProxyInfo& proxy_info) { - port_allocator_->set_proxy(user_agent_, proxy_info); - AllocatePorts(); -} - -rtc::ProxyInfo ConnectivityChecker::GetProxyInfo() const { - rtc::ProxyInfo proxy_info; - if (proxy_detect_) { - proxy_info = proxy_detect_->proxy(); - } - return proxy_info; -} - -void ConnectivityChecker::CheckNetworks() { - network_manager_->SignalNetworksChanged.connect( - this, &ConnectivityChecker::OnNetworksChanged); - network_manager_->StartUpdating(); -} - -void ConnectivityChecker::OnMessage(rtc::Message *msg) { - switch (msg->message_id) { - case MSG_START: - ASSERT(worker_ == rtc::Thread::Current()); - worker_->PostDelayed(timeout_ms_, this, MSG_TIMEOUT); - CheckNetworks(); - break; - case MSG_STOP: - // We're being stopped, free resources. - CleanUp(); - break; - case MSG_TIMEOUT: - // We need to signal results on the main thread. - main_->Post(this, MSG_SIGNAL_RESULTS); - break; - case MSG_SIGNAL_RESULTS: - ASSERT(main_ == rtc::Thread::Current()); - SignalCheckDone(this); - break; - default: - LOG(LS_ERROR) << "Unknown message: " << msg->message_id; - } -} - -void ConnectivityChecker::OnProxyDetect(rtc::SignalThread* thread) { - ASSERT(worker_ == rtc::Thread::Current()); - if (proxy_detect_->proxy().type != rtc::PROXY_NONE) { - SetProxyInfo(proxy_detect_->proxy()); - } -} - -void ConnectivityChecker::OnRequestDone(rtc::AsyncHttpRequest* request) { - ASSERT(worker_ == rtc::Thread::Current()); - // Since we don't know what nic were actually used for the http request, - // for now, just use the first one. - std::vector<rtc::Network*> networks; - network_manager_->GetNetworks(&networks); - if (networks.empty()) { - LOG(LS_ERROR) << "No networks while registering http start."; - return; - } - rtc::ProxyInfo proxy_info = request->proxy(); - NicMap::iterator i = -#ifdef USE_WEBRTC_DEV_BRANCH - nics_.find(NicId(networks[0]->GetBestIP(), proxy_info.address)); -#else // USE_WEBRTC_DEV_BRANCH - nics_.find(NicId(networks[0]->ip(), proxy_info.address)); -#endif // USE_WEBRTC_DEV_BRANCH - if (i != nics_.end()) { - int port = request->port(); - uint32 now = rtc::Time(); - NicInfo* nic_info = &i->second; - if (port == rtc::HTTP_SECURE_PORT) { - nic_info->https.rtt = now - nic_info->https.start_time_ms; - } else { - LOG(LS_ERROR) << "Got response with unknown port: " << port; - } - } else { - LOG(LS_ERROR) << "No nic info found while receiving response."; - } -} - -void ConnectivityChecker::OnConfigReady( - const std::string& username, const std::string& password, - const PortConfiguration* config, const rtc::ProxyInfo& proxy_info) { - ASSERT(worker_ == rtc::Thread::Current()); - - // Since we send requests on both HTTP and HTTPS we will get two - // configs per nic. Results from the second will overwrite the - // result from the first. - // TODO: Handle multiple pings on one nic. - CreateRelayPorts(username, password, config, proxy_info); -} - -void ConnectivityChecker::OnRelayPortComplete(Port* port) { - ASSERT(worker_ == rtc::Thread::Current()); - RelayPort* relay_port = reinterpret_cast<RelayPort*>(port); - const ProtocolAddress* address = relay_port->ServerAddress(0); -#ifdef USE_WEBRTC_DEV_BRANCH - rtc::IPAddress ip = port->Network()->GetBestIP(); -#else // USE_WEBRTC_DEV_BRANCH - rtc::IPAddress ip = port->Network()->ip(); -#endif // USE_WEBRTC_DEV_BRANCH - NicMap::iterator i = nics_.find(NicId(ip, port->proxy().address)); - if (i != nics_.end()) { - // We have it already, add the new information. - NicInfo* nic_info = &i->second; - ConnectInfo* connect_info = NULL; - if (address) { - switch (address->proto) { - case PROTO_UDP: - connect_info = &nic_info->udp; - break; - case PROTO_TCP: - connect_info = &nic_info->tcp; - break; - case PROTO_SSLTCP: - connect_info = &nic_info->ssltcp; - break; - default: - LOG(LS_ERROR) << " relay address with bad protocol added"; - } - if (connect_info) { - connect_info->rtt = - rtc::TimeSince(connect_info->start_time_ms); - } - } - } else { - LOG(LS_ERROR) << " got relay address for non-existing nic"; - } -} - -void ConnectivityChecker::OnStunPortComplete(Port* port) { - ASSERT(worker_ == rtc::Thread::Current()); - const std::vector<Candidate> candidates = port->Candidates(); - Candidate c = candidates[0]; -#ifdef USE_WEBRTC_DEV_BRANCH - rtc::IPAddress ip = port->Network()->GetBestIP(); -#else // USE_WEBRTC_DEV_BRANCH - rtc::IPAddress ip = port->Network()->ip(); -#endif // USE_WEBRTC_DEV_BRANCH - NicMap::iterator i = nics_.find(NicId(ip, port->proxy().address)); - if (i != nics_.end()) { - // We have it already, add the new information. - uint32 now = rtc::Time(); - NicInfo* nic_info = &i->second; - nic_info->external_address = c.address(); - - nic_info->stun_server_addresses = - static_cast<StunPort*>(port)->server_addresses(); - nic_info->stun.rtt = now - nic_info->stun.start_time_ms; - } else { - LOG(LS_ERROR) << "Got stun address for non-existing nic"; - } -} - -void ConnectivityChecker::OnStunPortError(Port* port) { - ASSERT(worker_ == rtc::Thread::Current()); - LOG(LS_ERROR) << "Stun address error."; -#ifdef USE_WEBRTC_DEV_BRANCH - rtc::IPAddress ip = port->Network()->GetBestIP(); -#else // USE_WEBRTC_DEV_BRANCH - rtc::IPAddress ip = port->Network()->ip(); -#endif // USE_WEBRTC_DEV_BRANCH - NicMap::iterator i = nics_.find(NicId(ip, port->proxy().address)); - if (i != nics_.end()) { - // We have it already, add the new information. - NicInfo* nic_info = &i->second; - - nic_info->stun_server_addresses = - static_cast<StunPort*>(port)->server_addresses(); - } -} - -void ConnectivityChecker::OnRelayPortError(Port* port) { - ASSERT(worker_ == rtc::Thread::Current()); - LOG(LS_ERROR) << "Relay address error."; -} - -void ConnectivityChecker::OnNetworksChanged() { - ASSERT(worker_ == rtc::Thread::Current()); - std::vector<rtc::Network*> networks; - network_manager_->GetNetworks(&networks); - if (networks.empty()) { - LOG(LS_ERROR) << "Machine has no networks; nothing to do"; - return; - } - AllocatePorts(); -} - -HttpPortAllocator* ConnectivityChecker::CreatePortAllocator( - rtc::NetworkManager* network_manager, - const std::string& user_agent, - const std::string& relay_token) { - return new TestHttpPortAllocator(network_manager, user_agent, relay_token); -} - -StunPort* ConnectivityChecker::CreateStunPort( - const std::string& username, const std::string& password, - const PortConfiguration* config, rtc::Network* network) { - return StunPort::Create(worker_, - socket_factory_.get(), - network, -#ifdef USE_WEBRTC_DEV_BRANCH - network->GetBestIP(), -#else // USE_WEBRTC_DEV_BRANCH - network->ip(), -#endif // USE_WEBRTC_DEV_BRANCH - 0, - 0, - username, - password, - config->stun_servers); -} - -RelayPort* ConnectivityChecker::CreateRelayPort( - const std::string& username, const std::string& password, - const PortConfiguration* config, rtc::Network* network) { - return RelayPort::Create(worker_, - socket_factory_.get(), - network, -#ifdef USE_WEBRTC_DEV_BRANCH - network->GetBestIP(), -#else // USE_WEBRTC_DEV_BRANCH - network->ip(), -#endif // USE_WEBRTC_DEV_BRANCH - port_allocator_->min_port(), - port_allocator_->max_port(), - username, - password); -} - -void ConnectivityChecker::CreateRelayPorts( - const std::string& username, const std::string& password, - const PortConfiguration* config, const rtc::ProxyInfo& proxy_info) { - PortConfiguration::RelayList::const_iterator relay; - std::vector<rtc::Network*> networks; - network_manager_->GetNetworks(&networks); - if (networks.empty()) { - LOG(LS_ERROR) << "Machine has no networks; no relay ports created."; - return; - } - for (relay = config->relays.begin(); - relay != config->relays.end(); ++relay) { - for (uint32 i = 0; i < networks.size(); ++i) { - NicMap::iterator iter = -#ifdef USE_WEBRTC_DEV_BRANCH - nics_.find(NicId(networks[i]->GetBestIP(), proxy_info.address)); -#else // USE_WEBRTC_DEV_BRANCH - nics_.find(NicId(networks[i]->ip(), proxy_info.address)); -#endif // USE_WEBRTC_DEV_BRANCH - if (iter != nics_.end()) { - // TODO: Now setting the same start time for all protocols. - // This might affect accuracy, but since we are mainly looking for - // connect failures or number that stick out, this is good enough. - uint32 now = rtc::Time(); - NicInfo* nic_info = &iter->second; - nic_info->udp.start_time_ms = now; - nic_info->tcp.start_time_ms = now; - nic_info->ssltcp.start_time_ms = now; - - // Add the addresses of this protocol. - PortList::const_iterator relay_port; - for (relay_port = relay->ports.begin(); - relay_port != relay->ports.end(); - ++relay_port) { - RelayPort* port = CreateRelayPort(username, password, - config, networks[i]); - port->AddServerAddress(*relay_port); - port->AddExternalAddress(*relay_port); - - nic_info->media_server_address = port->ServerAddress(0)->address; - - // Listen to network events. - port->SignalPortComplete.connect( - this, &ConnectivityChecker::OnRelayPortComplete); - port->SignalPortError.connect( - this, &ConnectivityChecker::OnRelayPortError); - - port->set_proxy(user_agent_, proxy_info); - - // Start fetching an address for this port. - port->PrepareAddress(); - ports_.push_back(port); - } - } else { - LOG(LS_ERROR) << "Failed to find nic info when creating relay ports."; - } - } - } -} - -void ConnectivityChecker::AllocatePorts() { - const std::string username = rtc::CreateRandomString(ICE_UFRAG_LENGTH); - const std::string password = rtc::CreateRandomString(ICE_PWD_LENGTH); - ServerAddresses stun_servers; - stun_servers.insert(stun_address_); - PortConfiguration config(stun_servers, username, password); - std::vector<rtc::Network*> networks; - network_manager_->GetNetworks(&networks); - if (networks.empty()) { - LOG(LS_ERROR) << "Machine has no networks; no ports will be allocated"; - return; - } - rtc::ProxyInfo proxy_info = GetProxyInfo(); - bool allocate_relay_ports = false; - for (uint32 i = 0; i < networks.size(); ++i) { -#ifdef USE_WEBRTC_DEV_BRANCH - if (AddNic(networks[i]->GetBestIP(), proxy_info.address)) { -#else // USE_WEBRTC_DEV_BRANCH - if (AddNic(networks[i]->ip(), proxy_info.address)) { -#endif // USE_WEBRTC_DEV_BRANCH - Port* port = CreateStunPort(username, password, &config, networks[i]); - if (port) { - - // Listen to network events. - port->SignalPortComplete.connect( - this, &ConnectivityChecker::OnStunPortComplete); - port->SignalPortError.connect( - this, &ConnectivityChecker::OnStunPortError); - - port->set_proxy(user_agent_, proxy_info); - port->PrepareAddress(); - ports_.push_back(port); - allocate_relay_ports = true; - } - } - } - - // If any new ip/proxy combinations were added, send a relay allocate. - if (allocate_relay_ports) { - AllocateRelayPorts(); - } - - // Initiate proxy detection. - InitiateProxyDetection(); -} - -void ConnectivityChecker::InitiateProxyDetection() { - // Only start if we haven't been started before. - if (!proxy_detect_) { - proxy_detect_ = new rtc::AutoDetectProxy(user_agent_); - rtc::Url<char> host_url("/", "relay.google.com", - rtc::HTTP_SECURE_PORT); - host_url.set_secure(true); - proxy_detect_->set_server_url(host_url.url()); - proxy_detect_->SignalWorkDone.connect( - this, &ConnectivityChecker::OnProxyDetect); - proxy_detect_->Start(); - } -} - -void ConnectivityChecker::AllocateRelayPorts() { - // Currently we are using the 'default' nic for http(s) requests. - TestHttpPortAllocatorSession* allocator_session = - reinterpret_cast<TestHttpPortAllocatorSession*>( - port_allocator_->CreateSessionInternal( - "connectivity checker test content", - ICE_CANDIDATE_COMPONENT_RTP, - rtc::CreateRandomString(ICE_UFRAG_LENGTH), - rtc::CreateRandomString(ICE_PWD_LENGTH))); - allocator_session->set_proxy(port_allocator_->proxy()); - allocator_session->SignalConfigReady.connect( - this, &ConnectivityChecker::OnConfigReady); - allocator_session->SignalRequestDone.connect( - this, &ConnectivityChecker::OnRequestDone); - - // Try https only since using http would result in credentials being sent - // over the network unprotected. - RegisterHttpStart(rtc::HTTP_SECURE_PORT); - allocator_session->SendSessionRequest("relay.l.google.com", - rtc::HTTP_SECURE_PORT); - - sessions_.push_back(allocator_session); -} - -void ConnectivityChecker::RegisterHttpStart(int port) { - // Since we don't know what nic were actually used for the http request, - // for now, just use the first one. - std::vector<rtc::Network*> networks; - network_manager_->GetNetworks(&networks); - if (networks.empty()) { - LOG(LS_ERROR) << "No networks while registering http start."; - return; - } - rtc::ProxyInfo proxy_info = GetProxyInfo(); - NicMap::iterator i = -#ifdef USE_WEBRTC_DEV_BRANCH - nics_.find(NicId(networks[0]->GetBestIP(), proxy_info.address)); -#else // USE_WEBRTC_DEV_BRANCH - nics_.find(NicId(networks[0]->ip(), proxy_info.address)); -#endif // USE_WEBRTC_DEV_BRANCH - if (i != nics_.end()) { - uint32 now = rtc::Time(); - NicInfo* nic_info = &i->second; - if (port == rtc::HTTP_SECURE_PORT) { - nic_info->https.start_time_ms = now; - } else { - LOG(LS_ERROR) << "Registering start time for unknown port: " << port; - } - } else { - LOG(LS_ERROR) << "Error, no nic info found while registering http start."; - } -} - -} // namespace rtc diff --git a/talk/p2p/client/connectivitychecker.h b/talk/p2p/client/connectivitychecker.h deleted file mode 100644 index ba3d00374..000000000 --- a/talk/p2p/client/connectivitychecker.h +++ /dev/null @@ -1,274 +0,0 @@ -// Copyright 2011 Google Inc. All Rights Reserved. - - -#ifndef WEBRTC_P2P_CLIENT_CONNECTIVITYCHECKER_H_ -#define WEBRTC_P2P_CLIENT_CONNECTIVITYCHECKER_H_ - -#include <map> -#include <string> - -#include "webrtc/p2p/base/basicpacketsocketfactory.h" -#include "webrtc/p2p/client/httpportallocator.h" -#include "webrtc/base/basictypes.h" -#include "webrtc/base/messagehandler.h" -#include "webrtc/base/network.h" -#include "webrtc/base/proxyinfo.h" -#include "webrtc/base/scoped_ptr.h" -#include "webrtc/base/sigslot.h" -#include "webrtc/base/socketaddress.h" - -namespace rtc { -class AsyncHttpRequest; -class AutoDetectProxy; -class BasicPacketSocketFactory; -class NetworkManager; -class PacketSocketFactory; -class SignalThread; -class TestHttpPortAllocatorSession; -class Thread; -} - -namespace cricket { -class HttpPortAllocator; -class Port; -class PortAllocatorSession; -struct PortConfiguration; -class RelayPort; -class StunPort; - -// Contains details about a discovered firewall that are of interest -// when debugging call failures. -struct FirewallInfo { - std::string brand; - std::string model; - - // TODO: List of current port mappings. -}; - -// Contains details about a specific connect attempt. -struct ConnectInfo { - ConnectInfo() - : rtt(-1), error(0) {} - // Time when the connection was initiated. Needed for calculating - // the round trip time. - uint32 start_time_ms; - // Round trip time in milliseconds or -1 for failed connection. - int32 rtt; - // Error code representing low level errors like socket errors. - int error; -}; - -// Identifier for a network interface and proxy address pair. -struct NicId { - NicId(const rtc::IPAddress& ip, - const rtc::SocketAddress& proxy_address) - : ip(ip), - proxy_address(proxy_address) { - } - rtc::IPAddress ip; - rtc::SocketAddress proxy_address; -}; - -// Comparator implementation identifying unique network interface and -// proxy address pairs. -class NicIdComparator { - public: - int compare(const NicId &first, const NicId &second) const { - if (first.ip == second.ip) { - // Compare proxy address. - if (first.proxy_address == second.proxy_address) { - return 0; - } else { - return first.proxy_address < second.proxy_address? -1 : 1; - } - } - return first.ip < second.ip ? -1 : 1; - } - - bool operator()(const NicId &first, const NicId &second) const { - return (compare(first, second) < 0); - } -}; - -// Contains information of a network interface and proxy address pair. -struct NicInfo { - NicInfo() {} - rtc::IPAddress ip; - rtc::ProxyInfo proxy_info; - rtc::SocketAddress external_address; - ServerAddresses stun_server_addresses; - rtc::SocketAddress media_server_address; - ConnectInfo stun; - ConnectInfo http; - ConnectInfo https; - ConnectInfo udp; - ConnectInfo tcp; - ConnectInfo ssltcp; - FirewallInfo firewall; -}; - -// Holds the result of the connectivity check. -class NicMap : public std::map<NicId, NicInfo, NicIdComparator> { -}; - -class TestHttpPortAllocatorSession : public HttpPortAllocatorSession { - public: - TestHttpPortAllocatorSession( - HttpPortAllocator* allocator, - const std::string& content_name, - int component, - const std::string& ice_ufrag, - const std::string& ice_pwd, - const std::vector<rtc::SocketAddress>& stun_hosts, - const std::vector<std::string>& relay_hosts, - const std::string& relay_token, - const std::string& user_agent) - : HttpPortAllocatorSession( - allocator, content_name, component, ice_ufrag, ice_pwd, stun_hosts, - relay_hosts, relay_token, user_agent) { - } - void set_proxy(const rtc::ProxyInfo& proxy) { - proxy_ = proxy; - } - - void ConfigReady(PortConfiguration* config); - - void OnRequestDone(rtc::SignalThread* data); - - sigslot::signal4<const std::string&, const std::string&, - const PortConfiguration*, - const rtc::ProxyInfo&> SignalConfigReady; - sigslot::signal1<rtc::AsyncHttpRequest*> SignalRequestDone; - - private: - rtc::ProxyInfo proxy_; -}; - -// Runs a request/response check on all network interface and proxy -// address combinations. The check is considered done either when all -// checks has been successful or when the check times out. -class ConnectivityChecker - : public rtc::MessageHandler, public sigslot::has_slots<> { - public: - ConnectivityChecker(rtc::Thread* worker, - const std::string& jid, - const std::string& session_id, - const std::string& user_agent, - const std::string& relay_token, - const std::string& connection); - virtual ~ConnectivityChecker(); - - // Virtual for gMock. - virtual bool Initialize(); - virtual void Start(); - - // MessageHandler implementation. - virtual void OnMessage(rtc::Message *msg); - - // Instruct checker to stop and wait until that's done. - // Virtual for gMock. - virtual void Stop() { - worker_->Stop(); - } - - const NicMap& GetResults() const { - return nics_; - } - - void set_timeout_ms(uint32 timeout) { - timeout_ms_ = timeout; - } - - void set_stun_address(const rtc::SocketAddress& stun_address) { - stun_address_ = stun_address; - } - - const std::string& connection() const { - return connection_; - } - - const std::string& jid() const { - return jid_; - } - - const std::string& session_id() const { - return session_id_; - } - - // Context: Main Thread. Signalled when the connectivity check is complete. - sigslot::signal1<ConnectivityChecker*> SignalCheckDone; - - protected: - // Can be overridden for test. - virtual rtc::NetworkManager* CreateNetworkManager() { - return new rtc::BasicNetworkManager(); - } - virtual rtc::BasicPacketSocketFactory* CreateSocketFactory( - rtc::Thread* thread) { - return new rtc::BasicPacketSocketFactory(thread); - } - virtual HttpPortAllocator* CreatePortAllocator( - rtc::NetworkManager* network_manager, - const std::string& user_agent, - const std::string& relay_token); - virtual StunPort* CreateStunPort( - const std::string& username, const std::string& password, - const PortConfiguration* config, rtc::Network* network); - virtual RelayPort* CreateRelayPort( - const std::string& username, const std::string& password, - const PortConfiguration* config, rtc::Network* network); - virtual void InitiateProxyDetection(); - virtual void SetProxyInfo(const rtc::ProxyInfo& info); - virtual rtc::ProxyInfo GetProxyInfo() const; - - rtc::Thread* worker() { - return worker_; - } - - private: - bool AddNic(const rtc::IPAddress& ip, - const rtc::SocketAddress& proxy_address); - void AllocatePorts(); - void AllocateRelayPorts(); - void CheckNetworks(); - void CreateRelayPorts( - const std::string& username, const std::string& password, - const PortConfiguration* config, const rtc::ProxyInfo& proxy_info); - - // Must be called by the worker thread. - void CleanUp(); - - void OnRequestDone(rtc::AsyncHttpRequest* request); - void OnRelayPortComplete(Port* port); - void OnStunPortComplete(Port* port); - void OnRelayPortError(Port* port); - void OnStunPortError(Port* port); - void OnNetworksChanged(); - void OnProxyDetect(rtc::SignalThread* thread); - void OnConfigReady( - const std::string& username, const std::string& password, - const PortConfiguration* config, const rtc::ProxyInfo& proxy); - void OnConfigWithProxyReady(const PortConfiguration*); - void RegisterHttpStart(int port); - rtc::Thread* worker_; - std::string jid_; - std::string session_id_; - std::string user_agent_; - std::string relay_token_; - std::string connection_; - rtc::AutoDetectProxy* proxy_detect_; - rtc::scoped_ptr<rtc::NetworkManager> network_manager_; - rtc::scoped_ptr<rtc::BasicPacketSocketFactory> socket_factory_; - rtc::scoped_ptr<HttpPortAllocator> port_allocator_; - NicMap nics_; - std::vector<Port*> ports_; - std::vector<PortAllocatorSession*> sessions_; - uint32 timeout_ms_; - rtc::SocketAddress stun_address_; - rtc::Thread* main_; - bool started_; -}; - -} // namespace cricket - -#endif // WEBRTC_P2P_CLIENT_CONNECTIVITYCHECKER_H_ diff --git a/talk/p2p/client/connectivitychecker_unittest.cc b/talk/p2p/client/connectivitychecker_unittest.cc deleted file mode 100644 index 5a2a60825..000000000 --- a/talk/p2p/client/connectivitychecker_unittest.cc +++ /dev/null @@ -1,392 +0,0 @@ -/* - * libjingle - * Copyright 2011, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <string> - -#include "webrtc/p2p/base/basicpacketsocketfactory.h" -#include "webrtc/p2p/base/relayport.h" -#include "webrtc/p2p/base/stunport.h" -#include "webrtc/p2p/client/connectivitychecker.h" -#include "webrtc/p2p/client/httpportallocator.h" -#include "webrtc/base/asynchttprequest.h" -#include "webrtc/base/fakenetwork.h" -#include "webrtc/base/gunit.h" -#include "webrtc/base/scoped_ptr.h" -#include "webrtc/base/socketaddress.h" - -namespace cricket { - -static const rtc::SocketAddress kClientAddr1("11.11.11.11", 0); -static const rtc::SocketAddress kClientAddr2("22.22.22.22", 0); -static const rtc::SocketAddress kExternalAddr("33.33.33.33", 3333); -static const rtc::SocketAddress kStunAddr("44.44.44.44", 4444); -static const rtc::SocketAddress kRelayAddr("55.55.55.55", 5555); -static const rtc::SocketAddress kProxyAddr("66.66.66.66", 6666); -static const rtc::ProxyType kProxyType = rtc::PROXY_HTTPS; -static const char kRelayHost[] = "relay.google.com"; -static const char kRelayToken[] = - "CAESFwoOb2phQGdvb2dsZS5jb20Q043h47MmGhBTB1rbfIXkhuarDCZe+xF6"; -static const char kBrowserAgent[] = "browser_test"; -static const char kJid[] = "a.b@c"; -static const char kUserName[] = "testuser"; -static const char kPassword[] = "testpassword"; -static const char kMagicCookie[] = "testcookie"; -static const char kRelayUdpPort[] = "4444"; -static const char kRelayTcpPort[] = "5555"; -static const char kRelaySsltcpPort[] = "6666"; -static const char kSessionId[] = "testsession"; -static const char kConnection[] = "testconnection"; -static const int kMinPort = 1000; -static const int kMaxPort = 2000; - -// Fake implementation to mock away real network usage. -class FakeRelayPort : public RelayPort { - public: - FakeRelayPort(rtc::Thread* thread, - rtc::PacketSocketFactory* factory, - rtc::Network* network, const rtc::IPAddress& ip, - int min_port, int max_port, - const std::string& username, const std::string& password) - : RelayPort(thread, factory, network, ip, min_port, max_port, - username, password) { - } - - // Just signal that we are done. - virtual void PrepareAddress() { - SignalPortComplete(this); - } -}; - -// Fake implementation to mock away real network usage. -class FakeStunPort : public StunPort { - public: - FakeStunPort(rtc::Thread* thread, - rtc::PacketSocketFactory* factory, - rtc::Network* network, - const rtc::IPAddress& ip, - int min_port, int max_port, - const std::string& username, const std::string& password, - const ServerAddresses& server_addr) - : StunPort(thread, factory, network, ip, min_port, max_port, - username, password, server_addr) { - } - - // Just set external address and signal that we are done. - virtual void PrepareAddress() { - AddAddress(kExternalAddr, kExternalAddr, rtc::SocketAddress(), "udp", "", - STUN_PORT_TYPE, ICE_TYPE_PREFERENCE_SRFLX, 0, true); - SignalPortComplete(this); - } -}; - -// Fake implementation to mock away real network usage by responding -// to http requests immediately. -class FakeHttpPortAllocatorSession : public TestHttpPortAllocatorSession { - public: - FakeHttpPortAllocatorSession( - HttpPortAllocator* allocator, - const std::string& content_name, - int component, - const std::string& ice_ufrag, const std::string& ice_pwd, - const std::vector<rtc::SocketAddress>& stun_hosts, - const std::vector<std::string>& relay_hosts, - const std::string& relay_token, - const std::string& agent) - : TestHttpPortAllocatorSession(allocator, - content_name, - component, - ice_ufrag, - ice_pwd, - stun_hosts, - relay_hosts, - relay_token, - agent) { - } - virtual void SendSessionRequest(const std::string& host, int port) { - FakeReceiveSessionResponse(host, port); - } - - // Pass results to the real implementation. - void FakeReceiveSessionResponse(const std::string& host, int port) { - rtc::AsyncHttpRequest* response = CreateAsyncHttpResponse(port); - TestHttpPortAllocatorSession::OnRequestDone(response); - response->Destroy(true); - } - - private: - // Helper method for creating a response to a relay session request. - rtc::AsyncHttpRequest* CreateAsyncHttpResponse(int port) { - rtc::AsyncHttpRequest* request = - new rtc::AsyncHttpRequest(kBrowserAgent); - std::stringstream ss; - ss << "username=" << kUserName << std::endl - << "password=" << kPassword << std::endl - << "magic_cookie=" << kMagicCookie << std::endl - << "relay.ip=" << kRelayAddr.ipaddr().ToString() << std::endl - << "relay.udp_port=" << kRelayUdpPort << std::endl - << "relay.tcp_port=" << kRelayTcpPort << std::endl - << "relay.ssltcp_port=" << kRelaySsltcpPort << std::endl; - request->response().document.reset( - new rtc::MemoryStream(ss.str().c_str())); - request->response().set_success(); - request->set_port(port); - request->set_secure(port == rtc::HTTP_SECURE_PORT); - return request; - } -}; - -// Fake implementation for creating fake http sessions. -class FakeHttpPortAllocator : public HttpPortAllocator { - public: - FakeHttpPortAllocator(rtc::NetworkManager* network_manager, - const std::string& user_agent) - : HttpPortAllocator(network_manager, user_agent) { - } - - virtual PortAllocatorSession* CreateSessionInternal( - const std::string& content_name, int component, - const std::string& ice_ufrag, const std::string& ice_pwd) { - std::vector<rtc::SocketAddress> stun_hosts; - stun_hosts.push_back(kStunAddr); - std::vector<std::string> relay_hosts; - relay_hosts.push_back(kRelayHost); - return new FakeHttpPortAllocatorSession(this, - content_name, - component, - ice_ufrag, - ice_pwd, - stun_hosts, - relay_hosts, - kRelayToken, - kBrowserAgent); - } -}; - -class ConnectivityCheckerForTest : public ConnectivityChecker { - public: - ConnectivityCheckerForTest(rtc::Thread* worker, - const std::string& jid, - const std::string& session_id, - const std::string& user_agent, - const std::string& relay_token, - const std::string& connection) - : ConnectivityChecker(worker, - jid, - session_id, - user_agent, - relay_token, - connection), - proxy_initiated_(false) { - } - - rtc::FakeNetworkManager* network_manager() const { - return network_manager_; - } - - FakeHttpPortAllocator* port_allocator() const { - return fake_port_allocator_; - } - - protected: - // Overridden methods for faking a real network. - virtual rtc::NetworkManager* CreateNetworkManager() { - network_manager_ = new rtc::FakeNetworkManager(); - return network_manager_; - } - virtual rtc::BasicPacketSocketFactory* CreateSocketFactory( - rtc::Thread* thread) { - // Create socket factory, for simplicity, let it run on the current thread. - socket_factory_ = - new rtc::BasicPacketSocketFactory(rtc::Thread::Current()); - return socket_factory_; - } - virtual HttpPortAllocator* CreatePortAllocator( - rtc::NetworkManager* network_manager, - const std::string& user_agent, - const std::string& relay_token) { - fake_port_allocator_ = - new FakeHttpPortAllocator(network_manager, user_agent); - return fake_port_allocator_; - } - virtual StunPort* CreateStunPort( - const std::string& username, const std::string& password, - const PortConfiguration* config, rtc::Network* network) { - return new FakeStunPort(worker(), - socket_factory_, - network, -#ifdef USE_WEBRTC_DEV_BRANCH - network->GetBestIP(), -#else // USE_WEBRTC_DEV_BRANCH - network->ip(), -#endif // USE_WEBRTC_DEV_BRANCH - kMinPort, - kMaxPort, - username, - password, - config->stun_servers); - } - virtual RelayPort* CreateRelayPort( - const std::string& username, const std::string& password, - const PortConfiguration* config, rtc::Network* network) { - return new FakeRelayPort(worker(), - socket_factory_, - network, -#ifdef USE_WEBRTC_DEV_BRANCH - network->GetBestIP(), -#else // USE_WEBRTC_DEV_BRANCH - network->ip(), -#endif // USE_WEBRTC_DEV_BRANCH - kMinPort, - kMaxPort, - username, - password); - } - virtual void InitiateProxyDetection() { - if (!proxy_initiated_) { - proxy_initiated_ = true; - proxy_info_.address = kProxyAddr; - proxy_info_.type = kProxyType; - SetProxyInfo(proxy_info_); - } - } - - virtual rtc::ProxyInfo GetProxyInfo() const { - return proxy_info_; - } - - private: - rtc::BasicPacketSocketFactory* socket_factory_; - FakeHttpPortAllocator* fake_port_allocator_; - rtc::FakeNetworkManager* network_manager_; - rtc::ProxyInfo proxy_info_; - bool proxy_initiated_; -}; - -class ConnectivityCheckerTest : public testing::Test { - protected: - void VerifyNic(const NicInfo& info, - const rtc::SocketAddress& local_address) { - // Verify that the external address has been set. - EXPECT_EQ(kExternalAddr, info.external_address); - - // Verify that the stun server address has been set. - EXPECT_EQ(1U, info.stun_server_addresses.size()); - EXPECT_EQ(kStunAddr, *(info.stun_server_addresses.begin())); - - // Verify that the media server address has been set. Don't care - // about port since it is different for different protocols. - EXPECT_EQ(kRelayAddr.ipaddr(), info.media_server_address.ipaddr()); - - // Verify that local ip matches. - EXPECT_EQ(local_address.ipaddr(), info.ip); - - // Verify that we have received responses for our - // pings. Unsuccessful ping has rtt value -1, successful >= 0. - EXPECT_GE(info.stun.rtt, 0); - EXPECT_GE(info.udp.rtt, 0); - EXPECT_GE(info.tcp.rtt, 0); - EXPECT_GE(info.ssltcp.rtt, 0); - - // If proxy has been set, verify address and type. - if (!info.proxy_info.address.IsNil()) { - EXPECT_EQ(kProxyAddr, info.proxy_info.address); - EXPECT_EQ(kProxyType, info.proxy_info.type); - } - } -}; - -// Tests a configuration with two network interfaces. Verifies that 4 -// combinations of ip/proxy are created and that all protocols are -// tested on each combination. -TEST_F(ConnectivityCheckerTest, TestStart) { - ConnectivityCheckerForTest connectivity_checker(rtc::Thread::Current(), - kJid, - kSessionId, - kBrowserAgent, - kRelayToken, - kConnection); - connectivity_checker.Initialize(); - connectivity_checker.set_stun_address(kStunAddr); - connectivity_checker.network_manager()->AddInterface(kClientAddr1); - connectivity_checker.network_manager()->AddInterface(kClientAddr2); - - connectivity_checker.Start(); - rtc::Thread::Current()->ProcessMessages(1000); - - NicMap nics = connectivity_checker.GetResults(); - - // There should be 4 nics in our map. 2 for each interface added, - // one with proxy set and one without. - EXPECT_EQ(4U, nics.size()); - - // First verify interfaces without proxy. - rtc::SocketAddress nilAddress; - - // First lookup the address of the first nic combined with no proxy. - NicMap::iterator i = nics.find(NicId(kClientAddr1.ipaddr(), nilAddress)); - ASSERT(i != nics.end()); - NicInfo info = i->second; - VerifyNic(info, kClientAddr1); - - // Then make sure the second device has been tested without proxy. - i = nics.find(NicId(kClientAddr2.ipaddr(), nilAddress)); - ASSERT(i != nics.end()); - info = i->second; - VerifyNic(info, kClientAddr2); - - // Now verify both interfaces with proxy. - i = nics.find(NicId(kClientAddr1.ipaddr(), kProxyAddr)); - ASSERT(i != nics.end()); - info = i->second; - VerifyNic(info, kClientAddr1); - - i = nics.find(NicId(kClientAddr2.ipaddr(), kProxyAddr)); - ASSERT(i != nics.end()); - info = i->second; - VerifyNic(info, kClientAddr2); -}; - -// Tests that nothing bad happens if thera are no network interfaces -// available to check. -TEST_F(ConnectivityCheckerTest, TestStartNoNetwork) { - ConnectivityCheckerForTest connectivity_checker(rtc::Thread::Current(), - kJid, - kSessionId, - kBrowserAgent, - kRelayToken, - kConnection); - connectivity_checker.Initialize(); - connectivity_checker.Start(); - rtc::Thread::Current()->ProcessMessages(1000); - - NicMap nics = connectivity_checker.GetResults(); - - // Verify that no nics where checked. - EXPECT_EQ(0U, nics.size()); -} - -} // namespace cricket diff --git a/talk/p2p/client/fakeportallocator.h b/talk/p2p/client/fakeportallocator.h deleted file mode 100644 index 04c5f47b8..000000000 --- a/talk/p2p/client/fakeportallocator.h +++ /dev/null @@ -1,138 +0,0 @@ -/* - * libjingle - * Copyright 2010, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef WEBRTC_P2P_CLIENT_FAKEPORTALLOCATOR_H_ -#define WEBRTC_P2P_CLIENT_FAKEPORTALLOCATOR_H_ - -#include <string> -#include "webrtc/p2p/base/basicpacketsocketfactory.h" -#include "webrtc/p2p/base/portallocator.h" -#include "webrtc/p2p/base/udpport.h" -#include "webrtc/base/scoped_ptr.h" - -namespace rtc { -class SocketFactory; -class Thread; -} - -namespace cricket { - -class FakePortAllocatorSession : public PortAllocatorSession { - public: - FakePortAllocatorSession(rtc::Thread* worker_thread, - rtc::PacketSocketFactory* factory, - const std::string& content_name, - int component, - const std::string& ice_ufrag, - const std::string& ice_pwd) - : PortAllocatorSession(content_name, component, ice_ufrag, ice_pwd, - cricket::PORTALLOCATOR_ENABLE_SHARED_UFRAG), - worker_thread_(worker_thread), - factory_(factory), - network_("network", "unittest", - rtc::IPAddress(INADDR_LOOPBACK), 8), - port_(), running_(false), - port_config_count_(0) { - network_.AddIP(rtc::IPAddress(INADDR_LOOPBACK)); - } - - virtual void StartGettingPorts() { - if (!port_) { - port_.reset(cricket::UDPPort::Create(worker_thread_, - factory_, - &network_, -#ifdef USE_WEBRTC_DEV_BRANCH - network_.GetBestIP(), -#else // USE_WEBRTC_DEV_BRANCH - network_.ip(), -#endif // USE_WEBRTC_DEV_BRANCH - 0, - 0, - username(), - password())); - AddPort(port_.get()); - } - ++port_config_count_; - running_ = true; - } - - virtual void StopGettingPorts() { running_ = false; } - virtual bool IsGettingPorts() { return running_; } - int port_config_count() { return port_config_count_; } - - void AddPort(cricket::Port* port) { - port->set_component(component_); - port->set_generation(0); - port->SignalPortComplete.connect( - this, &FakePortAllocatorSession::OnPortComplete); - port->PrepareAddress(); - SignalPortReady(this, port); - } - void OnPortComplete(cricket::Port* port) { - SignalCandidatesReady(this, port->Candidates()); - SignalCandidatesAllocationDone(this); - } - - private: - rtc::Thread* worker_thread_; - rtc::PacketSocketFactory* factory_; - rtc::Network network_; - rtc::scoped_ptr<cricket::Port> port_; - bool running_; - int port_config_count_; -}; - -class FakePortAllocator : public cricket::PortAllocator { - public: - FakePortAllocator(rtc::Thread* worker_thread, - rtc::PacketSocketFactory* factory) - : worker_thread_(worker_thread), factory_(factory) { - if (factory_ == NULL) { - owned_factory_.reset(new rtc::BasicPacketSocketFactory( - worker_thread_)); - factory_ = owned_factory_.get(); - } - } - - virtual cricket::PortAllocatorSession* CreateSessionInternal( - const std::string& content_name, - int component, - const std::string& ice_ufrag, - const std::string& ice_pwd) { - return new FakePortAllocatorSession( - worker_thread_, factory_, content_name, component, ice_ufrag, ice_pwd); - } - - private: - rtc::Thread* worker_thread_; - rtc::PacketSocketFactory* factory_; - rtc::scoped_ptr<rtc::BasicPacketSocketFactory> owned_factory_; -}; - -} // namespace cricket - -#endif // WEBRTC_P2P_CLIENT_FAKEPORTALLOCATOR_H_ diff --git a/talk/p2p/client/httpportallocator.cc b/talk/p2p/client/httpportallocator.cc deleted file mode 100644 index ce525936e..000000000 --- a/talk/p2p/client/httpportallocator.cc +++ /dev/null @@ -1,343 +0,0 @@ -/* - * libjingle - * Copyright 2004--2008, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "webrtc/p2p/client/httpportallocator.h" - -#include <algorithm> -#include <map> - -#include "webrtc/base/asynchttprequest.h" -#include "webrtc/base/basicdefs.h" -#include "webrtc/base/common.h" -#include "webrtc/base/helpers.h" -#include "webrtc/base/logging.h" -#include "webrtc/base/nethelpers.h" -#include "webrtc/base/signalthread.h" -#include "webrtc/base/stringencode.h" - -namespace { - -// Helper routine to remove whitespace from the ends of a string. -void Trim(std::string& str) { - size_t first = str.find_first_not_of(" \t\r\n"); - if (first == std::string::npos) { - str.clear(); - return; - } - - ASSERT(str.find_last_not_of(" \t\r\n") != std::string::npos); -} - -// Parses the lines in the result of the HTTP request that are of the form -// 'a=b' and returns them in a map. -typedef std::map<std::string, std::string> StringMap; -void ParseMap(const std::string& string, StringMap& map) { - size_t start_of_line = 0; - size_t end_of_line = 0; - - for (;;) { // for each line - start_of_line = string.find_first_not_of("\r\n", end_of_line); - if (start_of_line == std::string::npos) - break; - - end_of_line = string.find_first_of("\r\n", start_of_line); - if (end_of_line == std::string::npos) { - end_of_line = string.length(); - } - - size_t equals = string.find('=', start_of_line); - if ((equals >= end_of_line) || (equals == std::string::npos)) - continue; - - std::string key(string, start_of_line, equals - start_of_line); - std::string value(string, equals + 1, end_of_line - equals - 1); - - Trim(key); - Trim(value); - - if ((key.size() > 0) && (value.size() > 0)) - map[key] = value; - } -} - -} // namespace - -namespace cricket { - -// HttpPortAllocatorBase - -const int HttpPortAllocatorBase::kNumRetries = 5; - -const char HttpPortAllocatorBase::kCreateSessionURL[] = "/create_session"; - -HttpPortAllocatorBase::HttpPortAllocatorBase( - rtc::NetworkManager* network_manager, - rtc::PacketSocketFactory* socket_factory, - const std::string &user_agent) - : BasicPortAllocator(network_manager, socket_factory), agent_(user_agent) { - relay_hosts_.push_back("relay.google.com"); - stun_hosts_.push_back( - rtc::SocketAddress("stun.l.google.com", 19302)); -} - -HttpPortAllocatorBase::HttpPortAllocatorBase( - rtc::NetworkManager* network_manager, - const std::string &user_agent) - : BasicPortAllocator(network_manager), agent_(user_agent) { - relay_hosts_.push_back("relay.google.com"); - stun_hosts_.push_back( - rtc::SocketAddress("stun.l.google.com", 19302)); -} - -HttpPortAllocatorBase::~HttpPortAllocatorBase() { -} - -// HttpPortAllocatorSessionBase - -HttpPortAllocatorSessionBase::HttpPortAllocatorSessionBase( - HttpPortAllocatorBase* allocator, - const std::string& content_name, - int component, - const std::string& ice_ufrag, - const std::string& ice_pwd, - const std::vector<rtc::SocketAddress>& stun_hosts, - const std::vector<std::string>& relay_hosts, - const std::string& relay_token, - const std::string& user_agent) - : BasicPortAllocatorSession(allocator, content_name, component, - ice_ufrag, ice_pwd), - relay_hosts_(relay_hosts), stun_hosts_(stun_hosts), - relay_token_(relay_token), agent_(user_agent), attempts_(0) { -} - -HttpPortAllocatorSessionBase::~HttpPortAllocatorSessionBase() {} - -void HttpPortAllocatorSessionBase::GetPortConfigurations() { - // Creating relay sessions can take time and is done asynchronously. - // Creating stun sessions could also take time and could be done aysnc also, - // but for now is done here and added to the initial config. Note any later - // configs will have unresolved stun ips and will be discarded by the - // AllocationSequence. - ServerAddresses hosts; - for (std::vector<rtc::SocketAddress>::iterator it = stun_hosts_.begin(); - it != stun_hosts_.end(); ++it) { - hosts.insert(*it); - } - - PortConfiguration* config = new PortConfiguration(hosts, - username(), - password()); - ConfigReady(config); - TryCreateRelaySession(); -} - -void HttpPortAllocatorSessionBase::TryCreateRelaySession() { - if (allocator()->flags() & PORTALLOCATOR_DISABLE_RELAY) { - LOG(LS_VERBOSE) << "HttpPortAllocator: Relay ports disabled, skipping."; - return; - } - - if (attempts_ == HttpPortAllocator::kNumRetries) { - LOG(LS_ERROR) << "HttpPortAllocator: maximum number of requests reached; " - << "giving up on relay."; - return; - } - - if (relay_hosts_.size() == 0) { - LOG(LS_ERROR) << "HttpPortAllocator: no relay hosts configured."; - return; - } - - // Choose the next host to try. - std::string host = relay_hosts_[attempts_ % relay_hosts_.size()]; - attempts_++; - LOG(LS_INFO) << "HTTPPortAllocator: sending to relay host " << host; - if (relay_token_.empty()) { - LOG(LS_WARNING) << "No relay auth token found."; - } - - SendSessionRequest(host, rtc::HTTP_SECURE_PORT); -} - -std::string HttpPortAllocatorSessionBase::GetSessionRequestUrl() { - std::string url = std::string(HttpPortAllocator::kCreateSessionURL); - if (allocator()->flags() & PORTALLOCATOR_ENABLE_SHARED_UFRAG) { - ASSERT(!username().empty()); - ASSERT(!password().empty()); - url = url + "?username=" + rtc::s_url_encode(username()) + - "&password=" + rtc::s_url_encode(password()); - } - return url; -} - -void HttpPortAllocatorSessionBase::ReceiveSessionResponse( - const std::string& response) { - - StringMap map; - ParseMap(response, map); - - if (!username().empty() && map["username"] != username()) { - LOG(LS_WARNING) << "Received unexpected username value from relay server."; - } - if (!password().empty() && map["password"] != password()) { - LOG(LS_WARNING) << "Received unexpected password value from relay server."; - } - - std::string relay_ip = map["relay.ip"]; - std::string relay_udp_port = map["relay.udp_port"]; - std::string relay_tcp_port = map["relay.tcp_port"]; - std::string relay_ssltcp_port = map["relay.ssltcp_port"]; - - ServerAddresses hosts; - for (std::vector<rtc::SocketAddress>::iterator it = stun_hosts_.begin(); - it != stun_hosts_.end(); ++it) { - hosts.insert(*it); - } - - PortConfiguration* config = new PortConfiguration(hosts, - map["username"], - map["password"]); - - RelayServerConfig relay_config(RELAY_GTURN); - if (!relay_udp_port.empty()) { - rtc::SocketAddress address(relay_ip, atoi(relay_udp_port.c_str())); - relay_config.ports.push_back(ProtocolAddress(address, PROTO_UDP)); - } - if (!relay_tcp_port.empty()) { - rtc::SocketAddress address(relay_ip, atoi(relay_tcp_port.c_str())); - relay_config.ports.push_back(ProtocolAddress(address, PROTO_TCP)); - } - if (!relay_ssltcp_port.empty()) { - rtc::SocketAddress address(relay_ip, atoi(relay_ssltcp_port.c_str())); - relay_config.ports.push_back(ProtocolAddress(address, PROTO_SSLTCP)); - } - config->AddRelay(relay_config); - ConfigReady(config); -} - -// HttpPortAllocator - -HttpPortAllocator::HttpPortAllocator( - rtc::NetworkManager* network_manager, - rtc::PacketSocketFactory* socket_factory, - const std::string &user_agent) - : HttpPortAllocatorBase(network_manager, socket_factory, user_agent) { -} - -HttpPortAllocator::HttpPortAllocator( - rtc::NetworkManager* network_manager, - const std::string &user_agent) - : HttpPortAllocatorBase(network_manager, user_agent) { -} -HttpPortAllocator::~HttpPortAllocator() {} - -PortAllocatorSession* HttpPortAllocator::CreateSessionInternal( - const std::string& content_name, - int component, - const std::string& ice_ufrag, const std::string& ice_pwd) { - return new HttpPortAllocatorSession(this, content_name, component, - ice_ufrag, ice_pwd, stun_hosts(), - relay_hosts(), relay_token(), - user_agent()); -} - -// HttpPortAllocatorSession - -HttpPortAllocatorSession::HttpPortAllocatorSession( - HttpPortAllocator* allocator, - const std::string& content_name, - int component, - const std::string& ice_ufrag, - const std::string& ice_pwd, - const std::vector<rtc::SocketAddress>& stun_hosts, - const std::vector<std::string>& relay_hosts, - const std::string& relay, - const std::string& agent) - : HttpPortAllocatorSessionBase(allocator, content_name, component, - ice_ufrag, ice_pwd, stun_hosts, - relay_hosts, relay, agent) { -} - -HttpPortAllocatorSession::~HttpPortAllocatorSession() { - for (std::list<rtc::AsyncHttpRequest*>::iterator it = requests_.begin(); - it != requests_.end(); ++it) { - (*it)->Destroy(true); - } -} - -void HttpPortAllocatorSession::SendSessionRequest(const std::string& host, - int port) { - // Initiate an HTTP request to create a session through the chosen host. - rtc::AsyncHttpRequest* request = - new rtc::AsyncHttpRequest(user_agent()); - request->SignalWorkDone.connect(this, - &HttpPortAllocatorSession::OnRequestDone); - - request->set_secure(port == rtc::HTTP_SECURE_PORT); - request->set_proxy(allocator()->proxy()); - request->response().document.reset(new rtc::MemoryStream); - request->request().verb = rtc::HV_GET; - request->request().path = GetSessionRequestUrl(); - request->request().addHeader("X-Talk-Google-Relay-Auth", relay_token(), true); - request->request().addHeader("X-Stream-Type", "video_rtp", true); - request->set_host(host); - request->set_port(port); - request->Start(); - request->Release(); - - requests_.push_back(request); -} - -void HttpPortAllocatorSession::OnRequestDone(rtc::SignalThread* data) { - rtc::AsyncHttpRequest* request = - static_cast<rtc::AsyncHttpRequest*>(data); - - // Remove the request from the list of active requests. - std::list<rtc::AsyncHttpRequest*>::iterator it = - std::find(requests_.begin(), requests_.end(), request); - if (it != requests_.end()) { - requests_.erase(it); - } - - if (request->response().scode != 200) { - LOG(LS_WARNING) << "HTTPPortAllocator: request " - << " received error " << request->response().scode; - TryCreateRelaySession(); - return; - } - LOG(LS_INFO) << "HTTPPortAllocator: request succeeded"; - - rtc::MemoryStream* stream = - static_cast<rtc::MemoryStream*>(request->response().document.get()); - stream->Rewind(); - size_t length; - stream->GetSize(&length); - std::string resp = std::string(stream->GetBuffer(), length); - ReceiveSessionResponse(resp); -} - -} // namespace cricket diff --git a/talk/p2p/client/httpportallocator.h b/talk/p2p/client/httpportallocator.h deleted file mode 100644 index cab8e7e72..000000000 --- a/talk/p2p/client/httpportallocator.h +++ /dev/null @@ -1,190 +0,0 @@ -/* - * libjingle - * Copyright 2004--2008, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef WEBRTC_P2P_CLIENT_HTTPPORTALLOCATOR_H_ -#define WEBRTC_P2P_CLIENT_HTTPPORTALLOCATOR_H_ - -#include <list> -#include <string> -#include <vector> - -#include "webrtc/p2p/client/basicportallocator.h" - -class HttpPortAllocatorTest_TestSessionRequestUrl_Test; - -namespace rtc { -class AsyncHttpRequest; -class SignalThread; -} - -namespace cricket { - -class HttpPortAllocatorBase : public BasicPortAllocator { - public: - // The number of HTTP requests we should attempt before giving up. - static const int kNumRetries; - - // Records the URL that we will GET in order to create a session. - static const char kCreateSessionURL[]; - - HttpPortAllocatorBase(rtc::NetworkManager* network_manager, - const std::string& user_agent); - HttpPortAllocatorBase(rtc::NetworkManager* network_manager, - rtc::PacketSocketFactory* socket_factory, - const std::string& user_agent); - virtual ~HttpPortAllocatorBase(); - - // CreateSession is defined in BasicPortAllocator but is - // redefined here as pure virtual. - virtual PortAllocatorSession* CreateSessionInternal( - const std::string& content_name, - int component, - const std::string& ice_ufrag, - const std::string& ice_pwd) = 0; - - void SetStunHosts(const std::vector<rtc::SocketAddress>& hosts) { - if (!hosts.empty()) { - stun_hosts_ = hosts; - } - } - void SetRelayHosts(const std::vector<std::string>& hosts) { - if (!hosts.empty()) { - relay_hosts_ = hosts; - } - } - void SetRelayToken(const std::string& relay) { relay_token_ = relay; } - - const std::vector<rtc::SocketAddress>& stun_hosts() const { - return stun_hosts_; - } - - const std::vector<std::string>& relay_hosts() const { - return relay_hosts_; - } - - const std::string& relay_token() const { - return relay_token_; - } - - const std::string& user_agent() const { - return agent_; - } - - private: - std::vector<rtc::SocketAddress> stun_hosts_; - std::vector<std::string> relay_hosts_; - std::string relay_token_; - std::string agent_; -}; - -class RequestData; - -class HttpPortAllocatorSessionBase : public BasicPortAllocatorSession { - public: - HttpPortAllocatorSessionBase( - HttpPortAllocatorBase* allocator, - const std::string& content_name, - int component, - const std::string& ice_ufrag, - const std::string& ice_pwd, - const std::vector<rtc::SocketAddress>& stun_hosts, - const std::vector<std::string>& relay_hosts, - const std::string& relay, - const std::string& agent); - virtual ~HttpPortAllocatorSessionBase(); - - const std::string& relay_token() const { - return relay_token_; - } - - const std::string& user_agent() const { - return agent_; - } - - virtual void SendSessionRequest(const std::string& host, int port) = 0; - virtual void ReceiveSessionResponse(const std::string& response); - - // Made public for testing. Should be protected. - std::string GetSessionRequestUrl(); - - protected: - virtual void GetPortConfigurations(); - void TryCreateRelaySession(); - virtual HttpPortAllocatorBase* allocator() { - return static_cast<HttpPortAllocatorBase*>( - BasicPortAllocatorSession::allocator()); - } - - private: - std::vector<std::string> relay_hosts_; - std::vector<rtc::SocketAddress> stun_hosts_; - std::string relay_token_; - std::string agent_; - int attempts_; -}; - -class HttpPortAllocator : public HttpPortAllocatorBase { - public: - HttpPortAllocator(rtc::NetworkManager* network_manager, - const std::string& user_agent); - HttpPortAllocator(rtc::NetworkManager* network_manager, - rtc::PacketSocketFactory* socket_factory, - const std::string& user_agent); - virtual ~HttpPortAllocator(); - virtual PortAllocatorSession* CreateSessionInternal( - const std::string& content_name, - int component, - const std::string& ice_ufrag, const std::string& ice_pwd); -}; - -class HttpPortAllocatorSession : public HttpPortAllocatorSessionBase { - public: - HttpPortAllocatorSession( - HttpPortAllocator* allocator, - const std::string& content_name, - int component, - const std::string& ice_ufrag, - const std::string& ice_pwd, - const std::vector<rtc::SocketAddress>& stun_hosts, - const std::vector<std::string>& relay_hosts, - const std::string& relay, - const std::string& agent); - virtual ~HttpPortAllocatorSession(); - - virtual void SendSessionRequest(const std::string& host, int port); - - protected: - // Protected for diagnostics. - virtual void OnRequestDone(rtc::SignalThread* request); - - private: - std::list<rtc::AsyncHttpRequest*> requests_; -}; - -} // namespace cricket - -#endif // WEBRTC_P2P_CLIENT_HTTPPORTALLOCATOR_H_ diff --git a/talk/p2p/client/portallocator_unittest.cc b/talk/p2p/client/portallocator_unittest.cc deleted file mode 100644 index 5b1a86927..000000000 --- a/talk/p2p/client/portallocator_unittest.cc +++ /dev/null @@ -1,1083 +0,0 @@ -/* - * libjingle - * Copyright 2009 Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "webrtc/p2p/base/basicpacketsocketfactory.h" -#include "webrtc/p2p/base/constants.h" -#include "webrtc/p2p/base/p2ptransportchannel.h" -#include "webrtc/p2p/base/portallocatorsessionproxy.h" -#include "webrtc/p2p/base/testrelayserver.h" -#include "webrtc/p2p/base/teststunserver.h" -#include "webrtc/p2p/base/testturnserver.h" -#include "webrtc/p2p/client/basicportallocator.h" -#include "webrtc/p2p/client/httpportallocator.h" -#include "webrtc/base/fakenetwork.h" -#include "webrtc/base/firewallsocketserver.h" -#include "webrtc/base/gunit.h" -#include "webrtc/base/helpers.h" -#include "webrtc/base/logging.h" -#include "webrtc/base/natserver.h" -#include "webrtc/base/natsocketfactory.h" -#include "webrtc/base/network.h" -#include "webrtc/base/physicalsocketserver.h" -#include "webrtc/base/socketaddress.h" -#include "webrtc/base/ssladapter.h" -#include "webrtc/base/thread.h" -#include "webrtc/base/virtualsocketserver.h" - -using cricket::ServerAddresses; -using rtc::SocketAddress; -using rtc::Thread; - -static const SocketAddress kClientAddr("11.11.11.11", 0); -static const SocketAddress kPrivateAddr("192.168.1.11", 0); -static const SocketAddress kClientIPv6Addr( - "2401:fa00:4:1000:be30:5bff:fee5:c3", 0); -static const SocketAddress kClientAddr2("22.22.22.22", 0); -static const SocketAddress kNatAddr("77.77.77.77", rtc::NAT_SERVER_PORT); -static const SocketAddress kRemoteClientAddr("22.22.22.22", 0); -static const SocketAddress kStunAddr("99.99.99.1", cricket::STUN_SERVER_PORT); -static const SocketAddress kRelayUdpIntAddr("99.99.99.2", 5000); -static const SocketAddress kRelayUdpExtAddr("99.99.99.3", 5001); -static const SocketAddress kRelayTcpIntAddr("99.99.99.2", 5002); -static const SocketAddress kRelayTcpExtAddr("99.99.99.3", 5003); -static const SocketAddress kRelaySslTcpIntAddr("99.99.99.2", 5004); -static const SocketAddress kRelaySslTcpExtAddr("99.99.99.3", 5005); -static const SocketAddress kTurnUdpIntAddr("99.99.99.4", 3478); -static const SocketAddress kTurnTcpIntAddr("99.99.99.5", 3478); -static const SocketAddress kTurnUdpExtAddr("99.99.99.6", 0); - -// Minimum and maximum port for port range tests. -static const int kMinPort = 10000; -static const int kMaxPort = 10099; - -// Based on ICE_UFRAG_LENGTH -static const char kIceUfrag0[] = "TESTICEUFRAG0000"; -// Based on ICE_PWD_LENGTH -static const char kIcePwd0[] = "TESTICEPWD00000000000000"; - -static const char kContentName[] = "test content"; - -static const int kDefaultAllocationTimeout = 1000; -static const char kTurnUsername[] = "test"; -static const char kTurnPassword[] = "test"; - -namespace cricket { - -// Helper for dumping candidates -std::ostream& operator<<(std::ostream& os, const cricket::Candidate& c) { - os << c.ToString(); - return os; -} - -} // namespace cricket - -class PortAllocatorTest : public testing::Test, public sigslot::has_slots<> { - public: - PortAllocatorTest() - : pss_(new rtc::PhysicalSocketServer), - vss_(new rtc::VirtualSocketServer(pss_.get())), - fss_(new rtc::FirewallSocketServer(vss_.get())), - ss_scope_(fss_.get()), - nat_factory_(vss_.get(), kNatAddr), - nat_socket_factory_(&nat_factory_), - stun_server_(cricket::TestStunServer::Create(Thread::Current(), - kStunAddr)), - relay_server_(Thread::Current(), kRelayUdpIntAddr, kRelayUdpExtAddr, - kRelayTcpIntAddr, kRelayTcpExtAddr, - kRelaySslTcpIntAddr, kRelaySslTcpExtAddr), - turn_server_(Thread::Current(), kTurnUdpIntAddr, kTurnUdpExtAddr), - candidate_allocation_done_(false) { - cricket::ServerAddresses stun_servers; - stun_servers.insert(kStunAddr); - // Passing the addresses of GTURN servers will enable GTURN in - // Basicportallocator. - allocator_.reset(new cricket::BasicPortAllocator( - &network_manager_, - stun_servers, - kRelayUdpIntAddr, kRelayTcpIntAddr, kRelaySslTcpIntAddr)); - allocator_->set_step_delay(cricket::kMinimumStepDelay); - } - - void AddInterface(const SocketAddress& addr) { - network_manager_.AddInterface(addr); - } - bool SetPortRange(int min_port, int max_port) { - return allocator_->SetPortRange(min_port, max_port); - } - void ResetWithNatServer(const rtc::SocketAddress& stun_server) { - nat_server_.reset(new rtc::NATServer( - rtc::NAT_OPEN_CONE, vss_.get(), kNatAddr, vss_.get(), kNatAddr)); - - ServerAddresses stun_servers; - stun_servers.insert(stun_server); - allocator_.reset(new cricket::BasicPortAllocator( - &network_manager_, &nat_socket_factory_, stun_servers)); - allocator().set_step_delay(cricket::kMinimumStepDelay); - } - - // Create a BasicPortAllocator without GTURN and add the TURN servers. - void ResetWithTurnServers(const rtc::SocketAddress& udp_turn, - const rtc::SocketAddress& tcp_turn) { - allocator_.reset(new cricket::BasicPortAllocator(&network_manager_)); - allocator().set_step_delay(cricket::kMinimumStepDelay); - AddTurnServers(udp_turn, tcp_turn); - } - - void AddTurnServers(const rtc::SocketAddress& udp_turn, - const rtc::SocketAddress& tcp_turn) { - cricket::RelayServerConfig relay_server(cricket::RELAY_TURN); - cricket::RelayCredentials credentials(kTurnUsername, kTurnPassword); - relay_server.credentials = credentials; - - if (!udp_turn.IsNil()) { - relay_server.ports.push_back(cricket::ProtocolAddress( - kTurnUdpIntAddr, cricket::PROTO_UDP, false)); - } - if (!tcp_turn.IsNil()) { - relay_server.ports.push_back(cricket::ProtocolAddress( - kTurnTcpIntAddr, cricket::PROTO_TCP, false)); - } - allocator_->AddRelay(relay_server); - } - - bool CreateSession(int component) { - session_.reset(CreateSession("session", component)); - if (!session_) - return false; - return true; - } - - bool CreateSession(int component, const std::string& content_name) { - session_.reset(CreateSession("session", content_name, component)); - if (!session_) - return false; - return true; - } - - cricket::PortAllocatorSession* CreateSession( - const std::string& sid, int component) { - return CreateSession(sid, kContentName, component); - } - - cricket::PortAllocatorSession* CreateSession( - const std::string& sid, const std::string& content_name, int component) { - return CreateSession(sid, content_name, component, kIceUfrag0, kIcePwd0); - } - - cricket::PortAllocatorSession* CreateSession( - const std::string& sid, const std::string& content_name, int component, - const std::string& ice_ufrag, const std::string& ice_pwd) { - cricket::PortAllocatorSession* session = - allocator_->CreateSession( - sid, content_name, component, ice_ufrag, ice_pwd); - session->SignalPortReady.connect(this, - &PortAllocatorTest::OnPortReady); - session->SignalCandidatesReady.connect(this, - &PortAllocatorTest::OnCandidatesReady); - session->SignalCandidatesAllocationDone.connect(this, - &PortAllocatorTest::OnCandidatesAllocationDone); - return session; - } - - static bool CheckCandidate(const cricket::Candidate& c, - int component, const std::string& type, - const std::string& proto, - const SocketAddress& addr) { - return (c.component() == component && c.type() == type && - c.protocol() == proto && c.address().ipaddr() == addr.ipaddr() && - ((addr.port() == 0 && (c.address().port() != 0)) || - (c.address().port() == addr.port()))); - } - static bool CheckPort(const rtc::SocketAddress& addr, - int min_port, int max_port) { - return (addr.port() >= min_port && addr.port() <= max_port); - } - - void OnCandidatesAllocationDone(cricket::PortAllocatorSession* session) { - // We should only get this callback once, except in the mux test where - // we have multiple port allocation sessions. - if (session == session_.get()) { - ASSERT_FALSE(candidate_allocation_done_); - candidate_allocation_done_ = true; - } - } - - // Check if all ports allocated have send-buffer size |expected|. If - // |expected| == -1, check if GetOptions returns SOCKET_ERROR. - void CheckSendBufferSizesOfAllPorts(int expected) { - std::vector<cricket::PortInterface*>::iterator it; - for (it = ports_.begin(); it < ports_.end(); ++it) { - int send_buffer_size; - if (expected == -1) { - EXPECT_EQ(SOCKET_ERROR, - (*it)->GetOption(rtc::Socket::OPT_SNDBUF, - &send_buffer_size)); - } else { - EXPECT_EQ(0, (*it)->GetOption(rtc::Socket::OPT_SNDBUF, - &send_buffer_size)); - ASSERT_EQ(expected, send_buffer_size); - } - } - } - - protected: - cricket::BasicPortAllocator& allocator() { - return *allocator_; - } - - void OnPortReady(cricket::PortAllocatorSession* ses, - cricket::PortInterface* port) { - LOG(LS_INFO) << "OnPortReady: " << port->ToString(); - ports_.push_back(port); - } - void OnCandidatesReady(cricket::PortAllocatorSession* ses, - const std::vector<cricket::Candidate>& candidates) { - for (size_t i = 0; i < candidates.size(); ++i) { - LOG(LS_INFO) << "OnCandidatesReady: " << candidates[i].ToString(); - candidates_.push_back(candidates[i]); - } - } - - bool HasRelayAddress(const cricket::ProtocolAddress& proto_addr) { - for (size_t i = 0; i < allocator_->relays().size(); ++i) { - cricket::RelayServerConfig server_config = allocator_->relays()[i]; - cricket::PortList::const_iterator relay_port; - for (relay_port = server_config.ports.begin(); - relay_port != server_config.ports.end(); ++relay_port) { - if (proto_addr.address == relay_port->address && - proto_addr.proto == relay_port->proto) - return true; - } - } - return false; - } - - rtc::scoped_ptr<rtc::PhysicalSocketServer> pss_; - rtc::scoped_ptr<rtc::VirtualSocketServer> vss_; - rtc::scoped_ptr<rtc::FirewallSocketServer> fss_; - rtc::SocketServerScope ss_scope_; - rtc::scoped_ptr<rtc::NATServer> nat_server_; - rtc::NATSocketFactory nat_factory_; - rtc::BasicPacketSocketFactory nat_socket_factory_; - rtc::scoped_ptr<cricket::TestStunServer> stun_server_; - cricket::TestRelayServer relay_server_; - cricket::TestTurnServer turn_server_; - rtc::FakeNetworkManager network_manager_; - rtc::scoped_ptr<cricket::BasicPortAllocator> allocator_; - rtc::scoped_ptr<cricket::PortAllocatorSession> session_; - std::vector<cricket::PortInterface*> ports_; - std::vector<cricket::Candidate> candidates_; - bool candidate_allocation_done_; -}; - -// Tests that we can init the port allocator and create a session. -TEST_F(PortAllocatorTest, TestBasic) { - EXPECT_EQ(&network_manager_, allocator().network_manager()); - EXPECT_EQ(kStunAddr, *allocator().stun_servers().begin()); - ASSERT_EQ(1u, allocator().relays().size()); - EXPECT_EQ(cricket::RELAY_GTURN, allocator().relays()[0].type); - // Empty relay credentials are used for GTURN. - EXPECT_TRUE(allocator().relays()[0].credentials.username.empty()); - EXPECT_TRUE(allocator().relays()[0].credentials.password.empty()); - EXPECT_TRUE(HasRelayAddress(cricket::ProtocolAddress( - kRelayUdpIntAddr, cricket::PROTO_UDP))); - EXPECT_TRUE(HasRelayAddress(cricket::ProtocolAddress( - kRelayTcpIntAddr, cricket::PROTO_TCP))); - EXPECT_TRUE(HasRelayAddress(cricket::ProtocolAddress( - kRelaySslTcpIntAddr, cricket::PROTO_SSLTCP))); - EXPECT_TRUE(CreateSession(cricket::ICE_CANDIDATE_COMPONENT_RTP)); -} - -// Tests that we allocator session not trying to allocate ports for every 250ms. -TEST_F(PortAllocatorTest, TestNoNetworkInterface) { - EXPECT_TRUE(CreateSession(cricket::ICE_CANDIDATE_COMPONENT_RTP)); - session_->StartGettingPorts(); - // Waiting for one second to make sure BasicPortAllocatorSession has not - // called OnAllocate multiple times. In old behavior it's called every 250ms. - // When there are no network interfaces, each execution of OnAllocate will - // result in SignalCandidatesAllocationDone signal. - rtc::Thread::Current()->ProcessMessages(1000); - EXPECT_TRUE(candidate_allocation_done_); - EXPECT_EQ(0U, candidates_.size()); -} - -// Tests that we can get all the desired addresses successfully. -TEST_F(PortAllocatorTest, TestGetAllPortsWithMinimumStepDelay) { - AddInterface(kClientAddr); - EXPECT_TRUE(CreateSession(cricket::ICE_CANDIDATE_COMPONENT_RTP)); - session_->StartGettingPorts(); - ASSERT_EQ_WAIT(7U, candidates_.size(), kDefaultAllocationTimeout); - EXPECT_EQ(4U, ports_.size()); - EXPECT_PRED5(CheckCandidate, candidates_[0], - cricket::ICE_CANDIDATE_COMPONENT_RTP, "local", "udp", kClientAddr); - EXPECT_PRED5(CheckCandidate, candidates_[1], - cricket::ICE_CANDIDATE_COMPONENT_RTP, "stun", "udp", kClientAddr); - EXPECT_PRED5(CheckCandidate, candidates_[2], - cricket::ICE_CANDIDATE_COMPONENT_RTP, "relay", "udp", kRelayUdpIntAddr); - EXPECT_PRED5(CheckCandidate, candidates_[3], - cricket::ICE_CANDIDATE_COMPONENT_RTP, "relay", "udp", kRelayUdpExtAddr); - EXPECT_PRED5(CheckCandidate, candidates_[4], - cricket::ICE_CANDIDATE_COMPONENT_RTP, "relay", "tcp", kRelayTcpIntAddr); - EXPECT_PRED5(CheckCandidate, candidates_[5], - cricket::ICE_CANDIDATE_COMPONENT_RTP, "local", "tcp", kClientAddr); - EXPECT_PRED5(CheckCandidate, candidates_[6], - cricket::ICE_CANDIDATE_COMPONENT_RTP, - "relay", "ssltcp", kRelaySslTcpIntAddr); - EXPECT_TRUE(candidate_allocation_done_); -} - -// Verify candidates with default step delay of 1sec. -TEST_F(PortAllocatorTest, TestGetAllPortsWithOneSecondStepDelay) { - AddInterface(kClientAddr); - allocator_->set_step_delay(cricket::kDefaultStepDelay); - EXPECT_TRUE(CreateSession(cricket::ICE_CANDIDATE_COMPONENT_RTP)); - session_->StartGettingPorts(); - ASSERT_EQ_WAIT(2U, candidates_.size(), 1000); - EXPECT_EQ(2U, ports_.size()); - ASSERT_EQ_WAIT(4U, candidates_.size(), 2000); - EXPECT_EQ(3U, ports_.size()); - EXPECT_PRED5(CheckCandidate, candidates_[2], - cricket::ICE_CANDIDATE_COMPONENT_RTP, "relay", "udp", kRelayUdpIntAddr); - EXPECT_PRED5(CheckCandidate, candidates_[3], - cricket::ICE_CANDIDATE_COMPONENT_RTP, "relay", "udp", kRelayUdpExtAddr); - ASSERT_EQ_WAIT(6U, candidates_.size(), 1500); - EXPECT_PRED5(CheckCandidate, candidates_[4], - cricket::ICE_CANDIDATE_COMPONENT_RTP, "relay", "tcp", kRelayTcpIntAddr); - EXPECT_PRED5(CheckCandidate, candidates_[5], - cricket::ICE_CANDIDATE_COMPONENT_RTP, "local", "tcp", kClientAddr); - EXPECT_EQ(4U, ports_.size()); - ASSERT_EQ_WAIT(7U, candidates_.size(), 2000); - EXPECT_PRED5(CheckCandidate, candidates_[6], - cricket::ICE_CANDIDATE_COMPONENT_RTP, - "relay", "ssltcp", kRelaySslTcpIntAddr); - EXPECT_EQ(4U, ports_.size()); - EXPECT_TRUE(candidate_allocation_done_); - // If we Stop gathering now, we shouldn't get a second "done" callback. - session_->StopGettingPorts(); -} - -TEST_F(PortAllocatorTest, TestSetupVideoRtpPortsWithNormalSendBuffers) { - AddInterface(kClientAddr); - EXPECT_TRUE(CreateSession(cricket::ICE_CANDIDATE_COMPONENT_RTP, - cricket::CN_VIDEO)); - session_->StartGettingPorts(); - ASSERT_EQ_WAIT(7U, candidates_.size(), kDefaultAllocationTimeout); - EXPECT_TRUE(candidate_allocation_done_); - // If we Stop gathering now, we shouldn't get a second "done" callback. - session_->StopGettingPorts(); - - // All ports should have unset send-buffer sizes. - CheckSendBufferSizesOfAllPorts(-1); -} - -// Tests that we can get callback after StopGetAllPorts. -TEST_F(PortAllocatorTest, TestStopGetAllPorts) { - AddInterface(kClientAddr); - EXPECT_TRUE(CreateSession(cricket::ICE_CANDIDATE_COMPONENT_RTP)); - session_->StartGettingPorts(); - ASSERT_EQ_WAIT(2U, candidates_.size(), kDefaultAllocationTimeout); - EXPECT_EQ(2U, ports_.size()); - session_->StopGettingPorts(); - EXPECT_TRUE_WAIT(candidate_allocation_done_, kDefaultAllocationTimeout); -} - -// Test that we restrict client ports appropriately when a port range is set. -// We check the candidates for udp/stun/tcp ports, and the from address -// for relay ports. -TEST_F(PortAllocatorTest, TestGetAllPortsPortRange) { - AddInterface(kClientAddr); - // Check that an invalid port range fails. - EXPECT_FALSE(SetPortRange(kMaxPort, kMinPort)); - // Check that a null port range succeeds. - EXPECT_TRUE(SetPortRange(0, 0)); - // Check that a valid port range succeeds. - EXPECT_TRUE(SetPortRange(kMinPort, kMaxPort)); - EXPECT_TRUE(CreateSession(cricket::ICE_CANDIDATE_COMPONENT_RTP)); - session_->StartGettingPorts(); - ASSERT_EQ_WAIT(7U, candidates_.size(), kDefaultAllocationTimeout); - EXPECT_EQ(4U, ports_.size()); - // Check the port number for the UDP port object. - EXPECT_PRED3(CheckPort, candidates_[0].address(), kMinPort, kMaxPort); - // Check the port number for the STUN port object. - EXPECT_PRED3(CheckPort, candidates_[1].address(), kMinPort, kMaxPort); - // Check the port number used to connect to the relay server. - EXPECT_PRED3(CheckPort, relay_server_.GetConnection(0).source(), - kMinPort, kMaxPort); - // Check the port number for the TCP port object. - EXPECT_PRED3(CheckPort, candidates_[5].address(), kMinPort, kMaxPort); - EXPECT_TRUE(candidate_allocation_done_); -} - -// Test that we don't crash or malfunction if we have no network adapters. -TEST_F(PortAllocatorTest, TestGetAllPortsNoAdapters) { - EXPECT_TRUE(CreateSession(cricket::ICE_CANDIDATE_COMPONENT_RTP)); - session_->StartGettingPorts(); - rtc::Thread::Current()->ProcessMessages(100); - // Without network adapter, we should not get any candidate. - EXPECT_EQ(0U, candidates_.size()); - EXPECT_TRUE(candidate_allocation_done_); -} - -// Test that we can get OnCandidatesAllocationDone callback when all the ports -// are disabled. -TEST_F(PortAllocatorTest, TestDisableAllPorts) { - AddInterface(kClientAddr); - EXPECT_TRUE(CreateSession(cricket::ICE_CANDIDATE_COMPONENT_RTP)); - session_->set_flags(cricket::PORTALLOCATOR_DISABLE_UDP | - cricket::PORTALLOCATOR_DISABLE_STUN | - cricket::PORTALLOCATOR_DISABLE_RELAY | - cricket::PORTALLOCATOR_DISABLE_TCP); - session_->StartGettingPorts(); - rtc::Thread::Current()->ProcessMessages(100); - EXPECT_EQ(0U, candidates_.size()); - EXPECT_TRUE(candidate_allocation_done_); -} - -// Test that we don't crash or malfunction if we can't create UDP sockets. -TEST_F(PortAllocatorTest, TestGetAllPortsNoUdpSockets) { - AddInterface(kClientAddr); - fss_->set_udp_sockets_enabled(false); - EXPECT_TRUE(CreateSession(1)); - session_->StartGettingPorts(); - ASSERT_EQ_WAIT(5U, candidates_.size(), kDefaultAllocationTimeout); - EXPECT_EQ(2U, ports_.size()); - EXPECT_PRED5(CheckCandidate, candidates_[0], - cricket::ICE_CANDIDATE_COMPONENT_RTP, "relay", "udp", kRelayUdpIntAddr); - EXPECT_PRED5(CheckCandidate, candidates_[1], - cricket::ICE_CANDIDATE_COMPONENT_RTP, "relay", "udp", kRelayUdpExtAddr); - EXPECT_PRED5(CheckCandidate, candidates_[2], - cricket::ICE_CANDIDATE_COMPONENT_RTP, "relay", "tcp", kRelayTcpIntAddr); - EXPECT_PRED5(CheckCandidate, candidates_[3], - cricket::ICE_CANDIDATE_COMPONENT_RTP, "local", "tcp", kClientAddr); - EXPECT_PRED5(CheckCandidate, candidates_[4], - cricket::ICE_CANDIDATE_COMPONENT_RTP, - "relay", "ssltcp", kRelaySslTcpIntAddr); - EXPECT_TRUE(candidate_allocation_done_); -} - -// Test that we don't crash or malfunction if we can't create UDP sockets or -// listen on TCP sockets. We still give out a local TCP address, since -// apparently this is needed for the remote side to accept our connection. -TEST_F(PortAllocatorTest, TestGetAllPortsNoUdpSocketsNoTcpListen) { - AddInterface(kClientAddr); - fss_->set_udp_sockets_enabled(false); - fss_->set_tcp_listen_enabled(false); - EXPECT_TRUE(CreateSession(1)); - session_->StartGettingPorts(); - ASSERT_EQ_WAIT(5U, candidates_.size(), kDefaultAllocationTimeout); - EXPECT_EQ(2U, ports_.size()); - EXPECT_PRED5(CheckCandidate, candidates_[0], - 1, "relay", "udp", kRelayUdpIntAddr); - EXPECT_PRED5(CheckCandidate, candidates_[1], - 1, "relay", "udp", kRelayUdpExtAddr); - EXPECT_PRED5(CheckCandidate, candidates_[2], - 1, "relay", "tcp", kRelayTcpIntAddr); - EXPECT_PRED5(CheckCandidate, candidates_[3], - 1, "local", "tcp", kClientAddr); - EXPECT_PRED5(CheckCandidate, candidates_[4], - 1, "relay", "ssltcp", kRelaySslTcpIntAddr); - EXPECT_TRUE(candidate_allocation_done_); -} - -// Test that we don't crash or malfunction if we can't create any sockets. -// TODO: Find a way to exit early here. -TEST_F(PortAllocatorTest, TestGetAllPortsNoSockets) { - AddInterface(kClientAddr); - fss_->set_tcp_sockets_enabled(false); - fss_->set_udp_sockets_enabled(false); - EXPECT_TRUE(CreateSession(cricket::ICE_CANDIDATE_COMPONENT_RTP)); - session_->StartGettingPorts(); - WAIT(candidates_.size() > 0, 2000); - // TODO - Check candidate_allocation_done signal. - // In case of Relay, ports creation will succeed but sockets will fail. - // There is no error reporting from RelayEntry to handle this failure. -} - -// Testing STUN timeout. -TEST_F(PortAllocatorTest, TestGetAllPortsNoUdpAllowed) { - fss_->AddRule(false, rtc::FP_UDP, rtc::FD_ANY, kClientAddr); - AddInterface(kClientAddr); - EXPECT_TRUE(CreateSession(cricket::ICE_CANDIDATE_COMPONENT_RTP)); - session_->StartGettingPorts(); - EXPECT_EQ_WAIT(2U, candidates_.size(), kDefaultAllocationTimeout); - EXPECT_EQ(2U, ports_.size()); - EXPECT_PRED5(CheckCandidate, candidates_[0], - cricket::ICE_CANDIDATE_COMPONENT_RTP, "local", "udp", kClientAddr); - EXPECT_PRED5(CheckCandidate, candidates_[1], - cricket::ICE_CANDIDATE_COMPONENT_RTP, "local", "tcp", kClientAddr); - // RelayPort connection timeout is 3sec. TCP connection with RelayServer - // will be tried after 3 seconds. - EXPECT_EQ_WAIT(6U, candidates_.size(), 4000); - EXPECT_EQ(3U, ports_.size()); - EXPECT_PRED5(CheckCandidate, candidates_[2], - cricket::ICE_CANDIDATE_COMPONENT_RTP, "relay", "udp", kRelayUdpIntAddr); - EXPECT_PRED5(CheckCandidate, candidates_[3], - cricket::ICE_CANDIDATE_COMPONENT_RTP, "relay", "tcp", kRelayTcpIntAddr); - EXPECT_PRED5(CheckCandidate, candidates_[4], - cricket::ICE_CANDIDATE_COMPONENT_RTP, "relay", "ssltcp", - kRelaySslTcpIntAddr); - EXPECT_PRED5(CheckCandidate, candidates_[5], - cricket::ICE_CANDIDATE_COMPONENT_RTP, "relay", "udp", kRelayUdpExtAddr); - // Stun Timeout is 9sec. - EXPECT_TRUE_WAIT(candidate_allocation_done_, 9000); -} - -TEST_F(PortAllocatorTest, TestCandidatePriorityOfMultipleInterfaces) { - AddInterface(kClientAddr); - AddInterface(kClientAddr2); - // Allocating only host UDP ports. This is done purely for testing - // convenience. - allocator().set_flags(cricket::PORTALLOCATOR_DISABLE_TCP | - cricket::PORTALLOCATOR_DISABLE_STUN | - cricket::PORTALLOCATOR_DISABLE_RELAY); - EXPECT_TRUE(CreateSession(cricket::ICE_CANDIDATE_COMPONENT_RTP)); - session_->StartGettingPorts(); - EXPECT_TRUE_WAIT(candidate_allocation_done_, kDefaultAllocationTimeout); - ASSERT_EQ(2U, candidates_.size()); - EXPECT_EQ(2U, ports_.size()); - // Candidates priorities should be different. - EXPECT_NE(candidates_[0].priority(), candidates_[1].priority()); -} - -// Test to verify ICE restart process. -TEST_F(PortAllocatorTest, TestGetAllPortsRestarts) { - AddInterface(kClientAddr); - EXPECT_TRUE(CreateSession(cricket::ICE_CANDIDATE_COMPONENT_RTP)); - session_->StartGettingPorts(); - EXPECT_EQ_WAIT(7U, candidates_.size(), kDefaultAllocationTimeout); - EXPECT_EQ(4U, ports_.size()); - EXPECT_TRUE(candidate_allocation_done_); - // TODO - Extend this to verify ICE restart. -} - -// Test ICE candidate filter mechanism with options Relay/Host/Reflexive. -// This test also verifies that when the allocator is only allowed to use -// relay (i.e. IceTransportsType is relay), the raddr is an empty -// address with the correct family. This is to prevent any local -// reflective address leakage in the sdp line. -TEST_F(PortAllocatorTest, TestCandidateFilterWithRelayOnly) { - AddInterface(kClientAddr); - // GTURN is not configured here. - ResetWithTurnServers(kTurnUdpIntAddr, rtc::SocketAddress()); - allocator().set_candidate_filter(cricket::CF_RELAY); - EXPECT_TRUE(CreateSession(cricket::ICE_CANDIDATE_COMPONENT_RTP)); - session_->StartGettingPorts(); - EXPECT_TRUE_WAIT(candidate_allocation_done_, kDefaultAllocationTimeout); - EXPECT_PRED5(CheckCandidate, - candidates_[0], - cricket::ICE_CANDIDATE_COMPONENT_RTP, - "relay", - "udp", - rtc::SocketAddress(kTurnUdpExtAddr.ipaddr(), 0)); - - EXPECT_EQ(1U, candidates_.size()); - EXPECT_EQ(1U, ports_.size()); // Only Relay port will be in ready state. - for (size_t i = 0; i < candidates_.size(); ++i) { - EXPECT_EQ(std::string(cricket::RELAY_PORT_TYPE), candidates_[i].type()); - EXPECT_EQ( - candidates_[0].related_address(), - rtc::EmptySocketAddressWithFamily(candidates_[0].address().family())); - } -} - -TEST_F(PortAllocatorTest, TestCandidateFilterWithHostOnly) { - AddInterface(kClientAddr); - allocator().set_flags(cricket::PORTALLOCATOR_ENABLE_SHARED_UFRAG | - cricket::PORTALLOCATOR_ENABLE_SHARED_SOCKET); - allocator().set_candidate_filter(cricket::CF_HOST); - EXPECT_TRUE(CreateSession(cricket::ICE_CANDIDATE_COMPONENT_RTP)); - session_->StartGettingPorts(); - EXPECT_TRUE_WAIT(candidate_allocation_done_, kDefaultAllocationTimeout); - EXPECT_EQ(2U, candidates_.size()); // Host UDP/TCP candidates only. - EXPECT_EQ(2U, ports_.size()); // UDP/TCP ports only. - for (size_t i = 0; i < candidates_.size(); ++i) { - EXPECT_EQ(std::string(cricket::LOCAL_PORT_TYPE), candidates_[i].type()); - } -} - -// Host is behind the NAT. -TEST_F(PortAllocatorTest, TestCandidateFilterWithReflexiveOnly) { - AddInterface(kPrivateAddr); - ResetWithNatServer(kStunAddr); - - allocator().set_flags(cricket::PORTALLOCATOR_ENABLE_SHARED_UFRAG | - cricket::PORTALLOCATOR_ENABLE_SHARED_SOCKET); - allocator().set_candidate_filter(cricket::CF_REFLEXIVE); - EXPECT_TRUE(CreateSession(cricket::ICE_CANDIDATE_COMPONENT_RTP)); - session_->StartGettingPorts(); - EXPECT_TRUE_WAIT(candidate_allocation_done_, kDefaultAllocationTimeout); - // Host is behind NAT, no private address will be exposed. Hence only UDP - // port with STUN candidate will be sent outside. - EXPECT_EQ(1U, candidates_.size()); // Only STUN candidate. - EXPECT_EQ(1U, ports_.size()); // Only UDP port will be in ready state. - for (size_t i = 0; i < candidates_.size(); ++i) { - EXPECT_EQ(std::string(cricket::STUN_PORT_TYPE), candidates_[i].type()); - EXPECT_EQ( - candidates_[0].related_address(), - rtc::EmptySocketAddressWithFamily(candidates_[0].address().family())); - } -} - -// Host is not behind the NAT. -TEST_F(PortAllocatorTest, TestCandidateFilterWithReflexiveOnlyAndNoNAT) { - AddInterface(kClientAddr); - allocator().set_flags(cricket::PORTALLOCATOR_ENABLE_SHARED_UFRAG | - cricket::PORTALLOCATOR_ENABLE_SHARED_SOCKET); - allocator().set_candidate_filter(cricket::CF_REFLEXIVE); - EXPECT_TRUE(CreateSession(cricket::ICE_CANDIDATE_COMPONENT_RTP)); - session_->StartGettingPorts(); - EXPECT_TRUE_WAIT(candidate_allocation_done_, kDefaultAllocationTimeout); - // Host has a public address, both UDP and TCP candidates will be exposed. - EXPECT_EQ(2U, candidates_.size()); // Local UDP + TCP candidate. - EXPECT_EQ(2U, ports_.size()); // UDP and TCP ports will be in ready state. - for (size_t i = 0; i < candidates_.size(); ++i) { - EXPECT_EQ(std::string(cricket::LOCAL_PORT_TYPE), candidates_[i].type()); - } -} - -TEST_F(PortAllocatorTest, TestBasicMuxFeatures) { - AddInterface(kClientAddr); - allocator().set_flags(cricket::PORTALLOCATOR_ENABLE_BUNDLE); - // Session ID - session1. - rtc::scoped_ptr<cricket::PortAllocatorSession> session1( - CreateSession("session1", cricket::ICE_CANDIDATE_COMPONENT_RTP)); - rtc::scoped_ptr<cricket::PortAllocatorSession> session2( - CreateSession("session1", cricket::ICE_CANDIDATE_COMPONENT_RTCP)); - session1->StartGettingPorts(); - session2->StartGettingPorts(); - // Each session should receive two proxy ports of local and stun. - ASSERT_EQ_WAIT(14U, candidates_.size(), kDefaultAllocationTimeout); - EXPECT_EQ(8U, ports_.size()); - - rtc::scoped_ptr<cricket::PortAllocatorSession> session3( - CreateSession("session1", cricket::ICE_CANDIDATE_COMPONENT_RTP)); - session3->StartGettingPorts(); - // Already allocated candidates and ports will be sent to the newly - // allocated proxy session. - ASSERT_EQ_WAIT(21U, candidates_.size(), kDefaultAllocationTimeout); - EXPECT_EQ(12U, ports_.size()); -} - -// This test verifies by changing ice_ufrag and/or ice_pwd -// will result in different set of candidates when BUNDLE is enabled. -// If BUNDLE is disabled, CreateSession will always allocate new -// set of candidates. -TEST_F(PortAllocatorTest, TestBundleIceRestart) { - AddInterface(kClientAddr); - allocator().set_flags(cricket::PORTALLOCATOR_ENABLE_BUNDLE); - // Session ID - session1. - rtc::scoped_ptr<cricket::PortAllocatorSession> session1( - CreateSession("session1", kContentName, - cricket::ICE_CANDIDATE_COMPONENT_RTP, - kIceUfrag0, kIcePwd0)); - session1->StartGettingPorts(); - ASSERT_EQ_WAIT(7U, candidates_.size(), kDefaultAllocationTimeout); - EXPECT_EQ(4U, ports_.size()); - - // Allocate a different session with sid |session1| and different ice_ufrag. - rtc::scoped_ptr<cricket::PortAllocatorSession> session2( - CreateSession("session1", kContentName, - cricket::ICE_CANDIDATE_COMPONENT_RTP, - "TestIceUfrag", kIcePwd0)); - session2->StartGettingPorts(); - ASSERT_EQ_WAIT(14U, candidates_.size(), kDefaultAllocationTimeout); - EXPECT_EQ(8U, ports_.size()); - // Verifying the candidate address different from previously allocated - // address. - // Skipping verification of component id and candidate type. - EXPECT_NE(candidates_[0].address(), candidates_[7].address()); - EXPECT_NE(candidates_[1].address(), candidates_[8].address()); - - // Allocating a different session with sid |session1| and - // different ice_pwd. - rtc::scoped_ptr<cricket::PortAllocatorSession> session3( - CreateSession("session1", kContentName, - cricket::ICE_CANDIDATE_COMPONENT_RTP, - kIceUfrag0, "TestIcePwd")); - session3->StartGettingPorts(); - ASSERT_EQ_WAIT(21U, candidates_.size(), kDefaultAllocationTimeout); - EXPECT_EQ(12U, ports_.size()); - // Verifying the candidate address different from previously - // allocated address. - EXPECT_NE(candidates_[7].address(), candidates_[14].address()); - EXPECT_NE(candidates_[8].address(), candidates_[15].address()); - - // Allocating a session with by changing both ice_ufrag and ice_pwd. - rtc::scoped_ptr<cricket::PortAllocatorSession> session4( - CreateSession("session1", kContentName, - cricket::ICE_CANDIDATE_COMPONENT_RTP, - "TestIceUfrag", "TestIcePwd")); - session4->StartGettingPorts(); - ASSERT_EQ_WAIT(28U, candidates_.size(), kDefaultAllocationTimeout); - EXPECT_EQ(16U, ports_.size()); - // Verifying the candidate address different from previously - // allocated address. - EXPECT_NE(candidates_[14].address(), candidates_[21].address()); - EXPECT_NE(candidates_[15].address(), candidates_[22].address()); -} - -// Test that when the PORTALLOCATOR_ENABLE_SHARED_UFRAG is enabled we got same -// ufrag and pwd for the collected candidates. -TEST_F(PortAllocatorTest, TestEnableSharedUfrag) { - allocator().set_flags(allocator().flags() | - cricket::PORTALLOCATOR_ENABLE_SHARED_UFRAG); - AddInterface(kClientAddr); - EXPECT_TRUE(CreateSession(cricket::ICE_CANDIDATE_COMPONENT_RTP)); - session_->StartGettingPorts(); - ASSERT_EQ_WAIT(7U, candidates_.size(), kDefaultAllocationTimeout); - EXPECT_PRED5(CheckCandidate, candidates_[0], - cricket::ICE_CANDIDATE_COMPONENT_RTP, "local", "udp", kClientAddr); - EXPECT_PRED5(CheckCandidate, candidates_[1], - cricket::ICE_CANDIDATE_COMPONENT_RTP, "stun", "udp", kClientAddr); - EXPECT_PRED5(CheckCandidate, candidates_[5], - cricket::ICE_CANDIDATE_COMPONENT_RTP, "local", "tcp", kClientAddr); - EXPECT_EQ(4U, ports_.size()); - EXPECT_EQ(kIceUfrag0, candidates_[0].username()); - EXPECT_EQ(kIceUfrag0, candidates_[1].username()); - EXPECT_EQ(kIceUfrag0, candidates_[2].username()); - EXPECT_EQ(kIcePwd0, candidates_[0].password()); - EXPECT_EQ(kIcePwd0, candidates_[1].password()); - EXPECT_TRUE(candidate_allocation_done_); -} - -// Test that when the PORTALLOCATOR_ENABLE_SHARED_UFRAG isn't enabled we got -// different ufrag and pwd for the collected candidates. -TEST_F(PortAllocatorTest, TestDisableSharedUfrag) { - allocator().set_flags(allocator().flags() & - ~cricket::PORTALLOCATOR_ENABLE_SHARED_UFRAG); - AddInterface(kClientAddr); - EXPECT_TRUE(CreateSession(cricket::ICE_CANDIDATE_COMPONENT_RTP)); - session_->StartGettingPorts(); - ASSERT_EQ_WAIT(7U, candidates_.size(), kDefaultAllocationTimeout); - EXPECT_PRED5(CheckCandidate, candidates_[0], - cricket::ICE_CANDIDATE_COMPONENT_RTP, "local", "udp", kClientAddr); - EXPECT_PRED5(CheckCandidate, candidates_[1], - cricket::ICE_CANDIDATE_COMPONENT_RTP, "stun", "udp", kClientAddr); - EXPECT_EQ(4U, ports_.size()); - // Port should generate random ufrag and pwd. - EXPECT_NE(kIceUfrag0, candidates_[0].username()); - EXPECT_NE(kIceUfrag0, candidates_[1].username()); - EXPECT_NE(candidates_[0].username(), candidates_[1].username()); - EXPECT_NE(kIcePwd0, candidates_[0].password()); - EXPECT_NE(kIcePwd0, candidates_[1].password()); - EXPECT_NE(candidates_[0].password(), candidates_[1].password()); - EXPECT_TRUE(candidate_allocation_done_); -} - -// Test that when PORTALLOCATOR_ENABLE_SHARED_SOCKET is enabled only one port -// is allocated for udp and stun. Also verify there is only one candidate -// (local) if stun candidate is same as local candidate, which will be the case -// in a public network like the below test. -TEST_F(PortAllocatorTest, TestSharedSocketWithoutNat) { - AddInterface(kClientAddr); - allocator_->set_flags(allocator().flags() | - cricket::PORTALLOCATOR_ENABLE_SHARED_UFRAG | - cricket::PORTALLOCATOR_ENABLE_SHARED_SOCKET); - EXPECT_TRUE(CreateSession(cricket::ICE_CANDIDATE_COMPONENT_RTP)); - session_->StartGettingPorts(); - ASSERT_EQ_WAIT(6U, candidates_.size(), kDefaultAllocationTimeout); - EXPECT_EQ(3U, ports_.size()); - EXPECT_PRED5(CheckCandidate, candidates_[0], - cricket::ICE_CANDIDATE_COMPONENT_RTP, "local", "udp", kClientAddr); - EXPECT_TRUE_WAIT(candidate_allocation_done_, kDefaultAllocationTimeout); -} - -// Test that when PORTALLOCATOR_ENABLE_SHARED_SOCKET is enabled only one port -// is allocated for udp and stun. In this test we should expect both stun and -// local candidates as client behind a nat. -TEST_F(PortAllocatorTest, TestSharedSocketWithNat) { - AddInterface(kClientAddr); - ResetWithNatServer(kStunAddr); - - allocator_->set_flags(allocator().flags() | - cricket::PORTALLOCATOR_ENABLE_SHARED_UFRAG | - cricket::PORTALLOCATOR_ENABLE_SHARED_SOCKET); - EXPECT_TRUE(CreateSession(cricket::ICE_CANDIDATE_COMPONENT_RTP)); - session_->StartGettingPorts(); - ASSERT_EQ_WAIT(3U, candidates_.size(), kDefaultAllocationTimeout); - ASSERT_EQ(2U, ports_.size()); - EXPECT_PRED5(CheckCandidate, candidates_[0], - cricket::ICE_CANDIDATE_COMPONENT_RTP, "local", "udp", kClientAddr); - EXPECT_PRED5(CheckCandidate, candidates_[1], - cricket::ICE_CANDIDATE_COMPONENT_RTP, "stun", "udp", - rtc::SocketAddress(kNatAddr.ipaddr(), 0)); - EXPECT_TRUE_WAIT(candidate_allocation_done_, kDefaultAllocationTimeout); - EXPECT_EQ(3U, candidates_.size()); -} - -// Test TURN port in shared socket mode with UDP and TCP TURN server adderesses. -TEST_F(PortAllocatorTest, TestSharedSocketWithoutNatUsingTurn) { - turn_server_.AddInternalSocket(kTurnTcpIntAddr, cricket::PROTO_TCP); - AddInterface(kClientAddr); - allocator_.reset(new cricket::BasicPortAllocator(&network_manager_)); - - AddTurnServers(kTurnUdpIntAddr, kTurnTcpIntAddr); - - allocator_->set_step_delay(cricket::kMinimumStepDelay); - allocator_->set_flags(allocator().flags() | - cricket::PORTALLOCATOR_ENABLE_SHARED_UFRAG | - cricket::PORTALLOCATOR_ENABLE_SHARED_SOCKET | - cricket::PORTALLOCATOR_DISABLE_TCP); - - EXPECT_TRUE(CreateSession(cricket::ICE_CANDIDATE_COMPONENT_RTP)); - session_->StartGettingPorts(); - - ASSERT_EQ_WAIT(3U, candidates_.size(), kDefaultAllocationTimeout); - ASSERT_EQ(3U, ports_.size()); - EXPECT_PRED5(CheckCandidate, candidates_[0], - cricket::ICE_CANDIDATE_COMPONENT_RTP, "local", "udp", kClientAddr); - EXPECT_PRED5(CheckCandidate, candidates_[1], - cricket::ICE_CANDIDATE_COMPONENT_RTP, "relay", "udp", - rtc::SocketAddress(kTurnUdpExtAddr.ipaddr(), 0)); - EXPECT_PRED5(CheckCandidate, candidates_[2], - cricket::ICE_CANDIDATE_COMPONENT_RTP, "relay", "udp", - rtc::SocketAddress(kTurnUdpExtAddr.ipaddr(), 0)); - EXPECT_TRUE_WAIT(candidate_allocation_done_, kDefaultAllocationTimeout); - EXPECT_EQ(3U, candidates_.size()); -} - -// Testing DNS resolve for the TURN server, this will test AllocationSequence -// handling the unresolved address signal from TurnPort. -TEST_F(PortAllocatorTest, TestSharedSocketWithServerAddressResolve) { - turn_server_.AddInternalSocket(rtc::SocketAddress("127.0.0.1", 3478), - cricket::PROTO_UDP); - AddInterface(kClientAddr); - allocator_.reset(new cricket::BasicPortAllocator(&network_manager_)); - cricket::RelayServerConfig relay_server(cricket::RELAY_TURN); - cricket::RelayCredentials credentials(kTurnUsername, kTurnPassword); - relay_server.credentials = credentials; - relay_server.ports.push_back(cricket::ProtocolAddress( - rtc::SocketAddress("localhost", 3478), - cricket::PROTO_UDP, false)); - allocator_->AddRelay(relay_server); - - allocator_->set_step_delay(cricket::kMinimumStepDelay); - allocator_->set_flags(allocator().flags() | - cricket::PORTALLOCATOR_ENABLE_SHARED_UFRAG | - cricket::PORTALLOCATOR_ENABLE_SHARED_SOCKET | - cricket::PORTALLOCATOR_DISABLE_TCP); - - EXPECT_TRUE(CreateSession(cricket::ICE_CANDIDATE_COMPONENT_RTP)); - session_->StartGettingPorts(); - - EXPECT_EQ_WAIT(2U, ports_.size(), kDefaultAllocationTimeout); -} - -// Test that when PORTALLOCATOR_ENABLE_SHARED_SOCKET is enabled only one port -// is allocated for udp/stun/turn. In this test we should expect all local, -// stun and turn candidates. -TEST_F(PortAllocatorTest, TestSharedSocketWithNatUsingTurn) { - AddInterface(kClientAddr); - ResetWithNatServer(kStunAddr); - - AddTurnServers(kTurnUdpIntAddr, rtc::SocketAddress()); - - allocator_->set_flags(allocator().flags() | - cricket::PORTALLOCATOR_ENABLE_SHARED_UFRAG | - cricket::PORTALLOCATOR_ENABLE_SHARED_SOCKET | - cricket::PORTALLOCATOR_DISABLE_TCP); - - EXPECT_TRUE(CreateSession(cricket::ICE_CANDIDATE_COMPONENT_RTP)); - session_->StartGettingPorts(); - - ASSERT_EQ_WAIT(3U, candidates_.size(), kDefaultAllocationTimeout); - ASSERT_EQ(2U, ports_.size()); - EXPECT_PRED5(CheckCandidate, candidates_[0], - cricket::ICE_CANDIDATE_COMPONENT_RTP, "local", "udp", kClientAddr); - EXPECT_PRED5(CheckCandidate, candidates_[1], - cricket::ICE_CANDIDATE_COMPONENT_RTP, "stun", "udp", - rtc::SocketAddress(kNatAddr.ipaddr(), 0)); - EXPECT_PRED5(CheckCandidate, candidates_[2], - cricket::ICE_CANDIDATE_COMPONENT_RTP, "relay", "udp", - rtc::SocketAddress(kTurnUdpExtAddr.ipaddr(), 0)); - EXPECT_TRUE_WAIT(candidate_allocation_done_, kDefaultAllocationTimeout); - EXPECT_EQ(3U, candidates_.size()); - // Local port will be created first and then TURN port. - EXPECT_EQ(2U, ports_[0]->Candidates().size()); - EXPECT_EQ(1U, ports_[1]->Candidates().size()); -} - -// Test that when PORTALLOCATOR_ENABLE_SHARED_SOCKET is enabled and the TURN -// server is also used as the STUN server, we should get 'local', 'stun', and -// 'relay' candidates. -TEST_F(PortAllocatorTest, TestSharedSocketWithNatUsingTurnAsStun) { - AddInterface(kClientAddr); - ResetWithNatServer(kTurnUdpIntAddr); - AddTurnServers(kTurnUdpIntAddr, rtc::SocketAddress()); - - // Must set the step delay to 0 to make sure the relay allocation phase is - // started before the STUN candidates are obtained, so that the STUN binding - // response is processed when both StunPort and TurnPort exist to reproduce - // webrtc issue 3537. - allocator_->set_step_delay(0); - allocator_->set_flags(allocator().flags() | - cricket::PORTALLOCATOR_ENABLE_SHARED_UFRAG | - cricket::PORTALLOCATOR_ENABLE_SHARED_SOCKET | - cricket::PORTALLOCATOR_DISABLE_TCP); - - EXPECT_TRUE(CreateSession(cricket::ICE_CANDIDATE_COMPONENT_RTP)); - session_->StartGettingPorts(); - - ASSERT_EQ_WAIT(3U, candidates_.size(), kDefaultAllocationTimeout); - EXPECT_PRED5(CheckCandidate, candidates_[0], - cricket::ICE_CANDIDATE_COMPONENT_RTP, "local", "udp", kClientAddr); - EXPECT_PRED5(CheckCandidate, candidates_[1], - cricket::ICE_CANDIDATE_COMPONENT_RTP, "stun", "udp", - rtc::SocketAddress(kNatAddr.ipaddr(), 0)); - EXPECT_PRED5(CheckCandidate, candidates_[2], - cricket::ICE_CANDIDATE_COMPONENT_RTP, "relay", "udp", - rtc::SocketAddress(kTurnUdpExtAddr.ipaddr(), 0)); - EXPECT_EQ(candidates_[2].related_address(), candidates_[1].address()); - - EXPECT_TRUE_WAIT(candidate_allocation_done_, kDefaultAllocationTimeout); - EXPECT_EQ(3U, candidates_.size()); - // Local port will be created first and then TURN port. - EXPECT_EQ(2U, ports_[0]->Candidates().size()); - EXPECT_EQ(1U, ports_[1]->Candidates().size()); -} - -// This test verifies when PORTALLOCATOR_ENABLE_SHARED_SOCKET flag is enabled -// and fail to generate STUN candidate, local UDP candidate is generated -// properly. -TEST_F(PortAllocatorTest, TestSharedSocketNoUdpAllowed) { - allocator().set_flags(allocator().flags() | - cricket::PORTALLOCATOR_DISABLE_RELAY | - cricket::PORTALLOCATOR_DISABLE_TCP | - cricket::PORTALLOCATOR_ENABLE_SHARED_UFRAG | - cricket::PORTALLOCATOR_ENABLE_SHARED_SOCKET); - fss_->AddRule(false, rtc::FP_UDP, rtc::FD_ANY, kClientAddr); - AddInterface(kClientAddr); - EXPECT_TRUE(CreateSession(cricket::ICE_CANDIDATE_COMPONENT_RTP)); - session_->StartGettingPorts(); - ASSERT_EQ_WAIT(1U, ports_.size(), kDefaultAllocationTimeout); - EXPECT_EQ(1U, candidates_.size()); - EXPECT_PRED5(CheckCandidate, candidates_[0], - cricket::ICE_CANDIDATE_COMPONENT_RTP, "local", "udp", kClientAddr); - // STUN timeout is 9sec. We need to wait to get candidate done signal. - EXPECT_TRUE_WAIT(candidate_allocation_done_, 10000); - EXPECT_EQ(1U, candidates_.size()); -} - -// This test verifies allocator can use IPv6 addresses along with IPv4. -TEST_F(PortAllocatorTest, TestEnableIPv6Addresses) { - allocator().set_flags(allocator().flags() | - cricket::PORTALLOCATOR_DISABLE_RELAY | - cricket::PORTALLOCATOR_ENABLE_IPV6 | - cricket::PORTALLOCATOR_ENABLE_SHARED_UFRAG | - cricket::PORTALLOCATOR_ENABLE_SHARED_SOCKET); - AddInterface(kClientIPv6Addr); - AddInterface(kClientAddr); - allocator_->set_step_delay(cricket::kMinimumStepDelay); - EXPECT_TRUE(CreateSession(cricket::ICE_CANDIDATE_COMPONENT_RTP)); - session_->StartGettingPorts(); - ASSERT_EQ_WAIT(4U, ports_.size(), kDefaultAllocationTimeout); - EXPECT_EQ(4U, candidates_.size()); - EXPECT_TRUE_WAIT(candidate_allocation_done_, kDefaultAllocationTimeout); - EXPECT_PRED5(CheckCandidate, candidates_[0], - cricket::ICE_CANDIDATE_COMPONENT_RTP, "local", "udp", - kClientIPv6Addr); - EXPECT_PRED5(CheckCandidate, candidates_[1], - cricket::ICE_CANDIDATE_COMPONENT_RTP, "local", "udp", - kClientAddr); - EXPECT_PRED5(CheckCandidate, candidates_[2], - cricket::ICE_CANDIDATE_COMPONENT_RTP, "local", "tcp", - kClientIPv6Addr); - EXPECT_PRED5(CheckCandidate, candidates_[3], - cricket::ICE_CANDIDATE_COMPONENT_RTP, "local", "tcp", - kClientAddr); - EXPECT_EQ(4U, candidates_.size()); -} - -// Test that the httpportallocator correctly maintains its lists of stun and -// relay servers, by never allowing an empty list. -TEST(HttpPortAllocatorTest, TestHttpPortAllocatorHostLists) { - rtc::FakeNetworkManager network_manager; - cricket::HttpPortAllocator alloc(&network_manager, "unit test agent"); - EXPECT_EQ(1U, alloc.relay_hosts().size()); - EXPECT_EQ(1U, alloc.stun_hosts().size()); - - std::vector<std::string> relay_servers; - std::vector<rtc::SocketAddress> stun_servers; - - alloc.SetRelayHosts(relay_servers); - alloc.SetStunHosts(stun_servers); - EXPECT_EQ(1U, alloc.relay_hosts().size()); - EXPECT_EQ(1U, alloc.stun_hosts().size()); - - relay_servers.push_back("1.unittest.corp.google.com"); - relay_servers.push_back("2.unittest.corp.google.com"); - stun_servers.push_back( - rtc::SocketAddress("1.unittest.corp.google.com", 0)); - stun_servers.push_back( - rtc::SocketAddress("2.unittest.corp.google.com", 0)); - - alloc.SetRelayHosts(relay_servers); - alloc.SetStunHosts(stun_servers); - EXPECT_EQ(2U, alloc.relay_hosts().size()); - EXPECT_EQ(2U, alloc.stun_hosts().size()); -} - -// Test that the HttpPortAllocator uses correct URL to create sessions. -TEST(HttpPortAllocatorTest, TestSessionRequestUrl) { - rtc::FakeNetworkManager network_manager; - cricket::HttpPortAllocator alloc(&network_manager, "unit test agent"); - - // Disable PORTALLOCATOR_ENABLE_SHARED_UFRAG. - alloc.set_flags(alloc.flags() & ~cricket::PORTALLOCATOR_ENABLE_SHARED_UFRAG); - rtc::scoped_ptr<cricket::HttpPortAllocatorSessionBase> session( - static_cast<cricket::HttpPortAllocatorSession*>( - alloc.CreateSessionInternal( - "test content", 0, kIceUfrag0, kIcePwd0))); - std::string url = session->GetSessionRequestUrl(); - LOG(LS_INFO) << "url: " << url; - EXPECT_EQ(std::string(cricket::HttpPortAllocator::kCreateSessionURL), url); - - // Enable PORTALLOCATOR_ENABLE_SHARED_UFRAG. - alloc.set_flags(alloc.flags() | cricket::PORTALLOCATOR_ENABLE_SHARED_UFRAG); - session.reset(static_cast<cricket::HttpPortAllocatorSession*>( - alloc.CreateSessionInternal("test content", 0, kIceUfrag0, kIcePwd0))); - url = session->GetSessionRequestUrl(); - LOG(LS_INFO) << "url: " << url; - std::vector<std::string> parts; - rtc::split(url, '?', &parts); - ASSERT_EQ(2U, parts.size()); - - std::vector<std::string> args_parts; - rtc::split(parts[1], '&', &args_parts); - - std::map<std::string, std::string> args; - for (std::vector<std::string>::iterator it = args_parts.begin(); - it != args_parts.end(); ++it) { - std::vector<std::string> parts; - rtc::split(*it, '=', &parts); - ASSERT_EQ(2U, parts.size()); - args[rtc::s_url_decode(parts[0])] = rtc::s_url_decode(parts[1]); - } - - EXPECT_EQ(kIceUfrag0, args["username"]); - EXPECT_EQ(kIcePwd0, args["password"]); -} diff --git a/talk/p2p/client/sessionmanagertask.h b/talk/p2p/client/sessionmanagertask.h deleted file mode 100644 index 753d93889..000000000 --- a/talk/p2p/client/sessionmanagertask.h +++ /dev/null @@ -1,93 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef WEBRTC_P2P_CLIENT_SESSIONMANAGERTASK_H_ -#define WEBRTC_P2P_CLIENT_SESSIONMANAGERTASK_H_ - -#include "webrtc/p2p/base/sessionmanager.h" -#include "webrtc/p2p/client/sessionsendtask.h" -#include "webrtc/libjingle/xmpp/xmppengine.h" -#include "webrtc/libjingle/xmpp/xmpptask.h" - -namespace cricket { - -// This class handles sending and receiving XMPP messages on behalf of the -// SessionManager. The sending part is handed over to SessionSendTask. - -class SessionManagerTask : public buzz::XmppTask { - public: - SessionManagerTask(buzz::XmppTaskParentInterface* parent, - SessionManager* session_manager) - : buzz::XmppTask(parent, buzz::XmppEngine::HL_SINGLE), - session_manager_(session_manager) { - } - - ~SessionManagerTask() { - } - - // Turns on simple support for sending messages, using SessionSendTask. - void EnableOutgoingMessages() { - session_manager_->SignalOutgoingMessage.connect( - this, &SessionManagerTask::OnOutgoingMessage); - session_manager_->SignalRequestSignaling.connect( - session_manager_, &SessionManager::OnSignalingReady); - } - - virtual int ProcessStart() { - const buzz::XmlElement *stanza = NextStanza(); - if (stanza == NULL) - return STATE_BLOCKED; - session_manager_->OnIncomingMessage(stanza); - return STATE_START; - } - - protected: - virtual bool HandleStanza(const buzz::XmlElement *stanza) { - if (!session_manager_->IsSessionMessage(stanza)) - return false; - // Responses are handled by the SessionSendTask that sent the request. - //if (stanza->Attr(buzz::QN_TYPE) != buzz::STR_SET) - // return false; - QueueStanza(stanza); - return true; - } - - private: - void OnOutgoingMessage(SessionManager* manager, - const buzz::XmlElement* stanza) { - cricket::SessionSendTask* sender = - new cricket::SessionSendTask(parent_, session_manager_); - sender->Send(stanza); - sender->Start(); - } - - SessionManager* session_manager_; -}; - -} // namespace cricket - -#endif // WEBRTC_P2P_CLIENT_SESSIONMANAGERTASK_H_ diff --git a/talk/p2p/client/sessionsendtask.h b/talk/p2p/client/sessionsendtask.h deleted file mode 100644 index 7dafc1e1f..000000000 --- a/talk/p2p/client/sessionsendtask.h +++ /dev/null @@ -1,145 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef WEBRTC_P2P_CLIENT_SESSIONSENDTASK_H_ -#define WEBRTC_P2P_CLIENT_SESSIONSENDTASK_H_ - -#include "webrtc/p2p/base/sessionmanager.h" -#include "webrtc/libjingle/xmpp/constants.h" -#include "webrtc/libjingle/xmpp/xmppclient.h" -#include "webrtc/libjingle/xmpp/xmppengine.h" -#include "webrtc/libjingle/xmpp/xmpptask.h" -#include "webrtc/base/common.h" - -namespace cricket { - -// The job of this task is to send an IQ stanza out (after stamping it with -// an ID attribute) and then wait for a response. If not response happens -// within 5 seconds, it will signal failure on a SessionManager. If an error -// happens it will also signal failure. If, however, the send succeeds this -// task will quietly go away. - -class SessionSendTask : public buzz::XmppTask { - public: - SessionSendTask(buzz::XmppTaskParentInterface* parent, - SessionManager* session_manager) - : buzz::XmppTask(parent, buzz::XmppEngine::HL_SINGLE), - session_manager_(session_manager) { - set_timeout_seconds(15); - session_manager_->SignalDestroyed.connect( - this, &SessionSendTask::OnSessionManagerDestroyed); - } - - virtual ~SessionSendTask() { - SignalDone(this); - } - - void Send(const buzz::XmlElement* stanza) { - ASSERT(stanza_.get() == NULL); - - // This should be an IQ of type set, result, or error. In the first case, - // we supply an ID. In the others, it should be present. - ASSERT(stanza->Name() == buzz::QN_IQ); - ASSERT(stanza->HasAttr(buzz::QN_TYPE)); - if (stanza->Attr(buzz::QN_TYPE) == "set") { - ASSERT(!stanza->HasAttr(buzz::QN_ID)); - } else { - ASSERT((stanza->Attr(buzz::QN_TYPE) == "result") || - (stanza->Attr(buzz::QN_TYPE) == "error")); - ASSERT(stanza->HasAttr(buzz::QN_ID)); - } - - stanza_.reset(new buzz::XmlElement(*stanza)); - if (stanza_->HasAttr(buzz::QN_ID)) { - set_task_id(stanza_->Attr(buzz::QN_ID)); - } else { - stanza_->SetAttr(buzz::QN_ID, task_id()); - } - } - - void OnSessionManagerDestroyed() { - // If the session manager doesn't exist anymore, we should still try to - // send the message, but avoid calling back into the SessionManager. - session_manager_ = NULL; - } - - sigslot::signal1<SessionSendTask *> SignalDone; - - protected: - virtual int OnTimeout() { - if (session_manager_ != NULL) { - session_manager_->OnFailedSend(stanza_.get(), NULL); - } - - return XmppTask::OnTimeout(); - } - - virtual int ProcessStart() { - SendStanza(stanza_.get()); - if (stanza_->Attr(buzz::QN_TYPE) == buzz::STR_SET) { - return STATE_RESPONSE; - } else { - return STATE_DONE; - } - } - - virtual int ProcessResponse() { - const buzz::XmlElement* next = NextStanza(); - if (next == NULL) - return STATE_BLOCKED; - - if (session_manager_ != NULL) { - if (next->Attr(buzz::QN_TYPE) == buzz::STR_RESULT) { - session_manager_->OnIncomingResponse(stanza_.get(), next); - } else { - session_manager_->OnFailedSend(stanza_.get(), next); - } - } - - return STATE_DONE; - } - - virtual bool HandleStanza(const buzz::XmlElement *stanza) { - if (!MatchResponseIq(stanza, - buzz::Jid(stanza_->Attr(buzz::QN_TO)), task_id())) - return false; - if (stanza->Attr(buzz::QN_TYPE) == buzz::STR_RESULT || - stanza->Attr(buzz::QN_TYPE) == buzz::STR_ERROR) { - QueueStanza(stanza); - return true; - } - return false; - } - - private: - SessionManager *session_manager_; - rtc::scoped_ptr<buzz::XmlElement> stanza_; -}; - -} - -#endif // WEBRTC_P2P_CLIENT_SESSIONSENDTASK_H_ diff --git a/talk/p2p/client/socketmonitor.cc b/talk/p2p/client/socketmonitor.cc deleted file mode 100644 index a3a33e311..000000000 --- a/talk/p2p/client/socketmonitor.cc +++ /dev/null @@ -1,114 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "webrtc/p2p/client/socketmonitor.h" - -#include "webrtc/base/common.h" - -namespace cricket { - -enum { - MSG_MONITOR_POLL, - MSG_MONITOR_START, - MSG_MONITOR_STOP, - MSG_MONITOR_SIGNAL -}; - -SocketMonitor::SocketMonitor(TransportChannel* channel, - rtc::Thread* worker_thread, - rtc::Thread* monitor_thread) { - channel_ = channel; - channel_thread_ = worker_thread; - monitoring_thread_ = monitor_thread; - monitoring_ = false; -} - -SocketMonitor::~SocketMonitor() { - channel_thread_->Clear(this); - monitoring_thread_->Clear(this); -} - -void SocketMonitor::Start(int milliseconds) { - rate_ = milliseconds; - if (rate_ < 250) - rate_ = 250; - channel_thread_->Post(this, MSG_MONITOR_START); -} - -void SocketMonitor::Stop() { - channel_thread_->Post(this, MSG_MONITOR_STOP); -} - -void SocketMonitor::OnMessage(rtc::Message *message) { - rtc::CritScope cs(&crit_); - switch (message->message_id) { - case MSG_MONITOR_START: - ASSERT(rtc::Thread::Current() == channel_thread_); - if (!monitoring_) { - monitoring_ = true; - PollSocket(true); - } - break; - - case MSG_MONITOR_STOP: - ASSERT(rtc::Thread::Current() == channel_thread_); - if (monitoring_) { - monitoring_ = false; - channel_thread_->Clear(this); - } - break; - - case MSG_MONITOR_POLL: - ASSERT(rtc::Thread::Current() == channel_thread_); - PollSocket(true); - break; - - case MSG_MONITOR_SIGNAL: { - ASSERT(rtc::Thread::Current() == monitoring_thread_); - std::vector<ConnectionInfo> infos = connection_infos_; - crit_.Leave(); - SignalUpdate(this, infos); - crit_.Enter(); - break; - } - } -} - -void SocketMonitor::PollSocket(bool poll) { - ASSERT(rtc::Thread::Current() == channel_thread_); - rtc::CritScope cs(&crit_); - - // Gather connection infos - channel_->GetStats(&connection_infos_); - - // Signal the monitoring thread, start another poll timer - monitoring_thread_->Post(this, MSG_MONITOR_SIGNAL); - if (poll) - channel_thread_->PostDelayed(rate_, this, MSG_MONITOR_POLL); -} - -} // namespace cricket diff --git a/talk/p2p/client/socketmonitor.h b/talk/p2p/client/socketmonitor.h deleted file mode 100644 index 77241fed0..000000000 --- a/talk/p2p/client/socketmonitor.h +++ /dev/null @@ -1,71 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef WEBRTC_P2P_CLIENT_SOCKETMONITOR_H_ -#define WEBRTC_P2P_CLIENT_SOCKETMONITOR_H_ - -#include <vector> - -#include "webrtc/p2p/base/transportchannel.h" -#include "webrtc/base/criticalsection.h" -#include "webrtc/base/sigslot.h" -#include "webrtc/base/thread.h" - -namespace cricket { - -class SocketMonitor : public rtc::MessageHandler, - public sigslot::has_slots<> { - public: - SocketMonitor(TransportChannel* channel, - rtc::Thread* worker_thread, - rtc::Thread* monitor_thread); - ~SocketMonitor(); - - void Start(int cms); - void Stop(); - - rtc::Thread* monitor_thread() { return monitoring_thread_; } - - sigslot::signal2<SocketMonitor*, - const std::vector<ConnectionInfo>&> SignalUpdate; - - protected: - void OnMessage(rtc::Message* message); - void PollSocket(bool poll); - - std::vector<ConnectionInfo> connection_infos_; - TransportChannel* channel_; - rtc::Thread* channel_thread_; - rtc::Thread* monitoring_thread_; - rtc::CriticalSection crit_; - uint32 rate_; - bool monitoring_; -}; - -} // namespace cricket - -#endif // WEBRTC_P2P_CLIENT_SOCKETMONITOR_H_ diff --git a/talk/xmllite/qname.cc b/talk/xmllite/qname.cc deleted file mode 100755 index 0dadb7909..000000000 --- a/talk/xmllite/qname.cc +++ /dev/null @@ -1,95 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "talk/xmllite/qname.h" - -namespace buzz { - -QName::QName() { -} - -QName::QName(const QName& qname) - : namespace_(qname.namespace_), - local_part_(qname.local_part_) { -} - -QName::QName(const StaticQName& const_value) - : namespace_(const_value.ns), - local_part_(const_value.local) { -} - -QName::QName(const std::string& ns, const std::string& local) - : namespace_(ns), - local_part_(local) { -} - -QName::QName(const std::string& merged_or_local) { - size_t i = merged_or_local.rfind(':'); - if (i == std::string::npos) { - local_part_ = merged_or_local; - } else { - namespace_ = merged_or_local.substr(0, i); - local_part_ = merged_or_local.substr(i + 1); - } -} - -QName::~QName() { -} - -std::string QName::Merged() const { - if (namespace_[0] == '\0') - return local_part_; - - std::string result; - result.reserve(namespace_.length() + 1 + local_part_.length()); - result += namespace_; - result += ':'; - result += local_part_; - return result; -} - -bool QName::IsEmpty() const { - return namespace_.empty() && local_part_.empty(); -} - -int QName::Compare(const StaticQName& other) const { - int result = local_part_.compare(other.local); - if (result != 0) - return result; - - return namespace_.compare(other.ns); -} - -int QName::Compare(const QName& other) const { - int result = local_part_.compare(other.local_part_); - if (result != 0) - return result; - - return namespace_.compare(other.namespace_); -} - -} // namespace buzz diff --git a/talk/xmllite/qname.h b/talk/xmllite/qname.h deleted file mode 100755 index 92e54d030..000000000 --- a/talk/xmllite/qname.h +++ /dev/null @@ -1,100 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef TALK_XMLLITE_QNAME_H_ -#define TALK_XMLLITE_QNAME_H_ - -#include <string> - -namespace buzz { - -class QName; - -// StaticQName is used to represend constant quailified names. They -// can be initialized statically and don't need intializers code, e.g. -// const StaticQName QN_FOO = { "foo_namespace", "foo" }; -// -// Beside this use case, QName should be used everywhere -// else. StaticQName instances are implicitly converted to QName -// objects. -struct StaticQName { - const char* const ns; - const char* const local; - - bool operator==(const QName& other) const; - bool operator!=(const QName& other) const; -}; - -class QName { - public: - QName(); - QName(const QName& qname); - QName(const StaticQName& const_value); - QName(const std::string& ns, const std::string& local); - explicit QName(const std::string& merged_or_local); - ~QName(); - - const std::string& Namespace() const { return namespace_; } - const std::string& LocalPart() const { return local_part_; } - std::string Merged() const; - bool IsEmpty() const; - - int Compare(const StaticQName& other) const; - int Compare(const QName& other) const; - - bool operator==(const StaticQName& other) const { - return Compare(other) == 0; - } - bool operator==(const QName& other) const { - return Compare(other) == 0; - } - bool operator!=(const StaticQName& other) const { - return Compare(other) != 0; - } - bool operator!=(const QName& other) const { - return Compare(other) != 0; - } - bool operator<(const QName& other) const { - return Compare(other) < 0; - } - - private: - std::string namespace_; - std::string local_part_; -}; - -inline bool StaticQName::operator==(const QName& other) const { - return other.Compare(*this) == 0; -} - -inline bool StaticQName::operator!=(const QName& other) const { - return other.Compare(*this) != 0; -} - -} // namespace buzz - -#endif // TALK_XMLLITE_QNAME_H_ diff --git a/talk/xmllite/qname_unittest.cc b/talk/xmllite/qname_unittest.cc deleted file mode 100755 index 72c171362..000000000 --- a/talk/xmllite/qname_unittest.cc +++ /dev/null @@ -1,131 +0,0 @@ -/* - * libjingle - * Copyright 2004, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <string> -#include "talk/xmllite/qname.h" -#include "webrtc/base/gunit.h" - -using buzz::StaticQName; -using buzz::QName; - -TEST(QNameTest, TestTrivial) { - QName name("test"); - EXPECT_EQ(name.LocalPart(), "test"); - EXPECT_EQ(name.Namespace(), ""); -} - -TEST(QNameTest, TestSplit) { - QName name("a:test"); - EXPECT_EQ(name.LocalPart(), "test"); - EXPECT_EQ(name.Namespace(), "a"); - QName name2("a-very:long:namespace:test-this"); - EXPECT_EQ(name2.LocalPart(), "test-this"); - EXPECT_EQ(name2.Namespace(), "a-very:long:namespace"); -} - -TEST(QNameTest, TestMerge) { - QName name("a", "test"); - EXPECT_EQ(name.LocalPart(), "test"); - EXPECT_EQ(name.Namespace(), "a"); - EXPECT_EQ(name.Merged(), "a:test"); - QName name2("a-very:long:namespace", "test-this"); - EXPECT_EQ(name2.LocalPart(), "test-this"); - EXPECT_EQ(name2.Namespace(), "a-very:long:namespace"); - EXPECT_EQ(name2.Merged(), "a-very:long:namespace:test-this"); -} - -TEST(QNameTest, TestAssignment) { - QName name("a", "test"); - // copy constructor - QName namecopy(name); - EXPECT_EQ(namecopy.LocalPart(), "test"); - EXPECT_EQ(namecopy.Namespace(), "a"); - QName nameassigned(""); - nameassigned = name; - EXPECT_EQ(nameassigned.LocalPart(), "test"); - EXPECT_EQ(nameassigned.Namespace(), "a"); -} - -TEST(QNameTest, TestConstAssignment) { - StaticQName name = { "a", "test" }; - QName namecopy(name); - EXPECT_EQ(namecopy.LocalPart(), "test"); - EXPECT_EQ(namecopy.Namespace(), "a"); - QName nameassigned(""); - nameassigned = name; - EXPECT_EQ(nameassigned.LocalPart(), "test"); - EXPECT_EQ(nameassigned.Namespace(), "a"); -} - -TEST(QNameTest, TestEquality) { - QName name("a-very:long:namespace:test-this"); - QName name2("a-very:long:namespace", "test-this"); - QName name3("a-very:long:namespaxe", "test-this"); - EXPECT_TRUE(name == name2); - EXPECT_FALSE(name == name3); -} - -TEST(QNameTest, TestCompare) { - QName name("a"); - QName name2("nsa", "a"); - QName name3("nsa", "b"); - QName name4("nsb", "b"); - - EXPECT_TRUE(name < name2); - EXPECT_FALSE(name2 < name); - - EXPECT_FALSE(name2 < name2); - - EXPECT_TRUE(name2 < name3); - EXPECT_FALSE(name3 < name2); - - EXPECT_TRUE(name3 < name4); - EXPECT_FALSE(name4 < name3); -} - -TEST(QNameTest, TestStaticQName) { - const StaticQName const_name1 = { "namespace", "local-name1" }; - const StaticQName const_name2 = { "namespace", "local-name2" }; - const QName name("namespace", "local-name1"); - const QName name1 = const_name1; - const QName name2 = const_name2; - - EXPECT_TRUE(name == const_name1); - EXPECT_TRUE(const_name1 == name); - EXPECT_FALSE(name != const_name1); - EXPECT_FALSE(const_name1 != name); - - EXPECT_TRUE(name == name1); - EXPECT_TRUE(name1 == name); - EXPECT_FALSE(name != name1); - EXPECT_FALSE(name1 != name); - - EXPECT_FALSE(name == name2); - EXPECT_FALSE(name2 == name); - EXPECT_TRUE(name != name2); - EXPECT_TRUE(name2 != name); -} diff --git a/talk/xmllite/xmlbuilder.cc b/talk/xmllite/xmlbuilder.cc deleted file mode 100755 index a091ed944..000000000 --- a/talk/xmllite/xmlbuilder.cc +++ /dev/null @@ -1,147 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "talk/xmllite/xmlbuilder.h" - -#include <set> -#include <vector> -#include "talk/xmllite/xmlconstants.h" -#include "talk/xmllite/xmlelement.h" -#include "webrtc/base/common.h" - -namespace buzz { - -XmlBuilder::XmlBuilder() : - pelCurrent_(NULL), - pelRoot_(), - pvParents_(new std::vector<XmlElement *>()) { -} - -void -XmlBuilder::Reset() { - pelRoot_.reset(); - pelCurrent_ = NULL; - pvParents_->clear(); -} - -XmlElement * -XmlBuilder::BuildElement(XmlParseContext * pctx, - const char * name, const char ** atts) { - QName tagName(pctx->ResolveQName(name, false)); - if (tagName.IsEmpty()) - return NULL; - - XmlElement * pelNew = new XmlElement(tagName); - - if (!*atts) - return pelNew; - - std::set<QName> seenNonlocalAtts; - - while (*atts) { - QName attName(pctx->ResolveQName(*atts, true)); - if (attName.IsEmpty()) { - delete pelNew; - return NULL; - } - - // verify that namespaced names are unique - if (!attName.Namespace().empty()) { - if (seenNonlocalAtts.count(attName)) { - delete pelNew; - return NULL; - } - seenNonlocalAtts.insert(attName); - } - - pelNew->AddAttr(attName, std::string(*(atts + 1))); - atts += 2; - } - - return pelNew; -} - -void -XmlBuilder::StartElement(XmlParseContext * pctx, - const char * name, const char ** atts) { - XmlElement * pelNew = BuildElement(pctx, name, atts); - if (pelNew == NULL) { - pctx->RaiseError(XML_ERROR_SYNTAX); - return; - } - - if (!pelCurrent_) { - pelCurrent_ = pelNew; - pelRoot_.reset(pelNew); - pvParents_->push_back(NULL); - } else { - pelCurrent_->AddElement(pelNew); - pvParents_->push_back(pelCurrent_); - pelCurrent_ = pelNew; - } -} - -void -XmlBuilder::EndElement(XmlParseContext * pctx, const char * name) { - RTC_UNUSED(pctx); - RTC_UNUSED(name); - pelCurrent_ = pvParents_->back(); - pvParents_->pop_back(); -} - -void -XmlBuilder::CharacterData(XmlParseContext * pctx, - const char * text, int len) { - RTC_UNUSED(pctx); - if (pelCurrent_) { - pelCurrent_->AddParsedText(text, len); - } -} - -void -XmlBuilder::Error(XmlParseContext * pctx, XML_Error err) { - RTC_UNUSED(pctx); - RTC_UNUSED(err); - pelRoot_.reset(NULL); - pelCurrent_ = NULL; - pvParents_->clear(); -} - -XmlElement * -XmlBuilder::CreateElement() { - return pelRoot_.release(); -} - -XmlElement * -XmlBuilder::BuiltElement() { - return pelRoot_.get(); -} - -XmlBuilder::~XmlBuilder() { -} - -} // namespace buzz diff --git a/talk/xmllite/xmlbuilder.h b/talk/xmllite/xmlbuilder.h deleted file mode 100755 index 38fc009fb..000000000 --- a/talk/xmllite/xmlbuilder.h +++ /dev/null @@ -1,78 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef _xmlbuilder_h_ -#define _xmlbuilder_h_ - -#include <string> -#include <vector> -#include "talk/xmllite/xmlparser.h" -#include "webrtc/base/scoped_ptr.h" - -#ifdef EXPAT_RELATIVE_PATH -#include "expat.h" -#else -#include "third_party/expat/v2_0_1/Source/lib/expat.h" -#endif // EXPAT_RELATIVE_PATH - -namespace buzz { - -class XmlElement; -class XmlParseContext; - - -class XmlBuilder : public XmlParseHandler { -public: - XmlBuilder(); - - static XmlElement * BuildElement(XmlParseContext * pctx, - const char * name, const char ** atts); - virtual void StartElement(XmlParseContext * pctx, - const char * name, const char ** atts); - virtual void EndElement(XmlParseContext * pctx, const char * name); - virtual void CharacterData(XmlParseContext * pctx, - const char * text, int len); - virtual void Error(XmlParseContext * pctx, XML_Error); - virtual ~XmlBuilder(); - - void Reset(); - - // Take ownership of the built element; second call returns NULL - XmlElement * CreateElement(); - - // Peek at the built element without taking ownership - XmlElement * BuiltElement(); - -private: - XmlElement * pelCurrent_; - rtc::scoped_ptr<XmlElement> pelRoot_; - rtc::scoped_ptr<std::vector<XmlElement*> > pvParents_; -}; - -} - -#endif diff --git a/talk/xmllite/xmlbuilder_unittest.cc b/talk/xmllite/xmlbuilder_unittest.cc deleted file mode 100755 index 56304cf49..000000000 --- a/talk/xmllite/xmlbuilder_unittest.cc +++ /dev/null @@ -1,194 +0,0 @@ -/* - * libjingle - * Copyright 2004, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <iostream> -#include <sstream> -#include <string> -#include "talk/xmllite/xmlbuilder.h" -#include "talk/xmllite/xmlelement.h" -#include "talk/xmllite/xmlparser.h" -#include "webrtc/base/common.h" -#include "webrtc/base/gunit.h" - -using buzz::XmlBuilder; -using buzz::XmlElement; -using buzz::XmlParser; - -TEST(XmlBuilderTest, TestTrivial) { - XmlBuilder builder; - XmlParser::ParseXml(&builder, "<testing/>"); - EXPECT_EQ("<testing/>", builder.BuiltElement()->Str()); -} - -TEST(XmlBuilderTest, TestAttributes1) { - XmlBuilder builder; - XmlParser::ParseXml(&builder, "<testing a='b'/>"); - EXPECT_EQ("<testing a=\"b\"/>", builder.BuiltElement()->Str()); -} - -TEST(XmlBuilderTest, TestAttributes2) { - XmlBuilder builder; - XmlParser::ParseXml(&builder, "<testing e='' long='some text'/>"); - EXPECT_EQ("<testing e=\"\" long=\"some text\"/>", - builder.BuiltElement()->Str()); -} - -TEST(XmlBuilderTest, TestNesting1) { - XmlBuilder builder; - XmlParser::ParseXml(&builder, - "<top><first/><second><third></third></second></top>"); - EXPECT_EQ("<top><first/><second><third/></second></top>", - builder.BuiltElement()->Str()); -} - -TEST(XmlBuilderTest, TestNesting2) { - XmlBuilder builder; - XmlParser::ParseXml(&builder, - "<top><fifth><deeper><and><deeper/></and><sibling><leaf/>" - "</sibling></deeper></fifth><first/><second><third></third>" - "</second></top>"); - EXPECT_EQ("<top><fifth><deeper><and><deeper/></and><sibling><leaf/>" - "</sibling></deeper></fifth><first/><second><third/>" - "</second></top>", builder.BuiltElement()->Str()); -} - -TEST(XmlBuilderTest, TestQuoting1) { - XmlBuilder builder; - XmlParser::ParseXml(&builder, "<testing a='>'/>"); - EXPECT_EQ("<testing a=\">\"/>", builder.BuiltElement()->Str()); -} - -TEST(XmlBuilderTest, TestQuoting2) { - XmlBuilder builder; - XmlParser::ParseXml(&builder, "<testing a='<>&"'/>"); - EXPECT_EQ("<testing a=\"<>&"\"/>", - builder.BuiltElement()->Str()); -} - -TEST(XmlBuilderTest, TestQuoting3) { - XmlBuilder builder; - XmlParser::ParseXml(&builder, "<testing a='so "important"'/>"); - EXPECT_EQ("<testing a=\"so "important"\"/>", - builder.BuiltElement()->Str()); -} - -TEST(XmlBuilderTest, TestQuoting4) { - XmlBuilder builder; - XmlParser::ParseXml(&builder, "<testing a='"important", yes'/>"); - EXPECT_EQ("<testing a=\""important", yes\"/>", - builder.BuiltElement()->Str()); -} - -TEST(XmlBuilderTest, TestQuoting5) { - XmlBuilder builder; - XmlParser::ParseXml(&builder, - "<testing a='<what is "important">'/>"); - EXPECT_EQ("<testing a=\"<what is "important">\"/>", - builder.BuiltElement()->Str()); -} - -TEST(XmlBuilderTest, TestText1) { - XmlBuilder builder; - XmlParser::ParseXml(&builder, "<testing>></testing>"); - EXPECT_EQ("<testing>></testing>", builder.BuiltElement()->Str()); -} - -TEST(XmlBuilderTest, TestText2) { - XmlBuilder builder; - XmlParser::ParseXml(&builder, "<testing><>&"</testing>"); - EXPECT_EQ("<testing><>&\"</testing>", - builder.BuiltElement()->Str()); -} - -TEST(XmlBuilderTest, TestText3) { - XmlBuilder builder; - XmlParser::ParseXml(&builder, "<testing>so <important></testing>"); - EXPECT_EQ("<testing>so <important></testing>", - builder.BuiltElement()->Str()); -} - -TEST(XmlBuilderTest, TestText4) { - XmlBuilder builder; - XmlParser::ParseXml(&builder, "<testing><important>, yes</testing>"); - EXPECT_EQ("<testing><important>, yes</testing>", - builder.BuiltElement()->Str()); -} - -TEST(XmlBuilderTest, TestText5) { - XmlBuilder builder; - XmlParser::ParseXml(&builder, - "<testing>importance &<important>&</testing>"); - EXPECT_EQ("<testing>importance &<important>&</testing>", - builder.BuiltElement()->Str()); -} - -TEST(XmlBuilderTest, TestNamespace1) { - XmlBuilder builder; - XmlParser::ParseXml(&builder, "<testing xmlns='foo'/>"); - EXPECT_EQ("<testing xmlns=\"foo\"/>", builder.BuiltElement()->Str()); -} - -TEST(XmlBuilderTest, TestNamespace2) { - XmlBuilder builder; - XmlParser::ParseXml(&builder, "<testing xmlns:a='foo' a:b='c'/>"); - EXPECT_EQ("<testing xmlns:a=\"foo\" a:b=\"c\"/>", - builder.BuiltElement()->Str()); -} - -TEST(XmlBuilderTest, TestNamespace3) { - XmlBuilder builder; - XmlParser::ParseXml(&builder, "<testing xmlns:a=''/>"); - EXPECT_TRUE(NULL == builder.BuiltElement()); -} - -TEST(XmlBuilderTest, TestNamespace4) { - XmlBuilder builder; - XmlParser::ParseXml(&builder, "<testing a:b='c'/>"); - EXPECT_TRUE(NULL == builder.BuiltElement()); -} - -TEST(XmlBuilderTest, TestAttrCollision1) { - XmlBuilder builder; - XmlParser::ParseXml(&builder, "<testing a='first' a='second'/>"); - EXPECT_TRUE(NULL == builder.BuiltElement()); -} - -TEST(XmlBuilderTest, TestAttrCollision2) { - XmlBuilder builder; - XmlParser::ParseXml(&builder, - "<testing xmlns:a='foo' xmlns:b='foo' a:x='c' b:x='d'/>"); - EXPECT_TRUE(NULL == builder.BuiltElement()); -} - -TEST(XmlBuilderTest, TestAttrCollision3) { - XmlBuilder builder; - XmlParser::ParseXml(&builder, - "<testing xmlns:a='foo'><nested xmlns:b='foo' a:x='c' b:x='d'/>" - "</testing>"); - EXPECT_TRUE(NULL == builder.BuiltElement()); -} - diff --git a/talk/xmllite/xmlconstants.cc b/talk/xmllite/xmlconstants.cc deleted file mode 100755 index f94d77910..000000000 --- a/talk/xmllite/xmlconstants.cc +++ /dev/null @@ -1,42 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "talk/xmllite/xmlconstants.h" - -namespace buzz { - -const char STR_EMPTY[] = ""; -const char NS_XML[] = "http://www.w3.org/XML/1998/namespace"; -const char NS_XMLNS[] = "http://www.w3.org/2000/xmlns/"; -const char STR_XMLNS[] = "xmlns"; -const char STR_XML[] = "xml"; -const char STR_VERSION[] = "version"; -const char STR_ENCODING[] = "encoding"; - -const StaticQName QN_XMLNS = { STR_EMPTY, STR_XMLNS }; - -} // namespace buzz diff --git a/talk/xmllite/xmlconstants.h b/talk/xmllite/xmlconstants.h deleted file mode 100755 index 3e5da9816..000000000 --- a/talk/xmllite/xmlconstants.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef TALK_XMLLITE_XMLCONSTANTS_H_ -#define TALK_XMLLITE_XMLCONSTANTS_H_ - -#include "talk/xmllite/qname.h" - -namespace buzz { - -extern const char STR_EMPTY[]; -extern const char NS_XML[]; -extern const char NS_XMLNS[]; -extern const char STR_XMLNS[]; -extern const char STR_XML[]; -extern const char STR_VERSION[]; -extern const char STR_ENCODING[]; - -extern const StaticQName QN_XMLNS; - -} // namespace buzz - -#endif // TALK_XMLLITE_XMLCONSTANTS_H_ diff --git a/talk/xmllite/xmlelement.cc b/talk/xmllite/xmlelement.cc deleted file mode 100755 index d76d0f57a..000000000 --- a/talk/xmllite/xmlelement.cc +++ /dev/null @@ -1,513 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "talk/xmllite/xmlelement.h" - -#include <ostream> -#include <sstream> -#include <string> -#include <vector> - -#include "talk/xmllite/qname.h" -#include "talk/xmllite/xmlbuilder.h" -#include "talk/xmllite/xmlconstants.h" -#include "talk/xmllite/xmlparser.h" -#include "talk/xmllite/xmlprinter.h" -#include "webrtc/base/common.h" - -namespace buzz { - -XmlChild::~XmlChild() { -} - -bool XmlText::IsTextImpl() const { - return true; -} - -XmlElement* XmlText::AsElementImpl() const { - return NULL; -} - -XmlText* XmlText::AsTextImpl() const { - return const_cast<XmlText *>(this); -} - -void XmlText::SetText(const std::string& text) { - text_ = text; -} - -void XmlText::AddParsedText(const char* buf, int len) { - text_.append(buf, len); -} - -void XmlText::AddText(const std::string& text) { - text_ += text; -} - -XmlText::~XmlText() { -} - -XmlElement::XmlElement(const QName& name) : - name_(name), - first_attr_(NULL), - last_attr_(NULL), - first_child_(NULL), - last_child_(NULL), - cdata_(false) { -} - -XmlElement::XmlElement(const XmlElement& elt) : - XmlChild(), - name_(elt.name_), - first_attr_(NULL), - last_attr_(NULL), - first_child_(NULL), - last_child_(NULL), - cdata_(false) { - - // copy attributes - XmlAttr* attr; - XmlAttr ** plast_attr = &first_attr_; - XmlAttr* newAttr = NULL; - for (attr = elt.first_attr_; attr; attr = attr->NextAttr()) { - newAttr = new XmlAttr(*attr); - *plast_attr = newAttr; - plast_attr = &(newAttr->next_attr_); - } - last_attr_ = newAttr; - - // copy children - XmlChild* pChild; - XmlChild ** ppLast = &first_child_; - XmlChild* newChild = NULL; - - for (pChild = elt.first_child_; pChild; pChild = pChild->NextChild()) { - if (pChild->IsText()) { - newChild = new XmlText(*(pChild->AsText())); - } else { - newChild = new XmlElement(*(pChild->AsElement())); - } - *ppLast = newChild; - ppLast = &(newChild->next_child_); - } - last_child_ = newChild; - - cdata_ = elt.cdata_; -} - -XmlElement::XmlElement(const QName& name, bool useDefaultNs) : - name_(name), - first_attr_(useDefaultNs ? new XmlAttr(QN_XMLNS, name.Namespace()) : NULL), - last_attr_(first_attr_), - first_child_(NULL), - last_child_(NULL), - cdata_(false) { -} - -bool XmlElement::IsTextImpl() const { - return false; -} - -XmlElement* XmlElement::AsElementImpl() const { - return const_cast<XmlElement *>(this); -} - -XmlText* XmlElement::AsTextImpl() const { - return NULL; -} - -const std::string XmlElement::BodyText() const { - if (first_child_ && first_child_->IsText() && last_child_ == first_child_) { - return first_child_->AsText()->Text(); - } - - return std::string(); -} - -void XmlElement::SetBodyText(const std::string& text) { - if (text.empty()) { - ClearChildren(); - } else if (first_child_ == NULL) { - AddText(text); - } else if (first_child_->IsText() && last_child_ == first_child_) { - first_child_->AsText()->SetText(text); - } else { - ClearChildren(); - AddText(text); - } -} - -const QName XmlElement::FirstElementName() const { - const XmlElement* element = FirstElement(); - if (element == NULL) - return QName(); - return element->Name(); -} - -XmlAttr* XmlElement::FirstAttr() { - return first_attr_; -} - -const std::string XmlElement::Attr(const StaticQName& name) const { - XmlAttr* attr; - for (attr = first_attr_; attr; attr = attr->next_attr_) { - if (attr->name_ == name) - return attr->value_; - } - return std::string(); -} - -const std::string XmlElement::Attr(const QName& name) const { - XmlAttr* attr; - for (attr = first_attr_; attr; attr = attr->next_attr_) { - if (attr->name_ == name) - return attr->value_; - } - return std::string(); -} - -bool XmlElement::HasAttr(const StaticQName& name) const { - XmlAttr* attr; - for (attr = first_attr_; attr; attr = attr->next_attr_) { - if (attr->name_ == name) - return true; - } - return false; -} - -bool XmlElement::HasAttr(const QName& name) const { - XmlAttr* attr; - for (attr = first_attr_; attr; attr = attr->next_attr_) { - if (attr->name_ == name) - return true; - } - return false; -} - -void XmlElement::SetAttr(const QName& name, const std::string& value) { - XmlAttr* attr; - for (attr = first_attr_; attr; attr = attr->next_attr_) { - if (attr->name_ == name) - break; - } - if (!attr) { - attr = new XmlAttr(name, value); - if (last_attr_) - last_attr_->next_attr_ = attr; - else - first_attr_ = attr; - last_attr_ = attr; - return; - } - attr->value_ = value; -} - -void XmlElement::ClearAttr(const QName& name) { - XmlAttr* attr; - XmlAttr* last_attr = NULL; - for (attr = first_attr_; attr; attr = attr->next_attr_) { - if (attr->name_ == name) - break; - last_attr = attr; - } - if (!attr) - return; - if (!last_attr) - first_attr_ = attr->next_attr_; - else - last_attr->next_attr_ = attr->next_attr_; - if (last_attr_ == attr) - last_attr_ = last_attr; - delete attr; -} - -XmlChild* XmlElement::FirstChild() { - return first_child_; -} - -XmlElement* XmlElement::FirstElement() { - XmlChild* pChild; - for (pChild = first_child_; pChild; pChild = pChild->next_child_) { - if (!pChild->IsText()) - return pChild->AsElement(); - } - return NULL; -} - -XmlElement* XmlElement::NextElement() { - XmlChild* pChild; - for (pChild = next_child_; pChild; pChild = pChild->next_child_) { - if (!pChild->IsText()) - return pChild->AsElement(); - } - return NULL; -} - -XmlElement* XmlElement::FirstWithNamespace(const std::string& ns) { - XmlChild* pChild; - for (pChild = first_child_; pChild; pChild = pChild->next_child_) { - if (!pChild->IsText() && pChild->AsElement()->Name().Namespace() == ns) - return pChild->AsElement(); - } - return NULL; -} - -XmlElement * -XmlElement::NextWithNamespace(const std::string& ns) { - XmlChild* pChild; - for (pChild = next_child_; pChild; pChild = pChild->next_child_) { - if (!pChild->IsText() && pChild->AsElement()->Name().Namespace() == ns) - return pChild->AsElement(); - } - return NULL; -} - -XmlElement * -XmlElement::FirstNamed(const QName& name) { - XmlChild* pChild; - for (pChild = first_child_; pChild; pChild = pChild->next_child_) { - if (!pChild->IsText() && pChild->AsElement()->Name() == name) - return pChild->AsElement(); - } - return NULL; -} - -XmlElement * -XmlElement::FirstNamed(const StaticQName& name) { - XmlChild* pChild; - for (pChild = first_child_; pChild; pChild = pChild->next_child_) { - if (!pChild->IsText() && pChild->AsElement()->Name() == name) - return pChild->AsElement(); - } - return NULL; -} - -XmlElement * -XmlElement::NextNamed(const QName& name) { - XmlChild* pChild; - for (pChild = next_child_; pChild; pChild = pChild->next_child_) { - if (!pChild->IsText() && pChild->AsElement()->Name() == name) - return pChild->AsElement(); - } - return NULL; -} - -XmlElement * -XmlElement::NextNamed(const StaticQName& name) { - XmlChild* pChild; - for (pChild = next_child_; pChild; pChild = pChild->next_child_) { - if (!pChild->IsText() && pChild->AsElement()->Name() == name) - return pChild->AsElement(); - } - return NULL; -} - -XmlElement* XmlElement::FindOrAddNamedChild(const QName& name) { - XmlElement* child = FirstNamed(name); - if (!child) { - child = new XmlElement(name); - AddElement(child); - } - - return child; -} - -const std::string XmlElement::TextNamed(const QName& name) const { - XmlChild* pChild; - for (pChild = first_child_; pChild; pChild = pChild->next_child_) { - if (!pChild->IsText() && pChild->AsElement()->Name() == name) - return pChild->AsElement()->BodyText(); - } - return std::string(); -} - -void XmlElement::InsertChildAfter(XmlChild* predecessor, XmlChild* next) { - if (predecessor == NULL) { - next->next_child_ = first_child_; - first_child_ = next; - } - else { - next->next_child_ = predecessor->next_child_; - predecessor->next_child_ = next; - } -} - -void XmlElement::RemoveChildAfter(XmlChild* predecessor) { - XmlChild* next; - - if (predecessor == NULL) { - next = first_child_; - first_child_ = next->next_child_; - } - else { - next = predecessor->next_child_; - predecessor->next_child_ = next->next_child_; - } - - if (last_child_ == next) - last_child_ = predecessor; - - delete next; -} - -void XmlElement::AddAttr(const QName& name, const std::string& value) { - ASSERT(!HasAttr(name)); - - XmlAttr ** pprev = last_attr_ ? &(last_attr_->next_attr_) : &first_attr_; - last_attr_ = (*pprev = new XmlAttr(name, value)); -} - -void XmlElement::AddAttr(const QName& name, const std::string& value, - int depth) { - XmlElement* element = this; - while (depth--) { - element = element->last_child_->AsElement(); - } - element->AddAttr(name, value); -} - -void XmlElement::AddParsedText(const char* cstr, int len) { - if (len == 0) - return; - - if (last_child_ && last_child_->IsText()) { - last_child_->AsText()->AddParsedText(cstr, len); - return; - } - XmlChild ** pprev = last_child_ ? &(last_child_->next_child_) : &first_child_; - last_child_ = *pprev = new XmlText(cstr, len); -} - -void XmlElement::AddCDATAText(const char* buf, int len) { - cdata_ = true; - AddParsedText(buf, len); -} - -void XmlElement::AddText(const std::string& text) { - if (text == STR_EMPTY) - return; - - if (last_child_ && last_child_->IsText()) { - last_child_->AsText()->AddText(text); - return; - } - XmlChild ** pprev = last_child_ ? &(last_child_->next_child_) : &first_child_; - last_child_ = *pprev = new XmlText(text); -} - -void XmlElement::AddText(const std::string& text, int depth) { - // note: the first syntax is ambigious for msvc 6 - // XmlElement* pel(this); - XmlElement* element = this; - while (depth--) { - element = element->last_child_->AsElement(); - } - element->AddText(text); -} - -void XmlElement::AddElement(XmlElement *child) { - if (child == NULL) - return; - - XmlChild ** pprev = last_child_ ? &(last_child_->next_child_) : &first_child_; - *pprev = child; - last_child_ = child; - child->next_child_ = NULL; -} - -void XmlElement::AddElement(XmlElement *child, int depth) { - XmlElement* element = this; - while (depth--) { - element = element->last_child_->AsElement(); - } - element->AddElement(child); -} - -void XmlElement::ClearNamedChildren(const QName& name) { - XmlChild* prev_child = NULL; - XmlChild* next_child; - XmlChild* child; - for (child = FirstChild(); child; child = next_child) { - next_child = child->NextChild(); - if (!child->IsText() && child->AsElement()->Name() == name) - { - RemoveChildAfter(prev_child); - continue; - } - prev_child = child; - } -} - -void XmlElement::ClearAttributes() { - XmlAttr* attr; - for (attr = first_attr_; attr; ) { - XmlAttr* to_delete = attr; - attr = attr->next_attr_; - delete to_delete; - } - first_attr_ = last_attr_ = NULL; -} - -void XmlElement::ClearChildren() { - XmlChild* pchild; - for (pchild = first_child_; pchild; ) { - XmlChild* to_delete = pchild; - pchild = pchild->next_child_; - delete to_delete; - } - first_child_ = last_child_ = NULL; -} - -std::string XmlElement::Str() const { - std::stringstream ss; - XmlPrinter::PrintXml(&ss, this); - return ss.str(); -} - -XmlElement* XmlElement::ForStr(const std::string& str) { - XmlBuilder builder; - XmlParser::ParseXml(&builder, str); - return builder.CreateElement(); -} - -XmlElement::~XmlElement() { - XmlAttr* attr; - for (attr = first_attr_; attr; ) { - XmlAttr* to_delete = attr; - attr = attr->next_attr_; - delete to_delete; - } - - XmlChild* pchild; - for (pchild = first_child_; pchild; ) { - XmlChild* to_delete = pchild; - pchild = pchild->next_child_; - delete to_delete; - } -} - -} // namespace buzz diff --git a/talk/xmllite/xmlelement.h b/talk/xmllite/xmlelement.h deleted file mode 100755 index 044d2c404..000000000 --- a/talk/xmllite/xmlelement.h +++ /dev/null @@ -1,251 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef TALK_XMLLITE_XMLELEMENT_H_ -#define TALK_XMLLITE_XMLELEMENT_H_ - -#include <iosfwd> -#include <string> - -#include "talk/xmllite/qname.h" -#include "webrtc/base/scoped_ptr.h" - -namespace buzz { - -class XmlChild; -class XmlText; -class XmlElement; -class XmlAttr; - -class XmlChild { - public: - XmlChild* NextChild() { return next_child_; } - const XmlChild* NextChild() const { return next_child_; } - - bool IsText() const { return IsTextImpl(); } - - XmlElement* AsElement() { return AsElementImpl(); } - const XmlElement* AsElement() const { return AsElementImpl(); } - - XmlText* AsText() { return AsTextImpl(); } - const XmlText* AsText() const { return AsTextImpl(); } - - - protected: - XmlChild() : - next_child_(NULL) { - } - - virtual bool IsTextImpl() const = 0; - virtual XmlElement* AsElementImpl() const = 0; - virtual XmlText* AsTextImpl() const = 0; - - - virtual ~XmlChild(); - - private: - friend class XmlElement; - - XmlChild(const XmlChild& noimpl); - - XmlChild* next_child_; -}; - -class XmlText : public XmlChild { - public: - explicit XmlText(const std::string& text) : - XmlChild(), - text_(text) { - } - explicit XmlText(const XmlText& t) : - XmlChild(), - text_(t.text_) { - } - explicit XmlText(const char* cstr, size_t len) : - XmlChild(), - text_(cstr, len) { - } - virtual ~XmlText(); - - const std::string& Text() const { return text_; } - void SetText(const std::string& text); - void AddParsedText(const char* buf, int len); - void AddText(const std::string& text); - - protected: - virtual bool IsTextImpl() const; - virtual XmlElement* AsElementImpl() const; - virtual XmlText* AsTextImpl() const; - - private: - std::string text_; -}; - -class XmlAttr { - public: - XmlAttr* NextAttr() const { return next_attr_; } - const QName& Name() const { return name_; } - const std::string& Value() const { return value_; } - - private: - friend class XmlElement; - - explicit XmlAttr(const QName& name, const std::string& value) : - next_attr_(NULL), - name_(name), - value_(value) { - } - explicit XmlAttr(const XmlAttr& att) : - next_attr_(NULL), - name_(att.name_), - value_(att.value_) { - } - - XmlAttr* next_attr_; - QName name_; - std::string value_; -}; - -class XmlElement : public XmlChild { - public: - explicit XmlElement(const QName& name); - explicit XmlElement(const QName& name, bool useDefaultNs); - explicit XmlElement(const XmlElement& elt); - - virtual ~XmlElement(); - - const QName& Name() const { return name_; } - void SetName(const QName& name) { name_ = name; } - - const std::string BodyText() const; - void SetBodyText(const std::string& text); - - const QName FirstElementName() const; - - XmlAttr* FirstAttr(); - const XmlAttr* FirstAttr() const - { return const_cast<XmlElement *>(this)->FirstAttr(); } - - // Attr will return an empty string if the attribute isn't there: - // use HasAttr to test presence of an attribute. - const std::string Attr(const StaticQName& name) const; - const std::string Attr(const QName& name) const; - bool HasAttr(const StaticQName& name) const; - bool HasAttr(const QName& name) const; - void SetAttr(const QName& name, const std::string& value); - void ClearAttr(const QName& name); - - XmlChild* FirstChild(); - const XmlChild* FirstChild() const { - return const_cast<XmlElement *>(this)->FirstChild(); - } - - XmlElement* FirstElement(); - const XmlElement* FirstElement() const { - return const_cast<XmlElement *>(this)->FirstElement(); - } - - XmlElement* NextElement(); - const XmlElement* NextElement() const { - return const_cast<XmlElement *>(this)->NextElement(); - } - - XmlElement* FirstWithNamespace(const std::string& ns); - const XmlElement* FirstWithNamespace(const std::string& ns) const { - return const_cast<XmlElement *>(this)->FirstWithNamespace(ns); - } - - XmlElement* NextWithNamespace(const std::string& ns); - const XmlElement* NextWithNamespace(const std::string& ns) const { - return const_cast<XmlElement *>(this)->NextWithNamespace(ns); - } - - XmlElement* FirstNamed(const StaticQName& name); - const XmlElement* FirstNamed(const StaticQName& name) const { - return const_cast<XmlElement *>(this)->FirstNamed(name); - } - - XmlElement* FirstNamed(const QName& name); - const XmlElement* FirstNamed(const QName& name) const { - return const_cast<XmlElement *>(this)->FirstNamed(name); - } - - XmlElement* NextNamed(const StaticQName& name); - const XmlElement* NextNamed(const StaticQName& name) const { - return const_cast<XmlElement *>(this)->NextNamed(name); - } - - XmlElement* NextNamed(const QName& name); - const XmlElement* NextNamed(const QName& name) const { - return const_cast<XmlElement *>(this)->NextNamed(name); - } - - // Finds the first element named 'name'. If that element can't be found then - // adds one and returns it. - XmlElement* FindOrAddNamedChild(const QName& name); - - const std::string TextNamed(const QName& name) const; - - void InsertChildAfter(XmlChild* predecessor, XmlChild* new_child); - void RemoveChildAfter(XmlChild* predecessor); - - void AddParsedText(const char* buf, int len); - // Note: CDATA is not supported by XMPP, therefore using this function will - // generate non-XMPP compatible XML. - void AddCDATAText(const char* buf, int len); - void AddText(const std::string& text); - void AddText(const std::string& text, int depth); - void AddElement(XmlElement* child); - void AddElement(XmlElement* child, int depth); - void AddAttr(const QName& name, const std::string& value); - void AddAttr(const QName& name, const std::string& value, int depth); - void ClearNamedChildren(const QName& name); - void ClearAttributes(); - void ClearChildren(); - - static XmlElement* ForStr(const std::string& str); - std::string Str() const; - - bool IsCDATA() const { return cdata_; } - - protected: - virtual bool IsTextImpl() const; - virtual XmlElement* AsElementImpl() const; - virtual XmlText* AsTextImpl() const; - - private: - QName name_; - XmlAttr* first_attr_; - XmlAttr* last_attr_; - XmlChild* first_child_; - XmlChild* last_child_; - bool cdata_; -}; - -} // namespace buzz - -#endif // TALK_XMLLITE_XMLELEMENT_H_ diff --git a/talk/xmllite/xmlelement_unittest.cc b/talk/xmllite/xmlelement_unittest.cc deleted file mode 100755 index 5b2e1067b..000000000 --- a/talk/xmllite/xmlelement_unittest.cc +++ /dev/null @@ -1,275 +0,0 @@ -/* - * libjingle - * Copyright 2004, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <iostream> -#include <sstream> -#include <string> -#include "talk/xmllite/xmlelement.h" -#include "webrtc/base/common.h" -#include "webrtc/base/gunit.h" -#include "webrtc/base/thread.h" - -using buzz::QName; -using buzz::XmlAttr; -using buzz::XmlChild; -using buzz::XmlElement; - -std::ostream& operator<<(std::ostream& os, const QName& name) { - os << name.Namespace() << ":" << name.LocalPart(); - return os; -} - -TEST(XmlElementTest, TestConstructors) { - XmlElement elt(QName("google:test", "first")); - EXPECT_EQ("<test:first xmlns:test=\"google:test\"/>", elt.Str()); - - XmlElement elt2(QName("google:test", "first"), true); - EXPECT_EQ("<first xmlns=\"google:test\"/>", elt2.Str()); -} - -TEST(XmlElementTest, TestAdd) { - XmlElement elt(QName("google:test", "root"), true); - elt.AddElement(new XmlElement(QName("google:test", "first"))); - elt.AddElement(new XmlElement(QName("google:test", "nested")), 1); - elt.AddText("nested-value", 2); - elt.AddText("between-", 1); - elt.AddText("value", 1); - elt.AddElement(new XmlElement(QName("google:test", "nested2")), 1); - elt.AddElement(new XmlElement(QName("google:test", "second"))); - elt.AddText("init-value", 1); - elt.AddElement(new XmlElement(QName("google:test", "nested3")), 1); - elt.AddText("trailing-value", 1); - - // make sure it looks ok overall - EXPECT_EQ("<root xmlns=\"google:test\">" - "<first><nested>nested-value</nested>between-value<nested2/></first>" - "<second>init-value<nested3/>trailing-value</second></root>", - elt.Str()); - - // make sure text was concatenated - XmlChild * pchild = - elt.FirstChild()->AsElement()->FirstChild()->NextChild(); - EXPECT_TRUE(pchild->IsText()); - EXPECT_EQ("between-value", pchild->AsText()->Text()); -} - -TEST(XmlElementTest, TestAttrs) { - XmlElement elt(QName("", "root")); - elt.SetAttr(QName("", "a"), "avalue"); - EXPECT_EQ("<root a=\"avalue\"/>", elt.Str()); - - elt.SetAttr(QName("", "b"), "bvalue"); - EXPECT_EQ("<root a=\"avalue\" b=\"bvalue\"/>", elt.Str()); - - elt.SetAttr(QName("", "a"), "avalue2"); - EXPECT_EQ("<root a=\"avalue2\" b=\"bvalue\"/>", elt.Str()); - - elt.SetAttr(QName("", "b"), "bvalue2"); - EXPECT_EQ("<root a=\"avalue2\" b=\"bvalue2\"/>", elt.Str()); - - elt.SetAttr(QName("", "c"), "cvalue"); - EXPECT_EQ("<root a=\"avalue2\" b=\"bvalue2\" c=\"cvalue\"/>", elt.Str()); - - XmlAttr * patt = elt.FirstAttr(); - EXPECT_EQ(QName("", "a"), patt->Name()); - EXPECT_EQ("avalue2", patt->Value()); - - patt = patt->NextAttr(); - EXPECT_EQ(QName("", "b"), patt->Name()); - EXPECT_EQ("bvalue2", patt->Value()); - - patt = patt->NextAttr(); - EXPECT_EQ(QName("", "c"), patt->Name()); - EXPECT_EQ("cvalue", patt->Value()); - - patt = patt->NextAttr(); - EXPECT_TRUE(NULL == patt); - - EXPECT_TRUE(elt.HasAttr(QName("", "a"))); - EXPECT_TRUE(elt.HasAttr(QName("", "b"))); - EXPECT_TRUE(elt.HasAttr(QName("", "c"))); - EXPECT_FALSE(elt.HasAttr(QName("", "d"))); - - elt.SetAttr(QName("", "d"), "dvalue"); - EXPECT_EQ("<root a=\"avalue2\" b=\"bvalue2\" c=\"cvalue\" d=\"dvalue\"/>", - elt.Str()); - EXPECT_TRUE(elt.HasAttr(QName("", "d"))); - - elt.ClearAttr(QName("", "z")); // not found, no effect - EXPECT_EQ("<root a=\"avalue2\" b=\"bvalue2\" c=\"cvalue\" d=\"dvalue\"/>", - elt.Str()); - - elt.ClearAttr(QName("", "b")); - EXPECT_EQ("<root a=\"avalue2\" c=\"cvalue\" d=\"dvalue\"/>", elt.Str()); - - elt.ClearAttr(QName("", "a")); - EXPECT_EQ("<root c=\"cvalue\" d=\"dvalue\"/>", elt.Str()); - - elt.ClearAttr(QName("", "d")); - EXPECT_EQ("<root c=\"cvalue\"/>", elt.Str()); - - elt.ClearAttr(QName("", "c")); - EXPECT_EQ("<root/>", elt.Str()); -} - -TEST(XmlElementTest, TestBodyText) { - XmlElement elt(QName("", "root")); - EXPECT_EQ("", elt.BodyText()); - - elt.AddText("body value text"); - - EXPECT_EQ("body value text", elt.BodyText()); - - elt.ClearChildren(); - elt.AddText("more value "); - elt.AddText("text"); - - EXPECT_EQ("more value text", elt.BodyText()); - - elt.ClearChildren(); - elt.AddText("decoy"); - elt.AddElement(new XmlElement(QName("", "dummy"))); - EXPECT_EQ("", elt.BodyText()); - - elt.SetBodyText("replacement"); - EXPECT_EQ("replacement", elt.BodyText()); - - elt.SetBodyText(""); - EXPECT_TRUE(NULL == elt.FirstChild()); - - elt.SetBodyText("goodbye"); - EXPECT_EQ("goodbye", elt.FirstChild()->AsText()->Text()); - EXPECT_EQ("goodbye", elt.BodyText()); -} - -TEST(XmlElementTest, TestCopyConstructor) { - XmlElement * element = XmlElement::ForStr( - "<root xmlns='test-foo'>This is a <em a='avalue' b='bvalue'>" - "little <b>little</b></em> test</root>"); - - XmlElement * pelCopy = new XmlElement(*element); - EXPECT_EQ("<root xmlns=\"test-foo\">This is a <em a=\"avalue\" b=\"bvalue\">" - "little <b>little</b></em> test</root>", pelCopy->Str()); - delete pelCopy; - - pelCopy = new XmlElement(*(element->FirstChild()->NextChild()->AsElement())); - EXPECT_EQ("<foo:em a=\"avalue\" b=\"bvalue\" xmlns:foo=\"test-foo\">" - "little <foo:b>little</foo:b></foo:em>", pelCopy->Str()); - - XmlAttr * patt = pelCopy->FirstAttr(); - EXPECT_EQ(QName("", "a"), patt->Name()); - EXPECT_EQ("avalue", patt->Value()); - - patt = patt->NextAttr(); - EXPECT_EQ(QName("", "b"), patt->Name()); - EXPECT_EQ("bvalue", patt->Value()); - - patt = patt->NextAttr(); - EXPECT_TRUE(NULL == patt); - delete pelCopy; - delete element; -} - -TEST(XmlElementTest, TestNameSearch) { - XmlElement * element = XmlElement::ForStr( - "<root xmlns='test-foo'>" - "<firstname>George</firstname>" - "<middlename>X.</middlename>" - "some text" - "<lastname>Harrison</lastname>" - "<firstname>John</firstname>" - "<middlename>Y.</middlename>" - "<lastname>Lennon</lastname>" - "</root>"); - EXPECT_TRUE(NULL == - element->FirstNamed(QName("", "firstname"))); - EXPECT_EQ(element->FirstChild(), - element->FirstNamed(QName("test-foo", "firstname"))); - EXPECT_EQ(element->FirstChild()->NextChild(), - element->FirstNamed(QName("test-foo", "middlename"))); - EXPECT_EQ(element->FirstElement()->NextElement(), - element->FirstNamed(QName("test-foo", "middlename"))); - EXPECT_EQ("Harrison", - element->TextNamed(QName("test-foo", "lastname"))); - EXPECT_EQ(element->FirstElement()->NextElement()->NextElement(), - element->FirstNamed(QName("test-foo", "lastname"))); - EXPECT_EQ("John", element->FirstNamed(QName("test-foo", "firstname"))-> - NextNamed(QName("test-foo", "firstname"))->BodyText()); - EXPECT_EQ("Y.", element->FirstNamed(QName("test-foo", "middlename"))-> - NextNamed(QName("test-foo", "middlename"))->BodyText()); - EXPECT_EQ("Lennon", element->FirstNamed(QName("test-foo", "lastname"))-> - NextNamed(QName("test-foo", "lastname"))->BodyText()); - EXPECT_TRUE(NULL == element->FirstNamed(QName("test-foo", "firstname"))-> - NextNamed(QName("test-foo", "firstname"))-> - NextNamed(QName("test-foo", "firstname"))); - - delete element; -} - -class XmlElementCreatorThread : public rtc::Thread { - public: - XmlElementCreatorThread(int count, buzz::QName qname) : - count_(count), qname_(qname) {} - - virtual ~XmlElementCreatorThread() { - Stop(); - } - - virtual void Run() { - std::vector<buzz::XmlElement*> elems; - for (int i = 0; i < count_; i++) { - elems.push_back(new XmlElement(qname_)); - } - for (int i = 0; i < count_; i++) { - delete elems[i]; - } - } - - private: - int count_; - buzz::QName qname_; -}; - -// If XmlElement creation and destruction isn't thread safe, -// this test should crash. -TEST(XmlElementTest, TestMultithread) { - int thread_count = 2; // Was 100, but that's too slow. - int elem_count = 100; // Was 100000, but that's too slow. - buzz::QName qname("foo", "bar"); - - std::vector<rtc::Thread*> threads; - for (int i = 0; i < thread_count; i++) { - threads.push_back( - new XmlElementCreatorThread(elem_count, qname)); - threads[i]->Start(); - } - - for (int i = 0; i < thread_count; i++) { - threads[i]->Stop(); - delete threads[i]; - } -} diff --git a/talk/xmllite/xmlnsstack.cc b/talk/xmllite/xmlnsstack.cc deleted file mode 100755 index bc66b4f50..000000000 --- a/talk/xmllite/xmlnsstack.cc +++ /dev/null @@ -1,195 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "talk/xmllite/xmlnsstack.h" - -#include <sstream> -#include <string> -#include <vector> - -#include "talk/xmllite/xmlconstants.h" -#include "talk/xmllite/xmlelement.h" - -namespace buzz { - -XmlnsStack::XmlnsStack() : - pxmlnsStack_(new std::vector<std::string>), - pxmlnsDepthStack_(new std::vector<size_t>) { -} - -XmlnsStack::~XmlnsStack() {} - -void XmlnsStack::PushFrame() { - pxmlnsDepthStack_->push_back(pxmlnsStack_->size()); -} - -void XmlnsStack::PopFrame() { - size_t prev_size = pxmlnsDepthStack_->back(); - pxmlnsDepthStack_->pop_back(); - if (prev_size < pxmlnsStack_->size()) { - pxmlnsStack_->erase(pxmlnsStack_->begin() + prev_size, - pxmlnsStack_->end()); - } -} - -std::pair<std::string, bool> XmlnsStack::NsForPrefix( - const std::string& prefix) { - if (prefix.length() >= 3 && - (prefix[0] == 'x' || prefix[0] == 'X') && - (prefix[1] == 'm' || prefix[1] == 'M') && - (prefix[2] == 'l' || prefix[2] == 'L')) { - if (prefix == "xml") - return std::make_pair(NS_XML, true); - if (prefix == "xmlns") - return std::make_pair(NS_XMLNS, true); - // Other names with xml prefix are illegal. - return std::make_pair(STR_EMPTY, false); - } - - std::vector<std::string>::iterator pos; - for (pos = pxmlnsStack_->end(); pos > pxmlnsStack_->begin(); ) { - pos -= 2; - if (*pos == prefix) - return std::make_pair(*(pos + 1), true); - } - - if (prefix == STR_EMPTY) - return std::make_pair(STR_EMPTY, true); // default namespace - - return std::make_pair(STR_EMPTY, false); // none found -} - -bool XmlnsStack::PrefixMatchesNs(const std::string& prefix, - const std::string& ns) { - const std::pair<std::string, bool> match = NsForPrefix(prefix); - return match.second && (match.first == ns); -} - -std::pair<std::string, bool> XmlnsStack::PrefixForNs(const std::string& ns, - bool isattr) { - if (ns == NS_XML) - return std::make_pair(std::string("xml"), true); - if (ns == NS_XMLNS) - return std::make_pair(std::string("xmlns"), true); - if (isattr ? ns == STR_EMPTY : PrefixMatchesNs(STR_EMPTY, ns)) - return std::make_pair(STR_EMPTY, true); - - std::vector<std::string>::iterator pos; - for (pos = pxmlnsStack_->end(); pos > pxmlnsStack_->begin(); ) { - pos -= 2; - if (*(pos + 1) == ns && - (!isattr || !pos->empty()) && PrefixMatchesNs(*pos, ns)) - return std::make_pair(*pos, true); - } - - return std::make_pair(STR_EMPTY, false); // none found -} - -std::string XmlnsStack::FormatQName(const QName& name, bool isAttr) { - std::string prefix(PrefixForNs(name.Namespace(), isAttr).first); - if (prefix == STR_EMPTY) - return name.LocalPart(); - else - return prefix + ':' + name.LocalPart(); -} - -void XmlnsStack::AddXmlns(const std::string & prefix, const std::string & ns) { - pxmlnsStack_->push_back(prefix); - pxmlnsStack_->push_back(ns); -} - -void XmlnsStack::RemoveXmlns() { - pxmlnsStack_->pop_back(); - pxmlnsStack_->pop_back(); -} - -static bool IsAsciiLetter(char ch) { - return ((ch >= 'a' && ch <= 'z') || - (ch >= 'A' && ch <= 'Z')); -} - -static std::string AsciiLower(const std::string & s) { - std::string result(s); - size_t i; - for (i = 0; i < result.length(); i++) { - if (result[i] >= 'A' && result[i] <= 'Z') - result[i] += 'a' - 'A'; - } - return result; -} - -static std::string SuggestPrefix(const std::string & ns) { - size_t len = ns.length(); - size_t i = ns.find_last_of('.'); - if (i != std::string::npos && len - i <= 4 + 1) - len = i; // chop off ".html" or ".xsd" or ".?{0,4}" - size_t last = len; - while (last > 0) { - last -= 1; - if (IsAsciiLetter(ns[last])) { - size_t first = last; - last += 1; - while (first > 0) { - if (!IsAsciiLetter(ns[first - 1])) - break; - first -= 1; - } - if (last - first > 4) - last = first + 3; - std::string candidate(AsciiLower(ns.substr(first, last - first))); - if (candidate.find("xml") != 0) - return candidate; - break; - } - } - return "ns"; -} - -std::pair<std::string, bool> XmlnsStack::AddNewPrefix(const std::string& ns, - bool isAttr) { - if (PrefixForNs(ns, isAttr).second) - return std::make_pair(STR_EMPTY, false); - - std::string base(SuggestPrefix(ns)); - std::string result(base); - int i = 2; - while (NsForPrefix(result).second) { - std::stringstream ss; - ss << base; - ss << (i++); - ss >> result; - } - AddXmlns(result, ns); - return std::make_pair(result, true); -} - -void XmlnsStack::Reset() { - pxmlnsStack_->clear(); - pxmlnsDepthStack_->clear(); -} - -} diff --git a/talk/xmllite/xmlnsstack.h b/talk/xmllite/xmlnsstack.h deleted file mode 100755 index a3c4368ac..000000000 --- a/talk/xmllite/xmlnsstack.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef TALK_XMLLITE_XMLNSSTACK_H_ -#define TALK_XMLLITE_XMLNSSTACK_H_ - -#include <string> -#include <vector> -#include "talk/xmllite/qname.h" -#include "webrtc/base/scoped_ptr.h" - -namespace buzz { - -class XmlnsStack { -public: - XmlnsStack(); - ~XmlnsStack(); - - void AddXmlns(const std::string& prefix, const std::string& ns); - void RemoveXmlns(); - void PushFrame(); - void PopFrame(); - void Reset(); - - std::pair<std::string, bool> NsForPrefix(const std::string& prefix); - bool PrefixMatchesNs(const std::string & prefix, const std::string & ns); - std::pair<std::string, bool> PrefixForNs(const std::string& ns, bool isAttr); - std::pair<std::string, bool> AddNewPrefix(const std::string& ns, bool isAttr); - std::string FormatQName(const QName & name, bool isAttr); - -private: - - rtc::scoped_ptr<std::vector<std::string> > pxmlnsStack_; - rtc::scoped_ptr<std::vector<size_t> > pxmlnsDepthStack_; -}; -} - -#endif // TALK_XMLLITE_XMLNSSTACK_H_ diff --git a/talk/xmllite/xmlnsstack_unittest.cc b/talk/xmllite/xmlnsstack_unittest.cc deleted file mode 100755 index 82a39dd07..000000000 --- a/talk/xmllite/xmlnsstack_unittest.cc +++ /dev/null @@ -1,258 +0,0 @@ -/* - * libjingle - * Copyright 2004, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "talk/xmllite/xmlnsstack.h" - -#include <iostream> -#include <sstream> -#include <string> - -#include "talk/xmllite/xmlconstants.h" -#include "webrtc/base/common.h" -#include "webrtc/base/gunit.h" - -using buzz::NS_XML; -using buzz::NS_XMLNS; -using buzz::QName; -using buzz::XmlnsStack; - -TEST(XmlnsStackTest, TestBuiltin) { - XmlnsStack stack; - - EXPECT_EQ(std::string(NS_XML), stack.NsForPrefix("xml").first); - EXPECT_EQ(std::string(NS_XMLNS), stack.NsForPrefix("xmlns").first); - EXPECT_EQ("", stack.NsForPrefix("").first); - - EXPECT_EQ("xml", stack.PrefixForNs(NS_XML, false).first); - EXPECT_EQ("xmlns", stack.PrefixForNs(NS_XMLNS, false).first); - EXPECT_EQ("", stack.PrefixForNs("", false).first); - EXPECT_EQ("", stack.PrefixForNs("", true).first); -} - -TEST(XmlnsStackTest, TestNsForPrefix) { - XmlnsStack stack; - stack.AddXmlns("pre1", "ns1"); - stack.AddXmlns("pre2", "ns2"); - stack.AddXmlns("pre1", "ns3"); - stack.AddXmlns("", "ns4"); - - EXPECT_EQ("ns3", stack.NsForPrefix("pre1").first); - EXPECT_TRUE(stack.NsForPrefix("pre1").second); - EXPECT_EQ("ns2", stack.NsForPrefix("pre2").first); - EXPECT_EQ("ns4", stack.NsForPrefix("").first); - EXPECT_EQ("", stack.NsForPrefix("pre3").first); - EXPECT_FALSE(stack.NsForPrefix("pre3").second); -} - -TEST(XmlnsStackTest, TestPrefixForNs) { - XmlnsStack stack; - stack.AddXmlns("pre1", "ns1"); - stack.AddXmlns("pre2", "ns2"); - stack.AddXmlns("pre1", "ns3"); - stack.AddXmlns("pre3", "ns2"); - stack.AddXmlns("pre4", "ns4"); - stack.AddXmlns("", "ns4"); - - EXPECT_EQ("", stack.PrefixForNs("ns1", false).first); - EXPECT_FALSE(stack.PrefixForNs("ns1", false).second); - EXPECT_EQ("", stack.PrefixForNs("ns1", true).first); - EXPECT_FALSE(stack.PrefixForNs("ns1", true).second); - EXPECT_EQ("pre3", stack.PrefixForNs("ns2", false).first); - EXPECT_TRUE(stack.PrefixForNs("ns2", false).second); - EXPECT_EQ("pre3", stack.PrefixForNs("ns2", true).first); - EXPECT_TRUE(stack.PrefixForNs("ns2", true).second); - EXPECT_EQ("pre1", stack.PrefixForNs("ns3", false).first); - EXPECT_EQ("pre1", stack.PrefixForNs("ns3", true).first); - EXPECT_EQ("", stack.PrefixForNs("ns4", false).first); - EXPECT_TRUE(stack.PrefixForNs("ns4", false).second); - EXPECT_EQ("pre4", stack.PrefixForNs("ns4", true).first); - EXPECT_EQ("", stack.PrefixForNs("ns5", false).first); - EXPECT_FALSE(stack.PrefixForNs("ns5", false).second); - EXPECT_EQ("", stack.PrefixForNs("ns5", true).first); - EXPECT_EQ("", stack.PrefixForNs("", false).first); - EXPECT_EQ("", stack.PrefixForNs("", true).first); - - stack.AddXmlns("", "ns6"); - EXPECT_EQ("", stack.PrefixForNs("ns6", false).first); - EXPECT_TRUE(stack.PrefixForNs("ns6", false).second); - EXPECT_EQ("", stack.PrefixForNs("ns6", true).first); - EXPECT_FALSE(stack.PrefixForNs("ns6", true).second); -} - -TEST(XmlnsStackTest, TestFrames) { - XmlnsStack stack; - stack.PushFrame(); - stack.AddXmlns("pre1", "ns1"); - stack.AddXmlns("pre2", "ns2"); - - stack.PushFrame(); - stack.AddXmlns("pre1", "ns3"); - stack.AddXmlns("pre3", "ns2"); - stack.AddXmlns("pre4", "ns4"); - - stack.PushFrame(); - stack.PushFrame(); - stack.AddXmlns("", "ns4"); - - // basic test - EXPECT_EQ("ns3", stack.NsForPrefix("pre1").first); - EXPECT_EQ("ns2", stack.NsForPrefix("pre2").first); - EXPECT_EQ("ns2", stack.NsForPrefix("pre3").first); - EXPECT_EQ("ns4", stack.NsForPrefix("pre4").first); - EXPECT_EQ("", stack.NsForPrefix("pre5").first); - EXPECT_FALSE(stack.NsForPrefix("pre5").second); - EXPECT_EQ("ns4", stack.NsForPrefix("").first); - EXPECT_TRUE(stack.NsForPrefix("").second); - - // pop the default xmlns definition - stack.PopFrame(); - EXPECT_EQ("ns3", stack.NsForPrefix("pre1").first); - EXPECT_EQ("ns2", stack.NsForPrefix("pre2").first); - EXPECT_EQ("ns2", stack.NsForPrefix("pre3").first); - EXPECT_EQ("ns4", stack.NsForPrefix("pre4").first); - EXPECT_EQ("", stack.NsForPrefix("pre5").first); - EXPECT_FALSE(stack.NsForPrefix("pre5").second); - EXPECT_EQ("", stack.NsForPrefix("").first); - EXPECT_TRUE(stack.NsForPrefix("").second); - - // pop empty frame (nop) - stack.PopFrame(); - EXPECT_EQ("ns3", stack.NsForPrefix("pre1").first); - EXPECT_EQ("ns2", stack.NsForPrefix("pre2").first); - EXPECT_EQ("ns2", stack.NsForPrefix("pre3").first); - EXPECT_EQ("ns4", stack.NsForPrefix("pre4").first); - EXPECT_EQ("", stack.NsForPrefix("pre5").first); - EXPECT_FALSE(stack.NsForPrefix("pre5").second); - EXPECT_EQ("", stack.NsForPrefix("").first); - EXPECT_TRUE(stack.NsForPrefix("").second); - - // pop frame with three defs - stack.PopFrame(); - EXPECT_EQ("ns1", stack.NsForPrefix("pre1").first); - EXPECT_EQ("ns2", stack.NsForPrefix("pre2").first); - EXPECT_EQ("", stack.NsForPrefix("pre3").first); - EXPECT_FALSE(stack.NsForPrefix("pre3").second); - EXPECT_EQ("", stack.NsForPrefix("pre4").first); - EXPECT_FALSE(stack.NsForPrefix("pre4").second); - EXPECT_EQ("", stack.NsForPrefix("pre5").first); - EXPECT_FALSE(stack.NsForPrefix("pre5").second); - EXPECT_EQ("", stack.NsForPrefix("").first); - EXPECT_TRUE(stack.NsForPrefix("").second); - - // pop frame with last two defs - stack.PopFrame(); - EXPECT_FALSE(stack.NsForPrefix("pre1").second); - EXPECT_FALSE(stack.NsForPrefix("pre2").second); - EXPECT_FALSE(stack.NsForPrefix("pre3").second); - EXPECT_FALSE(stack.NsForPrefix("pre4").second); - EXPECT_FALSE(stack.NsForPrefix("pre5").second); - EXPECT_TRUE(stack.NsForPrefix("").second); - EXPECT_EQ("", stack.NsForPrefix("pre1").first); - EXPECT_EQ("", stack.NsForPrefix("pre2").first); - EXPECT_EQ("", stack.NsForPrefix("pre3").first); - EXPECT_EQ("", stack.NsForPrefix("pre4").first); - EXPECT_EQ("", stack.NsForPrefix("pre5").first); - EXPECT_EQ("", stack.NsForPrefix("").first); -} - -TEST(XmlnsStackTest, TestAddNewPrefix) { - XmlnsStack stack; - - // builtin namespaces cannot be added - EXPECT_FALSE(stack.AddNewPrefix("", true).second); - EXPECT_FALSE(stack.AddNewPrefix("", false).second); - EXPECT_FALSE(stack.AddNewPrefix(NS_XML, true).second); - EXPECT_FALSE(stack.AddNewPrefix(NS_XML, false).second); - EXPECT_FALSE(stack.AddNewPrefix(NS_XMLNS, true).second); - EXPECT_FALSE(stack.AddNewPrefix(NS_XMLNS, false).second); - - // namespaces already added cannot be added again. - EXPECT_EQ("foo", stack.AddNewPrefix("http://a.b.com/foo.htm", true).first); - EXPECT_EQ("bare", stack.AddNewPrefix("http://a.b.com/bare", false).first); - EXPECT_EQ("z", stack.AddNewPrefix("z", false).first); - EXPECT_FALSE(stack.AddNewPrefix("http://a.b.com/foo.htm", true).second); - EXPECT_FALSE(stack.AddNewPrefix("http://a.b.com/bare", true).second); - EXPECT_FALSE(stack.AddNewPrefix("z", true).second); - EXPECT_FALSE(stack.AddNewPrefix("http://a.b.com/foo.htm", false).second); - EXPECT_FALSE(stack.AddNewPrefix("http://a.b.com/bare", false).second); - EXPECT_FALSE(stack.AddNewPrefix("z", false).second); - - // default namespace usable by non-attributes only - stack.AddXmlns("", "http://my/default"); - EXPECT_FALSE(stack.AddNewPrefix("http://my/default", false).second); - EXPECT_EQ("def", stack.AddNewPrefix("http://my/default", true).first); - - // namespace cannot start with 'xml' - EXPECT_EQ("ns", stack.AddNewPrefix("http://a.b.com/xmltest", true).first); - EXPECT_EQ("ns2", stack.AddNewPrefix("xmlagain", false).first); - - // verify added namespaces are still defined - EXPECT_EQ("http://a.b.com/foo.htm", stack.NsForPrefix("foo").first); - EXPECT_TRUE(stack.NsForPrefix("foo").second); - EXPECT_EQ("http://a.b.com/bare", stack.NsForPrefix("bare").first); - EXPECT_TRUE(stack.NsForPrefix("bare").second); - EXPECT_EQ("z", stack.NsForPrefix("z").first); - EXPECT_TRUE(stack.NsForPrefix("z").second); - EXPECT_EQ("http://my/default", stack.NsForPrefix("").first); - EXPECT_TRUE(stack.NsForPrefix("").second); - EXPECT_EQ("http://my/default", stack.NsForPrefix("def").first); - EXPECT_TRUE(stack.NsForPrefix("def").second); - EXPECT_EQ("http://a.b.com/xmltest", stack.NsForPrefix("ns").first); - EXPECT_TRUE(stack.NsForPrefix("ns").second); - EXPECT_EQ("xmlagain", stack.NsForPrefix("ns2").first); - EXPECT_TRUE(stack.NsForPrefix("ns2").second); -} - -TEST(XmlnsStackTest, TestFormatQName) { - XmlnsStack stack; - stack.AddXmlns("pre1", "ns1"); - stack.AddXmlns("pre2", "ns2"); - stack.AddXmlns("pre1", "ns3"); - stack.AddXmlns("", "ns4"); - - EXPECT_EQ("zip", - stack.FormatQName(QName("ns1", "zip"), false)); // no match - EXPECT_EQ("pre2:abracadabra", - stack.FormatQName(QName("ns2", "abracadabra"), false)); - EXPECT_EQ("pre1:a", - stack.FormatQName(QName("ns3", "a"), false)); - EXPECT_EQ("simple", - stack.FormatQName(QName("ns4", "simple"), false)); - EXPECT_EQ("root", - stack.FormatQName(QName("", "root"), false)); // no match - - EXPECT_EQ("zip", - stack.FormatQName(QName("ns1", "zip"), true)); // no match - EXPECT_EQ("pre2:abracadabra", - stack.FormatQName(QName("ns2", "abracadabra"), true)); - EXPECT_EQ("pre1:a", - stack.FormatQName(QName("ns3", "a"), true)); - EXPECT_EQ("simple", - stack.FormatQName(QName("ns4", "simple"), true)); // no match - EXPECT_EQ("root", - stack.FormatQName(QName("", "root"), true)); -} diff --git a/talk/xmllite/xmlparser.cc b/talk/xmllite/xmlparser.cc deleted file mode 100755 index c985b1f11..000000000 --- a/talk/xmllite/xmlparser.cc +++ /dev/null @@ -1,278 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "talk/xmllite/xmlparser.h" - -#include <string> -#include <vector> - -#include "talk/xmllite/xmlconstants.h" -#include "talk/xmllite/xmlelement.h" -#include "talk/xmllite/xmlnsstack.h" -#include "talk/xmllite/xmlnsstack.h" -#include "webrtc/base/common.h" - -namespace buzz { - - -static void -StartElementCallback(void * userData, const char *name, const char **atts) { - (static_cast<XmlParser *>(userData))->ExpatStartElement(name, atts); -} - -static void -EndElementCallback(void * userData, const char *name) { - (static_cast<XmlParser *>(userData))->ExpatEndElement(name); -} - -static void -CharacterDataCallback(void * userData, const char *text, int len) { - (static_cast<XmlParser *>(userData))->ExpatCharacterData(text, len); -} - -static void -XmlDeclCallback(void * userData, const char * ver, const char * enc, int st) { - (static_cast<XmlParser *>(userData))->ExpatXmlDecl(ver, enc, st); -} - -XmlParser::XmlParser(XmlParseHandler *pxph) : - pxph_(pxph), sentError_(false) { - expat_ = XML_ParserCreate(NULL); - XML_SetUserData(expat_, this); - XML_SetElementHandler(expat_, StartElementCallback, EndElementCallback); - XML_SetCharacterDataHandler(expat_, CharacterDataCallback); - XML_SetXmlDeclHandler(expat_, XmlDeclCallback); -} - -void -XmlParser::Reset() { - if (!XML_ParserReset(expat_, NULL)) { - XML_ParserFree(expat_); - expat_ = XML_ParserCreate(NULL); - } - XML_SetUserData(expat_, this); - XML_SetElementHandler(expat_, StartElementCallback, EndElementCallback); - XML_SetCharacterDataHandler(expat_, CharacterDataCallback); - XML_SetXmlDeclHandler(expat_, XmlDeclCallback); - context_.Reset(); - sentError_ = false; -} - -static bool -XmlParser_StartsWithXmlns(const char *name) { - return name[0] == 'x' && - name[1] == 'm' && - name[2] == 'l' && - name[3] == 'n' && - name[4] == 's'; -} - -void -XmlParser::ExpatStartElement(const char *name, const char **atts) { - if (context_.RaisedError() != XML_ERROR_NONE) - return; - const char **att; - context_.StartElement(); - for (att = atts; *att; att += 2) { - if (XmlParser_StartsWithXmlns(*att)) { - if ((*att)[5] == '\0') { - context_.StartNamespace("", *(att + 1)); - } - else if ((*att)[5] == ':') { - if (**(att + 1) == '\0') { - // In XML 1.0 empty namespace illegal with prefix (not in 1.1) - context_.RaiseError(XML_ERROR_SYNTAX); - return; - } - context_.StartNamespace((*att) + 6, *(att + 1)); - } - } - } - context_.SetPosition(XML_GetCurrentLineNumber(expat_), - XML_GetCurrentColumnNumber(expat_), - XML_GetCurrentByteIndex(expat_)); - pxph_->StartElement(&context_, name, atts); -} - -void -XmlParser::ExpatEndElement(const char *name) { - if (context_.RaisedError() != XML_ERROR_NONE) - return; - context_.EndElement(); - context_.SetPosition(XML_GetCurrentLineNumber(expat_), - XML_GetCurrentColumnNumber(expat_), - XML_GetCurrentByteIndex(expat_)); - pxph_->EndElement(&context_, name); -} - -void -XmlParser::ExpatCharacterData(const char *text, int len) { - if (context_.RaisedError() != XML_ERROR_NONE) - return; - context_.SetPosition(XML_GetCurrentLineNumber(expat_), - XML_GetCurrentColumnNumber(expat_), - XML_GetCurrentByteIndex(expat_)); - pxph_->CharacterData(&context_, text, len); -} - -void -XmlParser::ExpatXmlDecl(const char * ver, const char * enc, int standalone) { - if (context_.RaisedError() != XML_ERROR_NONE) - return; - - if (ver && std::string("1.0") != ver) { - context_.RaiseError(XML_ERROR_SYNTAX); - return; - } - - if (standalone == 0) { - context_.RaiseError(XML_ERROR_SYNTAX); - return; - } - - if (enc && !((enc[0] == 'U' || enc[0] == 'u') && - (enc[1] == 'T' || enc[1] == 't') && - (enc[2] == 'F' || enc[2] == 'f') && - enc[3] == '-' && enc[4] =='8')) { - context_.RaiseError(XML_ERROR_INCORRECT_ENCODING); - return; - } - -} - -bool -XmlParser::Parse(const char *data, size_t len, bool isFinal) { - if (sentError_) - return false; - - if (XML_Parse(expat_, data, static_cast<int>(len), isFinal) != - XML_STATUS_OK) { - context_.SetPosition(XML_GetCurrentLineNumber(expat_), - XML_GetCurrentColumnNumber(expat_), - XML_GetCurrentByteIndex(expat_)); - context_.RaiseError(XML_GetErrorCode(expat_)); - } - - if (context_.RaisedError() != XML_ERROR_NONE) { - sentError_ = true; - pxph_->Error(&context_, context_.RaisedError()); - return false; - } - - return true; -} - -XmlParser::~XmlParser() { - XML_ParserFree(expat_); -} - -void -XmlParser::ParseXml(XmlParseHandler *pxph, std::string text) { - XmlParser parser(pxph); - parser.Parse(text.c_str(), text.length(), true); -} - -XmlParser::ParseContext::ParseContext() : - xmlnsstack_(), - raised_(XML_ERROR_NONE), - line_number_(0), - column_number_(0), - byte_index_(0) { -} - -void -XmlParser::ParseContext::StartNamespace(const char *prefix, const char *ns) { - xmlnsstack_.AddXmlns(*prefix ? prefix : STR_EMPTY, ns); -} - -void -XmlParser::ParseContext::StartElement() { - xmlnsstack_.PushFrame(); -} - -void -XmlParser::ParseContext::EndElement() { - xmlnsstack_.PopFrame(); -} - -QName -XmlParser::ParseContext::ResolveQName(const char* qname, bool isAttr) { - const char *c; - for (c = qname; *c; ++c) { - if (*c == ':') { - const std::pair<std::string, bool> result = - xmlnsstack_.NsForPrefix(std::string(qname, c - qname)); - if (!result.second) - return QName(); - return QName(result.first, c + 1); - } - } - if (isAttr) - return QName(STR_EMPTY, qname); - - std::pair<std::string, bool> result = xmlnsstack_.NsForPrefix(STR_EMPTY); - if (!result.second) - return QName(); - - return QName(result.first, qname); -} - -void -XmlParser::ParseContext::Reset() { - xmlnsstack_.Reset(); - raised_ = XML_ERROR_NONE; -} - -void -XmlParser::ParseContext::SetPosition(int line, int column, - long byte_index) { - line_number_ = line; - column_number_ = column; - byte_index_ = byte_index; -} - -void -XmlParser::ParseContext::GetPosition(unsigned long * line, - unsigned long * column, - unsigned long * byte_index) { - if (line != NULL) { - *line = static_cast<unsigned long>(line_number_); - } - - if (column != NULL) { - *column = static_cast<unsigned long>(column_number_); - } - - if (byte_index != NULL) { - *byte_index = static_cast<unsigned long>(byte_index_); - } -} - -XmlParser::ParseContext::~ParseContext() { -} - -} // namespace buzz diff --git a/talk/xmllite/xmlparser.h b/talk/xmllite/xmlparser.h deleted file mode 100755 index 4a79858e4..000000000 --- a/talk/xmllite/xmlparser.h +++ /dev/null @@ -1,120 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef TALK_XMLLITE_XMLPARSER_H_ -#define TALK_XMLLITE_XMLPARSER_H_ - -#include <string> - -#include "talk/xmllite/xmlnsstack.h" -#ifdef EXPAT_RELATIVE_PATH -#include "expat.h" -#else -#include "third_party/expat/v2_0_1/Source/lib/expat.h" -#endif // EXPAT_RELATIVE_PATH - -struct XML_ParserStruct; -typedef struct XML_ParserStruct* XML_Parser; - -namespace buzz { - -class XmlParseHandler; -class XmlParseContext; -class XmlParser; - -class XmlParseContext { -public: - virtual ~XmlParseContext() {} - virtual QName ResolveQName(const char * qname, bool isAttr) = 0; - virtual void RaiseError(XML_Error err) = 0; - virtual void GetPosition(unsigned long * line, unsigned long * column, - unsigned long * byte_index) = 0; -}; - -class XmlParseHandler { -public: - virtual ~XmlParseHandler() {} - virtual void StartElement(XmlParseContext * pctx, - const char * name, const char ** atts) = 0; - virtual void EndElement(XmlParseContext * pctx, - const char * name) = 0; - virtual void CharacterData(XmlParseContext * pctx, - const char * text, int len) = 0; - virtual void Error(XmlParseContext * pctx, - XML_Error errorCode) = 0; -}; - -class XmlParser { -public: - static void ParseXml(XmlParseHandler * pxph, std::string text); - - explicit XmlParser(XmlParseHandler * pxph); - bool Parse(const char * data, size_t len, bool isFinal); - void Reset(); - virtual ~XmlParser(); - - // expat callbacks - void ExpatStartElement(const char * name, const char ** atts); - void ExpatEndElement(const char * name); - void ExpatCharacterData(const char * text, int len); - void ExpatXmlDecl(const char * ver, const char * enc, int standalone); - -private: - - class ParseContext : public XmlParseContext { - public: - ParseContext(); - virtual ~ParseContext(); - virtual QName ResolveQName(const char * qname, bool isAttr); - virtual void RaiseError(XML_Error err) { if (!raised_) raised_ = err; } - virtual void GetPosition(unsigned long * line, unsigned long * column, - unsigned long * byte_index); - XML_Error RaisedError() { return raised_; } - void Reset(); - - void StartElement(); - void EndElement(); - void StartNamespace(const char * prefix, const char * ns); - void SetPosition(int line, int column, long byte_index); - - private: - XmlnsStack xmlnsstack_; - XML_Error raised_; - XML_Size line_number_; - XML_Size column_number_; - XML_Index byte_index_; - }; - - ParseContext context_; - XML_Parser expat_; - XmlParseHandler * pxph_; - bool sentError_; -}; - -} // namespace buzz - -#endif // TALK_XMLLITE_XMLPARSER_H_ diff --git a/talk/xmllite/xmlparser_unittest.cc b/talk/xmllite/xmlparser_unittest.cc deleted file mode 100755 index 322f8be76..000000000 --- a/talk/xmllite/xmlparser_unittest.cc +++ /dev/null @@ -1,302 +0,0 @@ -/* - * libjingle - * Copyright 2004, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <iostream> -#include <sstream> -#include <string> -#include "talk/xmllite/qname.h" -#include "talk/xmllite/xmlparser.h" -#include "webrtc/base/common.h" -#include "webrtc/base/gunit.h" - -using buzz::QName; -using buzz::XmlParser; -using buzz::XmlParseContext; -using buzz::XmlParseHandler; - -class XmlParserTestHandler : public XmlParseHandler { - public: - virtual void StartElement(XmlParseContext * pctx, - const char * name, const char ** atts) { - ss_ << "START (" << pctx->ResolveQName(name, false).Merged(); - while (*atts) { - ss_ << ", " << pctx->ResolveQName(*atts, true).Merged() - << "='" << *(atts+1) << "'"; - atts += 2; - } - ss_ << ") "; - } - virtual void EndElement(XmlParseContext * pctx, const char * name) { - RTC_UNUSED(pctx); - RTC_UNUSED(name); - ss_ << "END "; - } - virtual void CharacterData(XmlParseContext * pctx, - const char * text, int len) { - RTC_UNUSED(pctx); - ss_ << "TEXT (" << std::string(text, len) << ") "; - } - virtual void Error(XmlParseContext * pctx, XML_Error code) { - RTC_UNUSED(pctx); - ss_ << "ERROR (" << static_cast<int>(code) << ") "; - } - virtual ~XmlParserTestHandler() { - } - - std::string Str() { - return ss_.str(); - } - - std::string StrClear() { - std::string result = ss_.str(); - ss_.str(""); - return result; - } - - private: - std::stringstream ss_; -}; - - -TEST(XmlParserTest, TestTrivial) { - XmlParserTestHandler handler; - XmlParser::ParseXml(&handler, "<testing/>"); - EXPECT_EQ("START (testing) END ", handler.Str()); -} - -TEST(XmlParserTest, TestAttributes) { - { - XmlParserTestHandler handler; - XmlParser::ParseXml(&handler, "<testing a='b'/>"); - EXPECT_EQ("START (testing, a='b') END ", handler.Str()); - } - { - XmlParserTestHandler handler; - XmlParser::ParseXml(&handler, "<testing e='' long='some text'/>"); - EXPECT_EQ("START (testing, e='', long='some text') END ", handler.Str()); - } -} - -TEST(XmlParserTest, TestNesting) { - { - XmlParserTestHandler handler; - XmlParser::ParseXml(&handler, - "<top><first/><second><third></third></second></top>"); - EXPECT_EQ("START (top) START (first) END START (second) START (third) " - "END END END ", handler.Str()); - } - { - XmlParserTestHandler handler; - XmlParser::ParseXml(&handler, "<top><fifth><deeper><and><deeper/></and>" - "<sibling><leaf/></sibling></deeper></fifth><first/><second>" - "<third></third></second></top>"); - EXPECT_EQ("START (top) START (fifth) START (deeper) START (and) START " - "(deeper) END END START (sibling) START (leaf) END END END " - "END START (first) END START (second) START (third) END END END ", - handler.Str()); - } -} - -TEST(XmlParserTest, TestXmlDecl) { - { - XmlParserTestHandler handler; - XmlParser::ParseXml(&handler, "<?xml version=\"1.0\"?><testing/>"); - EXPECT_EQ("START (testing) END ", handler.Str()); - } - { - XmlParserTestHandler handler; - XmlParser::ParseXml(&handler, - "<?xml version=\"1.0\" encoding=\"utf-8\"?><testing/>"); - EXPECT_EQ("START (testing) END ", handler.Str()); - } - { - XmlParserTestHandler handler; - XmlParser::ParseXml(&handler, - "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>" - "<testing/>"); - EXPECT_EQ("START (testing) END ", handler.Str()); - } -} - -TEST(XmlParserTest, TestNamespace) { - { - XmlParserTestHandler handler; - XmlParser::ParseXml(&handler, "<top xmlns='my-namespace' a='b'/>"); - EXPECT_EQ("START (my-namespace:top, xmlns='my-namespace', a='b') END ", - handler.Str()); - } - { - XmlParserTestHandler handler; - XmlParser::ParseXml(&handler, "<foo:top xmlns:foo='my-namespace' " - "a='b' foo:c='d'/>"); - EXPECT_EQ("START (my-namespace:top, " - "http://www.w3.org/2000/xmlns/:foo='my-namespace', " - "a='b', my-namespace:c='d') END ", handler.Str()); - } - { - XmlParserTestHandler handler; - XmlParser::ParseXml(&handler, "<top><nested xmlns='my-namespace'><leaf/>" - "</nested><sibling/></top>"); - EXPECT_EQ("START (top) START (my-namespace:nested, xmlns='my-namespace') " - "START (my-namespace:leaf) END END START (sibling) END END ", - handler.Str()); - } -} - -TEST(XmlParserTest, TestIncremental) { - XmlParserTestHandler handler; - XmlParser parser(&handler); - std::string fragment; - - fragment = "<stream:stream"; - parser.Parse(fragment.c_str(), fragment.length(), false); - EXPECT_EQ("", handler.StrClear()); - - fragment = " id=\"abcdefg\" xmlns=\""; - parser.Parse(fragment.c_str(), fragment.length(), false); - EXPECT_EQ("", handler.StrClear()); - - fragment = "j:c\" xmlns:stream='hm"; - parser.Parse(fragment.c_str(), fragment.length(), false); - EXPECT_EQ("", handler.StrClear()); - - fragment = "ph'><test"; - parser.Parse(fragment.c_str(), fragment.length(), false); - EXPECT_EQ("START (hmph:stream, id='abcdefg', xmlns='j:c', " - "http://www.w3.org/2000/xmlns/:stream='hmph') ", handler.StrClear()); - - fragment = "ing/><again/>abracad"; - parser.Parse(fragment.c_str(), fragment.length(), false); - EXPECT_EQ("START (j:c:testing) END START (j:c:again) END TEXT (abracad) ", - handler.StrClear()); - - fragment = "abra</stream:"; - parser.Parse(fragment.c_str(), fragment.length(), false); - EXPECT_EQ("TEXT (abra) ", handler.StrClear()); - - fragment = "stream>"; - parser.Parse(fragment.c_str(), fragment.length(), false); - EXPECT_EQ("END ", handler.StrClear()); -} - -TEST(XmlParserTest, TestReset) { - { - XmlParserTestHandler handler; - XmlParser parser(&handler); - std::string fragment; - - fragment = "<top><first/><second><third></third>"; - parser.Parse(fragment.c_str(), fragment.length(), false); - EXPECT_EQ("START (top) START (first) END START (second) START (third) END ", - handler.StrClear()); - - parser.Reset(); - fragment = "<tip><first/><second><third></third>"; - parser.Parse(fragment.c_str(), fragment.length(), false); - EXPECT_EQ("START (tip) START (first) END START (second) START (third) END ", - handler.StrClear()); - } - { - XmlParserTestHandler handler; - XmlParser parser(&handler); - std::string fragment; - - fragment = "<top xmlns='m'>"; - parser.Parse(fragment.c_str(), fragment.length(), false); - EXPECT_EQ("START (m:top, xmlns='m') ", handler.StrClear()); - - fragment = "<testing/><frag"; - parser.Parse(fragment.c_str(), fragment.length(), false); - EXPECT_EQ("START (m:testing) END ", handler.StrClear()); - - parser.Reset(); - fragment = "<testing><fragment/"; - parser.Parse(fragment.c_str(), fragment.length(), false); - EXPECT_EQ("START (testing) ", handler.StrClear()); - - fragment = ">"; - parser.Parse(fragment.c_str(), fragment.length(), false); - EXPECT_EQ("START (fragment) END ", handler.StrClear()); - } -} - -TEST(XmlParserTest, TestError) { - { - XmlParserTestHandler handler; - XmlParser::ParseXml(&handler, "junk"); - EXPECT_EQ("ERROR (2) ", handler.Str()); - } - { - XmlParserTestHandler handler; - XmlParser::ParseXml(&handler, "<top/> garbage "); - EXPECT_EQ("START (top) END ERROR (9) ", handler.Str()); - } - { - XmlParserTestHandler handler; - XmlParser::ParseXml(&handler, "<-hm->"); - EXPECT_EQ("ERROR (4) ", handler.Str()); - } - { - XmlParserTestHandler handler; - XmlParser::ParseXml(&handler, "<hello>&foobar;</hello>"); - EXPECT_EQ("START (hello) ERROR (11) ", handler.Str()); - } - { - XmlParserTestHandler handler; - XmlParser::ParseXml(&handler, - "<!DOCTYPE HTML PUBLIC \"foobar\" \"barfoo\">"); - EXPECT_EQ("ERROR (3) ", handler.Str()); - } - { - // XmlParser requires utf-8 - XmlParserTestHandler handler; - XmlParser::ParseXml(&handler, - "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?><test/>"); - EXPECT_EQ("ERROR (19) ", handler.Str()); - } - { - // XmlParser requires version 1.0 - XmlParserTestHandler handler; - XmlParser::ParseXml(&handler, - "<?xml version=\"2.0\"?><test/>"); - EXPECT_EQ("ERROR (2) ", handler.Str()); - } - { - // XmlParser requires standalone documents - XmlParserTestHandler handler; - XmlParser::ParseXml(&handler, - "<?xml version=\"1.0\" standalone=\"no\"?><test/>"); - EXPECT_EQ("ERROR (2) ", handler.Str()); - } - { - // XmlParser doesn't like empty namespace URIs - XmlParserTestHandler handler; - XmlParser::ParseXml(&handler, - "<test xmlns:foo='' foo:bar='huh?'>"); - EXPECT_EQ("ERROR (2) ", handler.Str()); - } -} diff --git a/talk/xmllite/xmlprinter.cc b/talk/xmllite/xmlprinter.cc deleted file mode 100755 index 1350454b8..000000000 --- a/talk/xmllite/xmlprinter.cc +++ /dev/null @@ -1,191 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "talk/xmllite/xmlprinter.h" - -#include <sstream> -#include <string> -#include <vector> - -#include "talk/xmllite/xmlconstants.h" -#include "talk/xmllite/xmlelement.h" -#include "talk/xmllite/xmlnsstack.h" - -namespace buzz { - -class XmlPrinterImpl { -public: - XmlPrinterImpl(std::ostream* pout, XmlnsStack* ns_stack); - void PrintElement(const XmlElement* element); - void PrintQuotedValue(const std::string& text); - void PrintBodyText(const std::string& text); - void PrintCDATAText(const std::string& text); - -private: - std::ostream *pout_; - XmlnsStack* ns_stack_; -}; - -void XmlPrinter::PrintXml(std::ostream* pout, const XmlElement* element) { - XmlnsStack ns_stack; - PrintXml(pout, element, &ns_stack); -} - -void XmlPrinter::PrintXml(std::ostream* pout, const XmlElement* element, - XmlnsStack* ns_stack) { - XmlPrinterImpl printer(pout, ns_stack); - printer.PrintElement(element); -} - -XmlPrinterImpl::XmlPrinterImpl(std::ostream* pout, XmlnsStack* ns_stack) - : pout_(pout), - ns_stack_(ns_stack) { -} - -void XmlPrinterImpl::PrintElement(const XmlElement* element) { - ns_stack_->PushFrame(); - - // first go through attrs of pel to add xmlns definitions - const XmlAttr* attr; - for (attr = element->FirstAttr(); attr; attr = attr->NextAttr()) { - if (attr->Name() == QN_XMLNS) { - ns_stack_->AddXmlns(STR_EMPTY, attr->Value()); - } else if (attr->Name().Namespace() == NS_XMLNS) { - ns_stack_->AddXmlns(attr->Name().LocalPart(), - attr->Value()); - } - } - - // then go through qnames to make sure needed xmlns definitons are added - std::vector<std::string> new_ns; - std::pair<std::string, bool> prefix; - prefix = ns_stack_->AddNewPrefix(element->Name().Namespace(), false); - if (prefix.second) { - new_ns.push_back(prefix.first); - new_ns.push_back(element->Name().Namespace()); - } - - for (attr = element->FirstAttr(); attr; attr = attr->NextAttr()) { - prefix = ns_stack_->AddNewPrefix(attr->Name().Namespace(), true); - if (prefix.second) { - new_ns.push_back(prefix.first); - new_ns.push_back(attr->Name().Namespace()); - } - } - - // print the element name - *pout_ << '<' << ns_stack_->FormatQName(element->Name(), false); - - // and the attributes - for (attr = element->FirstAttr(); attr; attr = attr->NextAttr()) { - *pout_ << ' ' << ns_stack_->FormatQName(attr->Name(), true) << "=\""; - PrintQuotedValue(attr->Value()); - *pout_ << '"'; - } - - // and the extra xmlns declarations - std::vector<std::string>::iterator i(new_ns.begin()); - while (i < new_ns.end()) { - if (*i == STR_EMPTY) { - *pout_ << " xmlns=\"" << *(i + 1) << '"'; - } else { - *pout_ << " xmlns:" << *i << "=\"" << *(i + 1) << '"'; - } - i += 2; - } - - // now the children - const XmlChild* child = element->FirstChild(); - - if (child == NULL) - *pout_ << "/>"; - else { - *pout_ << '>'; - while (child) { - if (child->IsText()) { - if (element->IsCDATA()) { - PrintCDATAText(child->AsText()->Text()); - } else { - PrintBodyText(child->AsText()->Text()); - } - } else { - PrintElement(child->AsElement()); - } - child = child->NextChild(); - } - *pout_ << "</" << ns_stack_->FormatQName(element->Name(), false) << '>'; - } - - ns_stack_->PopFrame(); -} - -void XmlPrinterImpl::PrintQuotedValue(const std::string& text) { - size_t safe = 0; - for (;;) { - size_t unsafe = text.find_first_of("<>&\"", safe); - if (unsafe == std::string::npos) - unsafe = text.length(); - *pout_ << text.substr(safe, unsafe - safe); - if (unsafe == text.length()) - return; - switch (text[unsafe]) { - case '<': *pout_ << "<"; break; - case '>': *pout_ << ">"; break; - case '&': *pout_ << "&"; break; - case '"': *pout_ << """; break; - } - safe = unsafe + 1; - if (safe == text.length()) - return; - } -} - -void XmlPrinterImpl::PrintBodyText(const std::string& text) { - size_t safe = 0; - for (;;) { - size_t unsafe = text.find_first_of("<>&", safe); - if (unsafe == std::string::npos) - unsafe = text.length(); - *pout_ << text.substr(safe, unsafe - safe); - if (unsafe == text.length()) - return; - switch (text[unsafe]) { - case '<': *pout_ << "<"; break; - case '>': *pout_ << ">"; break; - case '&': *pout_ << "&"; break; - } - safe = unsafe + 1; - if (safe == text.length()) - return; - } -} - -void XmlPrinterImpl::PrintCDATAText(const std::string& text) { - *pout_ << "<![CDATA[" << text << "]]>"; -} - -} // namespace buzz diff --git a/talk/xmllite/xmlprinter.h b/talk/xmllite/xmlprinter.h deleted file mode 100755 index 90cc255b7..000000000 --- a/talk/xmllite/xmlprinter.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef TALK_XMLLITE_XMLPRINTER_H_ -#define TALK_XMLLITE_XMLPRINTER_H_ - -#include <iosfwd> -#include <string> - -namespace buzz { - -class XmlElement; -class XmlnsStack; - -class XmlPrinter { - public: - static void PrintXml(std::ostream* pout, const XmlElement* pelt); - - static void PrintXml(std::ostream* pout, const XmlElement* pelt, - XmlnsStack* ns_stack); -}; - -} // namespace buzz - -#endif // TALK_XMLLITE_XMLPRINTER_H_ diff --git a/talk/xmllite/xmlprinter_unittest.cc b/talk/xmllite/xmlprinter_unittest.cc deleted file mode 100755 index 7100025dd..000000000 --- a/talk/xmllite/xmlprinter_unittest.cc +++ /dev/null @@ -1,62 +0,0 @@ -/* - * libjingle - * Copyright 2004, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "talk/xmllite/xmlprinter.h" - -#include <sstream> -#include <string> - -#include "talk/xmllite/qname.h" -#include "talk/xmllite/xmlelement.h" -#include "talk/xmllite/xmlnsstack.h" -#include "webrtc/base/common.h" -#include "webrtc/base/gunit.h" - -using buzz::QName; -using buzz::XmlElement; -using buzz::XmlnsStack; -using buzz::XmlPrinter; - -TEST(XmlPrinterTest, TestBasicPrinting) { - XmlElement elt(QName("google:test", "first")); - std::stringstream ss; - XmlPrinter::PrintXml(&ss, &elt); - EXPECT_EQ("<test:first xmlns:test=\"google:test\"/>", ss.str()); -} - -TEST(XmlPrinterTest, TestNamespacedPrinting) { - XmlElement elt(QName("google:test", "first")); - elt.AddElement(new XmlElement(QName("nested:test", "second"))); - std::stringstream ss; - - XmlnsStack ns_stack; - ns_stack.AddXmlns("gg", "google:test"); - ns_stack.AddXmlns("", "nested:test"); - - XmlPrinter::PrintXml(&ss, &elt, &ns_stack); - EXPECT_EQ("<gg:first><second/></gg:first>", ss.str()); -} diff --git a/talk/xmpp/asyncsocket.h b/talk/xmpp/asyncsocket.h deleted file mode 100644 index 2514742c9..000000000 --- a/talk/xmpp/asyncsocket.h +++ /dev/null @@ -1,89 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef TALK_XMPP_ASYNCSOCKET_H_ -#define TALK_XMPP_ASYNCSOCKET_H_ - -#include <string> - -#include "webrtc/base/sigslot.h" - -namespace rtc { - class SocketAddress; -} - -namespace buzz { - -class AsyncSocket { -public: - enum State { - STATE_CLOSED = 0, //!< Socket is not open. - STATE_CLOSING, //!< Socket is closing but can have buffered data - STATE_CONNECTING, //!< In the process of - STATE_OPEN, //!< Socket is connected -#if defined(FEATURE_ENABLE_SSL) - STATE_TLS_CONNECTING, //!< Establishing TLS connection - STATE_TLS_OPEN, //!< TLS connected -#endif - }; - - enum Error { - ERROR_NONE = 0, //!< No error - ERROR_WINSOCK, //!< Winsock error - ERROR_DNS, //!< Couldn't resolve host name - ERROR_WRONGSTATE, //!< Call made while socket is in the wrong state -#if defined(FEATURE_ENABLE_SSL) - ERROR_SSL, //!< Something went wrong with OpenSSL -#endif - }; - - virtual ~AsyncSocket() {} - virtual State state() = 0; - virtual Error error() = 0; - virtual int GetError() = 0; // winsock error code - - virtual bool Connect(const rtc::SocketAddress& addr) = 0; - virtual bool Read(char * data, size_t len, size_t* len_read) = 0; - virtual bool Write(const char * data, size_t len) = 0; - virtual bool Close() = 0; -#if defined(FEATURE_ENABLE_SSL) - // We allow matching any passed domain. This allows us to avoid - // handling the valuable certificates for logins into proxies. If - // both names are passed as empty, we do not require a match. - virtual bool StartTls(const std::string & domainname) = 0; -#endif - - sigslot::signal0<> SignalConnected; - sigslot::signal0<> SignalSSLConnected; - sigslot::signal0<> SignalClosed; - sigslot::signal0<> SignalRead; - sigslot::signal0<> SignalError; -}; - -} - -#endif // TALK_XMPP_ASYNCSOCKET_H_ diff --git a/talk/xmpp/chatroommodule.h b/talk/xmpp/chatroommodule.h deleted file mode 100644 index 145ab89c1..000000000 --- a/talk/xmpp/chatroommodule.h +++ /dev/null @@ -1,270 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef TALK_XMPP_CHATROOMMODULE_H_ -#define TALK_XMPP_CHATROOMMODULE_H_ - -#include "webrtc/libjingle/xmpp/module.h" -#include "webrtc/libjingle/xmpp/rostermodule.h" - -namespace buzz { - -// forward declarations -class XmppChatroomModule; -class XmppChatroomHandler; -class XmppChatroomMember; -class XmppChatroomMemberEnumerator; - -enum XmppChatroomState { - XMPP_CHATROOM_STATE_NOT_IN_ROOM = 0, - XMPP_CHATROOM_STATE_REQUESTED_ENTER = 1, - XMPP_CHATROOM_STATE_IN_ROOM = 2, - XMPP_CHATROOM_STATE_REQUESTED_EXIT = 3, -}; - -//! Module that encapsulates a chatroom. -class XmppChatroomModule : public XmppModule { -public: - - //! Creates a new XmppChatroomModule - static XmppChatroomModule* Create(); - virtual ~XmppChatroomModule() {} - - //! Sets the chatroom handler (callbacks) for the chatroom - virtual XmppReturnStatus set_chatroom_handler(XmppChatroomHandler* handler) = 0; - - //! Gets the chatroom handler for the module - virtual XmppChatroomHandler* chatroom_handler() = 0; - - //! Sets the jid of the chatroom. - //! Has to be set before entering the chatroom and can't be changed - //! while in the chatroom - virtual XmppReturnStatus set_chatroom_jid(const Jid& chatroom_jid) = 0; - - //! The jid for the chatroom - virtual const Jid& chatroom_jid() const = 0; - - //! Sets the nickname of the member - //! Has to be set before entering the chatroom and can't be changed - //! while in the chatroom - virtual XmppReturnStatus set_nickname(const std::string& nickname) = 0; - - //! The nickname of the member in the chatroom - virtual const std::string& nickname() const = 0; - - //! Returns the jid of the member (this is the chatroom_jid plus the - //! nickname as the resource name) - virtual const Jid member_jid() const = 0; - - //! Requests that the user enter a chatroom - //! The EnterChatroom callback will be called when the request is complete. - //! Password should be empty for a room that doesn't require a password - //! If the room doesn't exist, the server will create an "Instant Room" if the - //! server policy supports this action. - //! There will be different methods for creating/configuring a "Reserved Room" - //! Async callback for this method is ChatroomEnteredStatus - virtual XmppReturnStatus RequestEnterChatroom(const std::string& password, - const std::string& client_version, - const std::string& locale) = 0; - - //! Requests that the user exit a chatroom - //! Async callback for this method is ChatroomExitedStatus - virtual XmppReturnStatus RequestExitChatroom() = 0; - - //! Requests a status change - //! status is the standard XMPP status code - //! extended_status is the extended status when status is XMPP_PRESENCE_XA - virtual XmppReturnStatus RequestConnectionStatusChange( - XmppPresenceConnectionStatus connection_status) = 0; - - //! Returns the number of members in the room - virtual size_t GetChatroomMemberCount() = 0; - - //! Gets an enumerator for the members in the chatroom - //! The caller must delete the enumerator when the caller is finished with it. - //! The caller must also ensure that the lifetime of the enumerator is - //! scoped by the XmppChatRoomModule that created it. - virtual XmppReturnStatus CreateMemberEnumerator(XmppChatroomMemberEnumerator** enumerator) = 0; - - //! Gets the subject of the chatroom - virtual const std::string subject() = 0; - - //! Returns the current state of the user with respect to the chatroom - virtual XmppChatroomState state() = 0; - - virtual XmppReturnStatus SendMessage(const XmlElement& message) = 0; -}; - -//! Class for enumerating participatns -class XmppChatroomMemberEnumerator { -public: - virtual ~XmppChatroomMemberEnumerator() { } - //! Returns the member at the current position - //! Returns null if the enumerator is before the beginning - //! or after the end of the collection - virtual XmppChatroomMember* current() = 0; - - //! Returns whether the enumerator is valid - //! This returns true if the collection has changed - //! since the enumerator was created - virtual bool IsValid() = 0; - - //! Returns whether the enumerator is before the beginning - //! This is the initial state of the enumerator - virtual bool IsBeforeBeginning() = 0; - - //! Returns whether the enumerator is after the end - virtual bool IsAfterEnd() = 0; - - //! Advances the enumerator to the next position - //! Returns false is the enumerator is advanced - //! off the end of the collection - virtual bool Next() = 0; - - //! Advances the enumerator to the previous position - //! Returns false is the enumerator is advanced - //! off the end of the collection - virtual bool Prev() = 0; -}; - - -//! Represents a single member in a chatroom -class XmppChatroomMember { -public: - virtual ~XmppChatroomMember() { } - - //! The jid for the member in the chatroom - virtual const Jid member_jid() const = 0; - - //! The full jid for the member - //! This is only available in non-anonymous rooms. - //! If the room is anonymous, this returns JID_EMPTY - virtual const Jid full_jid() const = 0; - - //! Returns the backing presence for this member - virtual const XmppPresence* presence() const = 0; - - //! The nickname for this member - virtual const std::string name() const = 0; -}; - -//! Status codes for ChatroomEnteredStatus callback -enum XmppChatroomEnteredStatus -{ - //! User successfully entered the room - XMPP_CHATROOM_ENTERED_SUCCESS = 0, - //! The nickname confliced with somebody already in the room - XMPP_CHATROOM_ENTERED_FAILURE_NICKNAME_CONFLICT = 1, - //! A password is required to enter the room - XMPP_CHATROOM_ENTERED_FAILURE_PASSWORD_REQUIRED = 2, - //! The specified password was incorrect - XMPP_CHATROOM_ENTERED_FAILURE_PASSWORD_INCORRECT = 3, - //! The user is not a member of a member-only room - XMPP_CHATROOM_ENTERED_FAILURE_NOT_A_MEMBER = 4, - //! The user cannot enter because the user has been banned - XMPP_CHATROOM_ENTERED_FAILURE_MEMBER_BANNED = 5, - //! The room has the maximum number of users already - XMPP_CHATROOM_ENTERED_FAILURE_MAX_USERS = 6, - //! The room has been locked by an administrator - XMPP_CHATROOM_ENTERED_FAILURE_ROOM_LOCKED = 7, - //! Someone in the room has blocked you - XMPP_CHATROOM_ENTERED_FAILURE_MEMBER_BLOCKED = 8, - //! You have blocked someone in the room - XMPP_CHATROOM_ENTERED_FAILURE_MEMBER_BLOCKING = 9, - //! Client is old. User must upgrade to a more recent version for - // hangouts to work. - XMPP_CHATROOM_ENTERED_FAILURE_OUTDATED_CLIENT = 10, - //! Some other reason - XMPP_CHATROOM_ENTERED_FAILURE_UNSPECIFIED = 2000, -}; - -//! Status codes for ChatroomExitedStatus callback -enum XmppChatroomExitedStatus -{ - //! The user requested to exit and did so - XMPP_CHATROOM_EXITED_REQUESTED = 0, - //! The user was banned from the room - XMPP_CHATROOM_EXITED_BANNED = 1, - //! The user has been kicked out of the room - XMPP_CHATROOM_EXITED_KICKED = 2, - //! The user has been removed from the room because the - //! user is no longer a member of a member-only room - //! or the room has changed to membership-only - XMPP_CHATROOM_EXITED_NOT_A_MEMBER = 3, - //! The system is shutting down - XMPP_CHATROOM_EXITED_SYSTEM_SHUTDOWN = 4, - //! For some other reason - XMPP_CHATROOM_EXITED_UNSPECIFIED = 5, -}; - -//! The XmppChatroomHandler is the interface for callbacks from the -//! the chatroom -class XmppChatroomHandler { -public: - virtual ~XmppChatroomHandler() {} - - //! Indicates the response to RequestEnterChatroom method - //! XMPP_CHATROOM_SUCCESS represents success. - //! Other status codes are for errors - virtual void ChatroomEnteredStatus(XmppChatroomModule* room, - const XmppPresence* presence, - XmppChatroomEnteredStatus status) = 0; - - - //! Indicates that the user has exited the chatroom, either due to - //! a call to RequestExitChatroom or for some other reason. - //! status indicates the reason the user exited - virtual void ChatroomExitedStatus(XmppChatroomModule* room, - XmppChatroomExitedStatus status) = 0; - - //! Indicates a member entered the room. - //! It can be called before ChatroomEnteredStatus. - virtual void MemberEntered(XmppChatroomModule* room, - const XmppChatroomMember* entered_member) = 0; - - //! Indicates that a member exited the room. - virtual void MemberExited(XmppChatroomModule* room, - const XmppChatroomMember* exited_member) = 0; - - //! Indicates that the data for the member has changed - //! (such as the nickname or presence) - virtual void MemberChanged(XmppChatroomModule* room, - const XmppChatroomMember* changed_member) = 0; - - //! Indicates a new message has been received - //! message is the message - - // $TODO - message should be changed - //! to a strongly-typed message class that contains info - //! such as the sender, message bodies, etc., - virtual void MessageReceived(XmppChatroomModule* room, - const XmlElement& message) = 0; -}; - - -} - -#endif // TALK_XMPP_CHATROOMMODULE_H_ diff --git a/talk/xmpp/chatroommodule_unittest.cc b/talk/xmpp/chatroommodule_unittest.cc deleted file mode 100644 index 400a2dd8e..000000000 --- a/talk/xmpp/chatroommodule_unittest.cc +++ /dev/null @@ -1,297 +0,0 @@ -/* - * libjingle - * Copyright 2004, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <iostream> -#include <sstream> -#include <string> -#include "buzz/chatroommodule.h" -#include "buzz/constants.h" -#include "buzz/xmlelement.h" -#include "buzz/xmppengine.h" -#include "common/common.h" -#include "engine/util_unittest.h" -#include "test/unittest-inl.h" -#include "test/unittest.h" - -#define TEST_OK(x) TEST_EQ((x),XMPP_RETURN_OK) -#define TEST_BADARGUMENT(x) TEST_EQ((x),XMPP_RETURN_BADARGUMENT) - -namespace buzz { - -class MultiUserChatModuleTest; - -static void -WriteEnteredStatus(std::ostream& os, XmppChatroomEnteredStatus status) { - switch(status) { - case XMPP_CHATROOM_ENTERED_SUCCESS: - os<<"success"; - break; - case XMPP_CHATROOM_ENTERED_FAILURE_NICKNAME_CONFLICT: - os<<"failure(nickname conflict)"; - break; - case XMPP_CHATROOM_ENTERED_FAILURE_PASSWORD_REQUIRED: - os<<"failure(password required)"; - break; - case XMPP_CHATROOM_ENTERED_FAILURE_PASSWORD_INCORRECT: - os<<"failure(password incorrect)"; - break; - case XMPP_CHATROOM_ENTERED_FAILURE_NOT_A_MEMBER: - os<<"failure(not a member)"; - break; - case XMPP_CHATROOM_ENTERED_FAILURE_MEMBER_BANNED: - os<<"failure(member banned)"; - break; - case XMPP_CHATROOM_ENTERED_FAILURE_MAX_USERS: - os<<"failure(max users)"; - break; - case XMPP_CHATROOM_ENTERED_FAILURE_ROOM_LOCKED: - os<<"failure(room locked)"; - break; - case XMPP_CHATROOM_ENTERED_FAILURE_UNSPECIFIED: - os<<"failure(unspecified)"; - break; - default: - os<<"unknown"; - break; - } -} - -static void -WriteExitedStatus(std::ostream& os, XmppChatroomExitedStatus status) { - switch (status) { - case XMPP_CHATROOM_EXITED_REQUESTED: - os<<"requested"; - break; - case XMPP_CHATROOM_EXITED_BANNED: - os<<"banned"; - break; - case XMPP_CHATROOM_EXITED_KICKED: - os<<"kicked"; - break; - case XMPP_CHATROOM_EXITED_NOT_A_MEMBER: - os<<"not member"; - break; - case XMPP_CHATROOM_EXITED_SYSTEM_SHUTDOWN: - os<<"system shutdown"; - break; - case XMPP_CHATROOM_EXITED_UNSPECIFIED: - os<<"unspecified"; - break; - default: - os<<"unknown"; - break; - } -} - -//! This session handler saves all calls to a string. These are events and -//! data delivered form the engine to application code. -class XmppTestChatroomHandler : public XmppChatroomHandler { -public: - XmppTestChatroomHandler() {} - virtual ~XmppTestChatroomHandler() {} - - void ChatroomEnteredStatus(XmppChatroomModule* room, - XmppChatroomEnteredStatus status) { - RTC_UNUSED(room); - ss_ <<"[ChatroomEnteredStatus status: "; - WriteEnteredStatus(ss_, status); - ss_ <<"]"; - } - - - void ChatroomExitedStatus(XmppChatroomModule* room, - XmppChatroomExitedStatus status) { - RTC_UNUSED(room); - ss_ <<"[ChatroomExitedStatus status: "; - WriteExitedStatus(ss_, status); - ss_ <<"]"; - } - - void MemberEntered(XmppChatroomModule* room, - const XmppChatroomMember* entered_member) { - RTC_UNUSED(room); - ss_ << "[MemberEntered " << entered_member->member_jid().Str() << "]"; - } - - void MemberExited(XmppChatroomModule* room, - const XmppChatroomMember* exited_member) { - RTC_UNUSED(room); - ss_ << "[MemberExited " << exited_member->member_jid().Str() << "]"; - } - - void MemberChanged(XmppChatroomModule* room, - const XmppChatroomMember* changed_member) { - RTC_UNUSED(room); - ss_ << "[MemberChanged " << changed_member->member_jid().Str() << "]"; - } - - virtual void MessageReceived(XmppChatroomModule* room, const XmlElement& message) { - RTC_UNUSED2(room, message); - } - - - std::string Str() { - return ss_.str(); - } - - std::string StrClear() { - std::string result = ss_.str(); - ss_.str(""); - return result; - } - -private: - std::stringstream ss_; -}; - -//! This is the class that holds all of the unit test code for the -//! roster module -class XmppChatroomModuleTest : public UnitTest { -public: - XmppChatroomModuleTest() {} - - void TestEnterExitChatroom() { - std::stringstream dump; - - // Configure the engine - scoped_ptr<XmppEngine> engine(XmppEngine::Create()); - XmppTestHandler handler(engine.get()); - - // Configure the module and handler - scoped_ptr<XmppChatroomModule> chatroom(XmppChatroomModule::Create()); - - // Configure the module handler - chatroom->RegisterEngine(engine.get()); - - // Set up callbacks - engine->SetOutputHandler(&handler); - engine->AddStanzaHandler(&handler); - engine->SetSessionHandler(&handler); - - // Set up minimal login info - engine->SetUser(Jid("david@my-server")); - engine->SetPassword("david"); - - // Do the whole login handshake - RunLogin(this, engine.get(), &handler); - TEST_EQ("", handler.OutputActivity()); - - // Get the chatroom and set the handler - XmppTestChatroomHandler chatroom_handler; - chatroom->set_chatroom_handler(static_cast<XmppChatroomHandler*>(&chatroom_handler)); - - // try to enter the chatroom - TEST_EQ(chatroom->state(), XMPP_CHATROOM_STATE_NOT_IN_ROOM); - chatroom->set_nickname("thirdwitch"); - chatroom->set_chatroom_jid(Jid("darkcave@my-server")); - chatroom->RequestEnterChatroom("", XMPP_CONNECTION_STATUS_UNKNOWN, "en"); - TEST_EQ(chatroom_handler.StrClear(), ""); - TEST_EQ(handler.OutputActivity(), - "<presence to=\"darkcave@my-server/thirdwitch\">" - "<muc:x xmlns:muc=\"http://jabber.org/protocol/muc\"/>" - "</presence>"); - TEST_EQ(chatroom->state(), XMPP_CHATROOM_STATE_REQUESTED_ENTER); - - // simulate the server and test the client - std::string input; - input = "<presence from=\"darkcave@my-server/firstwitch\" to=\"david@my-server\">" - "<x xmlns=\"http://jabber.org/protocol/muc#user\">" - "<item affiliation=\"owner\" role=\"participant\"/>" - "</x>" - "</presence>"; - TEST_OK(engine->HandleInput(input.c_str(), input.length())); - TEST_EQ(chatroom_handler.StrClear(), ""); - TEST_EQ(chatroom->state(), XMPP_CHATROOM_STATE_REQUESTED_ENTER); - - input = "<presence from=\"darkcave@my-server/secondwitch\" to=\"david@my-server\">" - "<x xmlns=\"http://jabber.org/protocol/muc#user\">" - "<item affiliation=\"member\" role=\"participant\"/>" - "</x>" - "</presence>"; - TEST_OK(engine->HandleInput(input.c_str(), input.length())); - TEST_EQ(chatroom_handler.StrClear(), ""); - TEST_EQ(chatroom->state(), XMPP_CHATROOM_STATE_REQUESTED_ENTER); - - input = "<presence from=\"darkcave@my-server/thirdwitch\" to=\"david@my-server\">" - "<x xmlns=\"http://jabber.org/protocol/muc#user\">" - "<item affiliation=\"member\" role=\"participant\"/>" - "</x>" - "</presence>"; - TEST_OK(engine->HandleInput(input.c_str(), input.length())); - TEST_EQ(chatroom_handler.StrClear(), - "[ChatroomEnteredStatus status: success]"); - TEST_EQ(chatroom->state(), XMPP_CHATROOM_STATE_IN_ROOM); - - // simulate somebody else entering the room after we entered - input = "<presence from=\"darkcave@my-server/fourthwitch\" to=\"david@my-server\">" - "<x xmlns=\"http://jabber.org/protocol/muc#user\">" - "<item affiliation=\"member\" role=\"participant\"/>" - "</x>" - "</presence>"; - TEST_OK(engine->HandleInput(input.c_str(), input.length())); - TEST_EQ(chatroom_handler.StrClear(), "[MemberEntered darkcave@my-server/fourthwitch]"); - TEST_EQ(chatroom->state(), XMPP_CHATROOM_STATE_IN_ROOM); - - // simulate somebody else leaving the room after we entered - input = "<presence from=\"darkcave@my-server/secondwitch\" to=\"david@my-server\" type=\"unavailable\">" - "<x xmlns=\"http://jabber.org/protocol/muc#user\">" - "<item affiliation=\"member\" role=\"participant\"/>" - "</x>" - "</presence>"; - TEST_OK(engine->HandleInput(input.c_str(), input.length())); - TEST_EQ(chatroom_handler.StrClear(), "[MemberExited darkcave@my-server/secondwitch]"); - TEST_EQ(chatroom->state(), XMPP_CHATROOM_STATE_IN_ROOM); - - // try to leave the room - chatroom->RequestExitChatroom(); - TEST_EQ(chatroom_handler.StrClear(), ""); - TEST_EQ(handler.OutputActivity(), - "<presence to=\"darkcave@my-server/thirdwitch\" type=\"unavailable\"/>"); - TEST_EQ(chatroom->state(), XMPP_CHATROOM_STATE_REQUESTED_EXIT); - - // simulate the server and test the client - input = "<presence from=\"darkcave@my-server/thirdwitch\" to=\"david@my-server\" type=\"unavailable\">" - "<x xmlns=\"http://jabber.org/protocol/muc#user\">" - "<item affiliation=\"member\" role=\"participant\"/>" - "</x>" - "</presence>"; - TEST_OK(engine->HandleInput(input.c_str(), input.length())); - TEST_EQ(chatroom_handler.StrClear(), - "[ChatroomExitedStatus status: requested]"); - TEST_EQ(chatroom->state(), XMPP_CHATROOM_STATE_NOT_IN_ROOM); - } - -}; - -// A global function that creates the test suite for this set of tests. -TestBase* ChatroomModuleTest_Create() { - TestSuite* suite = new TestSuite("ChatroomModuleTest"); - ADD_TEST(suite, XmppChatroomModuleTest, TestEnterExitChatroom); - return suite; -} - -} diff --git a/talk/xmpp/chatroommoduleimpl.cc b/talk/xmpp/chatroommoduleimpl.cc deleted file mode 100644 index 33c752e85..000000000 --- a/talk/xmpp/chatroommoduleimpl.cc +++ /dev/null @@ -1,752 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <algorithm> -#include <iostream> -#include <map> -#include <sstream> -#include <string> -#include <vector> -#include "webrtc/libjingle/xmpp/chatroommodule.h" -#include "webrtc/libjingle/xmpp/constants.h" -#include "webrtc/libjingle/xmpp/moduleimpl.h" -#include "webrtc/base/common.h" - -namespace buzz { - -// forward declarations -class XmppChatroomImpl; -class XmppChatroomMemberImpl; - -//! Module that encapsulates multiple chatrooms. -//! Each chatroom is represented by an XmppChatroomImpl instance -class XmppChatroomModuleImpl : public XmppChatroomModule, - public XmppModuleImpl, public XmppIqHandler { -public: - IMPLEMENT_XMPPMODULE - - // Creates a chatroom with specified Jid - XmppChatroomModuleImpl(); - ~XmppChatroomModuleImpl(); - - // XmppChatroomModule - virtual XmppReturnStatus set_chatroom_handler(XmppChatroomHandler* handler); - virtual XmppChatroomHandler* chatroom_handler(); - virtual XmppReturnStatus set_chatroom_jid(const Jid& chatroom_jid); - virtual const Jid& chatroom_jid() const; - virtual XmppReturnStatus set_nickname(const std::string& nickname); - virtual const std::string& nickname() const; - virtual const Jid member_jid() const; - virtual XmppReturnStatus RequestEnterChatroom(const std::string& password, - const std::string& client_version, - const std::string& locale); - virtual XmppReturnStatus RequestExitChatroom(); - virtual XmppReturnStatus RequestConnectionStatusChange( - XmppPresenceConnectionStatus connection_status); - virtual size_t GetChatroomMemberCount(); - virtual XmppReturnStatus CreateMemberEnumerator(XmppChatroomMemberEnumerator** enumerator); - virtual const std::string subject(); - virtual XmppChatroomState state() { return chatroom_state_; } - virtual XmppReturnStatus SendMessage(const XmlElement& message); - - // XmppModule - virtual void IqResponse(XmppIqCookie cookie, const XmlElement * pelStanza) {RTC_UNUSED2(cookie, pelStanza);} - virtual bool HandleStanza(const XmlElement *); - -private: - friend class XmppChatroomMemberEnumeratorImpl; - - XmppReturnStatus ServerChangeMyPresence(const XmlElement& presence); - XmppReturnStatus ClientChangeMyPresence(XmppChatroomState new_state); - XmppReturnStatus ChangePresence(XmppChatroomState new_state, const XmlElement* presence, bool isServer); - XmppReturnStatus ServerChangedOtherPresence(const XmlElement& presence_element); - XmppChatroomEnteredStatus GetEnterFailureFromXml(const XmlElement* presence); - XmppChatroomExitedStatus GetExitFailureFromXml(const XmlElement* presence); - - bool CheckEnterChatroomStateOk(); - - void FireEnteredStatus(const XmlElement* presence, - XmppChatroomEnteredStatus status); - void FireExitStatus(XmppChatroomExitedStatus status); - void FireMessageReceived(const XmlElement& message); - void FireMemberEntered(const XmppChatroomMember* entered_member); - void FireMemberChanged(const XmppChatroomMember* changed_member); - void FireMemberExited(const XmppChatroomMember* exited_member); - - - typedef std::map<Jid, XmppChatroomMemberImpl*> JidMemberMap; - - XmppChatroomHandler* chatroom_handler_; - Jid chatroom_jid_; - std::string nickname_; - XmppChatroomState chatroom_state_; - JidMemberMap chatroom_jid_members_; - int chatroom_jid_members_version_; -}; - - -class XmppChatroomMemberImpl : public XmppChatroomMember { -public: - ~XmppChatroomMemberImpl() {} - XmppReturnStatus SetPresence(const XmppPresence* presence); - - // XmppChatroomMember - const Jid member_jid() const; - const Jid full_jid() const; - const std::string name() const; - const XmppPresence* presence() const; - -private: - rtc::scoped_ptr<XmppPresence> presence_; -}; - -class XmppChatroomMemberEnumeratorImpl : - public XmppChatroomMemberEnumerator { -public: - XmppChatroomMemberEnumeratorImpl(XmppChatroomModuleImpl::JidMemberMap* chatroom_jid_members, - int* map_version); - - // XmppChatroomMemberEnumerator - virtual XmppChatroomMember* current(); - virtual bool Next(); - virtual bool Prev(); - virtual bool IsValid(); - virtual bool IsBeforeBeginning(); - virtual bool IsAfterEnd(); - -private: - XmppChatroomModuleImpl::JidMemberMap* map_; - int map_version_created_; - int* map_version_; - XmppChatroomModuleImpl::JidMemberMap::iterator iterator_; - bool before_beginning_; -}; - - -// XmppChatroomModuleImpl ------------------------------------------------ -XmppChatroomModule * -XmppChatroomModule::Create() { - return new XmppChatroomModuleImpl(); -} - -XmppChatroomModuleImpl::XmppChatroomModuleImpl() : - chatroom_handler_(NULL), - chatroom_jid_(STR_EMPTY), - chatroom_state_(XMPP_CHATROOM_STATE_NOT_IN_ROOM), - chatroom_jid_members_version_(0) { -} - -XmppChatroomModuleImpl::~XmppChatroomModuleImpl() { - JidMemberMap::iterator iterator = chatroom_jid_members_.begin(); - while (iterator != chatroom_jid_members_.end()) { - delete iterator->second; - iterator++; - } -} - - -bool -XmppChatroomModuleImpl::HandleStanza(const XmlElement* stanza) { - ASSERT(engine() != NULL); - - // we handle stanzas that are for one of our chatrooms - Jid from_jid = Jid(stanza->Attr(QN_FROM)); - // see if it's one of our chatrooms - if (chatroom_jid_ != from_jid.BareJid()) { - return false; // not one of our chatrooms - } else { - // handle presence stanza - if (stanza->Name() == QN_PRESENCE) { - if (from_jid == member_jid()) { - ServerChangeMyPresence(*stanza); - } else { - ServerChangedOtherPresence(*stanza); - } - } else if (stanza->Name() == QN_MESSAGE) { - FireMessageReceived(*stanza); - } - return true; - } -} - - -XmppReturnStatus -XmppChatroomModuleImpl::set_chatroom_handler(XmppChatroomHandler* handler) { - // Calling with NULL removes the handler. - chatroom_handler_ = handler; - return XMPP_RETURN_OK; -} - - -XmppChatroomHandler* -XmppChatroomModuleImpl::chatroom_handler() { - return chatroom_handler_; -} - -XmppReturnStatus -XmppChatroomModuleImpl::set_chatroom_jid(const Jid& chatroom_jid) { - if (chatroom_state_ != XMPP_CHATROOM_STATE_NOT_IN_ROOM) { - return XMPP_RETURN_BADSTATE; // $TODO - this isn't a bad state, it's a bad call, diff error code? - } - if (chatroom_jid != chatroom_jid.BareJid()) { - // chatroom_jid must be a bare jid - return XMPP_RETURN_BADARGUMENT; - } - - chatroom_jid_ = chatroom_jid; - return XMPP_RETURN_OK; -} - -const Jid& -XmppChatroomModuleImpl::chatroom_jid() const { - return chatroom_jid_; -} - - XmppReturnStatus - XmppChatroomModuleImpl::set_nickname(const std::string& nickname) { - if (chatroom_state_ != XMPP_CHATROOM_STATE_NOT_IN_ROOM) { - return XMPP_RETURN_BADSTATE; // $TODO - this isn't a bad state, it's a bad call, diff error code? - } - nickname_ = nickname; - return XMPP_RETURN_OK; - } - - const std::string& - XmppChatroomModuleImpl::nickname() const { - return nickname_; - } - -const Jid -XmppChatroomModuleImpl::member_jid() const { - return Jid(chatroom_jid_.node(), chatroom_jid_.domain(), nickname_); -} - - -bool -XmppChatroomModuleImpl::CheckEnterChatroomStateOk() { - if (chatroom_jid_.IsValid() == false) { - ASSERT(0); - return false; - } - if (nickname_ == STR_EMPTY) { - ASSERT(0); - return false; - } - return true; -} - -std::string GetAttrValueFor(XmppPresenceConnectionStatus connection_status) { - switch (connection_status) { - default: - case XMPP_CONNECTION_STATUS_UNKNOWN: - return ""; - case XMPP_CONNECTION_STATUS_CONNECTING: - return STR_PSTN_CONFERENCE_STATUS_CONNECTING; - case XMPP_CONNECTION_STATUS_CONNECTED: - return STR_PSTN_CONFERENCE_STATUS_CONNECTED; - } -} - -XmppReturnStatus -XmppChatroomModuleImpl::RequestEnterChatroom( - const std::string& password, - const std::string& client_version, - const std::string& locale) { - RTC_UNUSED(password); - if (!engine()) - return XMPP_RETURN_BADSTATE; - - if (chatroom_state_ != XMPP_CHATROOM_STATE_NOT_IN_ROOM) - return XMPP_RETURN_BADSTATE; // $TODO - this isn't a bad state, it's a bad call, diff error code? - - if (CheckEnterChatroomStateOk() == false) { - return XMPP_RETURN_BADSTATE; - } - - // entering a chatroom is a presence request to the server - XmlElement element(QN_PRESENCE); - element.AddAttr(QN_TO, member_jid().Str()); - - XmlElement* muc_x = new XmlElement(QN_MUC_X); - element.AddElement(muc_x); - - if (!client_version.empty()) { - XmlElement* client_version_element = new XmlElement(QN_CLIENT_VERSION, - false); - client_version_element->SetBodyText(client_version); - muc_x->AddElement(client_version_element); - } - - if (!locale.empty()) { - XmlElement* locale_element = new XmlElement(QN_LOCALE, false); - - locale_element->SetBodyText(locale); - muc_x->AddElement(locale_element); - } - - XmppReturnStatus status = engine()->SendStanza(&element); - if (status == XMPP_RETURN_OK) { - return ClientChangeMyPresence(XMPP_CHATROOM_STATE_REQUESTED_ENTER); - } - return status; -} - -XmppReturnStatus -XmppChatroomModuleImpl::RequestExitChatroom() { - if (!engine()) - return XMPP_RETURN_BADSTATE; - - // exiting a chatroom is a presence request to the server - XmlElement element(QN_PRESENCE); - element.AddAttr(QN_TO, member_jid().Str()); - element.AddAttr(QN_TYPE, "unavailable"); - XmppReturnStatus status = engine()->SendStanza(&element); - if (status == XMPP_RETURN_OK && - chatroom_state_ == XMPP_CHATROOM_STATE_IN_ROOM) { - return ClientChangeMyPresence(XMPP_CHATROOM_STATE_REQUESTED_EXIT); - } - return status; -} - -XmppReturnStatus -XmppChatroomModuleImpl::RequestConnectionStatusChange( - XmppPresenceConnectionStatus connection_status) { - if (!engine()) - return XMPP_RETURN_BADSTATE; - - if (chatroom_state_ != XMPP_CHATROOM_STATE_IN_ROOM) { - // $TODO - this isn't a bad state, it's a bad call, diff error code? - return XMPP_RETURN_BADSTATE; - } - - if (CheckEnterChatroomStateOk() == false) { - return XMPP_RETURN_BADSTATE; - } - - // entering a chatroom is a presence request to the server - XmlElement element(QN_PRESENCE); - element.AddAttr(QN_TO, member_jid().Str()); - element.AddElement(new XmlElement(QN_MUC_X)); - if (connection_status != XMPP_CONNECTION_STATUS_UNKNOWN) { - XmlElement* con_status_element = - new XmlElement(QN_GOOGLE_PSTN_CONFERENCE_STATUS); - con_status_element->AddAttr(QN_STATUS, GetAttrValueFor(connection_status)); - element.AddElement(con_status_element); - } - XmppReturnStatus status = engine()->SendStanza(&element); - - return status; -} - -size_t -XmppChatroomModuleImpl::GetChatroomMemberCount() { - return chatroom_jid_members_.size(); -} - -XmppReturnStatus -XmppChatroomModuleImpl::CreateMemberEnumerator(XmppChatroomMemberEnumerator** enumerator) { - *enumerator = new XmppChatroomMemberEnumeratorImpl(&chatroom_jid_members_, &chatroom_jid_members_version_); - return XMPP_RETURN_OK; -} - -const std::string -XmppChatroomModuleImpl::subject() { - return ""; //NYI -} - -XmppReturnStatus -XmppChatroomModuleImpl::SendMessage(const XmlElement& message) { - XmppReturnStatus xmpp_status = XMPP_RETURN_OK; - - // can only send a message if we're in the room - if (chatroom_state_ != XMPP_CHATROOM_STATE_IN_ROOM) { - return XMPP_RETURN_BADSTATE; // $TODO - this isn't a bad state, it's a bad call, diff error code? - } - - if (message.Name() != QN_MESSAGE) { - IFR(XMPP_RETURN_BADARGUMENT); - } - - const std::string& type = message.Attr(QN_TYPE); - if (type != "groupchat") { - IFR(XMPP_RETURN_BADARGUMENT); - } - - if (message.HasAttr(QN_FROM)) { - IFR(XMPP_RETURN_BADARGUMENT); - } - - if (message.Attr(QN_TO) != chatroom_jid_.Str()) { - IFR(XMPP_RETURN_BADARGUMENT); - } - - IFR(engine()->SendStanza(&message)); - - return xmpp_status; -} - -enum TransitionType { - TRANSITION_TYPE_NONE = 0, - TRANSITION_TYPE_ENTER_SUCCESS = 1, - TRANSITION_TYPE_ENTER_FAILURE = 2, - TRANSITION_TYPE_EXIT_VOLUNTARILY = 3, - TRANSITION_TYPE_EXIT_INVOLUNTARILY = 4, -}; - -struct StateTransitionDescription { - XmppChatroomState old_state; - XmppChatroomState new_state; - bool is_valid_server_transition; - bool is_valid_client_transition; - TransitionType transition_type; -}; - -StateTransitionDescription Transitions[] = { - { XMPP_CHATROOM_STATE_NOT_IN_ROOM, XMPP_CHATROOM_STATE_REQUESTED_ENTER, false, true, TRANSITION_TYPE_NONE, }, - { XMPP_CHATROOM_STATE_NOT_IN_ROOM, XMPP_CHATROOM_STATE_IN_ROOM, false, false, TRANSITION_TYPE_ENTER_SUCCESS, }, - { XMPP_CHATROOM_STATE_NOT_IN_ROOM, XMPP_CHATROOM_STATE_REQUESTED_EXIT, false, false, TRANSITION_TYPE_NONE, }, - { XMPP_CHATROOM_STATE_REQUESTED_ENTER, XMPP_CHATROOM_STATE_NOT_IN_ROOM, true, false, TRANSITION_TYPE_ENTER_FAILURE, }, - { XMPP_CHATROOM_STATE_REQUESTED_ENTER, XMPP_CHATROOM_STATE_IN_ROOM, true, false, TRANSITION_TYPE_ENTER_SUCCESS, }, - { XMPP_CHATROOM_STATE_REQUESTED_ENTER, XMPP_CHATROOM_STATE_REQUESTED_EXIT, false, false, TRANSITION_TYPE_NONE, }, - { XMPP_CHATROOM_STATE_IN_ROOM, XMPP_CHATROOM_STATE_NOT_IN_ROOM, true, false, TRANSITION_TYPE_EXIT_INVOLUNTARILY, }, - { XMPP_CHATROOM_STATE_IN_ROOM, XMPP_CHATROOM_STATE_REQUESTED_ENTER, false, false, TRANSITION_TYPE_NONE, }, - { XMPP_CHATROOM_STATE_IN_ROOM, XMPP_CHATROOM_STATE_REQUESTED_EXIT, false, true, TRANSITION_TYPE_NONE, }, - { XMPP_CHATROOM_STATE_REQUESTED_EXIT, XMPP_CHATROOM_STATE_NOT_IN_ROOM, true, false, TRANSITION_TYPE_EXIT_VOLUNTARILY, }, - { XMPP_CHATROOM_STATE_REQUESTED_EXIT, XMPP_CHATROOM_STATE_REQUESTED_ENTER, false, false, TRANSITION_TYPE_NONE, }, - { XMPP_CHATROOM_STATE_REQUESTED_EXIT, XMPP_CHATROOM_STATE_IN_ROOM, false, false, TRANSITION_TYPE_NONE, }, -}; - - - -void -XmppChatroomModuleImpl::FireEnteredStatus(const XmlElement* presence, - XmppChatroomEnteredStatus status) { - if (chatroom_handler_) { - rtc::scoped_ptr<XmppPresence> xmpp_presence(XmppPresence::Create()); - xmpp_presence->set_raw_xml(presence); - chatroom_handler_->ChatroomEnteredStatus(this, xmpp_presence.get(), status); - } -} - -void -XmppChatroomModuleImpl::FireExitStatus(XmppChatroomExitedStatus status) { - if (chatroom_handler_) - chatroom_handler_->ChatroomExitedStatus(this, status); -} - -void -XmppChatroomModuleImpl::FireMessageReceived(const XmlElement& message) { - if (chatroom_handler_) - chatroom_handler_->MessageReceived(this, message); -} - -void -XmppChatroomModuleImpl::FireMemberEntered(const XmppChatroomMember* entered_member) { - if (chatroom_handler_) - chatroom_handler_->MemberEntered(this, entered_member); -} - -void -XmppChatroomModuleImpl::FireMemberChanged( - const XmppChatroomMember* changed_member) { - if (chatroom_handler_) - chatroom_handler_->MemberChanged(this, changed_member); -} - -void -XmppChatroomModuleImpl::FireMemberExited(const XmppChatroomMember* exited_member) { - if (chatroom_handler_) - chatroom_handler_->MemberExited(this, exited_member); -} - - -XmppReturnStatus -XmppChatroomModuleImpl::ServerChangedOtherPresence(const XmlElement& - presence_element) { - XmppReturnStatus xmpp_status = XMPP_RETURN_OK; - rtc::scoped_ptr<XmppPresence> presence(XmppPresence::Create()); - IFR(presence->set_raw_xml(&presence_element)); - - JidMemberMap::iterator pos = chatroom_jid_members_.find(presence->jid()); - - if (pos == chatroom_jid_members_.end()) { - if (presence->available() == XMPP_PRESENCE_AVAILABLE) { - XmppChatroomMemberImpl* member = new XmppChatroomMemberImpl(); - member->SetPresence(presence.get()); - chatroom_jid_members_.insert(std::make_pair(member->member_jid(), member)); - chatroom_jid_members_version_++; - FireMemberEntered(member); - } - } else { - XmppChatroomMemberImpl* member = pos->second; - if (presence->available() == XMPP_PRESENCE_AVAILABLE) { - member->SetPresence(presence.get()); - chatroom_jid_members_version_++; - FireMemberChanged(member); - } - else if (presence->available() == XMPP_PRESENCE_UNAVAILABLE) { - member->SetPresence(presence.get()); - chatroom_jid_members_.erase(pos); - chatroom_jid_members_version_++; - FireMemberExited(member); - delete member; - } - } - - return xmpp_status; -} - -XmppReturnStatus -XmppChatroomModuleImpl::ClientChangeMyPresence(XmppChatroomState new_state) { - return ChangePresence(new_state, NULL, false); -} - -XmppReturnStatus -XmppChatroomModuleImpl::ServerChangeMyPresence(const XmlElement& presence) { - XmppChatroomState new_state; - - if (presence.HasAttr(QN_TYPE) == false) { - new_state = XMPP_CHATROOM_STATE_IN_ROOM; - } else { - new_state = XMPP_CHATROOM_STATE_NOT_IN_ROOM; - } - return ChangePresence(new_state, &presence, true); - -} - -XmppReturnStatus -XmppChatroomModuleImpl::ChangePresence(XmppChatroomState new_state, - const XmlElement* presence, - bool isServer) { - RTC_UNUSED(presence); - - XmppChatroomState old_state = chatroom_state_; - - // do nothing if state hasn't changed - if (old_state == new_state) - return XMPP_RETURN_OK; - - // find the right transition description - StateTransitionDescription* transition_desc = NULL; - for (int i=0; i < ARRAY_SIZE(Transitions); i++) { - if (Transitions[i].old_state == old_state && - Transitions[i].new_state == new_state) { - transition_desc = &Transitions[i]; - break; - } - } - - if (transition_desc == NULL) { - ASSERT(0); - return XMPP_RETURN_BADSTATE; - } - - // we assert for any invalid transition states, and we'll - if (isServer) { - // $TODO send original stanza back to server and log an error? - // Disable the assert because of b/6133072 - // ASSERT(transition_desc->is_valid_server_transition); - if (!transition_desc->is_valid_server_transition) { - return XMPP_RETURN_BADSTATE; - } - } else { - if (transition_desc->is_valid_client_transition == false) { - ASSERT(0); - return XMPP_RETURN_BADARGUMENT; - } - } - - // set the new state and then fire any notifications to the handler - chatroom_state_ = new_state; - - switch (transition_desc->transition_type) { - case TRANSITION_TYPE_ENTER_SUCCESS: - FireEnteredStatus(presence, XMPP_CHATROOM_ENTERED_SUCCESS); - break; - case TRANSITION_TYPE_ENTER_FAILURE: - FireEnteredStatus(presence, GetEnterFailureFromXml(presence)); - break; - case TRANSITION_TYPE_EXIT_INVOLUNTARILY: - FireExitStatus(GetExitFailureFromXml(presence)); - break; - case TRANSITION_TYPE_EXIT_VOLUNTARILY: - FireExitStatus(XMPP_CHATROOM_EXITED_REQUESTED); - break; - case TRANSITION_TYPE_NONE: - break; - } - - return XMPP_RETURN_OK; -} - -XmppChatroomEnteredStatus -XmppChatroomModuleImpl::GetEnterFailureFromXml(const XmlElement* presence) { - XmppChatroomEnteredStatus status = XMPP_CHATROOM_ENTERED_FAILURE_UNSPECIFIED; - const XmlElement* error = presence->FirstNamed(QN_ERROR); - if (error != NULL && error->HasAttr(QN_CODE)) { - int code = atoi(error->Attr(QN_CODE).c_str()); - switch (code) { - case 401: status = XMPP_CHATROOM_ENTERED_FAILURE_PASSWORD_REQUIRED; break; - case 403: { - status = XMPP_CHATROOM_ENTERED_FAILURE_MEMBER_BANNED; - if (error->FirstNamed(QN_GOOGLE_SESSION_BLOCKED)) { - status = XMPP_CHATROOM_ENTERED_FAILURE_MEMBER_BLOCKED; - } else if (error->FirstNamed(QN_GOOGLE_SESSION_BLOCKING)) { - status = XMPP_CHATROOM_ENTERED_FAILURE_MEMBER_BLOCKING; - } - break; - } - case 405: status = XMPP_CHATROOM_ENTERED_FAILURE_ROOM_LOCKED; break; - case 406: status = XMPP_CHATROOM_ENTERED_FAILURE_OUTDATED_CLIENT; break; - case 407: status = XMPP_CHATROOM_ENTERED_FAILURE_NOT_A_MEMBER; break; - case 409: status = XMPP_CHATROOM_ENTERED_FAILURE_NICKNAME_CONFLICT; break; - // http://xmpp.org/extensions/xep-0045.html#enter-maxusers - case 503: status = XMPP_CHATROOM_ENTERED_FAILURE_MAX_USERS; break; - } - } - return status; -} - -XmppChatroomExitedStatus -XmppChatroomModuleImpl::GetExitFailureFromXml(const XmlElement* presence) { - XmppChatroomExitedStatus status = XMPP_CHATROOM_EXITED_UNSPECIFIED; - const XmlElement* muc_user = presence->FirstNamed(QN_MUC_USER_X); - if (muc_user != NULL) { - const XmlElement* user_status = muc_user->FirstNamed(QN_MUC_USER_STATUS); - if (user_status != NULL && user_status->HasAttr(QN_CODE)) { - int code = atoi(user_status->Attr(QN_CODE).c_str()); - switch (code) { - case 307: status = XMPP_CHATROOM_EXITED_KICKED; break; - case 322: status = XMPP_CHATROOM_EXITED_NOT_A_MEMBER; break; - case 332: status = XMPP_CHATROOM_EXITED_SYSTEM_SHUTDOWN; break; - } - } - } - return status; -} - -XmppReturnStatus -XmppChatroomMemberImpl::SetPresence(const XmppPresence* presence) { - ASSERT(presence != NULL); - - // copy presence - presence_.reset(XmppPresence::Create()); - presence_->set_raw_xml(presence->raw_xml()); - return XMPP_RETURN_OK; -} - -const Jid -XmppChatroomMemberImpl::member_jid() const { - return presence_->jid(); -} - -const Jid -XmppChatroomMemberImpl::full_jid() const { - return Jid(""); -} - -const std::string -XmppChatroomMemberImpl::name() const { - return member_jid().resource(); -} - -const XmppPresence* -XmppChatroomMemberImpl::presence() const { - return presence_.get(); -} - - -// XmppChatroomMemberEnumeratorImpl -------------------------------------- -XmppChatroomMemberEnumeratorImpl::XmppChatroomMemberEnumeratorImpl( - XmppChatroomModuleImpl::JidMemberMap* map, int* map_version) { - map_ = map; - map_version_ = map_version; - map_version_created_ = *map_version_; - iterator_ = map->begin(); - before_beginning_ = true; -} - -XmppChatroomMember* -XmppChatroomMemberEnumeratorImpl::current() { - if (IsValid() == false) { - return NULL; - } else if (IsBeforeBeginning() || IsAfterEnd()) { - return NULL; - } else { - return iterator_->second; - } -} - -bool -XmppChatroomMemberEnumeratorImpl::Prev() { - if (IsValid() == false) { - return false; - } else if (IsBeforeBeginning()) { - return false; - } else if (iterator_ == map_->begin()) { - before_beginning_ = true; - return false; - } else { - iterator_--; - return current() != NULL; - } -} - -bool -XmppChatroomMemberEnumeratorImpl::Next() { - if (IsValid() == false) { - return false; - } else if (IsBeforeBeginning()) { - before_beginning_ = false; - iterator_ = map_->begin(); - return current() != NULL; - } else if (IsAfterEnd()) { - return false; - } else { - iterator_++; - return current() != NULL; - } -} - -bool -XmppChatroomMemberEnumeratorImpl::IsValid() { - return map_version_created_ == *map_version_; -} - -bool -XmppChatroomMemberEnumeratorImpl::IsBeforeBeginning() { - return before_beginning_; -} - -bool -XmppChatroomMemberEnumeratorImpl::IsAfterEnd() { - return (iterator_ == map_->end()); -} - - - -} // namespace buzz diff --git a/talk/xmpp/constants.cc b/talk/xmpp/constants.cc deleted file mode 100644 index fce9c75d0..000000000 --- a/talk/xmpp/constants.cc +++ /dev/null @@ -1,631 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "webrtc/libjingle/xmpp/constants.h" - -#include <string> - -#include "webrtc/libjingle/xmllite/qname.h" -#include "webrtc/libjingle/xmllite/xmlconstants.h" -#include "webrtc/libjingle/xmllite/xmlelement.h" -#include "webrtc/libjingle/xmpp/jid.h" -#include "webrtc/base/basicdefs.h" - -namespace buzz { - -// TODO: Remove static objects of complex types, particularly -// Jid and QName. - -const char NS_CLIENT[] = "jabber:client"; -const char NS_SERVER[] = "jabber:server"; -const char NS_STREAM[] = "http://etherx.jabber.org/streams"; -const char NS_XSTREAM[] = "urn:ietf:params:xml:ns:xmpp-streams"; -const char NS_TLS[] = "urn:ietf:params:xml:ns:xmpp-tls"; -const char NS_SASL[] = "urn:ietf:params:xml:ns:xmpp-sasl"; -const char NS_BIND[] = "urn:ietf:params:xml:ns:xmpp-bind"; -const char NS_DIALBACK[] = "jabber:server:dialback"; -const char NS_SESSION[] = "urn:ietf:params:xml:ns:xmpp-session"; -const char NS_STANZA[] = "urn:ietf:params:xml:ns:xmpp-stanzas"; -const char NS_PRIVACY[] = "jabber:iq:privacy"; -const char NS_ROSTER[] = "jabber:iq:roster"; -const char NS_VCARD[] = "vcard-temp"; -const char NS_AVATAR_HASH[] = "google:avatar"; -const char NS_VCARD_UPDATE[] = "vcard-temp:x:update"; -const char STR_CLIENT[] = "client"; -const char STR_SERVER[] = "server"; -const char STR_STREAM[] = "stream"; - -const char STR_GET[] = "get"; -const char STR_SET[] = "set"; -const char STR_RESULT[] = "result"; -const char STR_ERROR[] = "error"; - -const char STR_FORM[] = "form"; -const char STR_SUBMIT[] = "submit"; -const char STR_TEXT_SINGLE[] = "text-single"; -const char STR_LIST_SINGLE[] = "list-single"; -const char STR_LIST_MULTI[] = "list-multi"; -const char STR_HIDDEN[] = "hidden"; -const char STR_FORM_TYPE[] = "FORM_TYPE"; - -const char STR_FROM[] = "from"; -const char STR_TO[] = "to"; -const char STR_BOTH[] = "both"; -const char STR_REMOVE[] = "remove"; -const char STR_TRUE[] = "true"; - -const char STR_TYPE[] = "type"; -const char STR_NAME[] = "name"; -const char STR_ID[] = "id"; -const char STR_JID[] = "jid"; -const char STR_SUBSCRIPTION[] = "subscription"; -const char STR_ASK[] = "ask"; -const char STR_X[] = "x"; -const char STR_GOOGLE_COM[] = "google.com"; -const char STR_GMAIL_COM[] = "gmail.com"; -const char STR_GOOGLEMAIL_COM[] = "googlemail.com"; -const char STR_DEFAULT_DOMAIN[] = "default.talk.google.com"; -const char STR_TALK_GOOGLE_COM[] = "talk.google.com"; -const char STR_TALKX_L_GOOGLE_COM[] = "talkx.l.google.com"; -const char STR_XMPP_GOOGLE_COM[] = "xmpp.google.com"; -const char STR_XMPPX_L_GOOGLE_COM[] = "xmppx.l.google.com"; - -#ifdef FEATURE_ENABLE_VOICEMAIL -const char STR_VOICEMAIL[] = "voicemail"; -const char STR_OUTGOINGVOICEMAIL[] = "outgoingvoicemail"; -#endif - -const char STR_UNAVAILABLE[] = "unavailable"; - -const char NS_PING[] = "urn:xmpp:ping"; -const StaticQName QN_PING = { NS_PING, "ping" }; - -const char NS_MUC_UNIQUE[] = "http://jabber.org/protocol/muc#unique"; -const StaticQName QN_MUC_UNIQUE_QUERY = { NS_MUC_UNIQUE, "unique" }; -const StaticQName QN_HANGOUT_ID = { STR_EMPTY, "hangout-id" }; - -const char STR_GOOGLE_MUC_LOOKUP_JID[] = "lookup.groupchat.google.com"; - -const char STR_MUC_ROOMCONFIG_ROOMNAME[] = "muc#roomconfig_roomname"; -const char STR_MUC_ROOMCONFIG_FEATURES[] = "muc#roomconfig_features"; -const char STR_MUC_ROOM_FEATURE_ENTERPRISE[] = "muc_enterprise"; -const char STR_MUC_ROOMCONFIG[] = "http://jabber.org/protocol/muc#roomconfig"; -const char STR_MUC_ROOM_FEATURE_HANGOUT[] = "muc_es"; -const char STR_MUC_ROOM_FEATURE_HANGOUT_LITE[] = "muc_lite"; -const char STR_MUC_ROOM_FEATURE_BROADCAST[] = "broadcast"; -const char STR_MUC_ROOM_FEATURE_MULTI_USER_VC[] = "muc_muvc"; -const char STR_MUC_ROOM_FEATURE_RECORDABLE[] = "recordable"; -const char STR_MUC_ROOM_FEATURE_CUSTOM_RECORDING[] = "custom_recording"; -const char STR_MUC_ROOM_OWNER_PROFILE_ID[] = "muc#roominfo_owner_profile_id"; -const char STR_MUC_ROOM_FEATURE_ABUSE_RECORDABLE[] = "abuse_recordable"; - -const char STR_ID_TYPE_CONVERSATION[] = "conversation"; -const char NS_GOOGLE_MUC_HANGOUT[] = "google:muc#hangout"; -const StaticQName QN_GOOGLE_MUC_HANGOUT_INVITE = - { NS_GOOGLE_MUC_HANGOUT, "invite" }; -const StaticQName QN_GOOGLE_MUC_HANGOUT_INVITE_TYPE = - { NS_GOOGLE_MUC_HANGOUT, "invite-type" }; -const StaticQName QN_ATTR_CREATE_ACTIVITY = - { STR_EMPTY, "create-activity" }; -const StaticQName QN_GOOGLE_MUC_HANGOUT_PUBLIC = - { NS_GOOGLE_MUC_HANGOUT, "public" }; -const StaticQName QN_GOOGLE_MUC_HANGOUT_INVITEE = - { NS_GOOGLE_MUC_HANGOUT, "invitee" }; -const StaticQName QN_GOOGLE_MUC_HANGOUT_NOTIFICATION_STATUS = - { NS_GOOGLE_MUC_HANGOUT, "notification-status" }; -const StaticQName QN_GOOGLE_MUC_HANGOUT_NOTIFICATION_TYPE = { - NS_GOOGLE_MUC_HANGOUT, "notification-type" }; -const StaticQName QN_GOOGLE_MUC_HANGOUT_HANGOUT_START_CONTEXT = { - NS_GOOGLE_MUC_HANGOUT, "hangout-start-context" }; -const StaticQName QN_GOOGLE_MUC_HANGOUT_CONVERSATION_ID = { - NS_GOOGLE_MUC_HANGOUT, "conversation-id" }; - -const StaticQName QN_STREAM_STREAM = { NS_STREAM, STR_STREAM }; -const StaticQName QN_STREAM_FEATURES = { NS_STREAM, "features" }; -const StaticQName QN_STREAM_ERROR = { NS_STREAM, "error" }; - -const StaticQName QN_XSTREAM_BAD_FORMAT = { NS_XSTREAM, "bad-format" }; -const StaticQName QN_XSTREAM_BAD_NAMESPACE_PREFIX = - { NS_XSTREAM, "bad-namespace-prefix" }; -const StaticQName QN_XSTREAM_CONFLICT = { NS_XSTREAM, "conflict" }; -const StaticQName QN_XSTREAM_CONNECTION_TIMEOUT = - { NS_XSTREAM, "connection-timeout" }; -const StaticQName QN_XSTREAM_HOST_GONE = { NS_XSTREAM, "host-gone" }; -const StaticQName QN_XSTREAM_HOST_UNKNOWN = { NS_XSTREAM, "host-unknown" }; -const StaticQName QN_XSTREAM_IMPROPER_ADDRESSIING = - { NS_XSTREAM, "improper-addressing" }; -const StaticQName QN_XSTREAM_INTERNAL_SERVER_ERROR = - { NS_XSTREAM, "internal-server-error" }; -const StaticQName QN_XSTREAM_INVALID_FROM = { NS_XSTREAM, "invalid-from" }; -const StaticQName QN_XSTREAM_INVALID_ID = { NS_XSTREAM, "invalid-id" }; -const StaticQName QN_XSTREAM_INVALID_NAMESPACE = - { NS_XSTREAM, "invalid-namespace" }; -const StaticQName QN_XSTREAM_INVALID_XML = { NS_XSTREAM, "invalid-xml" }; -const StaticQName QN_XSTREAM_NOT_AUTHORIZED = { NS_XSTREAM, "not-authorized" }; -const StaticQName QN_XSTREAM_POLICY_VIOLATION = - { NS_XSTREAM, "policy-violation" }; -const StaticQName QN_XSTREAM_REMOTE_CONNECTION_FAILED = - { NS_XSTREAM, "remote-connection-failed" }; -const StaticQName QN_XSTREAM_RESOURCE_CONSTRAINT = - { NS_XSTREAM, "resource-constraint" }; -const StaticQName QN_XSTREAM_RESTRICTED_XML = { NS_XSTREAM, "restricted-xml" }; -const StaticQName QN_XSTREAM_SEE_OTHER_HOST = { NS_XSTREAM, "see-other-host" }; -const StaticQName QN_XSTREAM_SYSTEM_SHUTDOWN = - { NS_XSTREAM, "system-shutdown" }; -const StaticQName QN_XSTREAM_UNDEFINED_CONDITION = - { NS_XSTREAM, "undefined-condition" }; -const StaticQName QN_XSTREAM_UNSUPPORTED_ENCODING = - { NS_XSTREAM, "unsupported-encoding" }; -const StaticQName QN_XSTREAM_UNSUPPORTED_STANZA_TYPE = - { NS_XSTREAM, "unsupported-stanza-type" }; -const StaticQName QN_XSTREAM_UNSUPPORTED_VERSION = - { NS_XSTREAM, "unsupported-version" }; -const StaticQName QN_XSTREAM_XML_NOT_WELL_FORMED = - { NS_XSTREAM, "xml-not-well-formed" }; -const StaticQName QN_XSTREAM_TEXT = { NS_XSTREAM, "text" }; - -const StaticQName QN_TLS_STARTTLS = { NS_TLS, "starttls" }; -const StaticQName QN_TLS_REQUIRED = { NS_TLS, "required" }; -const StaticQName QN_TLS_PROCEED = { NS_TLS, "proceed" }; -const StaticQName QN_TLS_FAILURE = { NS_TLS, "failure" }; - -const StaticQName QN_SASL_MECHANISMS = { NS_SASL, "mechanisms" }; -const StaticQName QN_SASL_MECHANISM = { NS_SASL, "mechanism" }; -const StaticQName QN_SASL_AUTH = { NS_SASL, "auth" }; -const StaticQName QN_SASL_CHALLENGE = { NS_SASL, "challenge" }; -const StaticQName QN_SASL_RESPONSE = { NS_SASL, "response" }; -const StaticQName QN_SASL_ABORT = { NS_SASL, "abort" }; -const StaticQName QN_SASL_SUCCESS = { NS_SASL, "success" }; -const StaticQName QN_SASL_FAILURE = { NS_SASL, "failure" }; -const StaticQName QN_SASL_ABORTED = { NS_SASL, "aborted" }; -const StaticQName QN_SASL_INCORRECT_ENCODING = - { NS_SASL, "incorrect-encoding" }; -const StaticQName QN_SASL_INVALID_AUTHZID = { NS_SASL, "invalid-authzid" }; -const StaticQName QN_SASL_INVALID_MECHANISM = { NS_SASL, "invalid-mechanism" }; -const StaticQName QN_SASL_MECHANISM_TOO_WEAK = - { NS_SASL, "mechanism-too-weak" }; -const StaticQName QN_SASL_NOT_AUTHORIZED = { NS_SASL, "not-authorized" }; -const StaticQName QN_SASL_TEMPORARY_AUTH_FAILURE = - { NS_SASL, "temporary-auth-failure" }; - -// These are non-standard. -const char NS_GOOGLE_AUTH_PROTOCOL[] = - "http://www.google.com/talk/protocol/auth"; -const StaticQName QN_GOOGLE_AUTH_CLIENT_USES_FULL_BIND_RESULT = - { NS_GOOGLE_AUTH_PROTOCOL, "client-uses-full-bind-result" }; -const StaticQName QN_GOOGLE_ALLOW_NON_GOOGLE_ID_XMPP_LOGIN = - { NS_GOOGLE_AUTH_PROTOCOL, "allow-non-google-login" }; -const StaticQName QN_GOOGLE_AUTH_SERVICE = - { NS_GOOGLE_AUTH_PROTOCOL, "service" }; - -const StaticQName QN_DIALBACK_RESULT = { NS_DIALBACK, "result" }; -const StaticQName QN_DIALBACK_VERIFY = { NS_DIALBACK, "verify" }; - -const StaticQName QN_STANZA_BAD_REQUEST = { NS_STANZA, "bad-request" }; -const StaticQName QN_STANZA_CONFLICT = { NS_STANZA, "conflict" }; -const StaticQName QN_STANZA_FEATURE_NOT_IMPLEMENTED = - { NS_STANZA, "feature-not-implemented" }; -const StaticQName QN_STANZA_FORBIDDEN = { NS_STANZA, "forbidden" }; -const StaticQName QN_STANZA_GONE = { NS_STANZA, "gone" }; -const StaticQName QN_STANZA_INTERNAL_SERVER_ERROR = - { NS_STANZA, "internal-server-error" }; -const StaticQName QN_STANZA_ITEM_NOT_FOUND = { NS_STANZA, "item-not-found" }; -const StaticQName QN_STANZA_JID_MALFORMED = { NS_STANZA, "jid-malformed" }; -const StaticQName QN_STANZA_NOT_ACCEPTABLE = { NS_STANZA, "not-acceptable" }; -const StaticQName QN_STANZA_NOT_ALLOWED = { NS_STANZA, "not-allowed" }; -const StaticQName QN_STANZA_PAYMENT_REQUIRED = - { NS_STANZA, "payment-required" }; -const StaticQName QN_STANZA_RECIPIENT_UNAVAILABLE = - { NS_STANZA, "recipient-unavailable" }; -const StaticQName QN_STANZA_REDIRECT = { NS_STANZA, "redirect" }; -const StaticQName QN_STANZA_REGISTRATION_REQUIRED = - { NS_STANZA, "registration-required" }; -const StaticQName QN_STANZA_REMOTE_SERVER_NOT_FOUND = - { NS_STANZA, "remote-server-not-found" }; -const StaticQName QN_STANZA_REMOTE_SERVER_TIMEOUT = - { NS_STANZA, "remote-server-timeout" }; -const StaticQName QN_STANZA_RESOURCE_CONSTRAINT = - { NS_STANZA, "resource-constraint" }; -const StaticQName QN_STANZA_SERVICE_UNAVAILABLE = - { NS_STANZA, "service-unavailable" }; -const StaticQName QN_STANZA_SUBSCRIPTION_REQUIRED = - { NS_STANZA, "subscription-required" }; -const StaticQName QN_STANZA_UNDEFINED_CONDITION = - { NS_STANZA, "undefined-condition" }; -const StaticQName QN_STANZA_UNEXPECTED_REQUEST = - { NS_STANZA, "unexpected-request" }; -const StaticQName QN_STANZA_TEXT = { NS_STANZA, "text" }; - -const StaticQName QN_BIND_BIND = { NS_BIND, "bind" }; -const StaticQName QN_BIND_RESOURCE = { NS_BIND, "resource" }; -const StaticQName QN_BIND_JID = { NS_BIND, "jid" }; - -const StaticQName QN_MESSAGE = { NS_CLIENT, "message" }; -const StaticQName QN_BODY = { NS_CLIENT, "body" }; -const StaticQName QN_SUBJECT = { NS_CLIENT, "subject" }; -const StaticQName QN_THREAD = { NS_CLIENT, "thread" }; -const StaticQName QN_PRESENCE = { NS_CLIENT, "presence" }; -const StaticQName QN_SHOW = { NS_CLIENT, "show" }; -const StaticQName QN_STATUS = { NS_CLIENT, "status" }; -const StaticQName QN_LANG = { NS_CLIENT, "lang" }; -const StaticQName QN_PRIORITY = { NS_CLIENT, "priority" }; -const StaticQName QN_IQ = { NS_CLIENT, "iq" }; -const StaticQName QN_ERROR = { NS_CLIENT, "error" }; - -const StaticQName QN_SERVER_MESSAGE = { NS_SERVER, "message" }; -const StaticQName QN_SERVER_BODY = { NS_SERVER, "body" }; -const StaticQName QN_SERVER_SUBJECT = { NS_SERVER, "subject" }; -const StaticQName QN_SERVER_THREAD = { NS_SERVER, "thread" }; -const StaticQName QN_SERVER_PRESENCE = { NS_SERVER, "presence" }; -const StaticQName QN_SERVER_SHOW = { NS_SERVER, "show" }; -const StaticQName QN_SERVER_STATUS = { NS_SERVER, "status" }; -const StaticQName QN_SERVER_LANG = { NS_SERVER, "lang" }; -const StaticQName QN_SERVER_PRIORITY = { NS_SERVER, "priority" }; -const StaticQName QN_SERVER_IQ = { NS_SERVER, "iq" }; -const StaticQName QN_SERVER_ERROR = { NS_SERVER, "error" }; - -const StaticQName QN_SESSION_SESSION = { NS_SESSION, "session" }; - -const StaticQName QN_PRIVACY_QUERY = { NS_PRIVACY, "query" }; -const StaticQName QN_PRIVACY_ACTIVE = { NS_PRIVACY, "active" }; -const StaticQName QN_PRIVACY_DEFAULT = { NS_PRIVACY, "default" }; -const StaticQName QN_PRIVACY_LIST = { NS_PRIVACY, "list" }; -const StaticQName QN_PRIVACY_ITEM = { NS_PRIVACY, "item" }; -const StaticQName QN_PRIVACY_IQ = { NS_PRIVACY, "iq" }; -const StaticQName QN_PRIVACY_MESSAGE = { NS_PRIVACY, "message" }; -const StaticQName QN_PRIVACY_PRESENCE_IN = { NS_PRIVACY, "presence-in" }; -const StaticQName QN_PRIVACY_PRESENCE_OUT = { NS_PRIVACY, "presence-out" }; - -const StaticQName QN_ROSTER_QUERY = { NS_ROSTER, "query" }; -const StaticQName QN_ROSTER_ITEM = { NS_ROSTER, "item" }; -const StaticQName QN_ROSTER_GROUP = { NS_ROSTER, "group" }; - -const StaticQName QN_VCARD = { NS_VCARD, "vCard" }; -const StaticQName QN_VCARD_FN = { NS_VCARD, "FN" }; -const StaticQName QN_VCARD_PHOTO = { NS_VCARD, "PHOTO" }; -const StaticQName QN_VCARD_PHOTO_BINVAL = { NS_VCARD, "BINVAL" }; -const StaticQName QN_VCARD_AVATAR_HASH = { NS_AVATAR_HASH, "hash" }; -const StaticQName QN_VCARD_AVATAR_HASH_MODIFIED = - { NS_AVATAR_HASH, "modified" }; - -const StaticQName QN_NAME = { STR_EMPTY, "name" }; -const StaticQName QN_AFFILIATION = { STR_EMPTY, "affiliation" }; -const StaticQName QN_ROLE = { STR_EMPTY, "role" }; - -#if defined(FEATURE_ENABLE_PSTN) -const StaticQName QN_VCARD_TEL = { NS_VCARD, "TEL" }; -const StaticQName QN_VCARD_VOICE = { NS_VCARD, "VOICE" }; -const StaticQName QN_VCARD_HOME = { NS_VCARD, "HOME" }; -const StaticQName QN_VCARD_WORK = { NS_VCARD, "WORK" }; -const StaticQName QN_VCARD_CELL = { NS_VCARD, "CELL" }; -const StaticQName QN_VCARD_NUMBER = { NS_VCARD, "NUMBER" }; -#endif - -const StaticQName QN_XML_LANG = { NS_XML, "lang" }; - -const StaticQName QN_ENCODING = { STR_EMPTY, STR_ENCODING }; -const StaticQName QN_VERSION = { STR_EMPTY, STR_VERSION }; -const StaticQName QN_TO = { STR_EMPTY, "to" }; -const StaticQName QN_FROM = { STR_EMPTY, "from" }; -const StaticQName QN_TYPE = { STR_EMPTY, "type" }; -const StaticQName QN_ID = { STR_EMPTY, "id" }; -const StaticQName QN_CODE = { STR_EMPTY, "code" }; - -const StaticQName QN_VALUE = { STR_EMPTY, "value" }; -const StaticQName QN_ACTION = { STR_EMPTY, "action" }; -const StaticQName QN_ORDER = { STR_EMPTY, "order" }; -const StaticQName QN_MECHANISM = { STR_EMPTY, "mechanism" }; -const StaticQName QN_ASK = { STR_EMPTY, "ask" }; -const StaticQName QN_JID = { STR_EMPTY, "jid" }; -const StaticQName QN_NICK = { STR_EMPTY, "nick" }; -const StaticQName QN_SUBSCRIPTION = { STR_EMPTY, "subscription" }; -const StaticQName QN_TITLE1 = { STR_EMPTY, "title1" }; -const StaticQName QN_TITLE2 = { STR_EMPTY, "title2" }; - -const StaticQName QN_XMLNS_CLIENT = { NS_XMLNS, STR_CLIENT }; -const StaticQName QN_XMLNS_SERVER = { NS_XMLNS, STR_SERVER }; -const StaticQName QN_XMLNS_STREAM = { NS_XMLNS, STR_STREAM }; - - -// Presence -const char STR_SHOW_AWAY[] = "away"; -const char STR_SHOW_CHAT[] = "chat"; -const char STR_SHOW_DND[] = "dnd"; -const char STR_SHOW_XA[] = "xa"; -const char STR_SHOW_OFFLINE[] = "offline"; - -const char NS_GOOGLE_PSTN_CONFERENCE[] = "http://www.google.com/pstn-conference"; -const StaticQName QN_GOOGLE_PSTN_CONFERENCE_STATUS = { NS_GOOGLE_PSTN_CONFERENCE, "status" }; -const StaticQName QN_ATTR_STATUS = { STR_EMPTY, "status" }; - -// Presence connection status -const char STR_PSTN_CONFERENCE_STATUS_CONNECTING[] = "connecting"; -const char STR_PSTN_CONFERENCE_STATUS_JOINING[] = "joining"; -const char STR_PSTN_CONFERENCE_STATUS_CONNECTED[] = "connected"; -const char STR_PSTN_CONFERENCE_STATUS_HANGUP[] = "hangup"; - -// Subscription -const char STR_SUBSCRIBE[] = "subscribe"; -const char STR_SUBSCRIBED[] = "subscribed"; -const char STR_UNSUBSCRIBE[] = "unsubscribe"; -const char STR_UNSUBSCRIBED[] = "unsubscribed"; - -// Google Invite -const char NS_GOOGLE_SUBSCRIBE[] = "google:subscribe"; -const StaticQName QN_INVITATION = { NS_GOOGLE_SUBSCRIBE, "invitation" }; -const StaticQName QN_INVITE_NAME = { NS_GOOGLE_SUBSCRIBE, "name" }; -const StaticQName QN_INVITE_SUBJECT = { NS_GOOGLE_SUBSCRIBE, "subject" }; -const StaticQName QN_INVITE_MESSAGE = { NS_GOOGLE_SUBSCRIBE, "body" }; - -// Kick -const char NS_GOOGLE_MUC_ADMIN[] = "google:muc#admin"; -const StaticQName QN_GOOGLE_MUC_ADMIN_QUERY = { NS_GOOGLE_MUC_ADMIN, "query" }; -const StaticQName QN_GOOGLE_MUC_ADMIN_QUERY_ITEM = - { NS_GOOGLE_MUC_ADMIN, "item" }; -const StaticQName QN_GOOGLE_MUC_ADMIN_QUERY_ITEM_REASON = - { NS_GOOGLE_MUC_ADMIN, "reason" }; - -// PubSub: http://xmpp.org/extensions/xep-0060.html -const char NS_PUBSUB[] = "http://jabber.org/protocol/pubsub"; -const StaticQName QN_PUBSUB = { NS_PUBSUB, "pubsub" }; -const StaticQName QN_PUBSUB_ITEMS = { NS_PUBSUB, "items" }; -const StaticQName QN_PUBSUB_ITEM = { NS_PUBSUB, "item" }; -const StaticQName QN_PUBSUB_PUBLISH = { NS_PUBSUB, "publish" }; -const StaticQName QN_PUBSUB_RETRACT = { NS_PUBSUB, "retract" }; -const StaticQName QN_ATTR_PUBLISHER = { STR_EMPTY, "publisher" }; - -const char NS_PUBSUB_EVENT[] = "http://jabber.org/protocol/pubsub#event"; -const StaticQName QN_NODE = { STR_EMPTY, "node" }; -const StaticQName QN_PUBSUB_EVENT = { NS_PUBSUB_EVENT, "event" }; -const StaticQName QN_PUBSUB_EVENT_ITEMS = { NS_PUBSUB_EVENT, "items" }; -const StaticQName QN_PUBSUB_EVENT_ITEM = { NS_PUBSUB_EVENT, "item" }; -const StaticQName QN_PUBSUB_EVENT_RETRACT = { NS_PUBSUB_EVENT, "retract" }; -const StaticQName QN_NOTIFY = { STR_EMPTY, "notify" }; - -const char NS_PRESENTER[] = "google:presenter"; -const StaticQName QN_PRESENTER_PRESENTER = { NS_PRESENTER, "presenter" }; -const StaticQName QN_PRESENTER_PRESENTATION_ITEM = - { NS_PRESENTER, "presentation-item" }; -const StaticQName QN_PRESENTER_PRESENTATION_TYPE = - { NS_PRESENTER, "presentation-type" }; -const StaticQName QN_PRESENTER_PRESENTATION_ID = - { NS_PRESENTER, "presentation-id" }; - -// JEP 0030 -const StaticQName QN_CATEGORY = { STR_EMPTY, "category" }; -const StaticQName QN_VAR = { STR_EMPTY, "var" }; -const char NS_DISCO_INFO[] = "http://jabber.org/protocol/disco#info"; -const char NS_DISCO_ITEMS[] = "http://jabber.org/protocol/disco#items"; -const StaticQName QN_DISCO_INFO_QUERY = { NS_DISCO_INFO, "query" }; -const StaticQName QN_DISCO_IDENTITY = { NS_DISCO_INFO, "identity" }; -const StaticQName QN_DISCO_FEATURE = { NS_DISCO_INFO, "feature" }; - -const StaticQName QN_DISCO_ITEMS_QUERY = { NS_DISCO_ITEMS, "query" }; -const StaticQName QN_DISCO_ITEM = { NS_DISCO_ITEMS, "item" }; - -// JEP 0020 -const char NS_FEATURE[] = "http://jabber.org/protocol/feature-neg"; -const StaticQName QN_FEATURE_FEATURE = { NS_FEATURE, "feature" }; - -// JEP 0004 -const char NS_XDATA[] = "jabber:x:data"; -const StaticQName QN_XDATA_X = { NS_XDATA, "x" }; -const StaticQName QN_XDATA_INSTRUCTIONS = { NS_XDATA, "instructions" }; -const StaticQName QN_XDATA_TITLE = { NS_XDATA, "title" }; -const StaticQName QN_XDATA_FIELD = { NS_XDATA, "field" }; -const StaticQName QN_XDATA_REPORTED = { NS_XDATA, "reported" }; -const StaticQName QN_XDATA_ITEM = { NS_XDATA, "item" }; -const StaticQName QN_XDATA_DESC = { NS_XDATA, "desc" }; -const StaticQName QN_XDATA_REQUIRED = { NS_XDATA, "required" }; -const StaticQName QN_XDATA_VALUE = { NS_XDATA, "value" }; -const StaticQName QN_XDATA_OPTION = { NS_XDATA, "option" }; - -// JEP 0045 -const char NS_MUC[] = "http://jabber.org/protocol/muc"; -const StaticQName QN_MUC_X = { NS_MUC, "x" }; -const StaticQName QN_MUC_ITEM = { NS_MUC, "item" }; -const StaticQName QN_MUC_AFFILIATION = { NS_MUC, "affiliation" }; -const StaticQName QN_MUC_ROLE = { NS_MUC, "role" }; -const char STR_AFFILIATION_NONE[] = "none"; -const char STR_ROLE_PARTICIPANT[] = "participant"; - -const char NS_GOOGLE_SESSION[] = "http://www.google.com/session"; -const StaticQName QN_GOOGLE_CIRCLE_ID = { STR_EMPTY, "google-circle-id" }; -const StaticQName QN_GOOGLE_USER_ID = { STR_EMPTY, "google-user-id" }; -const StaticQName QN_GOOGLE_SESSION_BLOCKED = { NS_GOOGLE_SESSION, "blocked" }; -const StaticQName QN_GOOGLE_SESSION_BLOCKING = - { NS_GOOGLE_SESSION, "blocking" }; - -const char NS_MUC_OWNER[] = "http://jabber.org/protocol/muc#owner"; -const StaticQName QN_MUC_OWNER_QUERY = { NS_MUC_OWNER, "query" }; - -const char NS_MUC_USER[] = "http://jabber.org/protocol/muc#user"; -const StaticQName QN_MUC_USER_CONTINUE = { NS_MUC_USER, "continue" }; -const StaticQName QN_MUC_USER_X = { NS_MUC_USER, "x" }; -const StaticQName QN_MUC_USER_ITEM = { NS_MUC_USER, "item" }; -const StaticQName QN_MUC_USER_STATUS = { NS_MUC_USER, "status" }; -const StaticQName QN_MUC_USER_REASON = { NS_MUC_USER, "reason" }; -const StaticQName QN_MUC_USER_ABUSE_VIOLATION = { NS_MUC_USER, "abuse-violation" }; - -// JEP 0055 - Jabber Search -const char NS_SEARCH[] = "jabber:iq:search"; -const StaticQName QN_SEARCH_QUERY = { NS_SEARCH, "query" }; -const StaticQName QN_SEARCH_ITEM = { NS_SEARCH, "item" }; -const StaticQName QN_SEARCH_ROOM_NAME = { NS_SEARCH, "room-name" }; -const StaticQName QN_SEARCH_ROOM_DOMAIN = { NS_SEARCH, "room-domain" }; -const StaticQName QN_SEARCH_ROOM_JID = { NS_SEARCH, "room-jid" }; -const StaticQName QN_SEARCH_HANGOUT_ID = { NS_SEARCH, "hangout-id" }; -const StaticQName QN_SEARCH_EXTERNAL_ID = { NS_SEARCH, "external-id" }; - -// JEP 0115 -const char NS_CAPS[] = "http://jabber.org/protocol/caps"; -const StaticQName QN_CAPS_C = { NS_CAPS, "c" }; -const StaticQName QN_VER = { STR_EMPTY, "ver" }; -const StaticQName QN_EXT = { STR_EMPTY, "ext" }; - -// JEP 0153 -const char kNSVCard[] = "vcard-temp:x:update"; -const StaticQName kQnVCardX = { kNSVCard, "x" }; -const StaticQName kQnVCardPhoto = { kNSVCard, "photo" }; - -// JEP 0172 User Nickname -const char NS_NICKNAME[] = "http://jabber.org/protocol/nick"; -const StaticQName QN_NICKNAME = { NS_NICKNAME, "nick" }; - -// JEP 0085 chat state -const char NS_CHATSTATE[] = "http://jabber.org/protocol/chatstates"; -const StaticQName QN_CS_ACTIVE = { NS_CHATSTATE, "active" }; -const StaticQName QN_CS_COMPOSING = { NS_CHATSTATE, "composing" }; -const StaticQName QN_CS_PAUSED = { NS_CHATSTATE, "paused" }; -const StaticQName QN_CS_INACTIVE = { NS_CHATSTATE, "inactive" }; -const StaticQName QN_CS_GONE = { NS_CHATSTATE, "gone" }; - -// JEP 0091 Delayed Delivery -const char kNSDelay[] = "jabber:x:delay"; -const StaticQName kQnDelayX = { kNSDelay, "x" }; -const StaticQName kQnStamp = { STR_EMPTY, "stamp" }; - -// Google time stamping (higher resolution) -const char kNSTimestamp[] = "google:timestamp"; -const StaticQName kQnTime = { kNSTimestamp, "time" }; -const StaticQName kQnMilliseconds = { STR_EMPTY, "ms" }; - -// Jingle Info -const char NS_JINGLE_INFO[] = "google:jingleinfo"; -const StaticQName QN_JINGLE_INFO_QUERY = { NS_JINGLE_INFO, "query" }; -const StaticQName QN_JINGLE_INFO_STUN = { NS_JINGLE_INFO, "stun" }; -const StaticQName QN_JINGLE_INFO_RELAY = { NS_JINGLE_INFO, "relay" }; -const StaticQName QN_JINGLE_INFO_SERVER = { NS_JINGLE_INFO, "server" }; -const StaticQName QN_JINGLE_INFO_TOKEN = { NS_JINGLE_INFO, "token" }; -const StaticQName QN_JINGLE_INFO_HOST = { STR_EMPTY, "host" }; -const StaticQName QN_JINGLE_INFO_TCP = { STR_EMPTY, "tcp" }; -const StaticQName QN_JINGLE_INFO_UDP = { STR_EMPTY, "udp" }; -const StaticQName QN_JINGLE_INFO_TCPSSL = { STR_EMPTY, "tcpssl" }; - -// Call Performance Logging -const char NS_GOOGLE_CALLPERF_STATS[] = "google:call-perf-stats"; -const StaticQName QN_CALLPERF_STATS = - { NS_GOOGLE_CALLPERF_STATS, "callPerfStats" }; -const StaticQName QN_CALLPERF_SESSIONID = { STR_EMPTY, "sessionId" }; -const StaticQName QN_CALLPERF_LOCALUSER = { STR_EMPTY, "localUser" }; -const StaticQName QN_CALLPERF_REMOTEUSER = { STR_EMPTY, "remoteUser" }; -const StaticQName QN_CALLPERF_STARTTIME = { STR_EMPTY, "startTime" }; -const StaticQName QN_CALLPERF_CALL_LENGTH = { STR_EMPTY, "callLength" }; -const StaticQName QN_CALLPERF_CALL_ACCEPTED = { STR_EMPTY, "callAccepted" }; -const StaticQName QN_CALLPERF_CALL_ERROR_CODE = { STR_EMPTY, "callErrorCode" }; -const StaticQName QN_CALLPERF_TERMINATE_CODE = { STR_EMPTY, "terminateCode" }; -const StaticQName QN_CALLPERF_DATAPOINT = - { NS_GOOGLE_CALLPERF_STATS, "dataPoint" }; -const StaticQName QN_CALLPERF_DATAPOINT_TIME = { STR_EMPTY, "timeStamp" }; -const StaticQName QN_CALLPERF_DATAPOINT_FRACTION_LOST = - { STR_EMPTY, "fraction_lost" }; -const StaticQName QN_CALLPERF_DATAPOINT_CUM_LOST = { STR_EMPTY, "cum_lost" }; -const StaticQName QN_CALLPERF_DATAPOINT_EXT_MAX = { STR_EMPTY, "ext_max" }; -const StaticQName QN_CALLPERF_DATAPOINT_JITTER = { STR_EMPTY, "jitter" }; -const StaticQName QN_CALLPERF_DATAPOINT_RTT = { STR_EMPTY, "RTT" }; -const StaticQName QN_CALLPERF_DATAPOINT_BYTES_R = - { STR_EMPTY, "bytesReceived" }; -const StaticQName QN_CALLPERF_DATAPOINT_PACKETS_R = - { STR_EMPTY, "packetsReceived" }; -const StaticQName QN_CALLPERF_DATAPOINT_BYTES_S = { STR_EMPTY, "bytesSent" }; -const StaticQName QN_CALLPERF_DATAPOINT_PACKETS_S = - { STR_EMPTY, "packetsSent" }; -const StaticQName QN_CALLPERF_DATAPOINT_PROCESS_CPU = - { STR_EMPTY, "processCpu" }; -const StaticQName QN_CALLPERF_DATAPOINT_SYSTEM_CPU = { STR_EMPTY, "systemCpu" }; -const StaticQName QN_CALLPERF_DATAPOINT_CPUS = { STR_EMPTY, "cpus" }; -const StaticQName QN_CALLPERF_CONNECTION = - { NS_GOOGLE_CALLPERF_STATS, "connection" }; -const StaticQName QN_CALLPERF_CONNECTION_LOCAL_ADDRESS = - { STR_EMPTY, "localAddress" }; -const StaticQName QN_CALLPERF_CONNECTION_REMOTE_ADDRESS = - { STR_EMPTY, "remoteAddress" }; -const StaticQName QN_CALLPERF_CONNECTION_FLAGS = { STR_EMPTY, "flags" }; -const StaticQName QN_CALLPERF_CONNECTION_RTT = { STR_EMPTY, "rtt" }; -const StaticQName QN_CALLPERF_CONNECTION_TOTAL_BYTES_S = - { STR_EMPTY, "totalBytesSent" }; -const StaticQName QN_CALLPERF_CONNECTION_BYTES_SECOND_S = - { STR_EMPTY, "bytesSecondSent" }; -const StaticQName QN_CALLPERF_CONNECTION_TOTAL_BYTES_R = - { STR_EMPTY, "totalBytesRecv" }; -const StaticQName QN_CALLPERF_CONNECTION_BYTES_SECOND_R = - { STR_EMPTY, "bytesSecondRecv" }; -const StaticQName QN_CALLPERF_CANDIDATE = - { NS_GOOGLE_CALLPERF_STATS, "candidate" }; -const StaticQName QN_CALLPERF_CANDIDATE_ENDPOINT = { STR_EMPTY, "endpoint" }; -const StaticQName QN_CALLPERF_CANDIDATE_PROTOCOL = { STR_EMPTY, "protocol" }; -const StaticQName QN_CALLPERF_CANDIDATE_ADDRESS = { STR_EMPTY, "address" }; -const StaticQName QN_CALLPERF_MEDIA = { NS_GOOGLE_CALLPERF_STATS, "media" }; -const StaticQName QN_CALLPERF_MEDIA_DIRECTION = { STR_EMPTY, "direction" }; -const StaticQName QN_CALLPERF_MEDIA_SSRC = { STR_EMPTY, "SSRC" }; -const StaticQName QN_CALLPERF_MEDIA_ENERGY = { STR_EMPTY, "energy" }; -const StaticQName QN_CALLPERF_MEDIA_FIR = { STR_EMPTY, "fir" }; -const StaticQName QN_CALLPERF_MEDIA_NACK = { STR_EMPTY, "nack" }; -const StaticQName QN_CALLPERF_MEDIA_FPS = { STR_EMPTY, "fps" }; -const StaticQName QN_CALLPERF_MEDIA_FPS_NETWORK = { STR_EMPTY, "fpsNetwork" }; -const StaticQName QN_CALLPERF_MEDIA_FPS_DECODED = { STR_EMPTY, "fpsDecoded" }; -const StaticQName QN_CALLPERF_MEDIA_JITTER_BUFFER_SIZE = - { STR_EMPTY, "jitterBufferSize" }; -const StaticQName QN_CALLPERF_MEDIA_PREFERRED_JITTER_BUFFER_SIZE = - { STR_EMPTY, "preferredJitterBufferSize" }; -const StaticQName QN_CALLPERF_MEDIA_TOTAL_PLAYOUT_DELAY = - { STR_EMPTY, "totalPlayoutDelay" }; - -// Muc invites. -const StaticQName QN_MUC_USER_INVITE = { NS_MUC_USER, "invite" }; - -// Multiway audio/video. -const char NS_GOOGLE_MUC_USER[] = "google:muc#user"; -const StaticQName QN_GOOGLE_MUC_USER_AVAILABLE_MEDIA = - { NS_GOOGLE_MUC_USER, "available-media" }; -const StaticQName QN_GOOGLE_MUC_USER_ENTRY = { NS_GOOGLE_MUC_USER, "entry" }; -const StaticQName QN_GOOGLE_MUC_USER_MEDIA = { NS_GOOGLE_MUC_USER, "media" }; -const StaticQName QN_GOOGLE_MUC_USER_TYPE = { NS_GOOGLE_MUC_USER, "type" }; -const StaticQName QN_GOOGLE_MUC_USER_SRC_ID = { NS_GOOGLE_MUC_USER, "src-id" }; -const StaticQName QN_GOOGLE_MUC_USER_STATUS = { NS_GOOGLE_MUC_USER, "status" }; -const StaticQName QN_CLIENT_VERSION = { NS_GOOGLE_MUC_USER, "client-version" }; -const StaticQName QN_LOCALE = { NS_GOOGLE_MUC_USER, "locale" }; -const StaticQName QN_LABEL = { STR_EMPTY, "label" }; - -const char NS_GOOGLE_MUC_MEDIA[] = "google:muc#media"; -const StaticQName QN_GOOGLE_MUC_AUDIO_MUTE = - { NS_GOOGLE_MUC_MEDIA, "audio-mute" }; -const StaticQName QN_GOOGLE_MUC_VIDEO_MUTE = - { NS_GOOGLE_MUC_MEDIA, "video-mute" }; -const StaticQName QN_GOOGLE_MUC_VIDEO_PAUSE = - { NS_GOOGLE_MUC_MEDIA, "video-pause" }; -const StaticQName QN_GOOGLE_MUC_RECORDING = - { NS_GOOGLE_MUC_MEDIA, "recording" }; -const StaticQName QN_GOOGLE_MUC_MEDIA_BLOCK = { NS_GOOGLE_MUC_MEDIA, "block" }; -const StaticQName QN_STATE_ATTR = { STR_EMPTY, "state" }; - -const char AUTH_MECHANISM_GOOGLE_COOKIE[] = "X-GOOGLE-COOKIE"; -const char AUTH_MECHANISM_GOOGLE_TOKEN[] = "X-GOOGLE-TOKEN"; -const char AUTH_MECHANISM_OAUTH2[] = "X-OAUTH2"; -const char AUTH_MECHANISM_PLAIN[] = "PLAIN"; - -} // namespace buzz diff --git a/talk/xmpp/constants.h b/talk/xmpp/constants.h deleted file mode 100644 index 52088cae4..000000000 --- a/talk/xmpp/constants.h +++ /dev/null @@ -1,568 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef TALK_XMPP_CONSTANTS_H_ -#define TALK_XMPP_CONSTANTS_H_ - -#include <string> -#include "webrtc/libjingle/xmllite/qname.h" -#include "webrtc/libjingle/xmpp/jid.h" - -namespace buzz { - -extern const char NS_CLIENT[]; -extern const char NS_SERVER[]; -extern const char NS_STREAM[]; -extern const char NS_XSTREAM[]; -extern const char NS_TLS[]; -extern const char NS_SASL[]; -extern const char NS_BIND[]; -extern const char NS_DIALBACK[]; -extern const char NS_SESSION[]; -extern const char NS_STANZA[]; -extern const char NS_PRIVACY[]; -extern const char NS_ROSTER[]; -extern const char NS_VCARD[]; -extern const char NS_AVATAR_HASH[]; -extern const char NS_VCARD_UPDATE[]; -extern const char STR_CLIENT[]; -extern const char STR_SERVER[]; -extern const char STR_STREAM[]; - -extern const char STR_GET[]; -extern const char STR_SET[]; -extern const char STR_RESULT[]; -extern const char STR_ERROR[]; - -extern const char STR_FORM[]; -extern const char STR_SUBMIT[]; -extern const char STR_TEXT_SINGLE[]; -extern const char STR_LIST_SINGLE[]; -extern const char STR_LIST_MULTI[]; -extern const char STR_HIDDEN[]; -extern const char STR_FORM_TYPE[]; - -extern const char STR_FROM[]; -extern const char STR_TO[]; -extern const char STR_BOTH[]; -extern const char STR_REMOVE[]; -extern const char STR_TRUE[]; - -extern const char STR_TYPE[]; -extern const char STR_NAME[]; -extern const char STR_ID[]; -extern const char STR_JID[]; -extern const char STR_SUBSCRIPTION[]; -extern const char STR_ASK[]; -extern const char STR_X[]; -extern const char STR_GOOGLE_COM[]; -extern const char STR_GMAIL_COM[]; -extern const char STR_GOOGLEMAIL_COM[]; -extern const char STR_DEFAULT_DOMAIN[]; -extern const char STR_TALK_GOOGLE_COM[]; -extern const char STR_TALKX_L_GOOGLE_COM[]; -extern const char STR_XMPP_GOOGLE_COM[]; -extern const char STR_XMPPX_L_GOOGLE_COM[]; - -#ifdef FEATURE_ENABLE_VOICEMAIL -extern const char STR_VOICEMAIL[]; -extern const char STR_OUTGOINGVOICEMAIL[]; -#endif - -extern const char STR_UNAVAILABLE[]; - -extern const char NS_PING[]; -extern const StaticQName QN_PING; - -extern const char NS_MUC_UNIQUE[]; -extern const StaticQName QN_MUC_UNIQUE_QUERY; -extern const StaticQName QN_HANGOUT_ID; - -extern const char STR_GOOGLE_MUC_LOOKUP_JID[]; -extern const char STR_MUC_ROOMCONFIG_ROOMNAME[]; -extern const char STR_MUC_ROOMCONFIG_FEATURES[]; -extern const char STR_MUC_ROOM_FEATURE_ENTERPRISE[]; -extern const char STR_MUC_ROOMCONFIG[]; -extern const char STR_MUC_ROOM_FEATURE_HANGOUT[]; -extern const char STR_MUC_ROOM_FEATURE_HANGOUT_LITE[]; -extern const char STR_MUC_ROOM_FEATURE_BROADCAST[]; -extern const char STR_MUC_ROOM_FEATURE_MULTI_USER_VC[]; -extern const char STR_MUC_ROOM_FEATURE_RECORDABLE[]; -extern const char STR_MUC_ROOM_FEATURE_CUSTOM_RECORDING[]; -extern const char STR_MUC_ROOM_OWNER_PROFILE_ID[]; -extern const char STR_MUC_ROOM_FEATURE_ABUSE_RECORDABLE[]; - -extern const char STR_ID_TYPE_CONVERSATION[]; -extern const char NS_GOOGLE_MUC_HANGOUT[]; -extern const StaticQName QN_GOOGLE_MUC_HANGOUT_INVITE; -extern const StaticQName QN_GOOGLE_MUC_HANGOUT_INVITE_TYPE; -extern const StaticQName QN_ATTR_CREATE_ACTIVITY; -extern const StaticQName QN_GOOGLE_MUC_HANGOUT_PUBLIC; -extern const StaticQName QN_GOOGLE_MUC_HANGOUT_INVITEE; -extern const StaticQName QN_GOOGLE_MUC_HANGOUT_NOTIFICATION_STATUS; -extern const StaticQName QN_GOOGLE_MUC_HANGOUT_NOTIFICATION_TYPE; -extern const StaticQName QN_GOOGLE_MUC_HANGOUT_HANGOUT_START_CONTEXT; -extern const StaticQName QN_GOOGLE_MUC_HANGOUT_CONVERSATION_ID; - -extern const StaticQName QN_STREAM_STREAM; -extern const StaticQName QN_STREAM_FEATURES; -extern const StaticQName QN_STREAM_ERROR; - -extern const StaticQName QN_XSTREAM_BAD_FORMAT; -extern const StaticQName QN_XSTREAM_BAD_NAMESPACE_PREFIX; -extern const StaticQName QN_XSTREAM_CONFLICT; -extern const StaticQName QN_XSTREAM_CONNECTION_TIMEOUT; -extern const StaticQName QN_XSTREAM_HOST_GONE; -extern const StaticQName QN_XSTREAM_HOST_UNKNOWN; -extern const StaticQName QN_XSTREAM_IMPROPER_ADDRESSIING; -extern const StaticQName QN_XSTREAM_INTERNAL_SERVER_ERROR; -extern const StaticQName QN_XSTREAM_INVALID_FROM; -extern const StaticQName QN_XSTREAM_INVALID_ID; -extern const StaticQName QN_XSTREAM_INVALID_NAMESPACE; -extern const StaticQName QN_XSTREAM_INVALID_XML; -extern const StaticQName QN_XSTREAM_NOT_AUTHORIZED; -extern const StaticQName QN_XSTREAM_POLICY_VIOLATION; -extern const StaticQName QN_XSTREAM_REMOTE_CONNECTION_FAILED; -extern const StaticQName QN_XSTREAM_RESOURCE_CONSTRAINT; -extern const StaticQName QN_XSTREAM_RESTRICTED_XML; -extern const StaticQName QN_XSTREAM_SEE_OTHER_HOST; -extern const StaticQName QN_XSTREAM_SYSTEM_SHUTDOWN; -extern const StaticQName QN_XSTREAM_UNDEFINED_CONDITION; -extern const StaticQName QN_XSTREAM_UNSUPPORTED_ENCODING; -extern const StaticQName QN_XSTREAM_UNSUPPORTED_STANZA_TYPE; -extern const StaticQName QN_XSTREAM_UNSUPPORTED_VERSION; -extern const StaticQName QN_XSTREAM_XML_NOT_WELL_FORMED; -extern const StaticQName QN_XSTREAM_TEXT; - -extern const StaticQName QN_TLS_STARTTLS; -extern const StaticQName QN_TLS_REQUIRED; -extern const StaticQName QN_TLS_PROCEED; -extern const StaticQName QN_TLS_FAILURE; - -extern const StaticQName QN_SASL_MECHANISMS; -extern const StaticQName QN_SASL_MECHANISM; -extern const StaticQName QN_SASL_AUTH; -extern const StaticQName QN_SASL_CHALLENGE; -extern const StaticQName QN_SASL_RESPONSE; -extern const StaticQName QN_SASL_ABORT; -extern const StaticQName QN_SASL_SUCCESS; -extern const StaticQName QN_SASL_FAILURE; -extern const StaticQName QN_SASL_ABORTED; -extern const StaticQName QN_SASL_INCORRECT_ENCODING; -extern const StaticQName QN_SASL_INVALID_AUTHZID; -extern const StaticQName QN_SASL_INVALID_MECHANISM; -extern const StaticQName QN_SASL_MECHANISM_TOO_WEAK; -extern const StaticQName QN_SASL_NOT_AUTHORIZED; -extern const StaticQName QN_SASL_TEMPORARY_AUTH_FAILURE; - -// These are non-standard. -extern const char NS_GOOGLE_AUTH[]; -extern const char NS_GOOGLE_AUTH_PROTOCOL[]; -extern const StaticQName QN_GOOGLE_AUTH_CLIENT_USES_FULL_BIND_RESULT; -extern const StaticQName QN_GOOGLE_ALLOW_NON_GOOGLE_ID_XMPP_LOGIN; -extern const StaticQName QN_GOOGLE_AUTH_SERVICE; - -extern const StaticQName QN_DIALBACK_RESULT; -extern const StaticQName QN_DIALBACK_VERIFY; - -extern const StaticQName QN_STANZA_BAD_REQUEST; -extern const StaticQName QN_STANZA_CONFLICT; -extern const StaticQName QN_STANZA_FEATURE_NOT_IMPLEMENTED; -extern const StaticQName QN_STANZA_FORBIDDEN; -extern const StaticQName QN_STANZA_GONE; -extern const StaticQName QN_STANZA_INTERNAL_SERVER_ERROR; -extern const StaticQName QN_STANZA_ITEM_NOT_FOUND; -extern const StaticQName QN_STANZA_JID_MALFORMED; -extern const StaticQName QN_STANZA_NOT_ACCEPTABLE; -extern const StaticQName QN_STANZA_NOT_ALLOWED; -extern const StaticQName QN_STANZA_PAYMENT_REQUIRED; -extern const StaticQName QN_STANZA_RECIPIENT_UNAVAILABLE; -extern const StaticQName QN_STANZA_REDIRECT; -extern const StaticQName QN_STANZA_REGISTRATION_REQUIRED; -extern const StaticQName QN_STANZA_REMOTE_SERVER_NOT_FOUND; -extern const StaticQName QN_STANZA_REMOTE_SERVER_TIMEOUT; -extern const StaticQName QN_STANZA_RESOURCE_CONSTRAINT; -extern const StaticQName QN_STANZA_SERVICE_UNAVAILABLE; -extern const StaticQName QN_STANZA_SUBSCRIPTION_REQUIRED; -extern const StaticQName QN_STANZA_UNDEFINED_CONDITION; -extern const StaticQName QN_STANZA_UNEXPECTED_REQUEST; -extern const StaticQName QN_STANZA_TEXT; - -extern const StaticQName QN_BIND_BIND; -extern const StaticQName QN_BIND_RESOURCE; -extern const StaticQName QN_BIND_JID; - -extern const StaticQName QN_MESSAGE; -extern const StaticQName QN_BODY; -extern const StaticQName QN_SUBJECT; -extern const StaticQName QN_THREAD; -extern const StaticQName QN_PRESENCE; -extern const StaticQName QN_SHOW; -extern const StaticQName QN_STATUS; -extern const StaticQName QN_LANG; -extern const StaticQName QN_PRIORITY; -extern const StaticQName QN_IQ; -extern const StaticQName QN_ERROR; - -extern const StaticQName QN_SERVER_MESSAGE; -extern const StaticQName QN_SERVER_BODY; -extern const StaticQName QN_SERVER_SUBJECT; -extern const StaticQName QN_SERVER_THREAD; -extern const StaticQName QN_SERVER_PRESENCE; -extern const StaticQName QN_SERVER_SHOW; -extern const StaticQName QN_SERVER_STATUS; -extern const StaticQName QN_SERVER_LANG; -extern const StaticQName QN_SERVER_PRIORITY; -extern const StaticQName QN_SERVER_IQ; -extern const StaticQName QN_SERVER_ERROR; - -extern const StaticQName QN_SESSION_SESSION; - -extern const StaticQName QN_PRIVACY_QUERY; -extern const StaticQName QN_PRIVACY_ACTIVE; -extern const StaticQName QN_PRIVACY_DEFAULT; -extern const StaticQName QN_PRIVACY_LIST; -extern const StaticQName QN_PRIVACY_ITEM; -extern const StaticQName QN_PRIVACY_IQ; -extern const StaticQName QN_PRIVACY_MESSAGE; -extern const StaticQName QN_PRIVACY_PRESENCE_IN; -extern const StaticQName QN_PRIVACY_PRESENCE_OUT; - -extern const StaticQName QN_ROSTER_QUERY; -extern const StaticQName QN_ROSTER_ITEM; -extern const StaticQName QN_ROSTER_GROUP; - -extern const StaticQName QN_VCARD; -extern const StaticQName QN_VCARD_FN; -extern const StaticQName QN_VCARD_PHOTO; -extern const StaticQName QN_VCARD_PHOTO_BINVAL; -extern const StaticQName QN_VCARD_AVATAR_HASH; -extern const StaticQName QN_VCARD_AVATAR_HASH_MODIFIED; - -#if defined(FEATURE_ENABLE_PSTN) -extern const StaticQName QN_VCARD_TEL; -extern const StaticQName QN_VCARD_VOICE; -extern const StaticQName QN_VCARD_HOME; -extern const StaticQName QN_VCARD_WORK; -extern const StaticQName QN_VCARD_CELL; -extern const StaticQName QN_VCARD_NUMBER; -#endif - -#if defined(FEATURE_ENABLE_RICHPROFILES) -extern const StaticQName QN_USER_PROFILE_QUERY; -extern const StaticQName QN_USER_PROFILE_URL; - -extern const StaticQName QN_ATOM_FEED; -extern const StaticQName QN_ATOM_ENTRY; -extern const StaticQName QN_ATOM_TITLE; -extern const StaticQName QN_ATOM_ID; -extern const StaticQName QN_ATOM_MODIFIED; -extern const StaticQName QN_ATOM_IMAGE; -extern const StaticQName QN_ATOM_LINK; -extern const StaticQName QN_ATOM_HREF; -#endif - -extern const StaticQName QN_XML_LANG; - -extern const StaticQName QN_ENCODING; -extern const StaticQName QN_VERSION; -extern const StaticQName QN_TO; -extern const StaticQName QN_FROM; -extern const StaticQName QN_TYPE; -extern const StaticQName QN_ID; -extern const StaticQName QN_CODE; -extern const StaticQName QN_NAME; -extern const StaticQName QN_VALUE; -extern const StaticQName QN_ACTION; -extern const StaticQName QN_ORDER; -extern const StaticQName QN_MECHANISM; -extern const StaticQName QN_ASK; -extern const StaticQName QN_JID; -extern const StaticQName QN_NICK; -extern const StaticQName QN_SUBSCRIPTION; -extern const StaticQName QN_TITLE1; -extern const StaticQName QN_TITLE2; -extern const StaticQName QN_AFFILIATION; -extern const StaticQName QN_ROLE; -extern const StaticQName QN_TIME; - -extern const StaticQName QN_XMLNS_CLIENT; -extern const StaticQName QN_XMLNS_SERVER; -extern const StaticQName QN_XMLNS_STREAM; - -// Presence -extern const char STR_SHOW_AWAY[]; -extern const char STR_SHOW_CHAT[]; -extern const char STR_SHOW_DND[]; -extern const char STR_SHOW_XA[]; -extern const char STR_SHOW_OFFLINE[]; - -extern const char NS_GOOGLE_PSTN_CONFERENCE[]; -extern const StaticQName QN_GOOGLE_PSTN_CONFERENCE_STATUS; -extern const StaticQName QN_ATTR_STATUS; - -// Presence connection status -extern const char STR_PSTN_CONFERENCE_STATUS_CONNECTING[]; -extern const char STR_PSTN_CONFERENCE_STATUS_JOINING[]; -extern const char STR_PSTN_CONFERENCE_STATUS_CONNECTED[]; -extern const char STR_PSTN_CONFERENCE_STATUS_HANGUP[]; - -// Subscription -extern const char STR_SUBSCRIBE[]; -extern const char STR_SUBSCRIBED[]; -extern const char STR_UNSUBSCRIBE[]; -extern const char STR_UNSUBSCRIBED[]; - -// Google Invite -extern const char NS_GOOGLE_SUBSCRIBE[]; -extern const StaticQName QN_INVITATION; -extern const StaticQName QN_INVITE_NAME; -extern const StaticQName QN_INVITE_SUBJECT; -extern const StaticQName QN_INVITE_MESSAGE; - -// Kick -extern const char NS_GOOGLE_MUC_ADMIN[]; -extern const StaticQName QN_GOOGLE_MUC_ADMIN_QUERY; -extern const StaticQName QN_GOOGLE_MUC_ADMIN_QUERY_ITEM; -extern const StaticQName QN_GOOGLE_MUC_ADMIN_QUERY_ITEM_REASON; - -// PubSub: http://xmpp.org/extensions/xep-0060.html -extern const char NS_PUBSUB[]; -extern const StaticQName QN_PUBSUB; -extern const StaticQName QN_PUBSUB_ITEMS; -extern const StaticQName QN_PUBSUB_ITEM; -extern const StaticQName QN_PUBSUB_PUBLISH; -extern const StaticQName QN_PUBSUB_RETRACT; -extern const StaticQName QN_ATTR_PUBLISHER; - -extern const char NS_PUBSUB_EVENT[]; -extern const StaticQName QN_NODE; -extern const StaticQName QN_PUBSUB_EVENT; -extern const StaticQName QN_PUBSUB_EVENT_ITEMS; -extern const StaticQName QN_PUBSUB_EVENT_ITEM; -extern const StaticQName QN_PUBSUB_EVENT_RETRACT; -extern const StaticQName QN_NOTIFY; - -extern const char NS_PRESENTER[]; -extern const StaticQName QN_PRESENTER_PRESENTER; -extern const StaticQName QN_PRESENTER_PRESENTATION_ITEM; -extern const StaticQName QN_PRESENTER_PRESENTATION_TYPE; -extern const StaticQName QN_PRESENTER_PRESENTATION_ID; - -// JEP 0030 -extern const StaticQName QN_CATEGORY; -extern const StaticQName QN_VAR; -extern const char NS_DISCO_INFO[]; -extern const char NS_DISCO_ITEMS[]; - -extern const StaticQName QN_DISCO_INFO_QUERY; -extern const StaticQName QN_DISCO_IDENTITY; -extern const StaticQName QN_DISCO_FEATURE; - -extern const StaticQName QN_DISCO_ITEMS_QUERY; -extern const StaticQName QN_DISCO_ITEM; - -// JEP 0020 -extern const char NS_FEATURE[]; -extern const StaticQName QN_FEATURE_FEATURE; - -// JEP 0004 -extern const char NS_XDATA[]; -extern const StaticQName QN_XDATA_X; -extern const StaticQName QN_XDATA_INSTRUCTIONS; -extern const StaticQName QN_XDATA_TITLE; -extern const StaticQName QN_XDATA_FIELD; -extern const StaticQName QN_XDATA_REPORTED; -extern const StaticQName QN_XDATA_ITEM; -extern const StaticQName QN_XDATA_DESC; -extern const StaticQName QN_XDATA_REQUIRED; -extern const StaticQName QN_XDATA_VALUE; -extern const StaticQName QN_XDATA_OPTION; - -// JEP 0045 -extern const char NS_MUC[]; -extern const StaticQName QN_MUC_X; -extern const StaticQName QN_MUC_ITEM; -extern const StaticQName QN_MUC_AFFILIATION; -extern const StaticQName QN_MUC_ROLE; -extern const StaticQName QN_CLIENT_VERSION; -extern const StaticQName QN_LOCALE; -extern const char STR_AFFILIATION_NONE[]; -extern const char STR_ROLE_PARTICIPANT[]; - -extern const char NS_GOOGLE_SESSION[]; -extern const StaticQName QN_GOOGLE_USER_ID; -extern const StaticQName QN_GOOGLE_CIRCLE_ID; -extern const StaticQName QN_GOOGLE_SESSION_BLOCKED; -extern const StaticQName QN_GOOGLE_SESSION_BLOCKING; - -extern const char NS_MUC_OWNER[]; -extern const StaticQName QN_MUC_OWNER_QUERY; - -extern const char NS_MUC_USER[]; -extern const StaticQName QN_MUC_USER_CONTINUE; -extern const StaticQName QN_MUC_USER_X; -extern const StaticQName QN_MUC_USER_ITEM; -extern const StaticQName QN_MUC_USER_STATUS; -extern const StaticQName QN_MUC_USER_REASON; -extern const StaticQName QN_MUC_USER_ABUSE_VIOLATION; - -// JEP 0055 - Jabber Search -extern const char NS_SEARCH[]; -extern const StaticQName QN_SEARCH_QUERY; -extern const StaticQName QN_SEARCH_ITEM; -extern const StaticQName QN_SEARCH_ROOM_NAME; -extern const StaticQName QN_SEARCH_ROOM_JID; -extern const StaticQName QN_SEARCH_ROOM_DOMAIN; -extern const StaticQName QN_SEARCH_HANGOUT_ID; -extern const StaticQName QN_SEARCH_EXTERNAL_ID; - -// JEP 0115 -extern const char NS_CAPS[]; -extern const StaticQName QN_CAPS_C; -extern const StaticQName QN_VER; -extern const StaticQName QN_EXT; - - -// Avatar - JEP 0153 -extern const char kNSVCard[]; -extern const StaticQName kQnVCardX; -extern const StaticQName kQnVCardPhoto; - -// JEP 0172 User Nickname -extern const char NS_NICKNAME[]; -extern const StaticQName QN_NICKNAME; - -// JEP 0085 chat state -extern const char NS_CHATSTATE[]; -extern const StaticQName QN_CS_ACTIVE; -extern const StaticQName QN_CS_COMPOSING; -extern const StaticQName QN_CS_PAUSED; -extern const StaticQName QN_CS_INACTIVE; -extern const StaticQName QN_CS_GONE; - -// JEP 0091 Delayed Delivery -extern const char kNSDelay[]; -extern const StaticQName kQnDelayX; -extern const StaticQName kQnStamp; - -// Google time stamping (higher resolution) -extern const char kNSTimestamp[]; -extern const StaticQName kQnTime; -extern const StaticQName kQnMilliseconds; - -extern const char NS_JINGLE_INFO[]; -extern const StaticQName QN_JINGLE_INFO_QUERY; -extern const StaticQName QN_JINGLE_INFO_STUN; -extern const StaticQName QN_JINGLE_INFO_RELAY; -extern const StaticQName QN_JINGLE_INFO_SERVER; -extern const StaticQName QN_JINGLE_INFO_TOKEN; -extern const StaticQName QN_JINGLE_INFO_HOST; -extern const StaticQName QN_JINGLE_INFO_TCP; -extern const StaticQName QN_JINGLE_INFO_UDP; -extern const StaticQName QN_JINGLE_INFO_TCPSSL; - -extern const char NS_GOOGLE_CALLPERF_STATS[]; -extern const StaticQName QN_CALLPERF_STATS; -extern const StaticQName QN_CALLPERF_SESSIONID; -extern const StaticQName QN_CALLPERF_LOCALUSER; -extern const StaticQName QN_CALLPERF_REMOTEUSER; -extern const StaticQName QN_CALLPERF_STARTTIME; -extern const StaticQName QN_CALLPERF_CALL_LENGTH; -extern const StaticQName QN_CALLPERF_CALL_ACCEPTED; -extern const StaticQName QN_CALLPERF_CALL_ERROR_CODE; -extern const StaticQName QN_CALLPERF_TERMINATE_CODE; -extern const StaticQName QN_CALLPERF_DATAPOINT; -extern const StaticQName QN_CALLPERF_DATAPOINT_TIME; -extern const StaticQName QN_CALLPERF_DATAPOINT_FRACTION_LOST; -extern const StaticQName QN_CALLPERF_DATAPOINT_CUM_LOST; -extern const StaticQName QN_CALLPERF_DATAPOINT_EXT_MAX; -extern const StaticQName QN_CALLPERF_DATAPOINT_JITTER; -extern const StaticQName QN_CALLPERF_DATAPOINT_RTT; -extern const StaticQName QN_CALLPERF_DATAPOINT_BYTES_R; -extern const StaticQName QN_CALLPERF_DATAPOINT_PACKETS_R; -extern const StaticQName QN_CALLPERF_DATAPOINT_BYTES_S; -extern const StaticQName QN_CALLPERF_DATAPOINT_PACKETS_S; -extern const StaticQName QN_CALLPERF_DATAPOINT_PROCESS_CPU; -extern const StaticQName QN_CALLPERF_DATAPOINT_SYSTEM_CPU; -extern const StaticQName QN_CALLPERF_DATAPOINT_CPUS; -extern const StaticQName QN_CALLPERF_CONNECTION; -extern const StaticQName QN_CALLPERF_CONNECTION_LOCAL_ADDRESS; -extern const StaticQName QN_CALLPERF_CONNECTION_REMOTE_ADDRESS; -extern const StaticQName QN_CALLPERF_CONNECTION_FLAGS; -extern const StaticQName QN_CALLPERF_CONNECTION_RTT; -extern const StaticQName QN_CALLPERF_CONNECTION_TOTAL_BYTES_S; -extern const StaticQName QN_CALLPERF_CONNECTION_BYTES_SECOND_S; -extern const StaticQName QN_CALLPERF_CONNECTION_TOTAL_BYTES_R; -extern const StaticQName QN_CALLPERF_CONNECTION_BYTES_SECOND_R; -extern const StaticQName QN_CALLPERF_CANDIDATE; -extern const StaticQName QN_CALLPERF_CANDIDATE_ENDPOINT; -extern const StaticQName QN_CALLPERF_CANDIDATE_PROTOCOL; -extern const StaticQName QN_CALLPERF_CANDIDATE_ADDRESS; -extern const StaticQName QN_CALLPERF_MEDIA; -extern const StaticQName QN_CALLPERF_MEDIA_DIRECTION; -extern const StaticQName QN_CALLPERF_MEDIA_SSRC; -extern const StaticQName QN_CALLPERF_MEDIA_ENERGY; -extern const StaticQName QN_CALLPERF_MEDIA_FIR; -extern const StaticQName QN_CALLPERF_MEDIA_NACK; -extern const StaticQName QN_CALLPERF_MEDIA_FPS; -extern const StaticQName QN_CALLPERF_MEDIA_FPS_NETWORK; -extern const StaticQName QN_CALLPERF_MEDIA_FPS_DECODED; -extern const StaticQName QN_CALLPERF_MEDIA_JITTER_BUFFER_SIZE; -extern const StaticQName QN_CALLPERF_MEDIA_PREFERRED_JITTER_BUFFER_SIZE; -extern const StaticQName QN_CALLPERF_MEDIA_TOTAL_PLAYOUT_DELAY; - -// Muc invites. -extern const StaticQName QN_MUC_USER_INVITE; - -// Multiway audio/video. -extern const char NS_GOOGLE_MUC_USER[]; -extern const StaticQName QN_GOOGLE_MUC_USER_AVAILABLE_MEDIA; -extern const StaticQName QN_GOOGLE_MUC_USER_ENTRY; -extern const StaticQName QN_GOOGLE_MUC_USER_MEDIA; -extern const StaticQName QN_GOOGLE_MUC_USER_TYPE; -extern const StaticQName QN_GOOGLE_MUC_USER_SRC_ID; -extern const StaticQName QN_GOOGLE_MUC_USER_STATUS; -extern const StaticQName QN_LABEL; - -extern const char NS_GOOGLE_MUC_MEDIA[]; -extern const StaticQName QN_GOOGLE_MUC_AUDIO_MUTE; -extern const StaticQName QN_GOOGLE_MUC_VIDEO_MUTE; -extern const StaticQName QN_GOOGLE_MUC_VIDEO_PAUSE; -extern const StaticQName QN_GOOGLE_MUC_RECORDING; -extern const StaticQName QN_GOOGLE_MUC_MEDIA_BLOCK; -extern const StaticQName QN_STATE_ATTR; - - -extern const char AUTH_MECHANISM_GOOGLE_COOKIE[]; -extern const char AUTH_MECHANISM_GOOGLE_TOKEN[]; -extern const char AUTH_MECHANISM_OAUTH2[]; -extern const char AUTH_MECHANISM_PLAIN[]; - -} // namespace buzz - -#endif // TALK_XMPP_CONSTANTS_H_ diff --git a/talk/xmpp/discoitemsquerytask.cc b/talk/xmpp/discoitemsquerytask.cc deleted file mode 100644 index b739ba35a..000000000 --- a/talk/xmpp/discoitemsquerytask.cc +++ /dev/null @@ -1,79 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "webrtc/libjingle/xmpp/constants.h" -#include "webrtc/libjingle/xmpp/discoitemsquerytask.h" -#include "webrtc/libjingle/xmpp/xmpptask.h" -#include "webrtc/base/scoped_ptr.h" - -namespace buzz { - -DiscoItemsQueryTask::DiscoItemsQueryTask(XmppTaskParentInterface* parent, - const Jid& to, - const std::string& node) - : IqTask(parent, STR_GET, to, MakeRequest(node)) { -} - -XmlElement* DiscoItemsQueryTask::MakeRequest(const std::string& node) { - XmlElement* element = new XmlElement(QN_DISCO_ITEMS_QUERY, true); - if (!node.empty()) { - element->AddAttr(QN_NODE, node); - } - return element; -} - -void DiscoItemsQueryTask::HandleResult(const XmlElement* stanza) { - const XmlElement* query = stanza->FirstNamed(QN_DISCO_ITEMS_QUERY); - if (query) { - std::vector<DiscoItem> items; - for (const buzz::XmlChild* child = query->FirstChild(); child; - child = child->NextChild()) { - DiscoItem item; - const buzz::XmlElement* child_element = child->AsElement(); - if (ParseItem(child_element, &item)) { - items.push_back(item); - } - } - SignalResult(items); - } else { - SignalError(this, NULL); - } -} - -bool DiscoItemsQueryTask::ParseItem(const XmlElement* element, - DiscoItem* item) { - if (element->HasAttr(QN_JID)) { - return false; - } - - item->jid = element->Attr(QN_JID); - item->name = element->Attr(QN_NAME); - item->node = element->Attr(QN_NODE); - return true; -} - -} // namespace buzz diff --git a/talk/xmpp/discoitemsquerytask.h b/talk/xmpp/discoitemsquerytask.h deleted file mode 100644 index c31d2616b..000000000 --- a/talk/xmpp/discoitemsquerytask.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -// Fires a disco items query, such as the following example: -// -// <iq type='get' -// from='foo@gmail.com/asdf' -// to='bar@google.com' -// id='1234'> -// <query xmlns=' http://jabber.org/protocol/disco#items' -// node='blah '/> -// </iq> -// -// Sample response: -// -// <iq type='result' -// from=' hendriks@google.com' -// to='rsturgell@google.com/asdf' -// id='1234'> -// <query xmlns=' http://jabber.org/protocol/disco#items ' -// node='blah'> -// <item something='somethingelse'/> -// </query> -// </iq> - - -#ifndef TALK_XMPP_DISCOITEMSQUERYTASK_H_ -#define TALK_XMPP_DISCOITEMSQUERYTASK_H_ - -#include <string> -#include <vector> - -#include "webrtc/libjingle/xmpp/iqtask.h" - -namespace buzz { - -struct DiscoItem { - std::string jid; - std::string node; - std::string name; -}; - -class DiscoItemsQueryTask : public IqTask { - public: - DiscoItemsQueryTask(XmppTaskParentInterface* parent, - const Jid& to, const std::string& node); - - sigslot::signal1<std::vector<DiscoItem> > SignalResult; - - private: - static XmlElement* MakeRequest(const std::string& node); - virtual void HandleResult(const XmlElement* result); - static bool ParseItem(const XmlElement* element, DiscoItem* item); -}; - -} // namespace buzz - -#endif // TALK_XMPP_DISCOITEMSQUERYTASK_H_ diff --git a/talk/xmpp/fakexmppclient.h b/talk/xmpp/fakexmppclient.h deleted file mode 100644 index 2e37dd194..000000000 --- a/talk/xmpp/fakexmppclient.h +++ /dev/null @@ -1,123 +0,0 @@ -/* - * libjingle - * Copyright 2011, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -// A fake XmppClient for use in unit tests. - -#ifndef TALK_XMPP_FAKEXMPPCLIENT_H_ -#define TALK_XMPP_FAKEXMPPCLIENT_H_ - -#include <string> -#include <vector> - -#include "webrtc/libjingle/xmpp/xmpptask.h" - -namespace buzz { - -class XmlElement; - -class FakeXmppClient : public XmppTaskParentInterface, - public XmppClientInterface { - public: - explicit FakeXmppClient(rtc::TaskParent* parent) - : XmppTaskParentInterface(parent) { - } - - // As XmppTaskParentInterface - virtual XmppClientInterface* GetClient() { - return this; - } - - virtual int ProcessStart() { - return STATE_RESPONSE; - } - - // As XmppClientInterface - virtual XmppEngine::State GetState() const { - return XmppEngine::STATE_OPEN; - } - - virtual const Jid& jid() const { - return jid_; - } - - virtual std::string NextId() { - // Implement if needed for tests. - return "0"; - } - - virtual XmppReturnStatus SendStanza(const XmlElement* stanza) { - sent_stanzas_.push_back(stanza); - return XMPP_RETURN_OK; - } - - const std::vector<const XmlElement*>& sent_stanzas() { - return sent_stanzas_; - } - - virtual XmppReturnStatus SendStanzaError( - const XmlElement * pelOriginal, - XmppStanzaError code, - const std::string & text) { - // Implement if needed for tests. - return XMPP_RETURN_OK; - } - - virtual void AddXmppTask(XmppTask* task, - XmppEngine::HandlerLevel level) { - tasks_.push_back(task); - } - - virtual void RemoveXmppTask(XmppTask* task) { - std::remove(tasks_.begin(), tasks_.end(), task); - } - - // As FakeXmppClient - void set_jid(const Jid& jid) { - jid_ = jid; - } - - // Takes ownership of stanza. - void HandleStanza(XmlElement* stanza) { - for (std::vector<XmppTask*>::iterator task = tasks_.begin(); - task != tasks_.end(); ++task) { - if ((*task)->HandleStanza(stanza)) { - delete stanza; - return; - } - } - delete stanza; - } - - private: - Jid jid_; - std::vector<XmppTask*> tasks_; - std::vector<const XmlElement*> sent_stanzas_; -}; - -} // namespace buzz - -#endif // TALK_XMPP_FAKEXMPPCLIENT_H_ diff --git a/talk/xmpp/hangoutpubsubclient.cc b/talk/xmpp/hangoutpubsubclient.cc deleted file mode 100644 index dacccf1a0..000000000 --- a/talk/xmpp/hangoutpubsubclient.cc +++ /dev/null @@ -1,417 +0,0 @@ -/* - * libjingle - * Copyright 2011, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "webrtc/libjingle/xmpp/hangoutpubsubclient.h" - -#include "webrtc/libjingle/xmllite/qname.h" -#include "webrtc/libjingle/xmllite/xmlelement.h" -#include "webrtc/libjingle/xmpp/constants.h" -#include "webrtc/libjingle/xmpp/jid.h" -#include "webrtc/base/logging.h" - - -// Gives a high-level API for MUC call PubSub needs such as -// presenter state, recording state, mute state, and remote mute. - -namespace buzz { - -namespace { -const char kPresenting[] = "s"; -const char kNotPresenting[] = "o"; - -} // namespace - -// A simple serialiazer where presence of item => true, lack of item -// => false. -class BoolStateSerializer : public PubSubStateSerializer<bool> { - virtual XmlElement* Write(const QName& state_name, const bool& state) { - if (!state) { - return NULL; - } - - return new XmlElement(state_name, true); - } - - virtual void Parse(const XmlElement* state_elem, bool *state_out) { - *state_out = state_elem != NULL; - } -}; - -class PresenterStateClient : public PubSubStateClient<bool> { - public: - PresenterStateClient(const std::string& publisher_nick, - PubSubClient* client, - const QName& state_name, - bool default_state) - : PubSubStateClient<bool>( - publisher_nick, client, state_name, default_state, - new PublishedNickKeySerializer(), NULL) { - } - - virtual void Publish(const std::string& published_nick, - const bool& state, - std::string* task_id_out) { - XmlElement* presenter_elem = new XmlElement(QN_PRESENTER_PRESENTER, true); - presenter_elem->AddAttr(QN_NICK, published_nick); - - XmlElement* presentation_item_elem = - new XmlElement(QN_PRESENTER_PRESENTATION_ITEM, false); - const std::string& presentation_type = state ? kPresenting : kNotPresenting; - presentation_item_elem->AddAttr( - QN_PRESENTER_PRESENTATION_TYPE, presentation_type); - - // The Presenter state is kind of dumb in that it doesn't always use - // retracts. It relies on setting the "type" to a special value. - std::string itemid = published_nick; - std::vector<XmlElement*> children; - children.push_back(presenter_elem); - children.push_back(presentation_item_elem); - client()->PublishItem(itemid, children, task_id_out); - } - - protected: - virtual bool ParseStateItem(const PubSubItem& item, - StateItemInfo* info_out, - bool* state_out) { - const XmlElement* presenter_elem = - item.elem->FirstNamed(QN_PRESENTER_PRESENTER); - const XmlElement* presentation_item_elem = - item.elem->FirstNamed(QN_PRESENTER_PRESENTATION_ITEM); - if (presentation_item_elem == NULL || presenter_elem == NULL) { - return false; - } - - info_out->publisher_nick = - client()->GetPublisherNickFromPubSubItem(item.elem); - info_out->published_nick = presenter_elem->Attr(QN_NICK); - *state_out = (presentation_item_elem->Attr( - QN_PRESENTER_PRESENTATION_TYPE) != kNotPresenting); - return true; - } - - virtual bool StatesEqual(const bool& state1, const bool& state2) { - // Make every item trigger an event, even if state doesn't change. - return false; - } -}; - -HangoutPubSubClient::HangoutPubSubClient(XmppTaskParentInterface* parent, - const Jid& mucjid, - const std::string& nick) - : mucjid_(mucjid), - nick_(nick) { - presenter_client_.reset(new PubSubClient(parent, mucjid, NS_PRESENTER)); - presenter_client_->SignalRequestError.connect( - this, &HangoutPubSubClient::OnPresenterRequestError); - - media_client_.reset(new PubSubClient(parent, mucjid, NS_GOOGLE_MUC_MEDIA)); - media_client_->SignalRequestError.connect( - this, &HangoutPubSubClient::OnMediaRequestError); - - presenter_state_client_.reset(new PresenterStateClient( - nick_, presenter_client_.get(), QN_PRESENTER_PRESENTER, false)); - presenter_state_client_->SignalStateChange.connect( - this, &HangoutPubSubClient::OnPresenterStateChange); - presenter_state_client_->SignalPublishResult.connect( - this, &HangoutPubSubClient::OnPresenterPublishResult); - presenter_state_client_->SignalPublishError.connect( - this, &HangoutPubSubClient::OnPresenterPublishError); - - audio_mute_state_client_.reset(new PubSubStateClient<bool>( - nick_, media_client_.get(), QN_GOOGLE_MUC_AUDIO_MUTE, false, - new PublishedNickKeySerializer(), new BoolStateSerializer())); - // Can't just repeat because we need to watch for remote mutes. - audio_mute_state_client_->SignalStateChange.connect( - this, &HangoutPubSubClient::OnAudioMuteStateChange); - audio_mute_state_client_->SignalPublishResult.connect( - this, &HangoutPubSubClient::OnAudioMutePublishResult); - audio_mute_state_client_->SignalPublishError.connect( - this, &HangoutPubSubClient::OnAudioMutePublishError); - - video_mute_state_client_.reset(new PubSubStateClient<bool>( - nick_, media_client_.get(), QN_GOOGLE_MUC_VIDEO_MUTE, false, - new PublishedNickKeySerializer(), new BoolStateSerializer())); - // Can't just repeat because we need to watch for remote mutes. - video_mute_state_client_->SignalStateChange.connect( - this, &HangoutPubSubClient::OnVideoMuteStateChange); - video_mute_state_client_->SignalPublishResult.connect( - this, &HangoutPubSubClient::OnVideoMutePublishResult); - video_mute_state_client_->SignalPublishError.connect( - this, &HangoutPubSubClient::OnVideoMutePublishError); - - video_pause_state_client_.reset(new PubSubStateClient<bool>( - nick_, media_client_.get(), QN_GOOGLE_MUC_VIDEO_PAUSE, false, - new PublishedNickKeySerializer(), new BoolStateSerializer())); - video_pause_state_client_->SignalStateChange.connect( - this, &HangoutPubSubClient::OnVideoPauseStateChange); - video_pause_state_client_->SignalPublishResult.connect( - this, &HangoutPubSubClient::OnVideoPausePublishResult); - video_pause_state_client_->SignalPublishError.connect( - this, &HangoutPubSubClient::OnVideoPausePublishError); - - recording_state_client_.reset(new PubSubStateClient<bool>( - nick_, media_client_.get(), QN_GOOGLE_MUC_RECORDING, false, - new PublishedNickKeySerializer(), new BoolStateSerializer())); - recording_state_client_->SignalStateChange.connect( - this, &HangoutPubSubClient::OnRecordingStateChange); - recording_state_client_->SignalPublishResult.connect( - this, &HangoutPubSubClient::OnRecordingPublishResult); - recording_state_client_->SignalPublishError.connect( - this, &HangoutPubSubClient::OnRecordingPublishError); - - media_block_state_client_.reset(new PubSubStateClient<bool>( - nick_, media_client_.get(), QN_GOOGLE_MUC_MEDIA_BLOCK, false, - new PublisherAndPublishedNicksKeySerializer(), - new BoolStateSerializer())); - media_block_state_client_->SignalStateChange.connect( - this, &HangoutPubSubClient::OnMediaBlockStateChange); - media_block_state_client_->SignalPublishResult.connect( - this, &HangoutPubSubClient::OnMediaBlockPublishResult); - media_block_state_client_->SignalPublishError.connect( - this, &HangoutPubSubClient::OnMediaBlockPublishError); -} - -HangoutPubSubClient::~HangoutPubSubClient() { -} - -void HangoutPubSubClient::RequestAll() { - presenter_client_->RequestItems(); - media_client_->RequestItems(); -} - -void HangoutPubSubClient::OnPresenterRequestError( - PubSubClient* client, const XmlElement* stanza) { - SignalRequestError(client->node(), stanza); -} - -void HangoutPubSubClient::OnMediaRequestError( - PubSubClient* client, const XmlElement* stanza) { - SignalRequestError(client->node(), stanza); -} - -void HangoutPubSubClient::PublishPresenterState( - bool presenting, std::string* task_id_out) { - presenter_state_client_->Publish(nick_, presenting, task_id_out); -} - -void HangoutPubSubClient::PublishAudioMuteState( - bool muted, std::string* task_id_out) { - audio_mute_state_client_->Publish(nick_, muted, task_id_out); -} - -void HangoutPubSubClient::PublishVideoMuteState( - bool muted, std::string* task_id_out) { - video_mute_state_client_->Publish(nick_, muted, task_id_out); -} - -void HangoutPubSubClient::PublishVideoPauseState( - bool paused, std::string* task_id_out) { - video_pause_state_client_->Publish(nick_, paused, task_id_out); -} - -void HangoutPubSubClient::PublishRecordingState( - bool recording, std::string* task_id_out) { - recording_state_client_->Publish(nick_, recording, task_id_out); -} - -// Remote mute is accomplished by setting another client's mute state. -void HangoutPubSubClient::RemoteMute( - const std::string& mutee_nick, std::string* task_id_out) { - audio_mute_state_client_->Publish(mutee_nick, true, task_id_out); -} - -// Block media is accomplished by setting another client's block -// state, kind of like remote mute. -void HangoutPubSubClient::BlockMedia( - const std::string& blockee_nick, std::string* task_id_out) { - media_block_state_client_->Publish(blockee_nick, true, task_id_out); -} - -void HangoutPubSubClient::OnPresenterStateChange( - const PubSubStateChange<bool>& change) { - SignalPresenterStateChange( - change.published_nick, change.old_state, change.new_state); -} - -void HangoutPubSubClient::OnPresenterPublishResult( - const std::string& task_id, const XmlElement* item) { - SignalPublishPresenterResult(task_id); -} - -void HangoutPubSubClient::OnPresenterPublishError( - const std::string& task_id, const XmlElement* item, - const XmlElement* stanza) { - SignalPublishPresenterError(task_id, stanza); -} - -// Since a remote mute is accomplished by another client setting our -// mute state, if our state changes to muted, we should mute ourselves. -// Note that remote un-muting is disallowed by the RoomServer. -void HangoutPubSubClient::OnAudioMuteStateChange( - const PubSubStateChange<bool>& change) { - bool was_muted = change.old_state; - bool is_muted = change.new_state; - bool remote_action = (!change.publisher_nick.empty() && - (change.publisher_nick != change.published_nick)); - - if (remote_action) { - const std::string& mutee_nick = change.published_nick; - const std::string& muter_nick = change.publisher_nick; - if (!is_muted) { - // The server should prevent remote un-mute. - LOG(LS_WARNING) << muter_nick << " remote unmuted " << mutee_nick; - return; - } - bool should_mute_locally = (mutee_nick == nick_); - SignalRemoteMute(mutee_nick, muter_nick, should_mute_locally); - } - SignalAudioMuteStateChange(change.published_nick, was_muted, is_muted); -} - -const std::string GetAudioMuteNickFromItem(const XmlElement* item) { - if (item != NULL) { - const XmlElement* audio_mute_state = - item->FirstNamed(QN_GOOGLE_MUC_AUDIO_MUTE); - if (audio_mute_state != NULL) { - return audio_mute_state->Attr(QN_NICK); - } - } - return std::string(); -} - -const std::string GetBlockeeNickFromItem(const XmlElement* item) { - if (item != NULL) { - const XmlElement* media_block_state = - item->FirstNamed(QN_GOOGLE_MUC_MEDIA_BLOCK); - if (media_block_state != NULL) { - return media_block_state->Attr(QN_NICK); - } - } - return std::string(); -} - -void HangoutPubSubClient::OnAudioMutePublishResult( - const std::string& task_id, const XmlElement* item) { - const std::string& mutee_nick = GetAudioMuteNickFromItem(item); - if (mutee_nick != nick_) { - SignalRemoteMuteResult(task_id, mutee_nick); - } else { - SignalPublishAudioMuteResult(task_id); - } -} - -void HangoutPubSubClient::OnAudioMutePublishError( - const std::string& task_id, const XmlElement* item, - const XmlElement* stanza) { - const std::string& mutee_nick = GetAudioMuteNickFromItem(item); - if (mutee_nick != nick_) { - SignalRemoteMuteError(task_id, mutee_nick, stanza); - } else { - SignalPublishAudioMuteError(task_id, stanza); - } -} - -void HangoutPubSubClient::OnVideoMuteStateChange( - const PubSubStateChange<bool>& change) { - SignalVideoMuteStateChange( - change.published_nick, change.old_state, change.new_state); -} - -void HangoutPubSubClient::OnVideoMutePublishResult( - const std::string& task_id, const XmlElement* item) { - SignalPublishVideoMuteResult(task_id); -} - -void HangoutPubSubClient::OnVideoMutePublishError( - const std::string& task_id, const XmlElement* item, - const XmlElement* stanza) { - SignalPublishVideoMuteError(task_id, stanza); -} - -void HangoutPubSubClient::OnVideoPauseStateChange( - const PubSubStateChange<bool>& change) { - SignalVideoPauseStateChange( - change.published_nick, change.old_state, change.new_state); -} - -void HangoutPubSubClient::OnVideoPausePublishResult( - const std::string& task_id, const XmlElement* item) { - SignalPublishVideoPauseResult(task_id); -} - -void HangoutPubSubClient::OnVideoPausePublishError( - const std::string& task_id, const XmlElement* item, - const XmlElement* stanza) { - SignalPublishVideoPauseError(task_id, stanza); -} - -void HangoutPubSubClient::OnRecordingStateChange( - const PubSubStateChange<bool>& change) { - SignalRecordingStateChange( - change.published_nick, change.old_state, change.new_state); -} - -void HangoutPubSubClient::OnRecordingPublishResult( - const std::string& task_id, const XmlElement* item) { - SignalPublishRecordingResult(task_id); -} - -void HangoutPubSubClient::OnRecordingPublishError( - const std::string& task_id, const XmlElement* item, - const XmlElement* stanza) { - SignalPublishRecordingError(task_id, stanza); -} - -void HangoutPubSubClient::OnMediaBlockStateChange( - const PubSubStateChange<bool>& change) { - const std::string& blockee_nick = change.published_nick; - const std::string& blocker_nick = change.publisher_nick; - - bool was_blockee = change.old_state; - bool is_blockee = change.new_state; - if (!was_blockee && is_blockee) { - SignalMediaBlock(blockee_nick, blocker_nick); - } - // TODO: Should we bother signaling unblock? Currently - // it isn't allowed, but it might happen when a participant leaves - // the room and the item is retracted. -} - -void HangoutPubSubClient::OnMediaBlockPublishResult( - const std::string& task_id, const XmlElement* item) { - const std::string& blockee_nick = GetBlockeeNickFromItem(item); - SignalMediaBlockResult(task_id, blockee_nick); -} - -void HangoutPubSubClient::OnMediaBlockPublishError( - const std::string& task_id, const XmlElement* item, - const XmlElement* stanza) { - const std::string& blockee_nick = GetBlockeeNickFromItem(item); - SignalMediaBlockError(task_id, blockee_nick, stanza); -} - -} // namespace buzz diff --git a/talk/xmpp/hangoutpubsubclient.h b/talk/xmpp/hangoutpubsubclient.h deleted file mode 100644 index 03c96f2e9..000000000 --- a/talk/xmpp/hangoutpubsubclient.h +++ /dev/null @@ -1,195 +0,0 @@ -/* - * libjingle - * Copyright 2011, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef TALK_XMPP_HANGOUTPUBSUBCLIENT_H_ -#define TALK_XMPP_HANGOUTPUBSUBCLIENT_H_ - -#include <map> -#include <string> -#include <vector> - -#include "webrtc/libjingle/xmpp/jid.h" -#include "webrtc/libjingle/xmpp/pubsubclient.h" -#include "webrtc/libjingle/xmpp/pubsubstateclient.h" -#include "webrtc/base/scoped_ptr.h" -#include "webrtc/base/sigslot.h" -#include "webrtc/base/sigslotrepeater.h" - -// Gives a high-level API for MUC call PubSub needs such as -// presenter state, recording state, mute state, and remote mute. - -namespace buzz { - -class Jid; -class XmlElement; -class XmppTaskParentInterface; - -// A client tied to a specific MUC jid and local nick. Provides ways -// to get updates and publish state and events. Must call -// RequestAll() to start getting updates. -class HangoutPubSubClient : public sigslot::has_slots<> { - public: - HangoutPubSubClient(XmppTaskParentInterface* parent, - const Jid& mucjid, - const std::string& nick); - ~HangoutPubSubClient(); - const Jid& mucjid() const { return mucjid_; } - const std::string& nick() const { return nick_; } - - // Requests all of the different states and subscribes for updates. - // Responses and updates will be signalled via the various signals. - void RequestAll(); - // Signal (nick, was_presenting, is_presenting) - sigslot::signal3<const std::string&, bool, bool> SignalPresenterStateChange; - // Signal (nick, was_muted, is_muted) - sigslot::signal3<const std::string&, bool, bool> SignalAudioMuteStateChange; - // Signal (nick, was_muted, is_muted) - sigslot::signal3<const std::string&, bool, bool> SignalVideoMuteStateChange; - // Signal (nick, was_paused, is_paused) - sigslot::signal3<const std::string&, bool, bool> SignalVideoPauseStateChange; - // Signal (nick, was_recording, is_recording) - sigslot::signal3<const std::string&, bool, bool> SignalRecordingStateChange; - // Signal (mutee_nick, muter_nick, should_mute_locally) - sigslot::signal3<const std::string&, - const std::string&, - bool> SignalRemoteMute; - // Signal (blockee_nick, blocker_nick) - sigslot::signal2<const std::string&, const std::string&> SignalMediaBlock; - - // Signal (node, error stanza) - sigslot::signal2<const std::string&, const XmlElement*> SignalRequestError; - - // On each of these, provide a task_id_out to get the task_id, which - // can be correlated to the error and result signals. - void PublishPresenterState( - bool presenting, std::string* task_id_out = NULL); - void PublishAudioMuteState( - bool muted, std::string* task_id_out = NULL); - void PublishVideoMuteState( - bool muted, std::string* task_id_out = NULL); - void PublishVideoPauseState( - bool paused, std::string* task_id_out = NULL); - void PublishRecordingState( - bool recording, std::string* task_id_out = NULL); - void RemoteMute( - const std::string& mutee_nick, std::string* task_id_out = NULL); - void BlockMedia( - const std::string& blockee_nick, std::string* task_id_out = NULL); - - // Signal task_id - sigslot::signal1<const std::string&> SignalPublishAudioMuteResult; - sigslot::signal1<const std::string&> SignalPublishVideoMuteResult; - sigslot::signal1<const std::string&> SignalPublishVideoPauseResult; - sigslot::signal1<const std::string&> SignalPublishPresenterResult; - sigslot::signal1<const std::string&> SignalPublishRecordingResult; - // Signal (task_id, mutee_nick) - sigslot::signal2<const std::string&, - const std::string&> SignalRemoteMuteResult; - // Signal (task_id, blockee_nick) - sigslot::signal2<const std::string&, - const std::string&> SignalMediaBlockResult; - - // Signal (task_id, error stanza) - sigslot::signal2<const std::string&, - const XmlElement*> SignalPublishAudioMuteError; - sigslot::signal2<const std::string&, - const XmlElement*> SignalPublishVideoMuteError; - sigslot::signal2<const std::string&, - const XmlElement*> SignalPublishVideoPauseError; - sigslot::signal2<const std::string&, - const XmlElement*> SignalPublishPresenterError; - sigslot::signal2<const std::string&, - const XmlElement*> SignalPublishRecordingError; - sigslot::signal2<const std::string&, - const XmlElement*> SignalPublishMediaBlockError; - // Signal (task_id, mutee_nick, error stanza) - sigslot::signal3<const std::string&, - const std::string&, - const XmlElement*> SignalRemoteMuteError; - // Signal (task_id, blockee_nick, error stanza) - sigslot::signal3<const std::string&, - const std::string&, - const XmlElement*> SignalMediaBlockError; - - - private: - void OnPresenterRequestError(PubSubClient* client, - const XmlElement* stanza); - void OnMediaRequestError(PubSubClient* client, - const XmlElement* stanza); - - void OnPresenterStateChange(const PubSubStateChange<bool>& change); - void OnPresenterPublishResult(const std::string& task_id, - const XmlElement* item); - void OnPresenterPublishError(const std::string& task_id, - const XmlElement* item, - const XmlElement* stanza); - void OnAudioMuteStateChange(const PubSubStateChange<bool>& change); - void OnAudioMutePublishResult(const std::string& task_id, - const XmlElement* item); - void OnAudioMutePublishError(const std::string& task_id, - const XmlElement* item, - const XmlElement* stanza); - void OnVideoMuteStateChange(const PubSubStateChange<bool>& change); - void OnVideoMutePublishResult(const std::string& task_id, - const XmlElement* item); - void OnVideoMutePublishError(const std::string& task_id, - const XmlElement* item, - const XmlElement* stanza); - void OnVideoPauseStateChange(const PubSubStateChange<bool>& change); - void OnVideoPausePublishResult(const std::string& task_id, - const XmlElement* item); - void OnVideoPausePublishError(const std::string& task_id, - const XmlElement* item, - const XmlElement* stanza); - void OnRecordingStateChange(const PubSubStateChange<bool>& change); - void OnRecordingPublishResult(const std::string& task_id, - const XmlElement* item); - void OnRecordingPublishError(const std::string& task_id, - const XmlElement* item, - const XmlElement* stanza); - void OnMediaBlockStateChange(const PubSubStateChange<bool>& change); - void OnMediaBlockPublishResult(const std::string& task_id, - const XmlElement* item); - void OnMediaBlockPublishError(const std::string& task_id, - const XmlElement* item, - const XmlElement* stanza); - Jid mucjid_; - std::string nick_; - rtc::scoped_ptr<PubSubClient> media_client_; - rtc::scoped_ptr<PubSubClient> presenter_client_; - rtc::scoped_ptr<PubSubStateClient<bool> > presenter_state_client_; - rtc::scoped_ptr<PubSubStateClient<bool> > audio_mute_state_client_; - rtc::scoped_ptr<PubSubStateClient<bool> > video_mute_state_client_; - rtc::scoped_ptr<PubSubStateClient<bool> > video_pause_state_client_; - rtc::scoped_ptr<PubSubStateClient<bool> > recording_state_client_; - rtc::scoped_ptr<PubSubStateClient<bool> > media_block_state_client_; -}; - -} // namespace buzz - -#endif // TALK_XMPP_HANGOUTPUBSUBCLIENT_H_ diff --git a/talk/xmpp/hangoutpubsubclient_unittest.cc b/talk/xmpp/hangoutpubsubclient_unittest.cc deleted file mode 100644 index 574e21a84..000000000 --- a/talk/xmpp/hangoutpubsubclient_unittest.cc +++ /dev/null @@ -1,746 +0,0 @@ -// Copyright 2011 Google Inc. All Rights Reserved - - -#include <string> - -#include "webrtc/libjingle/xmllite/qname.h" -#include "webrtc/libjingle/xmllite/xmlelement.h" -#include "webrtc/libjingle/xmpp/constants.h" -#include "webrtc/libjingle/xmpp/fakexmppclient.h" -#include "webrtc/libjingle/xmpp/hangoutpubsubclient.h" -#include "webrtc/libjingle/xmpp/jid.h" -#include "webrtc/base/faketaskrunner.h" -#include "webrtc/base/gunit.h" -#include "webrtc/base/sigslot.h" - -class TestHangoutPubSubListener : public sigslot::has_slots<> { - public: - TestHangoutPubSubListener() : - request_error_count(0), - publish_audio_mute_error_count(0), - publish_video_mute_error_count(0), - publish_video_pause_error_count(0), - publish_presenter_error_count(0), - publish_recording_error_count(0), - remote_mute_error_count(0) { - } - - void OnPresenterStateChange( - const std::string& nick, bool was_presenting, bool is_presenting) { - last_presenter_nick = nick; - last_was_presenting = was_presenting; - last_is_presenting = is_presenting; - } - - void OnAudioMuteStateChange( - const std::string& nick, bool was_muted, bool is_muted) { - last_audio_muted_nick = nick; - last_was_audio_muted = was_muted; - last_is_audio_muted = is_muted; - } - - void OnVideoMuteStateChange( - const std::string& nick, bool was_muted, bool is_muted) { - last_video_muted_nick = nick; - last_was_video_muted = was_muted; - last_is_video_muted = is_muted; - } - - void OnVideoPauseStateChange( - const std::string& nick, bool was_paused, bool is_paused) { - last_video_paused_nick = nick; - last_was_video_paused = was_paused; - last_is_video_paused = is_paused; - } - - void OnRecordingStateChange( - const std::string& nick, bool was_recording, bool is_recording) { - last_recording_nick = nick; - last_was_recording = was_recording; - last_is_recording = is_recording; - } - - void OnRemoteMute( - const std::string& mutee_nick, - const std::string& muter_nick, - bool should_mute_locally) { - last_mutee_nick = mutee_nick; - last_muter_nick = muter_nick; - last_should_mute = should_mute_locally; - } - - void OnMediaBlock( - const std::string& blockee_nick, - const std::string& blocker_nick) { - last_blockee_nick = blockee_nick; - last_blocker_nick = blocker_nick; - } - - void OnRequestError(const std::string& node, const buzz::XmlElement* stanza) { - ++request_error_count; - request_error_node = node; - } - - void OnPublishAudioMuteError(const std::string& task_id, - const buzz::XmlElement* stanza) { - ++publish_audio_mute_error_count; - error_task_id = task_id; - } - - void OnPublishVideoMuteError(const std::string& task_id, - const buzz::XmlElement* stanza) { - ++publish_video_mute_error_count; - error_task_id = task_id; - } - - void OnPublishVideoPauseError(const std::string& task_id, - const buzz::XmlElement* stanza) { - ++publish_video_pause_error_count; - error_task_id = task_id; - } - - void OnPublishPresenterError(const std::string& task_id, - const buzz::XmlElement* stanza) { - ++publish_presenter_error_count; - error_task_id = task_id; - } - - void OnPublishRecordingError(const std::string& task_id, - const buzz::XmlElement* stanza) { - ++publish_recording_error_count; - error_task_id = task_id; - } - - void OnRemoteMuteResult(const std::string& task_id, - const std::string& mutee_nick) { - result_task_id = task_id; - remote_mute_mutee_nick = mutee_nick; - } - - void OnRemoteMuteError(const std::string& task_id, - const std::string& mutee_nick, - const buzz::XmlElement* stanza) { - ++remote_mute_error_count; - error_task_id = task_id; - remote_mute_mutee_nick = mutee_nick; - } - - void OnMediaBlockResult(const std::string& task_id, - const std::string& blockee_nick) { - result_task_id = task_id; - media_blockee_nick = blockee_nick; - } - - void OnMediaBlockError(const std::string& task_id, - const std::string& blockee_nick, - const buzz::XmlElement* stanza) { - ++media_block_error_count; - error_task_id = task_id; - media_blockee_nick = blockee_nick; - } - - std::string last_presenter_nick; - bool last_is_presenting; - bool last_was_presenting; - std::string last_audio_muted_nick; - bool last_is_audio_muted; - bool last_was_audio_muted; - std::string last_video_muted_nick; - bool last_is_video_muted; - bool last_was_video_muted; - std::string last_video_paused_nick; - bool last_is_video_paused; - bool last_was_video_paused; - std::string last_recording_nick; - bool last_is_recording; - bool last_was_recording; - std::string last_mutee_nick; - std::string last_muter_nick; - bool last_should_mute; - std::string last_blockee_nick; - std::string last_blocker_nick; - - int request_error_count; - std::string request_error_node; - int publish_audio_mute_error_count; - int publish_video_mute_error_count; - int publish_video_pause_error_count; - int publish_presenter_error_count; - int publish_recording_error_count; - int remote_mute_error_count; - std::string result_task_id; - std::string error_task_id; - std::string remote_mute_mutee_nick; - int media_block_error_count; - std::string media_blockee_nick; -}; - -class HangoutPubSubClientTest : public testing::Test { - public: - HangoutPubSubClientTest() : - pubsubjid("room@domain.com"), - nick("me") { - - runner.reset(new rtc::FakeTaskRunner()); - xmpp_client = new buzz::FakeXmppClient(runner.get()); - client.reset(new buzz::HangoutPubSubClient(xmpp_client, pubsubjid, nick)); - listener.reset(new TestHangoutPubSubListener()); - client->SignalPresenterStateChange.connect( - listener.get(), &TestHangoutPubSubListener::OnPresenterStateChange); - client->SignalAudioMuteStateChange.connect( - listener.get(), &TestHangoutPubSubListener::OnAudioMuteStateChange); - client->SignalVideoMuteStateChange.connect( - listener.get(), &TestHangoutPubSubListener::OnVideoMuteStateChange); - client->SignalVideoPauseStateChange.connect( - listener.get(), &TestHangoutPubSubListener::OnVideoPauseStateChange); - client->SignalRecordingStateChange.connect( - listener.get(), &TestHangoutPubSubListener::OnRecordingStateChange); - client->SignalRemoteMute.connect( - listener.get(), &TestHangoutPubSubListener::OnRemoteMute); - client->SignalMediaBlock.connect( - listener.get(), &TestHangoutPubSubListener::OnMediaBlock); - client->SignalRequestError.connect( - listener.get(), &TestHangoutPubSubListener::OnRequestError); - client->SignalPublishAudioMuteError.connect( - listener.get(), &TestHangoutPubSubListener::OnPublishAudioMuteError); - client->SignalPublishVideoMuteError.connect( - listener.get(), &TestHangoutPubSubListener::OnPublishVideoMuteError); - client->SignalPublishVideoPauseError.connect( - listener.get(), &TestHangoutPubSubListener::OnPublishVideoPauseError); - client->SignalPublishPresenterError.connect( - listener.get(), &TestHangoutPubSubListener::OnPublishPresenterError); - client->SignalPublishRecordingError.connect( - listener.get(), &TestHangoutPubSubListener::OnPublishRecordingError); - client->SignalRemoteMuteResult.connect( - listener.get(), &TestHangoutPubSubListener::OnRemoteMuteResult); - client->SignalRemoteMuteError.connect( - listener.get(), &TestHangoutPubSubListener::OnRemoteMuteError); - client->SignalMediaBlockResult.connect( - listener.get(), &TestHangoutPubSubListener::OnMediaBlockResult); - client->SignalMediaBlockError.connect( - listener.get(), &TestHangoutPubSubListener::OnMediaBlockError); - } - - rtc::scoped_ptr<rtc::FakeTaskRunner> runner; - // xmpp_client deleted by deleting runner. - buzz::FakeXmppClient* xmpp_client; - rtc::scoped_ptr<buzz::HangoutPubSubClient> client; - rtc::scoped_ptr<TestHangoutPubSubListener> listener; - buzz::Jid pubsubjid; - std::string nick; -}; - -TEST_F(HangoutPubSubClientTest, TestRequest) { - ASSERT_EQ(0U, xmpp_client->sent_stanzas().size()); - - client->RequestAll(); - std::string expected_presenter_request = - "<cli:iq type=\"get\" to=\"room@domain.com\" id=\"0\" " - "xmlns:cli=\"jabber:client\">" - "<pub:pubsub xmlns:pub=\"http://jabber.org/protocol/pubsub\">" - "<pub:items node=\"google:presenter\"/>" - "</pub:pubsub>" - "</cli:iq>"; - - std::string expected_media_request = - "<cli:iq type=\"get\" to=\"room@domain.com\" id=\"0\" " - "xmlns:cli=\"jabber:client\">" - "<pub:pubsub xmlns:pub=\"http://jabber.org/protocol/pubsub\">" - "<pub:items node=\"google:muc#media\"/>" - "</pub:pubsub>" - "</cli:iq>"; - - ASSERT_EQ(2U, xmpp_client->sent_stanzas().size()); - EXPECT_EQ(expected_presenter_request, xmpp_client->sent_stanzas()[0]->Str()); - EXPECT_EQ(expected_media_request, xmpp_client->sent_stanzas()[1]->Str()); - - std::string presenter_response = - "<iq xmlns='jabber:client' id='0' type='result' from='room@domain.com'>" - " <pubsub xmlns='http://jabber.org/protocol/pubsub'>" - " <items node='google:presenter'>" - " <item id='12344'>" - " <presenter xmlns='google:presenter' nick='presenting-nick2'/>" - " <pre:presentation-item xmlns:pre='google:presenter'" - " pre:presentation-type='s'/>" - " </item>" - " <item id='12345'>" - " <presenter xmlns='google:presenter' nick='presenting-nick'/>" - " <pre:presentation-item xmlns:pre='google:presenter'" - " pre:presentation-type='o'/>" - " </item>" - // Some clients are "bad" in that they'll jam multiple states in - // all at once. We have to deal with it. - " <item id='12346'>" - " <presenter xmlns='google:presenter' nick='presenting-nick'/>" - " <pre:presentation-item xmlns:pre='google:presenter'" - " pre:presentation-type='s'/>" - " </item>" - " </items>" - " </pubsub>" - "</iq>"; - - xmpp_client->HandleStanza(buzz::XmlElement::ForStr(presenter_response)); - EXPECT_EQ("presenting-nick", listener->last_presenter_nick); - EXPECT_FALSE(listener->last_was_presenting); - EXPECT_TRUE(listener->last_is_presenting); - - std::string media_response = - "<iq xmlns='jabber:client' id='0' type='result' from='room@domain.com'>" - " <pubsub xmlns='http://jabber.org/protocol/pubsub'>" - " <items node='google:muc#media'>" - " <item id='audio-mute:muted-nick'>" - " <audio-mute nick='muted-nick' xmlns='google:muc#media'/>" - " </item>" - " <item id='video-mute:video-muted-nick'>" - " <video-mute nick='video-muted-nick' xmlns='google:muc#media'/>" - " </item>" - " <item id='video-pause:video-paused-nick'>" - " <video-pause nick='video-paused-nick' xmlns='google:muc#media'/>" - " </item>" - " <item id='recording:recording-nick'>" - " <recording nick='recording-nick' xmlns='google:muc#media'/>" - " </item>" - " </items>" - " </pubsub>" - "</iq>"; - - xmpp_client->HandleStanza(buzz::XmlElement::ForStr(media_response)); - EXPECT_EQ("muted-nick", listener->last_audio_muted_nick); - EXPECT_FALSE(listener->last_was_audio_muted); - EXPECT_TRUE(listener->last_is_audio_muted); - - EXPECT_EQ("video-muted-nick", listener->last_video_muted_nick); - EXPECT_FALSE(listener->last_was_video_muted); - EXPECT_TRUE(listener->last_is_video_muted); - - EXPECT_EQ("video-paused-nick", listener->last_video_paused_nick); - EXPECT_FALSE(listener->last_was_video_paused); - EXPECT_TRUE(listener->last_is_video_paused); - - EXPECT_EQ("recording-nick", listener->last_recording_nick); - EXPECT_FALSE(listener->last_was_recording); - EXPECT_TRUE(listener->last_is_recording); - - std::string incoming_presenter_resets_message = - "<message xmlns='jabber:client' from='room@domain.com'>" - " <event xmlns='http://jabber.org/protocol/pubsub#event'>" - " <items node='google:presenter'>" - " <item id='12348'>" - " <presenter xmlns='google:presenter' nick='presenting-nick'/>" - " <pre:presentation-item xmlns:pre='google:presenter'" - " pre:presentation-type='o'/>" - " </item>" - " </items>" - " </event>" - "</message>"; - - xmpp_client->HandleStanza( - buzz::XmlElement::ForStr(incoming_presenter_resets_message)); - EXPECT_EQ("presenting-nick", listener->last_presenter_nick); - //EXPECT_TRUE(listener->last_was_presenting); - EXPECT_FALSE(listener->last_is_presenting); - - std::string incoming_presenter_retracts_message = - "<message xmlns='jabber:client' from='room@domain.com'>" - " <event xmlns='http://jabber.org/protocol/pubsub#event'>" - " <items node='google:presenter'>" - " <retract id='12344'/>" - " </items>" - " </event>" - "</message>"; - - xmpp_client->HandleStanza( - buzz::XmlElement::ForStr(incoming_presenter_retracts_message)); - EXPECT_EQ("presenting-nick2", listener->last_presenter_nick); - EXPECT_TRUE(listener->last_was_presenting); - EXPECT_FALSE(listener->last_is_presenting); - - std::string incoming_media_retracts_message = - "<message xmlns='jabber:client' from='room@domain.com'>" - " <event xmlns='http://jabber.org/protocol/pubsub#event'>" - " <items node='google:muc#media'>" - " <item id='audio-mute:muted-nick'>" - " </item>" - " <retract id='video-mute:video-muted-nick'/>" - " <retract id='video-pause:video-paused-nick'/>" - " <retract id='recording:recording-nick'/>" - " </items>" - " </event>" - "</message>"; - - xmpp_client->HandleStanza( - buzz::XmlElement::ForStr(incoming_media_retracts_message)); - EXPECT_EQ("muted-nick", listener->last_audio_muted_nick); - EXPECT_TRUE(listener->last_was_audio_muted); - EXPECT_FALSE(listener->last_is_audio_muted); - - EXPECT_EQ("video-paused-nick", listener->last_video_paused_nick); - EXPECT_TRUE(listener->last_was_video_paused); - EXPECT_FALSE(listener->last_is_video_paused); - - EXPECT_EQ("recording-nick", listener->last_recording_nick); - EXPECT_TRUE(listener->last_was_recording); - EXPECT_FALSE(listener->last_is_recording); - - std::string incoming_presenter_changes_message = - "<message xmlns='jabber:client' from='room@domain.com'>" - " <event xmlns='http://jabber.org/protocol/pubsub#event'>" - " <items node='google:presenter'>" - " <item id='presenting-nick2'>" - " <presenter xmlns='google:presenter' nick='presenting-nick2'/>" - " <pre:presentation-item xmlns:pre='google:presenter'" - " pre:presentation-type='s'/>" - " </item>" - " </items>" - " </event>" - "</message>"; - - xmpp_client->HandleStanza( - buzz::XmlElement::ForStr(incoming_presenter_changes_message)); - EXPECT_EQ("presenting-nick2", listener->last_presenter_nick); - EXPECT_FALSE(listener->last_was_presenting); - EXPECT_TRUE(listener->last_is_presenting); - - xmpp_client->HandleStanza( - buzz::XmlElement::ForStr(incoming_presenter_changes_message)); - EXPECT_EQ("presenting-nick2", listener->last_presenter_nick); - EXPECT_TRUE(listener->last_was_presenting); - EXPECT_TRUE(listener->last_is_presenting); - - std::string incoming_media_changes_message = - "<message xmlns='jabber:client' from='room@domain.com'>" - " <event xmlns='http://jabber.org/protocol/pubsub#event'>" - " <items node='google:muc#media'>" - " <item id='audio-mute:muted-nick2'>" - " <audio-mute nick='muted-nick2' xmlns='google:muc#media'/>" - " </item>" - " <item id='video-pause:video-paused-nick2'>" - " <video-pause nick='video-paused-nick2' xmlns='google:muc#media'/>" - " </item>" - " <item id='recording:recording-nick2'>" - " <recording nick='recording-nick2' xmlns='google:muc#media'/>" - " </item>" - " </items>" - " </event>" - "</message>"; - - xmpp_client->HandleStanza( - buzz::XmlElement::ForStr(incoming_media_changes_message)); - EXPECT_EQ("muted-nick2", listener->last_audio_muted_nick); - EXPECT_FALSE(listener->last_was_audio_muted); - EXPECT_TRUE(listener->last_is_audio_muted); - - EXPECT_EQ("video-paused-nick2", listener->last_video_paused_nick); - EXPECT_FALSE(listener->last_was_video_paused); - EXPECT_TRUE(listener->last_is_video_paused); - - EXPECT_EQ("recording-nick2", listener->last_recording_nick); - EXPECT_FALSE(listener->last_was_recording); - EXPECT_TRUE(listener->last_is_recording); - - std::string incoming_remote_mute_message = - "<message xmlns='jabber:client' from='room@domain.com'>" - " <event xmlns='http://jabber.org/protocol/pubsub#event'>" - " <items node='google:muc#media'>" - " <item id='audio-mute:mutee' publisher='room@domain.com/muter'>" - " <audio-mute nick='mutee' xmlns='google:muc#media'/>" - " </item>" - " </items>" - " </event>" - "</message>"; - - listener->last_is_audio_muted = false; - xmpp_client->HandleStanza( - buzz::XmlElement::ForStr(incoming_remote_mute_message)); - EXPECT_EQ("mutee", listener->last_mutee_nick); - EXPECT_EQ("muter", listener->last_muter_nick); - EXPECT_FALSE(listener->last_should_mute); - EXPECT_EQ("mutee", listener->last_audio_muted_nick); - EXPECT_TRUE(listener->last_is_audio_muted); - - std::string incoming_remote_mute_me_message = - "<message xmlns='jabber:client' from='room@domain.com'>" - " <event xmlns='http://jabber.org/protocol/pubsub#event'>" - " <items node='google:muc#media'>" - " <item id='audio-mute:me' publisher='room@domain.com/muter'>" - " <audio-mute nick='me' xmlns='google:muc#media'/>" - " </item>" - " </items>" - " </event>" - "</message>"; - - listener->last_is_audio_muted = false; - xmpp_client->HandleStanza( - buzz::XmlElement::ForStr(incoming_remote_mute_me_message)); - EXPECT_EQ("me", listener->last_mutee_nick); - EXPECT_EQ("muter", listener->last_muter_nick); - EXPECT_TRUE(listener->last_should_mute); - EXPECT_EQ("me", listener->last_audio_muted_nick); - EXPECT_TRUE(listener->last_is_audio_muted); - - std::string incoming_media_block_message = - "<message xmlns='jabber:client' from='room@domain.com'>" - " <event xmlns='http://jabber.org/protocol/pubsub#event'>" - " <items node='google:muc#media'>" - " <item id='block:blocker:blockee'" - " publisher='room@domain.com/blocker'>" - " <block nick='blockee' xmlns='google:muc#media'/>" - " </item>" - " </items>" - " </event>" - "</message>"; - - xmpp_client->HandleStanza( - buzz::XmlElement::ForStr(incoming_media_block_message)); - EXPECT_EQ("blockee", listener->last_blockee_nick); - EXPECT_EQ("blocker", listener->last_blocker_nick); -} - -TEST_F(HangoutPubSubClientTest, TestRequestError) { - client->RequestAll(); - std::string result_iq = - "<iq xmlns='jabber:client' id='0' type='error' from='room@domain.com'>" - " <error type='auth'>" - " <forbidden xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>" - " </error>" - "</iq>"; - - xmpp_client->HandleStanza(buzz::XmlElement::ForStr(result_iq)); - EXPECT_EQ(1, listener->request_error_count); - EXPECT_EQ("google:presenter", listener->request_error_node); -} - -TEST_F(HangoutPubSubClientTest, TestPublish) { - client->PublishPresenterState(true); - std::string expected_presenter_iq = - "<cli:iq type=\"set\" to=\"room@domain.com\" id=\"0\" " - "xmlns:cli=\"jabber:client\">" - "<pubsub xmlns=\"http://jabber.org/protocol/pubsub\">" - "<publish node=\"google:presenter\">" - "<item id=\"me\">" - "<presenter xmlns=\"google:presenter\"" - " nick=\"me\"/>" - "<pre:presentation-item" - " pre:presentation-type=\"s\" xmlns:pre=\"google:presenter\"/>" - "</item>" - "</publish>" - "</pubsub>" - "</cli:iq>"; - - ASSERT_EQ(1U, xmpp_client->sent_stanzas().size()); - EXPECT_EQ(expected_presenter_iq, - xmpp_client->sent_stanzas()[0]->Str()); - - client->PublishAudioMuteState(true); - std::string expected_audio_mute_iq = - "<cli:iq type=\"set\" to=\"room@domain.com\" id=\"0\" " - "xmlns:cli=\"jabber:client\">" - "<pubsub xmlns=\"http://jabber.org/protocol/pubsub\">" - "<publish node=\"google:muc#media\">" - "<item id=\"audio-mute:me\">" - "<audio-mute xmlns=\"google:muc#media\" nick=\"me\"/>" - "</item>" - "</publish>" - "</pubsub>" - "</cli:iq>"; - - ASSERT_EQ(2U, xmpp_client->sent_stanzas().size()); - EXPECT_EQ(expected_audio_mute_iq, xmpp_client->sent_stanzas()[1]->Str()); - - client->PublishVideoPauseState(true); - std::string expected_video_pause_iq = - "<cli:iq type=\"set\" to=\"room@domain.com\" id=\"0\" " - "xmlns:cli=\"jabber:client\">" - "<pubsub xmlns=\"http://jabber.org/protocol/pubsub\">" - "<publish node=\"google:muc#media\">" - "<item id=\"video-pause:me\">" - "<video-pause xmlns=\"google:muc#media\" nick=\"me\"/>" - "</item>" - "</publish>" - "</pubsub>" - "</cli:iq>"; - - ASSERT_EQ(3U, xmpp_client->sent_stanzas().size()); - EXPECT_EQ(expected_video_pause_iq, xmpp_client->sent_stanzas()[2]->Str()); - - client->PublishRecordingState(true); - std::string expected_recording_iq = - "<cli:iq type=\"set\" to=\"room@domain.com\" id=\"0\" " - "xmlns:cli=\"jabber:client\">" - "<pubsub xmlns=\"http://jabber.org/protocol/pubsub\">" - "<publish node=\"google:muc#media\">" - "<item id=\"recording:me\">" - "<recording xmlns=\"google:muc#media\" nick=\"me\"/>" - "</item>" - "</publish>" - "</pubsub>" - "</cli:iq>"; - - ASSERT_EQ(4U, xmpp_client->sent_stanzas().size()); - EXPECT_EQ(expected_recording_iq, xmpp_client->sent_stanzas()[3]->Str()); - - client->RemoteMute("mutee"); - std::string expected_remote_mute_iq = - "<cli:iq type=\"set\" to=\"room@domain.com\" id=\"0\" " - "xmlns:cli=\"jabber:client\">" - "<pubsub xmlns=\"http://jabber.org/protocol/pubsub\">" - "<publish node=\"google:muc#media\">" - "<item id=\"audio-mute:mutee\">" - "<audio-mute xmlns=\"google:muc#media\" nick=\"mutee\"/>" - "</item>" - "</publish>" - "</pubsub>" - "</cli:iq>"; - - ASSERT_EQ(5U, xmpp_client->sent_stanzas().size()); - EXPECT_EQ(expected_remote_mute_iq, xmpp_client->sent_stanzas()[4]->Str()); - - client->PublishPresenterState(false); - std::string expected_presenter_retract_iq = - "<cli:iq type=\"set\" to=\"room@domain.com\" id=\"0\" " - "xmlns:cli=\"jabber:client\">" - "<pubsub xmlns=\"http://jabber.org/protocol/pubsub\">" - "<publish node=\"google:presenter\">" - "<item id=\"me\">" - "<presenter xmlns=\"google:presenter\"" - " nick=\"me\"/>" - "<pre:presentation-item" - " pre:presentation-type=\"o\" xmlns:pre=\"google:presenter\"/>" - "</item>" - "</publish>" - "</pubsub>" - "</cli:iq>"; - - ASSERT_EQ(6U, xmpp_client->sent_stanzas().size()); - EXPECT_EQ(expected_presenter_retract_iq, - xmpp_client->sent_stanzas()[5]->Str()); - - client->PublishAudioMuteState(false); - std::string expected_audio_mute_retract_iq = - "<cli:iq type=\"set\" to=\"room@domain.com\" id=\"0\" " - "xmlns:cli=\"jabber:client\">" - "<pubsub xmlns=\"http://jabber.org/protocol/pubsub\">" - "<retract node=\"google:muc#media\" notify=\"true\">" - "<item id=\"audio-mute:me\"/>" - "</retract>" - "</pubsub>" - "</cli:iq>"; - - ASSERT_EQ(7U, xmpp_client->sent_stanzas().size()); - EXPECT_EQ(expected_audio_mute_retract_iq, - xmpp_client->sent_stanzas()[6]->Str()); - - client->PublishVideoPauseState(false); - std::string expected_video_pause_retract_iq = - "<cli:iq type=\"set\" to=\"room@domain.com\" id=\"0\" " - "xmlns:cli=\"jabber:client\">" - "<pubsub xmlns=\"http://jabber.org/protocol/pubsub\">" - "<retract node=\"google:muc#media\" notify=\"true\">" - "<item id=\"video-pause:me\"/>" - "</retract>" - "</pubsub>" - "</cli:iq>"; - - ASSERT_EQ(8U, xmpp_client->sent_stanzas().size()); - EXPECT_EQ(expected_video_pause_retract_iq, - xmpp_client->sent_stanzas()[7]->Str()); - - client->BlockMedia("blockee"); - std::string expected_media_block_iq = - "<cli:iq type=\"set\" to=\"room@domain.com\" id=\"0\" " - "xmlns:cli=\"jabber:client\">" - "<pubsub xmlns=\"http://jabber.org/protocol/pubsub\">" - "<publish node=\"google:muc#media\">" - "<item id=\"block:me:blockee\">" - "<block xmlns=\"google:muc#media\" nick=\"blockee\"/>" - "</item>" - "</publish>" - "</pubsub>" - "</cli:iq>"; - - ASSERT_EQ(9U, xmpp_client->sent_stanzas().size()); - EXPECT_EQ(expected_media_block_iq, xmpp_client->sent_stanzas()[8]->Str()); -} - -TEST_F(HangoutPubSubClientTest, TestPublishPresenterError) { - std::string result_iq = - "<iq xmlns='jabber:client' id='0' type='error' from='room@domain.com'/>"; - - client->PublishPresenterState(true); - xmpp_client->HandleStanza(buzz::XmlElement::ForStr(result_iq)); - EXPECT_EQ(1, listener->publish_presenter_error_count); - EXPECT_EQ("0", listener->error_task_id); -} - - -TEST_F(HangoutPubSubClientTest, TestPublishAudioMuteError) { - std::string result_iq = - "<iq xmlns='jabber:client' id='0' type='error' from='room@domain.com'/>"; - - client->PublishAudioMuteState(true); - xmpp_client->HandleStanza(buzz::XmlElement::ForStr(result_iq)); - EXPECT_EQ(1, listener->publish_audio_mute_error_count); - EXPECT_EQ("0", listener->error_task_id); -} - -TEST_F(HangoutPubSubClientTest, TestPublishVideoPauseError) { - std::string result_iq = - "<iq xmlns='jabber:client' id='0' type='error' from='room@domain.com'/>"; - - client->PublishVideoPauseState(true); - xmpp_client->HandleStanza(buzz::XmlElement::ForStr(result_iq)); - EXPECT_EQ(1, listener->publish_video_pause_error_count); - EXPECT_EQ("0", listener->error_task_id); -} - -TEST_F(HangoutPubSubClientTest, TestPublishRecordingError) { - std::string result_iq = - "<iq xmlns='jabber:client' id='0' type='error' from='room@domain.com'/>"; - - client->PublishRecordingState(true); - xmpp_client->HandleStanza(buzz::XmlElement::ForStr(result_iq)); - EXPECT_EQ(1, listener->publish_recording_error_count); - EXPECT_EQ("0", listener->error_task_id); -} - -TEST_F(HangoutPubSubClientTest, TestPublishRemoteMuteResult) { - std::string result_iq = - "<iq xmlns='jabber:client' id='0' type='result' from='room@domain.com'/>"; - - client->RemoteMute("joe"); - xmpp_client->HandleStanza(buzz::XmlElement::ForStr(result_iq)); - EXPECT_EQ("joe", listener->remote_mute_mutee_nick); - EXPECT_EQ("0", listener->result_task_id); -} - -TEST_F(HangoutPubSubClientTest, TestRemoteMuteError) { - std::string result_iq = - "<iq xmlns='jabber:client' id='0' type='error' from='room@domain.com'/>"; - - client->RemoteMute("joe"); - xmpp_client->HandleStanza(buzz::XmlElement::ForStr(result_iq)); - EXPECT_EQ(1, listener->remote_mute_error_count); - EXPECT_EQ("joe", listener->remote_mute_mutee_nick); - EXPECT_EQ("0", listener->error_task_id); -} - -TEST_F(HangoutPubSubClientTest, TestPublishMediaBlockResult) { - std::string result_iq = - "<iq xmlns='jabber:client' id='0' type='result' from='room@domain.com'/>"; - - client->BlockMedia("joe"); - xmpp_client->HandleStanza(buzz::XmlElement::ForStr(result_iq)); - EXPECT_EQ("joe", listener->media_blockee_nick); - EXPECT_EQ("0", listener->result_task_id); -} - -TEST_F(HangoutPubSubClientTest, TestMediaBlockError) { - std::string result_iq = - "<iq xmlns='jabber:client' id='0' type='error' from='room@domain.com'/>"; - - client->BlockMedia("joe"); - xmpp_client->HandleStanza(buzz::XmlElement::ForStr(result_iq)); - EXPECT_EQ(1, listener->remote_mute_error_count); - EXPECT_EQ("joe", listener->media_blockee_nick); - EXPECT_EQ("0", listener->error_task_id); -} diff --git a/talk/xmpp/iqtask.cc b/talk/xmpp/iqtask.cc deleted file mode 100644 index d4cf310c4..000000000 --- a/talk/xmpp/iqtask.cc +++ /dev/null @@ -1,86 +0,0 @@ -/* - * libjingle - * Copyright 2011, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "webrtc/libjingle/xmpp/iqtask.h" - -#include "webrtc/libjingle/xmpp/constants.h" -#include "webrtc/libjingle/xmpp/xmppclient.h" - -namespace buzz { - -static const int kDefaultIqTimeoutSecs = 15; - -IqTask::IqTask(XmppTaskParentInterface* parent, - const std::string& verb, - const buzz::Jid& to, - buzz::XmlElement* el) - : buzz::XmppTask(parent, buzz::XmppEngine::HL_SINGLE), - to_(to), - stanza_(MakeIq(verb, to_, task_id())) { - stanza_->AddElement(el); - set_timeout_seconds(kDefaultIqTimeoutSecs); -} - -int IqTask::ProcessStart() { - buzz::XmppReturnStatus ret = SendStanza(stanza_.get()); - // TODO: HandleError(NULL) if SendStanza fails? - return (ret == buzz::XMPP_RETURN_OK) ? STATE_RESPONSE : STATE_ERROR; -} - -bool IqTask::HandleStanza(const buzz::XmlElement* stanza) { - if (!MatchResponseIq(stanza, to_, task_id())) - return false; - - if (stanza->Attr(buzz::QN_TYPE) != buzz::STR_RESULT && - stanza->Attr(buzz::QN_TYPE) != buzz::STR_ERROR) { - return false; - } - - QueueStanza(stanza); - return true; -} - -int IqTask::ProcessResponse() { - const buzz::XmlElement* stanza = NextStanza(); - if (stanza == NULL) - return STATE_BLOCKED; - - bool success = (stanza->Attr(buzz::QN_TYPE) == buzz::STR_RESULT); - if (success) { - HandleResult(stanza); - } else { - SignalError(this, stanza->FirstNamed(QN_ERROR)); - } - return STATE_DONE; -} - -int IqTask::OnTimeout() { - SignalError(this, NULL); - return XmppTask::OnTimeout(); -} - -} // namespace buzz diff --git a/talk/xmpp/iqtask.h b/talk/xmpp/iqtask.h deleted file mode 100644 index 8b0c04b09..000000000 --- a/talk/xmpp/iqtask.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * libjingle - * Copyright 2011, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef TALK_XMPP_IQTASK_H_ -#define TALK_XMPP_IQTASK_H_ - -#include <string> - -#include "webrtc/libjingle/xmpp/xmppengine.h" -#include "webrtc/libjingle/xmpp/xmpptask.h" - -namespace buzz { - -class IqTask : public XmppTask { - public: - IqTask(XmppTaskParentInterface* parent, - const std::string& verb, const Jid& to, - XmlElement* el); - virtual ~IqTask() {} - - const XmlElement* stanza() const { return stanza_.get(); } - - sigslot::signal2<IqTask*, - const XmlElement*> SignalError; - - protected: - virtual void HandleResult(const XmlElement* element) = 0; - - private: - virtual int ProcessStart(); - virtual bool HandleStanza(const XmlElement* stanza); - virtual int ProcessResponse(); - virtual int OnTimeout(); - - Jid to_; - rtc::scoped_ptr<XmlElement> stanza_; -}; - -} // namespace buzz - -#endif // TALK_XMPP_IQTASK_H_ diff --git a/talk/xmpp/jid.cc b/talk/xmpp/jid.cc deleted file mode 100644 index 0410458a4..000000000 --- a/talk/xmpp/jid.cc +++ /dev/null @@ -1,396 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "webrtc/libjingle/xmpp/jid.h" - -#include <ctype.h> - -#include <algorithm> -#include <string> - -#include "webrtc/libjingle/xmpp/constants.h" -#include "webrtc/base/common.h" -#include "webrtc/base/logging.h" - -namespace buzz { - -Jid::Jid() { -} - -Jid::Jid(const std::string& jid_string) { - if (jid_string.empty()) - return; - - // First find the slash and slice off that part - size_t slash = jid_string.find('/'); - resource_name_ = (slash == std::string::npos ? STR_EMPTY : - jid_string.substr(slash + 1)); - - // Now look for the node - size_t at = jid_string.find('@'); - size_t domain_begin; - if (at < slash && at != std::string::npos) { - node_name_ = jid_string.substr(0, at); - domain_begin = at + 1; - } else { - domain_begin = 0; - } - - // Now take what is left as the domain - size_t domain_length = (slash == std::string::npos) ? - (jid_string.length() - domain_begin) : (slash - domain_begin); - domain_name_ = jid_string.substr(domain_begin, domain_length); - - ValidateOrReset(); -} - -Jid::Jid(const std::string& node_name, - const std::string& domain_name, - const std::string& resource_name) - : node_name_(node_name), - domain_name_(domain_name), - resource_name_(resource_name) { - ValidateOrReset(); -} - -void Jid::ValidateOrReset() { - bool valid_node; - bool valid_domain; - bool valid_resource; - - node_name_ = PrepNode(node_name_, &valid_node); - domain_name_ = PrepDomain(domain_name_, &valid_domain); - resource_name_ = PrepResource(resource_name_, &valid_resource); - - if (!valid_node || !valid_domain || !valid_resource) { - node_name_.clear(); - domain_name_.clear(); - resource_name_.clear(); - } -} - -std::string Jid::Str() const { - if (!IsValid()) - return STR_EMPTY; - - std::string ret; - - if (!node_name_.empty()) - ret = node_name_ + "@"; - - ASSERT(domain_name_ != STR_EMPTY); - ret += domain_name_; - - if (!resource_name_.empty()) - ret += "/" + resource_name_; - - return ret; -} - -Jid::~Jid() { -} - -bool Jid::IsEmpty() const { - return (node_name_.empty() && domain_name_.empty() && - resource_name_.empty()); -} - -bool Jid::IsValid() const { - return !domain_name_.empty(); -} - -bool Jid::IsBare() const { - if (IsEmpty()) { - LOG(LS_VERBOSE) << "Warning: Calling IsBare() on the empty jid."; - return true; - } - return IsValid() && resource_name_.empty(); -} - -bool Jid::IsFull() const { - return IsValid() && !resource_name_.empty(); -} - -Jid Jid::BareJid() const { - if (!IsValid()) - return Jid(); - if (!IsFull()) - return *this; - return Jid(node_name_, domain_name_, STR_EMPTY); -} - -bool Jid::BareEquals(const Jid& other) const { - return other.node_name_ == node_name_ && - other.domain_name_ == domain_name_; -} - -void Jid::CopyFrom(const Jid& jid) { - this->node_name_ = jid.node_name_; - this->domain_name_ = jid.domain_name_; - this->resource_name_ = jid.resource_name_; -} - -bool Jid::operator==(const Jid& other) const { - return other.node_name_ == node_name_ && - other.domain_name_ == domain_name_ && - other.resource_name_ == resource_name_; -} - -int Jid::Compare(const Jid& other) const { - int compare_result; - compare_result = node_name_.compare(other.node_name_); - if (0 != compare_result) - return compare_result; - compare_result = domain_name_.compare(other.domain_name_); - if (0 != compare_result) - return compare_result; - compare_result = resource_name_.compare(other.resource_name_); - return compare_result; -} - -// --- JID parsing code: --- - -// Checks and normalizes the node part of a JID. -std::string Jid::PrepNode(const std::string& node, bool* valid) { - *valid = false; - std::string result; - - for (std::string::const_iterator i = node.begin(); i < node.end(); ++i) { - bool char_valid = true; - unsigned char ch = *i; - if (ch <= 0x7F) { - result += PrepNodeAscii(ch, &char_valid); - } - else { - // TODO: implement the correct stringprep protocol for these - result += tolower(ch); - } - if (!char_valid) { - return STR_EMPTY; - } - } - - if (result.length() > 1023) { - return STR_EMPTY; - } - *valid = true; - return result; -} - - -// Returns the appropriate mapping for an ASCII character in a node. -char Jid::PrepNodeAscii(char ch, bool* valid) { - *valid = true; - switch (ch) { - case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': - case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': - case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': - case 'V': case 'W': case 'X': case 'Y': case 'Z': - return (char)(ch + ('a' - 'A')); - - case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: - case 0x06: case 0x07: case 0x08: case 0x09: case 0x0A: case 0x0B: - case 0x0C: case 0x0D: case 0x0E: case 0x0F: case 0x10: case 0x11: - case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17: - case ' ': case '&': case '/': case ':': case '<': case '>': case '@': - case '\"': case '\'': - case 0x7F: - *valid = false; - return 0; - - default: - return ch; - } -} - - -// Checks and normalizes the resource part of a JID. -std::string Jid::PrepResource(const std::string& resource, bool* valid) { - *valid = false; - std::string result; - - for (std::string::const_iterator i = resource.begin(); - i < resource.end(); ++i) { - bool char_valid = true; - unsigned char ch = *i; - if (ch <= 0x7F) { - result += PrepResourceAscii(ch, &char_valid); - } - else { - // TODO: implement the correct stringprep protocol for these - result += ch; - } - } - - if (result.length() > 1023) { - return STR_EMPTY; - } - *valid = true; - return result; -} - -// Returns the appropriate mapping for an ASCII character in a resource. -char Jid::PrepResourceAscii(char ch, bool* valid) { - *valid = true; - switch (ch) { - case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: - case 0x06: case 0x07: case 0x08: case 0x09: case 0x0A: case 0x0B: - case 0x0C: case 0x0D: case 0x0E: case 0x0F: case 0x10: case 0x11: - case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17: - case 0x7F: - *valid = false; - return 0; - - default: - return ch; - } -} - -// Checks and normalizes the domain part of a JID. -std::string Jid::PrepDomain(const std::string& domain, bool* valid) { - *valid = false; - std::string result; - - // TODO: if the domain contains a ':', then we should parse it - // as an IPv6 address rather than giving an error about illegal domain. - PrepDomain(domain, &result, valid); - if (!*valid) { - return STR_EMPTY; - } - - if (result.length() > 1023) { - return STR_EMPTY; - } - *valid = true; - return result; -} - - -// Checks and normalizes an IDNA domain. -void Jid::PrepDomain(const std::string& domain, std::string* buf, bool* valid) { - *valid = false; - std::string::const_iterator last = domain.begin(); - for (std::string::const_iterator i = domain.begin(); i < domain.end(); ++i) { - bool label_valid = true; - char ch = *i; - switch (ch) { - case 0x002E: -#if 0 // FIX: This isn't UTF-8-aware. - case 0x3002: - case 0xFF0E: - case 0xFF61: -#endif - PrepDomainLabel(last, i, buf, &label_valid); - *buf += '.'; - last = i + 1; - break; - } - if (!label_valid) { - return; - } - } - PrepDomainLabel(last, domain.end(), buf, valid); -} - -// Checks and normalizes a domain label. -void Jid::PrepDomainLabel( - std::string::const_iterator start, std::string::const_iterator end, - std::string* buf, bool* valid) { - *valid = false; - - int start_len = static_cast<int>(buf->length()); - for (std::string::const_iterator i = start; i < end; ++i) { - bool char_valid = true; - unsigned char ch = *i; - if (ch <= 0x7F) { - *buf += PrepDomainLabelAscii(ch, &char_valid); - } - else { - // TODO: implement ToASCII for these - *buf += ch; - } - if (!char_valid) { - return; - } - } - - int count = static_cast<int>(buf->length() - start_len); - if (count == 0) { - return; - } - else if (count > 63) { - return; - } - - // Is this check needed? See comment in PrepDomainLabelAscii. - if ((*buf)[start_len] == '-') { - return; - } - if ((*buf)[buf->length() - 1] == '-') { - return; - } - *valid = true; -} - - -// Returns the appropriate mapping for an ASCII character in a domain label. -char Jid::PrepDomainLabelAscii(char ch, bool* valid) { - *valid = true; - // TODO: A literal reading of the spec seems to say that we do - // not need to check for these illegal characters (an "internationalized - // domain label" runs ToASCII with UseSTD3... set to false). But that - // can't be right. We should at least be checking that there are no '/' - // or '@' characters in the domain. Perhaps we should see what others - // do in this case. - - switch (ch) { - case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': - case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': - case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': - case 'V': case 'W': case 'X': case 'Y': case 'Z': - return (char)(ch + ('a' - 'A')); - - case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: - case 0x06: case 0x07: case 0x08: case 0x09: case 0x0A: case 0x0B: - case 0x0C: case 0x0D: case 0x0E: case 0x0F: case 0x10: case 0x11: - case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17: - case 0x18: case 0x19: case 0x1A: case 0x1B: case 0x1C: case 0x1D: - case 0x1E: case 0x1F: case 0x20: case 0x21: case 0x22: case 0x23: - case 0x24: case 0x25: case 0x26: case 0x27: case 0x28: case 0x29: - case 0x2A: case 0x2B: case 0x2C: case 0x2E: case 0x2F: case 0x3A: - case 0x3B: case 0x3C: case 0x3D: case 0x3E: case 0x3F: case 0x40: - case 0x5B: case 0x5C: case 0x5D: case 0x5E: case 0x5F: case 0x60: - case 0x7B: case 0x7C: case 0x7D: case 0x7E: case 0x7F: - *valid = false; - return 0; - - default: - return ch; - } -} - -} // namespace buzz diff --git a/talk/xmpp/jid.h b/talk/xmpp/jid.h deleted file mode 100644 index 2bfe0d99d..000000000 --- a/talk/xmpp/jid.h +++ /dev/null @@ -1,98 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef TALK_XMPP_JID_H_ -#define TALK_XMPP_JID_H_ - -#include <string> -#include "webrtc/libjingle/xmllite/xmlconstants.h" -#include "webrtc/base/basictypes.h" - -namespace buzz { - -// The Jid class encapsulates and provides parsing help for Jids. A Jid -// consists of three parts: the node, the domain and the resource, e.g.: -// -// node@domain/resource -// -// The node and resource are both optional. A valid jid is defined to have -// a domain. A bare jid is defined to not have a resource and a full jid -// *does* have a resource. -class Jid { -public: - explicit Jid(); - explicit Jid(const std::string& jid_string); - explicit Jid(const std::string& node_name, - const std::string& domain_name, - const std::string& resource_name); - ~Jid(); - - const std::string & node() const { return node_name_; } - const std::string & domain() const { return domain_name_; } - const std::string & resource() const { return resource_name_; } - - std::string Str() const; - Jid BareJid() const; - - bool IsEmpty() const; - bool IsValid() const; - bool IsBare() const; - bool IsFull() const; - - bool BareEquals(const Jid& other) const; - void CopyFrom(const Jid& jid); - bool operator==(const Jid& other) const; - bool operator!=(const Jid& other) const { return !operator==(other); } - - bool operator<(const Jid& other) const { return Compare(other) < 0; }; - bool operator>(const Jid& other) const { return Compare(other) > 0; }; - - int Compare(const Jid & other) const; - -private: - void ValidateOrReset(); - - static std::string PrepNode(const std::string& node, bool* valid); - static char PrepNodeAscii(char ch, bool* valid); - static std::string PrepResource(const std::string& start, bool* valid); - static char PrepResourceAscii(char ch, bool* valid); - static std::string PrepDomain(const std::string& domain, bool* valid); - static void PrepDomain(const std::string& domain, - std::string* buf, bool* valid); - static void PrepDomainLabel( - std::string::const_iterator start, std::string::const_iterator end, - std::string* buf, bool* valid); - static char PrepDomainLabelAscii(char ch, bool *valid); - - std::string node_name_; - std::string domain_name_; - std::string resource_name_; -}; - -} - -#endif // TALK_XMPP_JID_H_ diff --git a/talk/xmpp/jid_unittest.cc b/talk/xmpp/jid_unittest.cc deleted file mode 100644 index 9cae2f856..000000000 --- a/talk/xmpp/jid_unittest.cc +++ /dev/null @@ -1,115 +0,0 @@ -// Copyright 2004 Google Inc. All Rights Reserved - - -#include "webrtc/libjingle/xmpp/jid.h" -#include "webrtc/base/gunit.h" - -using buzz::Jid; - -TEST(JidTest, TestDomain) { - Jid jid("dude"); - EXPECT_EQ("", jid.node()); - EXPECT_EQ("dude", jid.domain()); - EXPECT_EQ("", jid.resource()); - EXPECT_EQ("dude", jid.Str()); - EXPECT_EQ("dude", jid.BareJid().Str()); - EXPECT_TRUE(jid.IsValid()); - EXPECT_TRUE(jid.IsBare()); - EXPECT_FALSE(jid.IsFull()); -} - -TEST(JidTest, TestNodeDomain) { - Jid jid("walter@dude"); - EXPECT_EQ("walter", jid.node()); - EXPECT_EQ("dude", jid.domain()); - EXPECT_EQ("", jid.resource()); - EXPECT_EQ("walter@dude", jid.Str()); - EXPECT_EQ("walter@dude", jid.BareJid().Str()); - EXPECT_TRUE(jid.IsValid()); - EXPECT_TRUE(jid.IsBare()); - EXPECT_FALSE(jid.IsFull()); -} - -TEST(JidTest, TestDomainResource) { - Jid jid("dude/bowlingalley"); - EXPECT_EQ("", jid.node()); - EXPECT_EQ("dude", jid.domain()); - EXPECT_EQ("bowlingalley", jid.resource()); - EXPECT_EQ("dude/bowlingalley", jid.Str()); - EXPECT_EQ("dude", jid.BareJid().Str()); - EXPECT_TRUE(jid.IsValid()); - EXPECT_FALSE(jid.IsBare()); - EXPECT_TRUE(jid.IsFull()); -} - -TEST(JidTest, TestNodeDomainResource) { - Jid jid("walter@dude/bowlingalley"); - EXPECT_EQ("walter", jid.node()); - EXPECT_EQ("dude", jid.domain()); - EXPECT_EQ("bowlingalley", jid.resource()); - EXPECT_EQ("walter@dude/bowlingalley", jid.Str()); - EXPECT_EQ("walter@dude", jid.BareJid().Str()); - EXPECT_TRUE(jid.IsValid()); - EXPECT_FALSE(jid.IsBare()); - EXPECT_TRUE(jid.IsFull()); -} - -TEST(JidTest, TestNode) { - Jid jid("walter@"); - EXPECT_EQ("", jid.node()); - EXPECT_EQ("", jid.domain()); - EXPECT_EQ("", jid.resource()); - EXPECT_EQ("", jid.Str()); - EXPECT_EQ("", jid.BareJid().Str()); - EXPECT_FALSE(jid.IsValid()); - EXPECT_TRUE(jid.IsBare()); - EXPECT_FALSE(jid.IsFull()); -} - -TEST(JidTest, TestResource) { - Jid jid("/bowlingalley"); - EXPECT_EQ("", jid.node()); - EXPECT_EQ("", jid.domain()); - EXPECT_EQ("", jid.resource()); - EXPECT_EQ("", jid.Str()); - EXPECT_EQ("", jid.BareJid().Str()); - EXPECT_FALSE(jid.IsValid()); - EXPECT_TRUE(jid.IsBare()); - EXPECT_FALSE(jid.IsFull()); -} - -TEST(JidTest, TestNodeResource) { - Jid jid("walter@/bowlingalley"); - EXPECT_EQ("", jid.node()); - EXPECT_EQ("", jid.domain()); - EXPECT_EQ("", jid.resource()); - EXPECT_EQ("", jid.Str()); - EXPECT_EQ("", jid.BareJid().Str()); - EXPECT_FALSE(jid.IsValid()); - EXPECT_TRUE(jid.IsBare()); - EXPECT_FALSE(jid.IsFull()); -} - -TEST(JidTest, TestFunky) { - Jid jid("bowling@muchat/walter@dude"); - EXPECT_EQ("bowling", jid.node()); - EXPECT_EQ("muchat", jid.domain()); - EXPECT_EQ("walter@dude", jid.resource()); - EXPECT_EQ("bowling@muchat/walter@dude", jid.Str()); - EXPECT_EQ("bowling@muchat", jid.BareJid().Str()); - EXPECT_TRUE(jid.IsValid()); - EXPECT_FALSE(jid.IsBare()); - EXPECT_TRUE(jid.IsFull()); -} - -TEST(JidTest, TestFunky2) { - Jid jid("muchat/walter@dude"); - EXPECT_EQ("", jid.node()); - EXPECT_EQ("muchat", jid.domain()); - EXPECT_EQ("walter@dude", jid.resource()); - EXPECT_EQ("muchat/walter@dude", jid.Str()); - EXPECT_EQ("muchat", jid.BareJid().Str()); - EXPECT_TRUE(jid.IsValid()); - EXPECT_FALSE(jid.IsBare()); - EXPECT_TRUE(jid.IsFull()); -} diff --git a/talk/xmpp/jingleinfotask.cc b/talk/xmpp/jingleinfotask.cc deleted file mode 100644 index 3b8fdde03..000000000 --- a/talk/xmpp/jingleinfotask.cc +++ /dev/null @@ -1,138 +0,0 @@ -/* - * libjingle - * Copyright 2010, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "webrtc/libjingle/xmpp/jingleinfotask.h" - -#include "webrtc/libjingle/xmpp/constants.h" -#include "webrtc/libjingle/xmpp/xmppclient.h" -#include "webrtc/libjingle/xmpp/xmpptask.h" -#include "webrtc/base/socketaddress.h" - -namespace buzz { - -class JingleInfoTask::JingleInfoGetTask : public XmppTask { - public: - explicit JingleInfoGetTask(XmppTaskParentInterface* parent) - : XmppTask(parent, XmppEngine::HL_SINGLE), - done_(false) {} - - virtual int ProcessStart() { - rtc::scoped_ptr<XmlElement> get( - MakeIq(STR_GET, Jid(), task_id())); - get->AddElement(new XmlElement(QN_JINGLE_INFO_QUERY, true)); - if (SendStanza(get.get()) != XMPP_RETURN_OK) { - return STATE_ERROR; - } - return STATE_RESPONSE; - } - virtual int ProcessResponse() { - if (done_) - return STATE_DONE; - return STATE_BLOCKED; - } - - protected: - virtual bool HandleStanza(const XmlElement * stanza) { - if (!MatchResponseIq(stanza, Jid(), task_id())) - return false; - - if (stanza->Attr(QN_TYPE) != STR_RESULT) - return false; - - // Queue the stanza with the parent so these don't get handled out of order - JingleInfoTask* parent = static_cast<JingleInfoTask*>(GetParent()); - parent->QueueStanza(stanza); - - // Wake ourselves so we can go into the done state - done_ = true; - Wake(); - return true; - } - - bool done_; -}; - - -void JingleInfoTask::RefreshJingleInfoNow() { - JingleInfoGetTask* get_task = new JingleInfoGetTask(this); - get_task->Start(); -} - -bool -JingleInfoTask::HandleStanza(const XmlElement * stanza) { - if (!MatchRequestIq(stanza, "set", QN_JINGLE_INFO_QUERY)) - return false; - - // only respect relay push from the server - Jid from(stanza->Attr(QN_FROM)); - if (!from.IsEmpty() && - !from.BareEquals(GetClient()->jid()) && - from != Jid(GetClient()->jid().domain())) - return false; - - QueueStanza(stanza); - return true; -} - -int -JingleInfoTask::ProcessStart() { - std::vector<std::string> relay_hosts; - std::vector<rtc::SocketAddress> stun_hosts; - std::string relay_token; - const XmlElement * stanza = NextStanza(); - if (stanza == NULL) - return STATE_BLOCKED; - const XmlElement * query = stanza->FirstNamed(QN_JINGLE_INFO_QUERY); - if (query == NULL) - return STATE_START; - const XmlElement *stun = query->FirstNamed(QN_JINGLE_INFO_STUN); - if (stun) { - for (const XmlElement *server = stun->FirstNamed(QN_JINGLE_INFO_SERVER); - server != NULL; server = server->NextNamed(QN_JINGLE_INFO_SERVER)) { - std::string host = server->Attr(QN_JINGLE_INFO_HOST); - std::string port = server->Attr(QN_JINGLE_INFO_UDP); - if (host != STR_EMPTY && host != STR_EMPTY) { - stun_hosts.push_back(rtc::SocketAddress(host, atoi(port.c_str()))); - } - } - } - - const XmlElement *relay = query->FirstNamed(QN_JINGLE_INFO_RELAY); - if (relay) { - relay_token = relay->TextNamed(QN_JINGLE_INFO_TOKEN); - for (const XmlElement *server = relay->FirstNamed(QN_JINGLE_INFO_SERVER); - server != NULL; server = server->NextNamed(QN_JINGLE_INFO_SERVER)) { - std::string host = server->Attr(QN_JINGLE_INFO_HOST); - if (host != STR_EMPTY) { - relay_hosts.push_back(host); - } - } - } - SignalJingleInfo(relay_token, relay_hosts, stun_hosts); - return STATE_START; -} -} diff --git a/talk/xmpp/jingleinfotask.h b/talk/xmpp/jingleinfotask.h deleted file mode 100644 index ac03ecfec..000000000 --- a/talk/xmpp/jingleinfotask.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * libjingle - * Copyright 2010, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef TALK_XMPP_JINGLEINFOTASK_H_ -#define TALK_XMPP_JINGLEINFOTASK_H_ - -#include <vector> - -#include "webrtc/p2p/client/httpportallocator.h" -#include "webrtc/libjingle/xmpp/xmppengine.h" -#include "webrtc/libjingle/xmpp/xmpptask.h" -#include "webrtc/base/sigslot.h" - -namespace buzz { - -class JingleInfoTask : public XmppTask { - public: - explicit JingleInfoTask(XmppTaskParentInterface* parent) : - XmppTask(parent, XmppEngine::HL_TYPE) {} - - virtual int ProcessStart(); - void RefreshJingleInfoNow(); - - sigslot::signal3<const std::string &, - const std::vector<std::string> &, - const std::vector<rtc::SocketAddress> &> - SignalJingleInfo; - - protected: - class JingleInfoGetTask; - friend class JingleInfoGetTask; - - virtual bool HandleStanza(const XmlElement * stanza); -}; -} - -#endif // TALK_XMPP_JINGLEINFOTASK_H_ diff --git a/talk/xmpp/module.h b/talk/xmpp/module.h deleted file mode 100644 index f1cff1191..000000000 --- a/talk/xmpp/module.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef TALK_XMPP_MODULE_H_ -#define TALK_XMPP_MODULE_H_ - -#include "webrtc/libjingle/xmpp/xmppengine.h" - -namespace buzz { - -class XmppEngine; - -//! This is the base class for extension modules. -//! An engine is registered with the module and the module then hooks the -//! appropriate parts of the engine to implement that set of features. It is -//! important to unregister modules before destructing the engine. -class XmppModule { -public: - virtual ~XmppModule() {} - - //! Register the engine with the module. Only one engine can be associated - //! with a module at a time. This method will return an error if there is - //! already an engine registered. - virtual XmppReturnStatus RegisterEngine(XmppEngine* engine) = 0; -}; - -} -#endif // TALK_XMPP_MODULE_H_ diff --git a/talk/xmpp/moduleimpl.cc b/talk/xmpp/moduleimpl.cc deleted file mode 100644 index 8ac755ded..000000000 --- a/talk/xmpp/moduleimpl.cc +++ /dev/null @@ -1,65 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "webrtc/libjingle/xmpp/moduleimpl.h" -#include "webrtc/base/common.h" - -namespace buzz { - -XmppModuleImpl::XmppModuleImpl() : - engine_(NULL), - stanza_handler_(this) { -} - -XmppModuleImpl::~XmppModuleImpl() -{ - if (engine_ != NULL) { - engine_->RemoveStanzaHandler(&stanza_handler_); - engine_ = NULL; - } -} - -XmppReturnStatus -XmppModuleImpl::RegisterEngine(XmppEngine* engine) -{ - if (NULL == engine || NULL != engine_) - return XMPP_RETURN_BADARGUMENT; - - engine->AddStanzaHandler(&stanza_handler_); - engine_ = engine; - - return XMPP_RETURN_OK; -} - -XmppEngine* -XmppModuleImpl::engine() { - ASSERT(NULL != engine_); - return engine_; -} - -} - diff --git a/talk/xmpp/moduleimpl.h b/talk/xmpp/moduleimpl.h deleted file mode 100644 index f1986f3bb..000000000 --- a/talk/xmpp/moduleimpl.h +++ /dev/null @@ -1,93 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef TALK_XMPP_MODULEIMPL_H_ -#define TALK_XMPP_MODULEIMPL_H_ - -#include "webrtc/libjingle/xmpp/module.h" -#include "webrtc/libjingle/xmpp/xmppengine.h" - -namespace buzz { - -//! This is the base implementation class for extension modules. -//! An engine is registered with the module and the module then hooks the -//! appropriate parts of the engine to implement that set of features. It is -//! important to unregister modules before destructing the engine. -class XmppModuleImpl { -protected: - XmppModuleImpl(); - virtual ~XmppModuleImpl(); - - //! Register the engine with the module. Only one engine can be associated - //! with a module at a time. This method will return an error if there is - //! already an engine registered. - XmppReturnStatus RegisterEngine(XmppEngine* engine); - - //! Gets the engine that this module is attached to. - XmppEngine* engine(); - - //! Process the given stanza. - //! The module must return true if it has handled the stanza. - //! A false return value causes the stanza to be passed on to - //! the next registered handler. - virtual bool HandleStanza(const XmlElement *) { return false; }; - -private: - - //! The ModuleSessionHelper nested class allows the Module - //! to hook into and get stanzas and events from the engine. - class ModuleStanzaHandler : public XmppStanzaHandler { - friend class XmppModuleImpl; - - ModuleStanzaHandler(XmppModuleImpl* module) : - module_(module) { - } - - bool HandleStanza(const XmlElement* stanza) { - return module_->HandleStanza(stanza); - } - - XmppModuleImpl* module_; - }; - - friend class ModuleStanzaHandler; - - XmppEngine* engine_; - ModuleStanzaHandler stanza_handler_; -}; - - -// This macro will implement the XmppModule interface for a class -// that derives from both XmppModuleImpl and XmppModule -#define IMPLEMENT_XMPPMODULE \ - XmppReturnStatus RegisterEngine(XmppEngine* engine) { \ - return XmppModuleImpl::RegisterEngine(engine); \ - } - -} - -#endif // TALK_XMPP_MODULEIMPL_H_ diff --git a/talk/xmpp/mucroomconfigtask.cc b/talk/xmpp/mucroomconfigtask.cc deleted file mode 100644 index 86ba5f6b8..000000000 --- a/talk/xmpp/mucroomconfigtask.cc +++ /dev/null @@ -1,91 +0,0 @@ -/* - * libjingle - * Copyright 2011, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <string> -#include <vector> - -#include "webrtc/libjingle/xmpp/mucroomconfigtask.h" - -#include "webrtc/libjingle/xmpp/constants.h" -#include "webrtc/base/scoped_ptr.h" - -namespace buzz { - -MucRoomConfigTask::MucRoomConfigTask( - XmppTaskParentInterface* parent, - const Jid& room_jid, - const std::string& room_name, - const std::vector<std::string>& room_features) - : IqTask(parent, STR_SET, room_jid, - MakeRequest(room_name, room_features)), - room_jid_(room_jid) { -} - -XmlElement* MucRoomConfigTask::MakeRequest( - const std::string& room_name, - const std::vector<std::string>& room_features) { - buzz::XmlElement* owner_query = new - buzz::XmlElement(buzz::QN_MUC_OWNER_QUERY, true); - - buzz::XmlElement* x_form = new buzz::XmlElement(buzz::QN_XDATA_X, true); - x_form->SetAttr(buzz::QN_TYPE, buzz::STR_FORM); - - buzz::XmlElement* roomname_field = - new buzz::XmlElement(buzz::QN_XDATA_FIELD, false); - roomname_field->SetAttr(buzz::QN_VAR, buzz::STR_MUC_ROOMCONFIG_ROOMNAME); - roomname_field->SetAttr(buzz::QN_TYPE, buzz::STR_TEXT_SINGLE); - - buzz::XmlElement* roomname_value = - new buzz::XmlElement(buzz::QN_XDATA_VALUE, false); - roomname_value->SetBodyText(room_name); - - roomname_field->AddElement(roomname_value); - x_form->AddElement(roomname_field); - - buzz::XmlElement* features_field = - new buzz::XmlElement(buzz::QN_XDATA_FIELD, false); - features_field->SetAttr(buzz::QN_VAR, buzz::STR_MUC_ROOMCONFIG_FEATURES); - features_field->SetAttr(buzz::QN_TYPE, buzz::STR_LIST_MULTI); - - for (std::vector<std::string>::const_iterator feature = room_features.begin(); - feature != room_features.end(); ++feature) { - buzz::XmlElement* features_value = - new buzz::XmlElement(buzz::QN_XDATA_VALUE, false); - features_value->SetBodyText(*feature); - features_field->AddElement(features_value); - } - - x_form->AddElement(features_field); - owner_query->AddElement(x_form); - return owner_query; -} - -void MucRoomConfigTask::HandleResult(const XmlElement* element) { - SignalResult(this); -} - -} // namespace buzz diff --git a/talk/xmpp/mucroomconfigtask.h b/talk/xmpp/mucroomconfigtask.h deleted file mode 100644 index 5626d3e9c..000000000 --- a/talk/xmpp/mucroomconfigtask.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * libjingle - * Copyright 2011, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef TALK_XMPP_MUCROOMCONFIGTASK_H_ -#define TALK_XMPP_MUCROOMCONFIGTASK_H_ - -#include <string> -#include "webrtc/libjingle/xmpp/iqtask.h" - -namespace buzz { - -// This task configures the muc room for document sharing and other enterprise -// specific goodies. -class MucRoomConfigTask : public IqTask { - public: - MucRoomConfigTask(XmppTaskParentInterface* parent, - const Jid& room_jid, - const std::string& room_name, - const std::vector<std::string>& room_features); - - // Room configuration does not return any reasonable error - // values. The First config request configures the room, subseqent - // ones are just ignored by server and server returns empty - // response. - sigslot::signal1<MucRoomConfigTask*> SignalResult; - - const Jid& room_jid() const { return room_jid_; } - - protected: - virtual void HandleResult(const XmlElement* stanza); - - private: - static XmlElement* MakeRequest(const std::string& room_name, - const std::vector<std::string>& room_features); - Jid room_jid_; -}; - -} // namespace buzz - -#endif // TALK_XMPP_MUCROOMCONFIGTASK_H_ diff --git a/talk/xmpp/mucroomconfigtask_unittest.cc b/talk/xmpp/mucroomconfigtask_unittest.cc deleted file mode 100644 index e9e1281b9..000000000 --- a/talk/xmpp/mucroomconfigtask_unittest.cc +++ /dev/null @@ -1,144 +0,0 @@ -/* - * libjingle - * Copyright 2011, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <string> -#include <vector> - -#include "webrtc/libjingle/xmllite/xmlelement.h" -#include "webrtc/libjingle/xmpp/constants.h" -#include "webrtc/libjingle/xmpp/fakexmppclient.h" -#include "webrtc/libjingle/xmpp/mucroomconfigtask.h" -#include "webrtc/base/faketaskrunner.h" -#include "webrtc/base/gunit.h" -#include "webrtc/base/sigslot.h" - -class MucRoomConfigListener : public sigslot::has_slots<> { - public: - MucRoomConfigListener() : result_count(0), error_count(0) {} - - void OnResult(buzz::MucRoomConfigTask*) { - ++result_count; - } - - void OnError(buzz::IqTask* task, - const buzz::XmlElement* error) { - ++error_count; - } - - int result_count; - int error_count; -}; - -class MucRoomConfigTaskTest : public testing::Test { - public: - MucRoomConfigTaskTest() : - room_jid("muc-jid-ponies@domain.com"), - room_name("ponies") { - } - - virtual void SetUp() { - runner = new rtc::FakeTaskRunner(); - xmpp_client = new buzz::FakeXmppClient(runner); - listener = new MucRoomConfigListener(); - } - - virtual void TearDown() { - delete listener; - // delete xmpp_client; Deleted by deleting runner. - delete runner; - } - - rtc::FakeTaskRunner* runner; - buzz::FakeXmppClient* xmpp_client; - MucRoomConfigListener* listener; - buzz::Jid room_jid; - std::string room_name; -}; - -TEST_F(MucRoomConfigTaskTest, TestConfigEnterprise) { - ASSERT_EQ(0U, xmpp_client->sent_stanzas().size()); - - std::vector<std::string> room_features; - room_features.push_back("feature1"); - room_features.push_back("feature2"); - buzz::MucRoomConfigTask* task = new buzz::MucRoomConfigTask( - xmpp_client, room_jid, "ponies", room_features); - EXPECT_EQ(room_jid, task->room_jid()); - - task->SignalResult.connect(listener, &MucRoomConfigListener::OnResult); - task->Start(); - - std::string expected_iq = - "<cli:iq type=\"set\" to=\"muc-jid-ponies@domain.com\" id=\"0\" " - "xmlns:cli=\"jabber:client\">" - "<query xmlns=\"http://jabber.org/protocol/muc#owner\">" - "<x xmlns=\"jabber:x:data\" type=\"form\">" - "<field var=\"muc#roomconfig_roomname\" type=\"text-single\">" - "<value>ponies</value>" - "</field>" - "<field var=\"muc#roomconfig_features\" type=\"list-multi\">" - "<value>feature1</value>" - "<value>feature2</value>" - "</field>" - "</x>" - "</query>" - "</cli:iq>"; - - ASSERT_EQ(1U, xmpp_client->sent_stanzas().size()); - EXPECT_EQ(expected_iq, xmpp_client->sent_stanzas()[0]->Str()); - - EXPECT_EQ(0, listener->result_count); - EXPECT_EQ(0, listener->error_count); - - std::string response_iq = - "<iq xmlns='jabber:client' id='0' type='result'" - " from='muc-jid-ponies@domain.com'>" - "</iq>"; - - xmpp_client->HandleStanza(buzz::XmlElement::ForStr(response_iq)); - - EXPECT_EQ(1, listener->result_count); - EXPECT_EQ(0, listener->error_count); -} - -TEST_F(MucRoomConfigTaskTest, TestError) { - std::vector<std::string> room_features; - buzz::MucRoomConfigTask* task = new buzz::MucRoomConfigTask( - xmpp_client, room_jid, "ponies", room_features); - task->SignalError.connect(listener, &MucRoomConfigListener::OnError); - task->Start(); - - std::string error_iq = - "<iq xmlns='jabber:client' id='0' type='error'" - " from='muc-jid-ponies@domain.com'>" - "</iq>"; - - xmpp_client->HandleStanza(buzz::XmlElement::ForStr(error_iq)); - - EXPECT_EQ(0, listener->result_count); - EXPECT_EQ(1, listener->error_count); -} diff --git a/talk/xmpp/mucroomdiscoverytask.cc b/talk/xmpp/mucroomdiscoverytask.cc deleted file mode 100644 index 0ec4fbe7c..000000000 --- a/talk/xmpp/mucroomdiscoverytask.cc +++ /dev/null @@ -1,83 +0,0 @@ -/* - * libjingle - * Copyright 2012, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "webrtc/libjingle/xmpp/mucroomdiscoverytask.h" - -#include "webrtc/libjingle/xmpp/constants.h" - -namespace buzz { - -MucRoomDiscoveryTask::MucRoomDiscoveryTask( - XmppTaskParentInterface* parent, - const Jid& room_jid) - : IqTask(parent, STR_GET, room_jid, - new buzz::XmlElement(buzz::QN_DISCO_INFO_QUERY)) { -} - -void MucRoomDiscoveryTask::HandleResult(const XmlElement* stanza) { - const XmlElement* query = stanza->FirstNamed(QN_DISCO_INFO_QUERY); - if (query == NULL) { - SignalError(this, NULL); - return; - } - - std::set<std::string> features; - std::map<std::string, std::string> extended_info; - const XmlElement* identity = query->FirstNamed(QN_DISCO_IDENTITY); - if (identity == NULL || !identity->HasAttr(QN_NAME)) { - SignalResult(this, false, "", "", features, extended_info); - return; - } - - const std::string name(identity->Attr(QN_NAME)); - - // Get the conversation id - const XmlElement* conversation = - identity->FirstNamed(QN_GOOGLE_MUC_HANGOUT_CONVERSATION_ID); - std::string conversation_id; - if (conversation != NULL) { - conversation_id = conversation->BodyText(); - } - - for (const XmlElement* feature = query->FirstNamed(QN_DISCO_FEATURE); - feature != NULL; feature = feature->NextNamed(QN_DISCO_FEATURE)) { - features.insert(feature->Attr(QN_VAR)); - } - - const XmlElement* data_x = query->FirstNamed(QN_XDATA_X); - if (data_x != NULL) { - for (const XmlElement* field = data_x->FirstNamed(QN_XDATA_FIELD); - field != NULL; field = field->NextNamed(QN_XDATA_FIELD)) { - const std::string key(field->Attr(QN_VAR)); - extended_info[key] = field->Attr(QN_XDATA_VALUE); - } - } - - SignalResult(this, true, name, conversation_id, features, extended_info); -} - -} // namespace buzz diff --git a/talk/xmpp/mucroomdiscoverytask.h b/talk/xmpp/mucroomdiscoverytask.h deleted file mode 100644 index dc5918d0c..000000000 --- a/talk/xmpp/mucroomdiscoverytask.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * libjingle - * Copyright 2012, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef TALK_XMPP_MUCROOMDISCOVERYTASK_H_ -#define TALK_XMPP_MUCROOMDISCOVERYTASK_H_ - -#include <map> -#include <string> -#include "webrtc/libjingle/xmpp/iqtask.h" - -namespace buzz { - -// This task requests the feature capabilities of the room. It is based on -// XEP-0030, and extended using XEP-0004. -class MucRoomDiscoveryTask : public IqTask { - public: - MucRoomDiscoveryTask(XmppTaskParentInterface* parent, - const Jid& room_jid); - - // Signal (exists, name, conversationId, features, extended_info) - sigslot::signal6<MucRoomDiscoveryTask*, - bool, - const std::string&, - const std::string&, - const std::set<std::string>&, - const std::map<std::string, std::string>& > SignalResult; - - protected: - virtual void HandleResult(const XmlElement* stanza); -}; - -} // namespace buzz - -#endif // TALK_XMPP_MUCROOMDISCOVERYTASK_H_ diff --git a/talk/xmpp/mucroomdiscoverytask_unittest.cc b/talk/xmpp/mucroomdiscoverytask_unittest.cc deleted file mode 100644 index 77fdf86c6..000000000 --- a/talk/xmpp/mucroomdiscoverytask_unittest.cc +++ /dev/null @@ -1,162 +0,0 @@ -/* - * libjingle - * Copyright 2011, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <string> -#include <vector> - -#include "webrtc/libjingle/xmllite/xmlelement.h" -#include "webrtc/libjingle/xmpp/constants.h" -#include "webrtc/libjingle/xmpp/fakexmppclient.h" -#include "webrtc/libjingle/xmpp/mucroomdiscoverytask.h" -#include "webrtc/base/faketaskrunner.h" -#include "webrtc/base/gunit.h" -#include "webrtc/base/sigslot.h" - -class MucRoomDiscoveryListener : public sigslot::has_slots<> { - public: - MucRoomDiscoveryListener() : error_count(0) {} - - void OnResult(buzz::MucRoomDiscoveryTask* task, - bool exists, - const std::string& name, - const std::string& conversation_id, - const std::set<std::string>& features, - const std::map<std::string, std::string>& extended_info) { - last_exists = exists; - last_name = name; - last_conversation_id = conversation_id; - last_features = features; - last_extended_info = extended_info; - } - - void OnError(buzz::IqTask* task, - const buzz::XmlElement* error) { - ++error_count; - } - - bool last_exists; - std::string last_name; - std::string last_conversation_id; - std::set<std::string> last_features; - std::map<std::string, std::string> last_extended_info; - int error_count; -}; - -class MucRoomDiscoveryTaskTest : public testing::Test { - public: - MucRoomDiscoveryTaskTest() : - room_jid("muc-jid-ponies@domain.com"), - room_name("ponies"), - conversation_id("test_conversation_id") { - } - - virtual void SetUp() { - runner = new rtc::FakeTaskRunner(); - xmpp_client = new buzz::FakeXmppClient(runner); - listener = new MucRoomDiscoveryListener(); - } - - virtual void TearDown() { - delete listener; - // delete xmpp_client; Deleted by deleting runner. - delete runner; - } - - rtc::FakeTaskRunner* runner; - buzz::FakeXmppClient* xmpp_client; - MucRoomDiscoveryListener* listener; - buzz::Jid room_jid; - std::string room_name; - std::string conversation_id; -}; - -TEST_F(MucRoomDiscoveryTaskTest, TestDiscovery) { - ASSERT_EQ(0U, xmpp_client->sent_stanzas().size()); - - buzz::MucRoomDiscoveryTask* task = new buzz::MucRoomDiscoveryTask( - xmpp_client, room_jid); - task->SignalResult.connect(listener, &MucRoomDiscoveryListener::OnResult); - task->Start(); - - std::string expected_iq = - "<cli:iq type=\"get\" to=\"muc-jid-ponies@domain.com\" id=\"0\" " - "xmlns:cli=\"jabber:client\">" - "<info:query xmlns:info=\"http://jabber.org/protocol/disco#info\"/>" - "</cli:iq>"; - - ASSERT_EQ(1U, xmpp_client->sent_stanzas().size()); - EXPECT_EQ(expected_iq, xmpp_client->sent_stanzas()[0]->Str()); - - EXPECT_EQ("", listener->last_name); - EXPECT_EQ("", listener->last_conversation_id); - - std::string response_iq = - "<iq xmlns='jabber:client'" - " from='muc-jid-ponies@domain.com' id='0' type='result'>" - " <info:query xmlns:info='http://jabber.org/protocol/disco#info'>" - " <info:identity name='ponies'>" - " <han:conversation-id xmlns:han='google:muc#hangout'>" - "test_conversation_id</han:conversation-id>" - " </info:identity>" - " <info:feature var='feature1'/>" - " <info:feature var='feature2'/>" - " <data:x xmlns:data='jabber:x:data'>" - " <data:field var='var1' data:value='value1' />" - " <data:field var='var2' data:value='value2' />" - " </data:x>" - " </info:query>" - "</iq>"; - - xmpp_client->HandleStanza(buzz::XmlElement::ForStr(response_iq)); - - EXPECT_EQ(true, listener->last_exists); - EXPECT_EQ(room_name, listener->last_name); - EXPECT_EQ(conversation_id, listener->last_conversation_id); - EXPECT_EQ(2U, listener->last_features.size()); - EXPECT_EQ(1U, listener->last_features.count("feature1")); - EXPECT_EQ(2U, listener->last_extended_info.size()); - EXPECT_EQ("value1", listener->last_extended_info["var1"]); - EXPECT_EQ(0, listener->error_count); -} - -TEST_F(MucRoomDiscoveryTaskTest, TestMissingName) { - buzz::MucRoomDiscoveryTask* task = new buzz::MucRoomDiscoveryTask( - xmpp_client, room_jid); - task->SignalError.connect(listener, &MucRoomDiscoveryListener::OnError); - task->Start(); - - std::string error_iq = - "<iq xmlns='jabber:client'" - " from='muc-jid-ponies@domain.com' id='0' type='result'>" - " <info:query xmlns:info='http://jabber.org/protocol/disco#info'>" - " <info:identity />" - " </info:query>" - "</iq>"; - EXPECT_EQ(0, listener->error_count); - xmpp_client->HandleStanza(buzz::XmlElement::ForStr(error_iq)); - EXPECT_EQ(0, listener->error_count); -} diff --git a/talk/xmpp/mucroomlookuptask.cc b/talk/xmpp/mucroomlookuptask.cc deleted file mode 100644 index 6832adeed..000000000 --- a/talk/xmpp/mucroomlookuptask.cc +++ /dev/null @@ -1,176 +0,0 @@ -/* - * libjingle - * Copyright 2011, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "webrtc/libjingle/xmpp/mucroomlookuptask.h" - -#include "webrtc/libjingle/xmpp/constants.h" -#include "webrtc/base/logging.h" -#include "webrtc/base/scoped_ptr.h" - - -namespace buzz { - -MucRoomLookupTask* -MucRoomLookupTask::CreateLookupTaskForRoomName(XmppTaskParentInterface* parent, - const Jid& lookup_server_jid, - const std::string& room_name, - const std::string& room_domain) { - return new MucRoomLookupTask(parent, lookup_server_jid, - MakeNameQuery(room_name, room_domain)); -} - -MucRoomLookupTask* -MucRoomLookupTask::CreateLookupTaskForRoomJid(XmppTaskParentInterface* parent, - const Jid& lookup_server_jid, - const Jid& room_jid) { - return new MucRoomLookupTask(parent, lookup_server_jid, - MakeJidQuery(room_jid)); -} - -MucRoomLookupTask* -MucRoomLookupTask::CreateLookupTaskForHangoutId(XmppTaskParentInterface* parent, - const Jid& lookup_server_jid, - const std::string& hangout_id) { - return new MucRoomLookupTask(parent, lookup_server_jid, - MakeHangoutIdQuery(hangout_id)); -} - -MucRoomLookupTask* -MucRoomLookupTask::CreateLookupTaskForExternalId( - XmppTaskParentInterface* parent, - const Jid& lookup_server_jid, - const std::string& external_id, - const std::string& type) { - return new MucRoomLookupTask(parent, lookup_server_jid, - MakeExternalIdQuery(external_id, type)); -} - -MucRoomLookupTask::MucRoomLookupTask(XmppTaskParentInterface* parent, - const Jid& lookup_server_jid, - XmlElement* query) - : IqTask(parent, STR_SET, lookup_server_jid, query) { -} - -XmlElement* MucRoomLookupTask::MakeNameQuery( - const std::string& room_name, const std::string& room_domain) { - XmlElement* name_elem = new XmlElement(QN_SEARCH_ROOM_NAME, false); - name_elem->SetBodyText(room_name); - - XmlElement* domain_elem = new XmlElement(QN_SEARCH_ROOM_DOMAIN, false); - domain_elem->SetBodyText(room_domain); - - XmlElement* query = new XmlElement(QN_SEARCH_QUERY, true); - query->AddElement(name_elem); - query->AddElement(domain_elem); - return query; -} - -XmlElement* MucRoomLookupTask::MakeJidQuery(const Jid& room_jid) { - XmlElement* jid_elem = new XmlElement(QN_SEARCH_ROOM_JID); - jid_elem->SetBodyText(room_jid.Str()); - - XmlElement* query = new XmlElement(QN_SEARCH_QUERY); - query->AddElement(jid_elem); - return query; -} - -XmlElement* MucRoomLookupTask::MakeExternalIdQuery( - const std::string& external_id, const std::string& type) { - XmlElement* external_id_elem = new XmlElement(QN_SEARCH_EXTERNAL_ID); - external_id_elem->SetAttr(QN_TYPE, type); - external_id_elem->SetBodyText(external_id); - - XmlElement* query = new XmlElement(QN_SEARCH_QUERY); - query->AddElement(external_id_elem); - return query; -} - -// Construct a stanza to lookup the muc jid for a given hangout id. eg: -// -// <query xmlns="jabber:iq:search"> -// <hangout-id>0b48ad092c893a53b7bfc87422caf38e93978798e</hangout-id> -// </query> -XmlElement* MucRoomLookupTask::MakeHangoutIdQuery( - const std::string& hangout_id) { - XmlElement* hangout_id_elem = new XmlElement(QN_SEARCH_HANGOUT_ID, false); - hangout_id_elem->SetBodyText(hangout_id); - - XmlElement* query = new XmlElement(QN_SEARCH_QUERY, true); - query->AddElement(hangout_id_elem); - return query; -} - -// Handle a response like the following: -// -// <query xmlns="jabber:iq:search"> -// <item jid="muvc-private-chat-guid@groupchat.google.com"> -// <room-name>0b48ad092c893a53b7bfc87422caf38e93978798e</room-name> -// <room-domain>hangout.google.com</room-domain> -// </item> -// </query> -void MucRoomLookupTask::HandleResult(const XmlElement* stanza) { - const XmlElement* query_elem = stanza->FirstNamed(QN_SEARCH_QUERY); - if (query_elem == NULL) { - SignalError(this, stanza); - return; - } - - const XmlElement* item_elem = query_elem->FirstNamed(QN_SEARCH_ITEM); - if (item_elem == NULL) { - SignalError(this, stanza); - return; - } - - MucRoomInfo room; - room.jid = Jid(item_elem->Attr(buzz::QN_JID)); - if (!room.jid.IsValid()) { - SignalError(this, stanza); - return; - } - - const XmlElement* room_name_elem = - item_elem->FirstNamed(QN_SEARCH_ROOM_NAME); - if (room_name_elem != NULL) { - room.name = room_name_elem->BodyText(); - } - - const XmlElement* room_domain_elem = - item_elem->FirstNamed(QN_SEARCH_ROOM_DOMAIN); - if (room_domain_elem != NULL) { - room.domain = room_domain_elem->BodyText(); - } - - const XmlElement* hangout_id_elem = - item_elem->FirstNamed(QN_SEARCH_HANGOUT_ID); - if (hangout_id_elem != NULL) { - room.hangout_id = hangout_id_elem->BodyText(); - } - - SignalResult(this, room); -} - -} // namespace buzz diff --git a/talk/xmpp/mucroomlookuptask.h b/talk/xmpp/mucroomlookuptask.h deleted file mode 100644 index 9bcca2c93..000000000 --- a/talk/xmpp/mucroomlookuptask.h +++ /dev/null @@ -1,93 +0,0 @@ -/* - * libjingle - * Copyright 2011, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef TALK_XMPP_MUCROOMLOOKUPTASK_H_ -#define TALK_XMPP_MUCROOMLOOKUPTASK_H_ - -#include <string> -#include "webrtc/libjingle/xmpp/iqtask.h" - -namespace buzz { - -struct MucRoomInfo { - Jid jid; - std::string name; - std::string domain; - std::string hangout_id; - - std::string full_name() const { - return name + "@" + domain; - } -}; - -class MucRoomLookupTask : public IqTask { - public: - enum IdType { - ID_TYPE_CONVERSATION, - ID_TYPE_HANGOUT - }; - - static MucRoomLookupTask* - CreateLookupTaskForRoomName(XmppTaskParentInterface* parent, - const Jid& lookup_server_jid, - const std::string& room_name, - const std::string& room_domain); - static MucRoomLookupTask* - CreateLookupTaskForRoomJid(XmppTaskParentInterface* parent, - const Jid& lookup_server_jid, - const Jid& room_jid); - static MucRoomLookupTask* - CreateLookupTaskForHangoutId(XmppTaskParentInterface* parent, - const Jid& lookup_server_jid, - const std::string& hangout_id); - static MucRoomLookupTask* - CreateLookupTaskForExternalId(XmppTaskParentInterface* parent, - const Jid& lookup_server_jid, - const std::string& external_id, - const std::string& type); - - sigslot::signal2<MucRoomLookupTask*, - const MucRoomInfo&> SignalResult; - - protected: - virtual void HandleResult(const XmlElement* element); - - private: - MucRoomLookupTask(XmppTaskParentInterface* parent, - const Jid& lookup_server_jid, - XmlElement* query); - static XmlElement* MakeNameQuery(const std::string& room_name, - const std::string& room_domain); - static XmlElement* MakeJidQuery(const Jid& room_jid); - static XmlElement* MakeHangoutIdQuery(const std::string& hangout_id); - static XmlElement* MakeExternalIdQuery(const std::string& external_id, - const std::string& type); -}; - -} // namespace buzz - -#endif // TALK_XMPP_MUCROOMLOOKUPTASK_H_ diff --git a/talk/xmpp/mucroomlookuptask_unittest.cc b/talk/xmpp/mucroomlookuptask_unittest.cc deleted file mode 100644 index 961e66495..000000000 --- a/talk/xmpp/mucroomlookuptask_unittest.cc +++ /dev/null @@ -1,204 +0,0 @@ -/* - * libjingle - * Copyright 2011, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <string> -#include <vector> - -#include "webrtc/libjingle/xmllite/xmlelement.h" -#include "webrtc/libjingle/xmpp/constants.h" -#include "webrtc/libjingle/xmpp/fakexmppclient.h" -#include "webrtc/libjingle/xmpp/mucroomlookuptask.h" -#include "webrtc/base/faketaskrunner.h" -#include "webrtc/base/gunit.h" -#include "webrtc/base/sigslot.h" - -class MucRoomLookupListener : public sigslot::has_slots<> { - public: - MucRoomLookupListener() : error_count(0) {} - - void OnResult(buzz::MucRoomLookupTask* task, - const buzz::MucRoomInfo& room) { - last_room = room; - } - - void OnError(buzz::IqTask* task, - const buzz::XmlElement* error) { - ++error_count; - } - - buzz::MucRoomInfo last_room; - int error_count; -}; - -class MucRoomLookupTaskTest : public testing::Test { - public: - MucRoomLookupTaskTest() : - lookup_server_jid("lookup@domain.com"), - room_jid("muc-jid-ponies@domain.com"), - room_name("ponies"), - room_domain("domain.com"), - room_full_name("ponies@domain.com"), - hangout_id("some_hangout_id") { - } - - virtual void SetUp() { - runner = new rtc::FakeTaskRunner(); - xmpp_client = new buzz::FakeXmppClient(runner); - listener = new MucRoomLookupListener(); - } - - virtual void TearDown() { - delete listener; - // delete xmpp_client; Deleted by deleting runner. - delete runner; - } - - rtc::FakeTaskRunner* runner; - buzz::FakeXmppClient* xmpp_client; - MucRoomLookupListener* listener; - buzz::Jid lookup_server_jid; - buzz::Jid room_jid; - std::string room_name; - std::string room_domain; - std::string room_full_name; - std::string hangout_id; -}; - -TEST_F(MucRoomLookupTaskTest, TestLookupName) { - ASSERT_EQ(0U, xmpp_client->sent_stanzas().size()); - - buzz::MucRoomLookupTask* task = - buzz::MucRoomLookupTask::CreateLookupTaskForRoomName( - xmpp_client, lookup_server_jid, room_name, room_domain); - task->SignalResult.connect(listener, &MucRoomLookupListener::OnResult); - task->Start(); - - std::string expected_iq = - "<cli:iq type=\"set\" to=\"lookup@domain.com\" id=\"0\" " - "xmlns:cli=\"jabber:client\">" - "<query xmlns=\"jabber:iq:search\">" - "<room-name>ponies</room-name>" - "<room-domain>domain.com</room-domain>" - "</query>" - "</cli:iq>"; - - ASSERT_EQ(1U, xmpp_client->sent_stanzas().size()); - EXPECT_EQ(expected_iq, xmpp_client->sent_stanzas()[0]->Str()); - - EXPECT_EQ("", listener->last_room.name); - - std::string response_iq = - "<iq xmlns='jabber:client' from='lookup@domain.com' id='0' type='result'>" - " <query xmlns='jabber:iq:search'>" - " <item jid='muc-jid-ponies@domain.com'>" - " <room-name>ponies</room-name>" - " <room-domain>domain.com</room-domain>" - " </item>" - " </query>" - "</iq>"; - - xmpp_client->HandleStanza(buzz::XmlElement::ForStr(response_iq)); - - EXPECT_EQ(room_name, listener->last_room.name); - EXPECT_EQ(room_domain, listener->last_room.domain); - EXPECT_EQ(room_jid, listener->last_room.jid); - EXPECT_EQ(room_full_name, listener->last_room.full_name()); - EXPECT_EQ(0, listener->error_count); -} - -TEST_F(MucRoomLookupTaskTest, TestLookupHangoutId) { - ASSERT_EQ(0U, xmpp_client->sent_stanzas().size()); - - buzz::MucRoomLookupTask* task = buzz::MucRoomLookupTask::CreateLookupTaskForHangoutId( - xmpp_client, lookup_server_jid, hangout_id); - task->SignalResult.connect(listener, &MucRoomLookupListener::OnResult); - task->Start(); - - std::string expected_iq = - "<cli:iq type=\"set\" to=\"lookup@domain.com\" id=\"0\" " - "xmlns:cli=\"jabber:client\">" - "<query xmlns=\"jabber:iq:search\">" - "<hangout-id>some_hangout_id</hangout-id>" - "</query>" - "</cli:iq>"; - - ASSERT_EQ(1U, xmpp_client->sent_stanzas().size()); - EXPECT_EQ(expected_iq, xmpp_client->sent_stanzas()[0]->Str()); - - EXPECT_EQ("", listener->last_room.name); - - std::string response_iq = - "<iq xmlns='jabber:client' from='lookup@domain.com' id='0' type='result'>" - " <query xmlns='jabber:iq:search'>" - " <item jid='muc-jid-ponies@domain.com'>" - " <room-name>some_hangout_id</room-name>" - " <room-domain>domain.com</room-domain>" - " </item>" - " </query>" - "</iq>"; - - xmpp_client->HandleStanza(buzz::XmlElement::ForStr(response_iq)); - - EXPECT_EQ(hangout_id, listener->last_room.name); - EXPECT_EQ(room_domain, listener->last_room.domain); - EXPECT_EQ(room_jid, listener->last_room.jid); - EXPECT_EQ(0, listener->error_count); -} - -TEST_F(MucRoomLookupTaskTest, TestError) { - buzz::MucRoomLookupTask* task = buzz::MucRoomLookupTask::CreateLookupTaskForRoomName( - xmpp_client, lookup_server_jid, room_name, room_domain); - task->SignalError.connect(listener, &MucRoomLookupListener::OnError); - task->Start(); - - std::string error_iq = - "<iq xmlns='jabber:client' id='0' type='error'" - " from='lookup@domain.com'>" - "</iq>"; - - EXPECT_EQ(0, listener->error_count); - xmpp_client->HandleStanza(buzz::XmlElement::ForStr(error_iq)); - EXPECT_EQ(1, listener->error_count); -} - -TEST_F(MucRoomLookupTaskTest, TestBadJid) { - buzz::MucRoomLookupTask* task = buzz::MucRoomLookupTask::CreateLookupTaskForRoomName( - xmpp_client, lookup_server_jid, room_name, room_domain); - task->SignalError.connect(listener, &MucRoomLookupListener::OnError); - task->Start(); - - std::string response_iq = - "<iq xmlns='jabber:client' from='lookup@domain.com' id='0' type='result'>" - " <query xmlns='jabber:iq:search'>" - " <item/>" - " </query>" - "</iq>"; - - EXPECT_EQ(0, listener->error_count); - xmpp_client->HandleStanza(buzz::XmlElement::ForStr(response_iq)); - EXPECT_EQ(1, listener->error_count); -} diff --git a/talk/xmpp/mucroomuniquehangoutidtask.cc b/talk/xmpp/mucroomuniquehangoutidtask.cc deleted file mode 100644 index db94741d9..000000000 --- a/talk/xmpp/mucroomuniquehangoutidtask.cc +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2012 Google Inc. All Rights Reserved. - - -#include "webrtc/libjingle/xmpp/mucroomuniquehangoutidtask.h" - -#include "webrtc/libjingle/xmpp/constants.h" - -namespace buzz { - -MucRoomUniqueHangoutIdTask::MucRoomUniqueHangoutIdTask(XmppTaskParentInterface* parent, - const Jid& lookup_server_jid) - : IqTask(parent, STR_GET, lookup_server_jid, MakeUniqueRequestXml()) { -} - -// Construct a stanza to request a unique room id. eg: -// -// <unique hangout-id="true" xmlns="http://jabber.org/protocol/muc#unique"/> -XmlElement* MucRoomUniqueHangoutIdTask::MakeUniqueRequestXml() { - XmlElement* xml = new XmlElement(QN_MUC_UNIQUE_QUERY, false); - xml->SetAttr(QN_HANGOUT_ID, STR_TRUE); - return xml; -} - -// Handle a response like the following: -// -// <unique hangout-id="hangout_id" -// xmlns="http://jabber.org/protocol/muc#unique"/> -// muvc-private-chat-guid@groupchat.google.com -// </unique> -void MucRoomUniqueHangoutIdTask::HandleResult(const XmlElement* stanza) { - - const XmlElement* unique_elem = stanza->FirstNamed(QN_MUC_UNIQUE_QUERY); - if (unique_elem == NULL || - !unique_elem->HasAttr(QN_HANGOUT_ID)) { - SignalError(this, stanza); - return; - } - - std::string hangout_id = unique_elem->Attr(QN_HANGOUT_ID); - - SignalResult(this, hangout_id); -} - -} // namespace buzz diff --git a/talk/xmpp/mucroomuniquehangoutidtask.h b/talk/xmpp/mucroomuniquehangoutidtask.h deleted file mode 100644 index 83de43480..000000000 --- a/talk/xmpp/mucroomuniquehangoutidtask.h +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2012 Google Inc. All Rights Reserved. - - -#ifndef TALK_XMPP_MUCROOMUNIQUEHANGOUTIDTASK_H_ -#define TALK_XMPP_MUCROOMUNIQUEHANGOUTIDTASK_H_ - -#include "webrtc/libjingle/xmpp/iqtask.h" - -namespace buzz { - -// Task to request a unique hangout id to be used when starting a hangout. -// The protocol is described in https://docs.google.com/a/google.com/ -// document/d/1EFLT6rCYPDVdqQXSQliXwqB3iUkpZJ9B_MNFeOZgN7g/edit -class MucRoomUniqueHangoutIdTask : public buzz::IqTask { - public: - MucRoomUniqueHangoutIdTask(buzz::XmppTaskParentInterface* parent, - const Jid& lookup_server_jid); - // signal(task, hangout_id) - sigslot::signal2<MucRoomUniqueHangoutIdTask*, const std::string&> SignalResult; - - protected: - virtual void HandleResult(const buzz::XmlElement* stanza); - - private: - static buzz::XmlElement* MakeUniqueRequestXml(); - -}; - -} // namespace buzz - -#endif // TALK_XMPP_MUCROOMUNIQUEHANGOUTIDTASK_H_ diff --git a/talk/xmpp/mucroomuniquehangoutidtask_unittest.cc b/talk/xmpp/mucroomuniquehangoutidtask_unittest.cc deleted file mode 100644 index d8f7c2037..000000000 --- a/talk/xmpp/mucroomuniquehangoutidtask_unittest.cc +++ /dev/null @@ -1,116 +0,0 @@ -/* - * libjingle - * Copyright 2011, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <string> -#include <vector> - -#include "webrtc/libjingle/xmllite/xmlelement.h" -#include "webrtc/libjingle/xmpp/constants.h" -#include "webrtc/libjingle/xmpp/fakexmppclient.h" -#include "webrtc/libjingle/xmpp/mucroomuniquehangoutidtask.h" -#include "webrtc/base/faketaskrunner.h" -#include "webrtc/base/gunit.h" -#include "webrtc/base/sigslot.h" - -class MucRoomUniqueHangoutIdListener : public sigslot::has_slots<> { - public: - MucRoomUniqueHangoutIdListener() : error_count(0) {} - - void OnResult(buzz::MucRoomUniqueHangoutIdTask* task, - const std::string& hangout_id) { - last_hangout_id = hangout_id; - } - - void OnError(buzz::IqTask* task, - const buzz::XmlElement* error) { - ++error_count; - } - - std::string last_hangout_id; - int error_count; -}; - -class MucRoomUniqueHangoutIdTaskTest : public testing::Test { - public: - MucRoomUniqueHangoutIdTaskTest() : - lookup_server_jid("lookup@domain.com"), - hangout_id("some_hangout_id") { - } - - virtual void SetUp() { - runner = new rtc::FakeTaskRunner(); - xmpp_client = new buzz::FakeXmppClient(runner); - listener = new MucRoomUniqueHangoutIdListener(); - } - - virtual void TearDown() { - delete listener; - // delete xmpp_client; Deleted by deleting runner. - delete runner; - } - - rtc::FakeTaskRunner* runner; - buzz::FakeXmppClient* xmpp_client; - MucRoomUniqueHangoutIdListener* listener; - buzz::Jid lookup_server_jid; - std::string hangout_id; -}; - -TEST_F(MucRoomUniqueHangoutIdTaskTest, Test) { - ASSERT_EQ(0U, xmpp_client->sent_stanzas().size()); - - buzz::MucRoomUniqueHangoutIdTask* task = new buzz::MucRoomUniqueHangoutIdTask( - xmpp_client, lookup_server_jid); - task->SignalResult.connect(listener, &MucRoomUniqueHangoutIdListener::OnResult); - task->Start(); - - std::string expected_iq = - "<cli:iq type=\"get\" to=\"lookup@domain.com\" id=\"0\" " - "xmlns:cli=\"jabber:client\">" - "<uni:unique hangout-id=\"true\" " - "xmlns:uni=\"http://jabber.org/protocol/muc#unique\"/>" - "</cli:iq>"; - - ASSERT_EQ(1U, xmpp_client->sent_stanzas().size()); - EXPECT_EQ(expected_iq, xmpp_client->sent_stanzas()[0]->Str()); - - EXPECT_EQ("", listener->last_hangout_id); - - std::string response_iq = - "<iq xmlns='jabber:client' from='lookup@domain.com' id='0' type='result'>" - "<unique hangout-id=\"some_hangout_id\" " - "xmlns=\"http://jabber.org/protocol/muc#unique\">" - "muvc-private-chat-00001234-5678-9abc-def0-123456789abc" - "</unique>" - "</iq>"; - - xmpp_client->HandleStanza(buzz::XmlElement::ForStr(response_iq)); - - EXPECT_EQ(hangout_id, listener->last_hangout_id); - EXPECT_EQ(0, listener->error_count); -} - diff --git a/talk/xmpp/pingtask.cc b/talk/xmpp/pingtask.cc deleted file mode 100644 index 619c3a8d9..000000000 --- a/talk/xmpp/pingtask.cc +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright 2011 Google Inc. All Rights Reserved. - - -#include "webrtc/libjingle/xmpp/pingtask.h" - -#include "webrtc/libjingle/xmpp/constants.h" -#include "webrtc/base/logging.h" -#include "webrtc/base/scoped_ptr.h" - -namespace buzz { - -PingTask::PingTask(buzz::XmppTaskParentInterface* parent, - rtc::MessageQueue* message_queue, - uint32 ping_period_millis, - uint32 ping_timeout_millis) - : buzz::XmppTask(parent, buzz::XmppEngine::HL_SINGLE), - message_queue_(message_queue), - ping_period_millis_(ping_period_millis), - ping_timeout_millis_(ping_timeout_millis), - next_ping_time_(0), - ping_response_deadline_(0) { - ASSERT(ping_period_millis >= ping_timeout_millis); -} - -bool PingTask::HandleStanza(const buzz::XmlElement* stanza) { - if (!MatchResponseIq(stanza, Jid(STR_EMPTY), task_id())) { - return false; - } - - if (stanza->Attr(buzz::QN_TYPE) != buzz::STR_RESULT && - stanza->Attr(buzz::QN_TYPE) != buzz::STR_ERROR) { - return false; - } - - QueueStanza(stanza); - return true; -} - -// This task runs indefinitely and remains in either the start or blocked -// states. -int PingTask::ProcessStart() { - if (ping_period_millis_ < ping_timeout_millis_) { - LOG(LS_ERROR) << "ping_period_millis should be >= ping_timeout_millis"; - return STATE_ERROR; - } - const buzz::XmlElement* stanza = NextStanza(); - if (stanza != NULL) { - // Received a ping response of some sort (don't care what it is). - ping_response_deadline_ = 0; - } - - uint32 now = rtc::Time(); - - // If the ping timed out, signal. - if (ping_response_deadline_ != 0 && now >= ping_response_deadline_) { - SignalTimeout(); - return STATE_ERROR; - } - - // Send a ping if it's time. - if (now >= next_ping_time_) { - rtc::scoped_ptr<buzz::XmlElement> stanza( - MakeIq(buzz::STR_GET, Jid(STR_EMPTY), task_id())); - stanza->AddElement(new buzz::XmlElement(QN_PING)); - SendStanza(stanza.get()); - - ping_response_deadline_ = now + ping_timeout_millis_; - next_ping_time_ = now + ping_period_millis_; - - // Wake ourselves up when it's time to send another ping or when the ping - // times out (so we can fire a signal). - message_queue_->PostDelayed(ping_timeout_millis_, this); - message_queue_->PostDelayed(ping_period_millis_, this); - } - - return STATE_BLOCKED; -} - -void PingTask::OnMessage(rtc::Message* msg) { - // Get the task manager to run this task so we can send a ping or signal or - // process a ping response. - Wake(); -} - -} // namespace buzz diff --git a/talk/xmpp/pingtask.h b/talk/xmpp/pingtask.h deleted file mode 100644 index 87d74b4b3..000000000 --- a/talk/xmpp/pingtask.h +++ /dev/null @@ -1,71 +0,0 @@ -/* - * libjingle - * Copyright 2011, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef TALK_XMPP_PINGTASK_H_ -#define TALK_XMPP_PINGTASK_H_ - -#include "webrtc/libjingle/xmpp/xmpptask.h" -#include "webrtc/base/messagehandler.h" -#include "webrtc/base/messagequeue.h" - -namespace buzz { - -// Task to periodically send pings to the server to ensure that the network -// connection is valid, implementing XEP-0199. -// -// This is especially useful on cellular networks because: -// 1. It keeps the connections alive through the cellular network's NATs or -// proxies. -// 2. It detects when the server has crashed or any other case in which the -// connection has broken without a fin or reset packet being sent to us. -class PingTask : public buzz::XmppTask, private rtc::MessageHandler { - public: - PingTask(buzz::XmppTaskParentInterface* parent, - rtc::MessageQueue* message_queue, uint32 ping_period_millis, - uint32 ping_timeout_millis); - - virtual bool HandleStanza(const buzz::XmlElement* stanza); - virtual int ProcessStart(); - - // Raised if there is no response to a ping within ping_timeout_millis. - // The task is automatically aborted after a timeout. - sigslot::signal0<> SignalTimeout; - - private: - // Implementation of MessageHandler. - virtual void OnMessage(rtc::Message* msg); - - rtc::MessageQueue* message_queue_; - uint32 ping_period_millis_; - uint32 ping_timeout_millis_; - uint32 next_ping_time_; - uint32 ping_response_deadline_; // 0 if the response has been received -}; - -} // namespace buzz - -#endif // TALK_XMPP_PINGTASK_H_ diff --git a/talk/xmpp/pingtask_unittest.cc b/talk/xmpp/pingtask_unittest.cc deleted file mode 100644 index a0b6618c0..000000000 --- a/talk/xmpp/pingtask_unittest.cc +++ /dev/null @@ -1,118 +0,0 @@ -/* - * libjingle - * Copyright 2011, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <string> -#include <vector> - -#include "webrtc/libjingle/xmllite/xmlelement.h" -#include "webrtc/libjingle/xmpp/constants.h" -#include "webrtc/libjingle/xmpp/fakexmppclient.h" -#include "webrtc/libjingle/xmpp/pingtask.h" -#include "webrtc/base/faketaskrunner.h" -#include "webrtc/base/gunit.h" -#include "webrtc/base/sigslot.h" - -class PingTaskTest; - -class PingXmppClient : public buzz::FakeXmppClient { - public: - PingXmppClient(rtc::TaskParent* parent, PingTaskTest* tst) : - FakeXmppClient(parent), test(tst) { - } - - buzz::XmppReturnStatus SendStanza(const buzz::XmlElement* stanza); - - private: - PingTaskTest* test; -}; - -class PingTaskTest : public testing::Test, public sigslot::has_slots<> { - public: - PingTaskTest() : respond_to_pings(true), timed_out(false) { - } - - virtual void SetUp() { - runner = new rtc::FakeTaskRunner(); - xmpp_client = new PingXmppClient(runner, this); - } - - virtual void TearDown() { - // delete xmpp_client; Deleted by deleting runner. - delete runner; - } - - void ConnectTimeoutSignal(buzz::PingTask* task) { - task->SignalTimeout.connect(this, &PingTaskTest::OnPingTimeout); - } - - void OnPingTimeout() { - timed_out = true; - } - - rtc::FakeTaskRunner* runner; - PingXmppClient* xmpp_client; - bool respond_to_pings; - bool timed_out; -}; - -buzz::XmppReturnStatus PingXmppClient::SendStanza( - const buzz::XmlElement* stanza) { - buzz::XmppReturnStatus result = FakeXmppClient::SendStanza(stanza); - if (test->respond_to_pings && (stanza->FirstNamed(buzz::QN_PING) != NULL)) { - std::string ping_response = - "<iq xmlns=\'jabber:client\' id='0' type='result'/>"; - HandleStanza(buzz::XmlElement::ForStr(ping_response)); - } - return result; -} - -TEST_F(PingTaskTest, TestSuccess) { - uint32 ping_period_millis = 100; - buzz::PingTask* task = new buzz::PingTask(xmpp_client, - rtc::Thread::Current(), - ping_period_millis, ping_period_millis / 10); - ConnectTimeoutSignal(task); - task->Start(); - unsigned int expected_ping_count = 5U; - EXPECT_EQ_WAIT(xmpp_client->sent_stanzas().size(), expected_ping_count, - ping_period_millis * (expected_ping_count + 1)); - EXPECT_FALSE(task->IsDone()); - EXPECT_FALSE(timed_out); -} - -TEST_F(PingTaskTest, TestTimeout) { - respond_to_pings = false; - uint32 ping_timeout_millis = 200; - buzz::PingTask* task = new buzz::PingTask(xmpp_client, - rtc::Thread::Current(), - ping_timeout_millis * 10, ping_timeout_millis); - ConnectTimeoutSignal(task); - task->Start(); - WAIT(false, ping_timeout_millis / 2); - EXPECT_FALSE(timed_out); - EXPECT_TRUE_WAIT(timed_out, ping_timeout_millis * 2); -} diff --git a/talk/xmpp/plainsaslhandler.h b/talk/xmpp/plainsaslhandler.h deleted file mode 100644 index f23782d65..000000000 --- a/talk/xmpp/plainsaslhandler.h +++ /dev/null @@ -1,81 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef TALK_XMPP_PLAINSASLHANDLER_H_ -#define TALK_XMPP_PLAINSASLHANDLER_H_ - -#include <algorithm> -#include "webrtc/libjingle/xmpp/saslhandler.h" -#include "webrtc/libjingle/xmpp/saslplainmechanism.h" -#include "webrtc/base/cryptstring.h" - -namespace buzz { - -class PlainSaslHandler : public SaslHandler { -public: - PlainSaslHandler(const Jid & jid, const rtc::CryptString & password, - bool allow_plain) : jid_(jid), password_(password), - allow_plain_(allow_plain) {} - - virtual ~PlainSaslHandler() {} - - // Should pick the best method according to this handler - // returns the empty string if none are suitable - virtual std::string ChooseBestSaslMechanism(const std::vector<std::string> & mechanisms, bool encrypted) { - - if (!encrypted && !allow_plain_) { - return ""; - } - - std::vector<std::string>::const_iterator it = std::find(mechanisms.begin(), mechanisms.end(), "PLAIN"); - if (it == mechanisms.end()) { - return ""; - } - else { - return "PLAIN"; - } - } - - // Creates a SaslMechanism for the given mechanism name (you own it - // once you get it). If not handled, return NULL. - virtual SaslMechanism * CreateSaslMechanism(const std::string & mechanism) { - if (mechanism == "PLAIN") { - return new SaslPlainMechanism(jid_, password_); - } - return NULL; - } - -private: - Jid jid_; - rtc::CryptString password_; - bool allow_plain_; -}; - - -} - -#endif // TALK_XMPP_PLAINSASLHANDLER_H_ diff --git a/talk/xmpp/presenceouttask.cc b/talk/xmpp/presenceouttask.cc deleted file mode 100644 index 39ef6466c..000000000 --- a/talk/xmpp/presenceouttask.cc +++ /dev/null @@ -1,157 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <time.h> -#include <sstream> -#include "webrtc/libjingle/xmpp/constants.h" -#include "webrtc/libjingle/xmpp/presenceouttask.h" -#include "webrtc/libjingle/xmpp/xmppclient.h" -#include "webrtc/base/stringencode.h" - -namespace buzz { - -XmppReturnStatus -PresenceOutTask::Send(const PresenceStatus & s) { - if (GetState() != STATE_INIT && GetState() != STATE_START) - return XMPP_RETURN_BADSTATE; - - XmlElement * presence = TranslateStatus(s); - QueueStanza(presence); - delete presence; - return XMPP_RETURN_OK; -} - -XmppReturnStatus -PresenceOutTask::SendDirected(const Jid & j, const PresenceStatus & s) { - if (GetState() != STATE_INIT && GetState() != STATE_START) - return XMPP_RETURN_BADSTATE; - - XmlElement * presence = TranslateStatus(s); - presence->AddAttr(QN_TO, j.Str()); - QueueStanza(presence); - delete presence; - return XMPP_RETURN_OK; -} - -XmppReturnStatus PresenceOutTask::SendProbe(const Jid & jid) { - if (GetState() != STATE_INIT && GetState() != STATE_START) - return XMPP_RETURN_BADSTATE; - - XmlElement * presence = new XmlElement(QN_PRESENCE); - presence->AddAttr(QN_TO, jid.Str()); - presence->AddAttr(QN_TYPE, "probe"); - - QueueStanza(presence); - delete presence; - return XMPP_RETURN_OK; -} - -int -PresenceOutTask::ProcessStart() { - const XmlElement * stanza = NextStanza(); - if (stanza == NULL) - return STATE_BLOCKED; - - if (SendStanza(stanza) != XMPP_RETURN_OK) - return STATE_ERROR; - - return STATE_START; -} - -XmlElement * -PresenceOutTask::TranslateStatus(const PresenceStatus & s) { - XmlElement * result = new XmlElement(QN_PRESENCE); - if (!s.available()) { - result->AddAttr(QN_TYPE, STR_UNAVAILABLE); - } - else { - if (s.show() != PresenceStatus::SHOW_ONLINE && - s.show() != PresenceStatus::SHOW_OFFLINE) { - result->AddElement(new XmlElement(QN_SHOW)); - switch (s.show()) { - default: - result->AddText(STR_SHOW_AWAY, 1); - break; - case PresenceStatus::SHOW_XA: - result->AddText(STR_SHOW_XA, 1); - break; - case PresenceStatus::SHOW_DND: - result->AddText(STR_SHOW_DND, 1); - break; - case PresenceStatus::SHOW_CHAT: - result->AddText(STR_SHOW_CHAT, 1); - break; - } - } - - result->AddElement(new XmlElement(QN_STATUS)); - result->AddText(s.status(), 1); - - if (!s.nick().empty()) { - result->AddElement(new XmlElement(QN_NICKNAME)); - result->AddText(s.nick(), 1); - } - - std::string pri; - rtc::ToString(s.priority(), &pri); - - result->AddElement(new XmlElement(QN_PRIORITY)); - result->AddText(pri, 1); - - if (s.know_capabilities()) { - result->AddElement(new XmlElement(QN_CAPS_C, true)); - result->AddAttr(QN_NODE, s.caps_node(), 1); - result->AddAttr(QN_VER, s.version(), 1); - - std::string caps; - caps.append(s.voice_capability() ? "voice-v1" : ""); - caps.append(s.pmuc_capability() ? " pmuc-v1" : ""); - caps.append(s.video_capability() ? " video-v1" : ""); - caps.append(s.camera_capability() ? " camera-v1" : ""); - - result->AddAttr(QN_EXT, caps, 1); - } - - // Put the delay mark on the presence according to JEP-0091 - { - result->AddElement(new XmlElement(kQnDelayX, true)); - - // This here is why we *love* the C runtime - time_t current_time_seconds; - time(¤t_time_seconds); - struct tm* current_time = gmtime(¤t_time_seconds); - char output[256]; - strftime(output, ARRAY_SIZE(output), "%Y%m%dT%H:%M:%S", current_time); - result->AddAttr(kQnStamp, output, 1); - } - } - - return result; -} - - -} diff --git a/talk/xmpp/presenceouttask.h b/talk/xmpp/presenceouttask.h deleted file mode 100644 index f6b04afe5..000000000 --- a/talk/xmpp/presenceouttask.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef TALK_XMPP_PRESENCEOUTTASK_H_ -#define TALK_XMPP_PRESENCEOUTTASK_H_ - -#include "webrtc/libjingle/xmpp/presencestatus.h" -#include "webrtc/libjingle/xmpp/xmppengine.h" -#include "webrtc/libjingle/xmpp/xmpptask.h" - -namespace buzz { - -class PresenceOutTask : public XmppTask { -public: - explicit PresenceOutTask(XmppTaskParentInterface* parent) - : XmppTask(parent) {} - virtual ~PresenceOutTask() {} - - XmppReturnStatus Send(const PresenceStatus & s); - XmppReturnStatus SendDirected(const Jid & j, const PresenceStatus & s); - XmppReturnStatus SendProbe(const Jid& jid); - - virtual int ProcessStart(); -private: - XmlElement * TranslateStatus(const PresenceStatus & s); -}; - -} - -#endif // TALK_XMPP_PRESENCEOUTTASK_H_ diff --git a/talk/xmpp/presencereceivetask.cc b/talk/xmpp/presencereceivetask.cc deleted file mode 100644 index 0a159ac7b..000000000 --- a/talk/xmpp/presencereceivetask.cc +++ /dev/null @@ -1,158 +0,0 @@ -/* - * libjingle - * Copyright 2004--2012, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "webrtc/libjingle/xmpp/presencereceivetask.h" - -#include "webrtc/libjingle/xmpp/constants.h" -#include "webrtc/base/stringencode.h" - -namespace buzz { - -static bool IsUtf8FirstByte(int c) { - return (((c)&0x80)==0) || // is single byte - ((unsigned char)((c)-0xc0)<0x3e); // or is lead byte -} - -PresenceReceiveTask::PresenceReceiveTask(XmppTaskParentInterface* parent) - : XmppTask(parent, XmppEngine::HL_TYPE) { -} - -PresenceReceiveTask::~PresenceReceiveTask() { - Stop(); -} - -int PresenceReceiveTask::ProcessStart() { - const XmlElement * stanza = NextStanza(); - if (stanza == NULL) { - return STATE_BLOCKED; - } - - Jid from(stanza->Attr(QN_FROM)); - HandlePresence(from, stanza); - - return STATE_START; -} - -bool PresenceReceiveTask::HandleStanza(const XmlElement * stanza) { - // Verify that this is a presence stanze - if (stanza->Name() != QN_PRESENCE) { - return false; // not sure if this ever happens. - } - - // Queue it up - QueueStanza(stanza); - - return true; -} - -void PresenceReceiveTask::HandlePresence(const Jid& from, - const XmlElement* stanza) { - if (stanza->Attr(QN_TYPE) == STR_ERROR) { - return; - } - - PresenceStatus status; - DecodeStatus(from, stanza, &status); - PresenceUpdate(status); -} - -void PresenceReceiveTask::DecodeStatus(const Jid& from, - const XmlElement* stanza, - PresenceStatus* presence_status) { - presence_status->set_jid(from); - if (stanza->Attr(QN_TYPE) == STR_UNAVAILABLE) { - presence_status->set_available(false); - } else { - presence_status->set_available(true); - const XmlElement * status_elem = stanza->FirstNamed(QN_STATUS); - if (status_elem != NULL) { - presence_status->set_status(status_elem->BodyText()); - - // Truncate status messages longer than 300 bytes - if (presence_status->status().length() > 300) { - size_t len = 300; - - // Be careful not to split legal utf-8 chars in half - while (!IsUtf8FirstByte(presence_status->status()[len]) && len > 0) { - len -= 1; - } - std::string truncated(presence_status->status(), 0, len); - presence_status->set_status(truncated); - } - } - - const XmlElement * priority = stanza->FirstNamed(QN_PRIORITY); - if (priority != NULL) { - int pri; - if (rtc::FromString(priority->BodyText(), &pri)) { - presence_status->set_priority(pri); - } - } - - const XmlElement * show = stanza->FirstNamed(QN_SHOW); - if (show == NULL || show->FirstChild() == NULL) { - presence_status->set_show(PresenceStatus::SHOW_ONLINE); - } else if (show->BodyText() == "away") { - presence_status->set_show(PresenceStatus::SHOW_AWAY); - } else if (show->BodyText() == "xa") { - presence_status->set_show(PresenceStatus::SHOW_XA); - } else if (show->BodyText() == "dnd") { - presence_status->set_show(PresenceStatus::SHOW_DND); - } else if (show->BodyText() == "chat") { - presence_status->set_show(PresenceStatus::SHOW_CHAT); - } else { - presence_status->set_show(PresenceStatus::SHOW_ONLINE); - } - - const XmlElement * caps = stanza->FirstNamed(QN_CAPS_C); - if (caps != NULL) { - std::string node = caps->Attr(QN_NODE); - std::string ver = caps->Attr(QN_VER); - std::string exts = caps->Attr(QN_EXT); - - presence_status->set_know_capabilities(true); - presence_status->set_caps_node(node); - presence_status->set_version(ver); - } - - const XmlElement* delay = stanza->FirstNamed(kQnDelayX); - if (delay != NULL) { - // Ideally we would parse this according to the Psuedo ISO-8601 rules - // that are laid out in JEP-0082: - // http://www.jabber.org/jeps/jep-0082.html - std::string stamp = delay->Attr(kQnStamp); - presence_status->set_sent_time(stamp); - } - - const XmlElement* nick = stanza->FirstNamed(QN_NICKNAME); - if (nick) { - presence_status->set_nick(nick->BodyText()); - } - } -} - -} // namespace buzz diff --git a/talk/xmpp/presencereceivetask.h b/talk/xmpp/presencereceivetask.h deleted file mode 100644 index 80e11d8d3..000000000 --- a/talk/xmpp/presencereceivetask.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - * libjingle - * Copyright 2004--2012, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef THIRD_PARTY_LIBJINGLE_FILES_TALK_XMPP_PRESENCERECEIVETASK_H_ -#define THIRD_PARTY_LIBJINGLE_FILES_TALK_XMPP_PRESENCERECEIVETASK_H_ - -#include "webrtc/base/sigslot.h" - -#include "webrtc/libjingle/xmpp/presencestatus.h" -#include "webrtc/libjingle/xmpp/xmpptask.h" - -namespace buzz { - -// A task to receive presence status callbacks from the XMPP server. -class PresenceReceiveTask : public XmppTask { - public: - // Arguments: - // parent a reference to task interface associated withe the XMPP client. - explicit PresenceReceiveTask(XmppTaskParentInterface* parent); - - // Shuts down the thread associated with this task. - virtual ~PresenceReceiveTask(); - - // Starts pulling queued status messages and dispatching them to the - // PresenceUpdate() callback. - virtual int ProcessStart(); - - // Slot for presence message callbacks - sigslot::signal1<const PresenceStatus&> PresenceUpdate; - - protected: - // Called by the XMPP engine when presence stanzas are received from the - // server. - virtual bool HandleStanza(const XmlElement * stanza); - - private: - // Handles presence stanzas by converting the data to PresenceStatus - // objects and passing those along to the SignalStatusUpadate() callback. - void HandlePresence(const Jid& from, const XmlElement * stanza); - - // Extracts presence information for the presence stanza sent form the - // server. - static void DecodeStatus(const Jid& from, const XmlElement * stanza, - PresenceStatus* status); -}; - -} // namespace buzz - -#endif // THIRD_PARTY_LIBJINGLE_FILES_TALK_XMPP_PRESENCERECEIVETASK_H_ diff --git a/talk/xmpp/presencestatus.cc b/talk/xmpp/presencestatus.cc deleted file mode 100644 index 2ab89b23b..000000000 --- a/talk/xmpp/presencestatus.cc +++ /dev/null @@ -1,62 +0,0 @@ -/* - * libjingle - * Copyright 2004--2012, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "webrtc/libjingle/xmpp/presencestatus.h" - -namespace buzz { -PresenceStatus::PresenceStatus() - : pri_(0), - show_(SHOW_NONE), - available_(false), - e_code_(0), - feedback_probation_(false), - know_capabilities_(false), - voice_capability_(false), - pmuc_capability_(false), - video_capability_(false), - camera_capability_(false) { -} - -void PresenceStatus::UpdateWith(const PresenceStatus& new_value) { - if (!new_value.know_capabilities()) { - bool k = know_capabilities(); - bool p = voice_capability(); - std::string node = caps_node(); - std::string v = version(); - - *this = new_value; - - set_know_capabilities(k); - set_caps_node(node); - set_voice_capability(p); - set_version(v); - } else { - *this = new_value; - } -} - -} // namespace buzz diff --git a/talk/xmpp/presencestatus.h b/talk/xmpp/presencestatus.h deleted file mode 100644 index c133e400b..000000000 --- a/talk/xmpp/presencestatus.h +++ /dev/null @@ -1,205 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef THIRD_PARTY_LIBJINGLE_FILES_TALK_XMPP_PRESENCESTATUS_H_ -#define THIRD_PARTY_LIBJINGLE_FILES_TALK_XMPP_PRESENCESTATUS_H_ - -#include "webrtc/libjingle/xmpp/constants.h" -#include "webrtc/libjingle/xmpp/jid.h" - -namespace buzz { - -class PresenceStatus { -public: - PresenceStatus(); - ~PresenceStatus() {} - - // These are arranged in "priority order", i.e., if we see - // two statuses at the same priority but with different Shows, - // we will show the one with the highest show in the following - // order. - enum Show { - SHOW_NONE = 0, - SHOW_OFFLINE = 1, - SHOW_XA = 2, - SHOW_AWAY = 3, - SHOW_DND = 4, - SHOW_ONLINE = 5, - SHOW_CHAT = 6, - }; - - const Jid& jid() const { return jid_; } - int priority() const { return pri_; } - Show show() const { return show_; } - const std::string& status() const { return status_; } - const std::string& nick() const { return nick_; } - bool available() const { return available_ ; } - int error_code() const { return e_code_; } - const std::string& error_string() const { return e_str_; } - bool know_capabilities() const { return know_capabilities_; } - bool voice_capability() const { return voice_capability_; } - bool pmuc_capability() const { return pmuc_capability_; } - bool video_capability() const { return video_capability_; } - bool camera_capability() const { return camera_capability_; } - const std::string& caps_node() const { return caps_node_; } - const std::string& version() const { return version_; } - bool feedback_probation() const { return feedback_probation_; } - const std::string& sent_time() const { return sent_time_; } - - void set_jid(const Jid& jid) { jid_ = jid; } - void set_priority(int pri) { pri_ = pri; } - void set_show(Show show) { show_ = show; } - void set_status(const std::string& status) { status_ = status; } - void set_nick(const std::string& nick) { nick_ = nick; } - void set_available(bool a) { available_ = a; } - void set_error(int e_code, const std::string e_str) - { e_code_ = e_code; e_str_ = e_str; } - void set_know_capabilities(bool f) { know_capabilities_ = f; } - void set_voice_capability(bool f) { voice_capability_ = f; } - void set_pmuc_capability(bool f) { pmuc_capability_ = f; } - void set_video_capability(bool f) { video_capability_ = f; } - void set_camera_capability(bool f) { camera_capability_ = f; } - void set_caps_node(const std::string& f) { caps_node_ = f; } - void set_version(const std::string& v) { version_ = v; } - void set_feedback_probation(bool f) { feedback_probation_ = f; } - void set_sent_time(const std::string& time) { sent_time_ = time; } - - void UpdateWith(const PresenceStatus& new_value); - - bool HasQuietStatus() const { - if (status_.empty()) - return false; - return !(QuietStatus().empty()); - } - - // Knowledge of other clients' silly automatic status strings - - // Don't show these. - std::string QuietStatus() const { - if (jid_.resource().find("Psi") != std::string::npos) { - if (status_ == "Online" || - status_.find("Auto Status") != std::string::npos) - return STR_EMPTY; - } - if (jid_.resource().find("Gaim") != std::string::npos) { - if (status_ == "Sorry, I ran out for a bit!") - return STR_EMPTY; - } - return TrimStatus(status_); - } - - std::string ExplicitStatus() const { - std::string result = QuietStatus(); - if (result.empty()) { - result = ShowStatus(); - } - return result; - } - - std::string ShowStatus() const { - std::string result; - if (!available()) { - result = "Offline"; - } - else { - switch (show()) { - case SHOW_AWAY: - case SHOW_XA: - result = "Idle"; - break; - case SHOW_DND: - result = "Busy"; - break; - case SHOW_CHAT: - result = "Chatty"; - break; - default: - result = "Available"; - break; - } - } - return result; - } - - static std::string TrimStatus(const std::string& st) { - std::string s(st); - int j = 0; - bool collapsing = true; - for (unsigned int i = 0; i < s.length(); i+= 1) { - if (s[i] <= ' ' && s[i] >= 0) { - if (collapsing) { - continue; - } - else { - s[j] = ' '; - j += 1; - collapsing = true; - } - } - else { - s[j] = s[i]; - j += 1; - collapsing = false; - } - } - if (collapsing && j > 0) { - j -= 1; - } - s.erase(j, s.length()); - return s; - } - -private: - Jid jid_; - int pri_; - Show show_; - std::string status_; - std::string nick_; - bool available_; - int e_code_; - std::string e_str_; - bool feedback_probation_; - - // capabilities (valid only if know_capabilities_ - bool know_capabilities_; - bool voice_capability_; - bool pmuc_capability_; - bool video_capability_; - bool camera_capability_; - std::string caps_node_; - std::string version_; - - std::string sent_time_; // from the jabber:x:delay element -}; - -class MucPresenceStatus : public PresenceStatus { -}; - -} // namespace buzz - - -#endif // THIRD_PARTY_LIBJINGLE_FILES_TALK_XMPP_PRESENCESTATUS_H_ - diff --git a/talk/xmpp/prexmppauth.h b/talk/xmpp/prexmppauth.h deleted file mode 100644 index 7ddc85bf6..000000000 --- a/talk/xmpp/prexmppauth.h +++ /dev/null @@ -1,88 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef TALK_XMPP_PREXMPPAUTH_H_ -#define TALK_XMPP_PREXMPPAUTH_H_ - -#include "webrtc/libjingle/xmpp/saslhandler.h" -#include "webrtc/base/cryptstring.h" -#include "webrtc/base/sigslot.h" - -namespace rtc { - class SocketAddress; -} - -namespace buzz { - -class Jid; -class SaslMechanism; - -class CaptchaChallenge { - public: - CaptchaChallenge() : captcha_needed_(false) {} - CaptchaChallenge(const std::string& token, const std::string& url) - : captcha_needed_(true), captcha_token_(token), captcha_image_url_(url) { - } - - bool captcha_needed() const { return captcha_needed_; } - const std::string& captcha_token() const { return captcha_token_; } - - // This url is relative to the gaia server. Once we have better tools - // for cracking URLs, we should probably make this a full URL - const std::string& captcha_image_url() const { return captcha_image_url_; } - - private: - bool captcha_needed_; - std::string captcha_token_; - std::string captcha_image_url_; -}; - -class PreXmppAuth : public SaslHandler { -public: - virtual ~PreXmppAuth() {} - - virtual void StartPreXmppAuth( - const Jid& jid, - const rtc::SocketAddress& server, - const rtc::CryptString& pass, - const std::string& auth_mechanism, - const std::string& auth_token) = 0; - - sigslot::signal0<> SignalAuthDone; - - virtual bool IsAuthDone() const = 0; - virtual bool IsAuthorized() const = 0; - virtual bool HadError() const = 0; - virtual int GetError() const = 0; - virtual CaptchaChallenge GetCaptchaChallenge() const = 0; - virtual std::string GetAuthMechanism() const = 0; - virtual std::string GetAuthToken() const = 0; -}; - -} - -#endif // TALK_XMPP_PREXMPPAUTH_H_ diff --git a/talk/xmpp/pubsub_task.cc b/talk/xmpp/pubsub_task.cc deleted file mode 100644 index 98446fd58..000000000 --- a/talk/xmpp/pubsub_task.cc +++ /dev/null @@ -1,217 +0,0 @@ -/* - * libjingle - * Copyright 2004--2006, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "webrtc/libjingle/xmpp/pubsub_task.h" - -#include <map> -#include <string> - -#include "webrtc/libjingle/xmpp/constants.h" -#include "webrtc/libjingle/xmpp/xmppengine.h" -#include "webrtc/base/common.h" - -namespace buzz { - -PubsubTask::PubsubTask(XmppTaskParentInterface* parent, - const buzz::Jid& pubsub_node_jid) - : buzz::XmppTask(parent, buzz::XmppEngine::HL_SENDER), - pubsub_node_jid_(pubsub_node_jid) { -} - -PubsubTask::~PubsubTask() { -} - -// Checks for pubsub publish events as well as responses to get IQs. -bool PubsubTask::HandleStanza(const buzz::XmlElement* stanza) { - const buzz::QName& stanza_name(stanza->Name()); - if (stanza_name == buzz::QN_MESSAGE) { - if (MatchStanzaFrom(stanza, pubsub_node_jid_)) { - const buzz::XmlElement* pubsub_event_item = - stanza->FirstNamed(QN_PUBSUB_EVENT); - if (pubsub_event_item != NULL) { - QueueStanza(pubsub_event_item); - return true; - } - } - } else if (stanza_name == buzz::QN_IQ) { - if (MatchResponseIq(stanza, pubsub_node_jid_, task_id())) { - const buzz::XmlElement* pubsub_item = stanza->FirstNamed(QN_PUBSUB); - if (pubsub_item != NULL) { - QueueStanza(pubsub_item); - return true; - } - } - } - return false; -} - -int PubsubTask::ProcessResponse() { - const buzz::XmlElement* stanza = NextStanza(); - if (stanza == NULL) { - return STATE_BLOCKED; - } - - if (stanza->Attr(buzz::QN_TYPE) == buzz::STR_ERROR) { - OnPubsubError(stanza->FirstNamed(buzz::QN_ERROR)); - return STATE_RESPONSE; - } - - const buzz::QName& stanza_name(stanza->Name()); - if (stanza_name == QN_PUBSUB_EVENT) { - HandlePubsubEventMessage(stanza); - } else if (stanza_name == QN_PUBSUB) { - HandlePubsubIqGetResponse(stanza); - } - - return STATE_RESPONSE; -} - -// Registers a function pointer to be called when the value of the pubsub -// node changes. -// Note that this does not actually change the XMPP pubsub -// subscription. All publish events are always received by everyone in the -// MUC. This function just controls whether the handle function will get -// called when the event is received. -bool PubsubTask::SubscribeToNode(const std::string& pubsub_node, - NodeHandler handler) { - subscribed_nodes_[pubsub_node] = handler; - rtc::scoped_ptr<buzz::XmlElement> get_iq_request( - MakeIq(buzz::STR_GET, pubsub_node_jid_, task_id())); - if (!get_iq_request) { - return false; - } - buzz::XmlElement* pubsub_element = new buzz::XmlElement(QN_PUBSUB, true); - buzz::XmlElement* items_element = new buzz::XmlElement(QN_PUBSUB_ITEMS, true); - - items_element->AddAttr(buzz::QN_NODE, pubsub_node); - pubsub_element->AddElement(items_element); - get_iq_request->AddElement(pubsub_element); - - if (SendStanza(get_iq_request.get()) != buzz::XMPP_RETURN_OK) { - return false; - } - - return true; -} - -void PubsubTask::UnsubscribeFromNode(const std::string& pubsub_node) { - subscribed_nodes_.erase(pubsub_node); -} - -void PubsubTask::OnPubsubError(const buzz::XmlElement* error_stanza) { -} - -// Checks for a pubsub event message like the following: -// -// <message from="muvc-private-chat-some-id@groupchat.google.com" -// to="john@site.com/gcomm582B14C9"> -// <event xmlns:"http://jabber.org/protocol/pubsub#event"> -// <items node="node-name"> -// <item id="some-id"> -// <payload/> -// </item> -// </items> -// </event> -// </message> -// -// It also checks for retraction event messages like the following: -// -// <message from="muvc-private-chat-some-id@groupchat.google.com" -// to="john@site.com/gcomm582B14C9"> -// <event xmlns:"http://jabber.org/protocol/pubsub#event"> -// <items node="node-name"> -// <retract id="some-id"/> -// </items> -// </event> -// </message> -void PubsubTask::HandlePubsubEventMessage( - const buzz::XmlElement* pubsub_event) { - ASSERT(pubsub_event->Name() == QN_PUBSUB_EVENT); - for (const buzz::XmlChild* child = pubsub_event->FirstChild(); - child != NULL; - child = child->NextChild()) { - const buzz::XmlElement* child_element = child->AsElement(); - const buzz::QName& child_name(child_element->Name()); - if (child_name == QN_PUBSUB_EVENT_ITEMS) { - HandlePubsubItems(child_element); - } - } -} - -// Checks for a response to an pubsub IQ get like the following: -// -// <iq from="muvc-private-chat-some-id@groupchat.google.com" -// to="john@site.com/gcomm582B14C9" -// type="result"> -// <pubsub xmlns:"http://jabber.org/protocol/pubsub"> -// <items node="node-name"> -// <item id="some-id"> -// <payload/> -// </item> -// </items> -// </event> -// </message> -void PubsubTask::HandlePubsubIqGetResponse( - const buzz::XmlElement* pubsub_iq_response) { - ASSERT(pubsub_iq_response->Name() == QN_PUBSUB); - for (const buzz::XmlChild* child = pubsub_iq_response->FirstChild(); - child != NULL; - child = child->NextChild()) { - const buzz::XmlElement* child_element = child->AsElement(); - const buzz::QName& child_name(child_element->Name()); - if (child_name == QN_PUBSUB_ITEMS) { - HandlePubsubItems(child_element); - } - } -} - -// Calls registered handlers in response to pubsub event or response to -// IQ pubsub get. -// 'items' is the child of a pubsub#event:event node or pubsub:pubsub node. -void PubsubTask::HandlePubsubItems(const buzz::XmlElement* items) { - ASSERT(items->HasAttr(QN_NODE)); - const std::string& node_name(items->Attr(QN_NODE)); - NodeSubscriptions::iterator iter = subscribed_nodes_.find(node_name); - if (iter != subscribed_nodes_.end()) { - NodeHandler handler = iter->second; - const buzz::XmlElement* item = items->FirstElement(); - while (item != NULL) { - const buzz::QName& item_name(item->Name()); - if (item_name != QN_PUBSUB_EVENT_ITEM && - item_name != QN_PUBSUB_EVENT_RETRACT && - item_name != QN_PUBSUB_ITEM) { - continue; - } - - (this->*handler)(item); - item = item->NextElement(); - } - return; - } -} - -} diff --git a/talk/xmpp/pubsub_task.h b/talk/xmpp/pubsub_task.h deleted file mode 100644 index a219b6009..000000000 --- a/talk/xmpp/pubsub_task.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - * libjingle - * Copyright 2004--2011, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef TALK_XMPP_PUBSUB_TASK_H_ -#define TALK_XMPP_PUBSUB_TASK_H_ - -#include <map> -#include <string> -#include "webrtc/libjingle/xmllite/xmlelement.h" -#include "webrtc/libjingle/xmpp/jid.h" -#include "webrtc/libjingle/xmpp/xmpptask.h" - -namespace buzz { - -// Base class to help write pubsub tasks. -// In ProcessStart call SubscribeNode with namespaces of interest along with -// NodeHandlers. -// When pubsub notifications arrive and matches the namespace, the NodeHandlers -// will be called back. -class PubsubTask : public buzz::XmppTask { - public: - virtual ~PubsubTask(); - - protected: - typedef void (PubsubTask::*NodeHandler)(const buzz::XmlElement* node); - - PubsubTask(XmppTaskParentInterface* parent, const buzz::Jid& pubsub_node_jid); - - virtual bool HandleStanza(const buzz::XmlElement* stanza); - virtual int ProcessResponse(); - - bool SubscribeToNode(const std::string& pubsub_node, NodeHandler handler); - void UnsubscribeFromNode(const std::string& pubsub_node); - - // Called when there is an error. Derived class can do what it needs to. - virtual void OnPubsubError(const buzz::XmlElement* error_stanza); - - private: - typedef std::map<std::string, NodeHandler> NodeSubscriptions; - - void HandlePubsubIqGetResponse(const buzz::XmlElement* pubsub_iq_response); - void HandlePubsubEventMessage(const buzz::XmlElement* pubsub_event_message); - void HandlePubsubItems(const buzz::XmlElement* items); - - buzz::Jid pubsub_node_jid_; - NodeSubscriptions subscribed_nodes_; -}; - -} // namespace buzz - -#endif // TALK_XMPP_PUBSUB_TASK_H_ diff --git a/talk/xmpp/pubsubclient.cc b/talk/xmpp/pubsubclient.cc deleted file mode 100644 index a5793efae..000000000 --- a/talk/xmpp/pubsubclient.cc +++ /dev/null @@ -1,146 +0,0 @@ -/* - * libjingle - * Copyright 2011, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "webrtc/libjingle/xmpp/pubsubclient.h" - -#include <string> -#include <vector> - -#include "webrtc/libjingle/xmpp/constants.h" -#include "webrtc/libjingle/xmpp/jid.h" -#include "webrtc/libjingle/xmpp/pubsubtasks.h" - -namespace buzz { - -void PubSubClient::RequestItems() { - PubSubRequestTask* request_task = - new PubSubRequestTask(parent_, pubsubjid_, node_); - request_task->SignalResult.connect(this, &PubSubClient::OnRequestResult); - request_task->SignalError.connect(this, &PubSubClient::OnRequestError); - - PubSubReceiveTask* receive_task = - new PubSubReceiveTask(parent_, pubsubjid_, node_); - receive_task->SignalUpdate.connect(this, &PubSubClient::OnReceiveUpdate); - - receive_task->Start(); - request_task->Start(); -} - -void PubSubClient::PublishItem( - const std::string& itemid, XmlElement* payload, std::string* task_id_out) { - std::vector<XmlElement*> children; - children.push_back(payload); - PublishItem(itemid, children, task_id_out); -} - -void PubSubClient::PublishItem( - const std::string& itemid, const std::vector<XmlElement*>& children, - std::string* task_id_out) { - PubSubPublishTask* publish_task = - new PubSubPublishTask(parent_, pubsubjid_, node_, itemid, children); - publish_task->SignalError.connect(this, &PubSubClient::OnPublishError); - publish_task->SignalResult.connect(this, &PubSubClient::OnPublishResult); - publish_task->Start(); - if (task_id_out) { - *task_id_out = publish_task->task_id(); - } -} - -void PubSubClient::RetractItem( - const std::string& itemid, std::string* task_id_out) { - PubSubRetractTask* retract_task = - new PubSubRetractTask(parent_, pubsubjid_, node_, itemid); - retract_task->SignalError.connect(this, &PubSubClient::OnRetractError); - retract_task->SignalResult.connect(this, &PubSubClient::OnRetractResult); - retract_task->Start(); - if (task_id_out) { - *task_id_out = retract_task->task_id(); - } -} - -void PubSubClient::OnRequestResult(PubSubRequestTask* task, - const std::vector<PubSubItem>& items) { - SignalItems(this, items); -} - -void PubSubClient::OnRequestError(IqTask* task, - const XmlElement* stanza) { - SignalRequestError(this, stanza); -} - -void PubSubClient::OnReceiveUpdate(PubSubReceiveTask* task, - const std::vector<PubSubItem>& items) { - SignalItems(this, items); -} - -const XmlElement* GetItemFromStanza(const XmlElement* stanza) { - if (stanza != NULL) { - const XmlElement* pubsub = stanza->FirstNamed(QN_PUBSUB); - if (pubsub != NULL) { - const XmlElement* publish = pubsub->FirstNamed(QN_PUBSUB_PUBLISH); - if (publish != NULL) { - return publish->FirstNamed(QN_PUBSUB_ITEM); - } - } - } - return NULL; -} - -void PubSubClient::OnPublishResult(PubSubPublishTask* task) { - const XmlElement* item = GetItemFromStanza(task->stanza()); - SignalPublishResult(this, task->task_id(), item); -} - -void PubSubClient::OnPublishError(IqTask* task, - const XmlElement* error_stanza) { - PubSubPublishTask* publish_task = - static_cast<PubSubPublishTask*>(task); - const XmlElement* item = GetItemFromStanza(publish_task->stanza()); - SignalPublishError(this, publish_task->task_id(), item, error_stanza); -} - -void PubSubClient::OnRetractResult(PubSubRetractTask* task) { - SignalRetractResult(this, task->task_id()); -} - -void PubSubClient::OnRetractError(IqTask* task, - const XmlElement* stanza) { - PubSubRetractTask* retract_task = - static_cast<PubSubRetractTask*>(task); - SignalRetractError(this, retract_task->task_id(), stanza); -} - - -const std::string PubSubClient::GetPublisherNickFromPubSubItem( - const XmlElement* item_elem) { - if (item_elem == NULL) { - return ""; - } - - return Jid(item_elem->Attr(QN_ATTR_PUBLISHER)).resource(); -} -} // namespace buzz diff --git a/talk/xmpp/pubsubclient.h b/talk/xmpp/pubsubclient.h deleted file mode 100644 index 64659577c..000000000 --- a/talk/xmpp/pubsubclient.h +++ /dev/null @@ -1,128 +0,0 @@ -/* - * libjingle - * Copyright 2011, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef TALK_XMPP_PUBSUBCLIENT_H_ -#define TALK_XMPP_PUBSUBCLIENT_H_ - -#include <string> -#include <vector> - -#include "webrtc/libjingle/xmpp/jid.h" -#include "webrtc/libjingle/xmpp/pubsubtasks.h" -#include "webrtc/base/sigslot.h" -#include "webrtc/base/sigslotrepeater.h" -#include "webrtc/base/task.h" - -// Easy to use clients built on top of the tasks for XEP-0060 -// (http://xmpp.org/extensions/xep-0060.html). - -namespace buzz { - -class Jid; -class XmlElement; -class XmppTaskParentInterface; - -// An easy-to-use pubsub client that handles the three tasks of -// getting, publishing, and listening for updates. Tied to a specific -// pubsub jid and node. All you have to do is RequestItems, listen -// for SignalItems and PublishItems. -class PubSubClient : public sigslot::has_slots<> { - public: - PubSubClient(XmppTaskParentInterface* parent, - const Jid& pubsubjid, - const std::string& node) - : parent_(parent), - pubsubjid_(pubsubjid), - node_(node) {} - - const std::string& node() const { return node_; } - - // Requests the <pubsub><items>, which will be returned via - // SignalItems, or SignalRequestError if there is a failure. Should - // auto-subscribe. - void RequestItems(); - // Fired when either <pubsub><items> are returned or when - // <event><items> are received. - sigslot::signal2<PubSubClient*, - const std::vector<PubSubItem>&> SignalItems; - // Signal (this, error stanza) - sigslot::signal2<PubSubClient*, - const XmlElement*> SignalRequestError; - // Signal (this, task_id, item, error stanza) - sigslot::signal4<PubSubClient*, - const std::string&, - const XmlElement*, - const XmlElement*> SignalPublishError; - // Signal (this, task_id, item) - sigslot::signal3<PubSubClient*, - const std::string&, - const XmlElement*> SignalPublishResult; - // Signal (this, task_id, error stanza) - sigslot::signal3<PubSubClient*, - const std::string&, - const XmlElement*> SignalRetractError; - // Signal (this, task_id) - sigslot::signal2<PubSubClient*, - const std::string&> SignalRetractResult; - - // Publish an item. Takes ownership of payload. - void PublishItem(const std::string& itemid, - XmlElement* payload, - std::string* task_id_out); - // Publish an item. Takes ownership of children. - void PublishItem(const std::string& itemid, - const std::vector<XmlElement*>& children, - std::string* task_id_out); - // Retract (delete) an item. - void RetractItem(const std::string& itemid, - std::string* task_id_out); - - // Get the publisher nick if it exists from the pubsub item. - const std::string GetPublisherNickFromPubSubItem(const XmlElement* item_elem); - - private: - void OnRequestError(IqTask* task, - const XmlElement* stanza); - void OnRequestResult(PubSubRequestTask* task, - const std::vector<PubSubItem>& items); - void OnReceiveUpdate(PubSubReceiveTask* task, - const std::vector<PubSubItem>& items); - void OnPublishResult(PubSubPublishTask* task); - void OnPublishError(IqTask* task, - const XmlElement* stanza); - void OnRetractResult(PubSubRetractTask* task); - void OnRetractError(IqTask* task, - const XmlElement* stanza); - - XmppTaskParentInterface* parent_; - Jid pubsubjid_; - std::string node_; -}; - -} // namespace buzz - -#endif // TALK_XMPP_PUBSUBCLIENT_H_ diff --git a/talk/xmpp/pubsubclient_unittest.cc b/talk/xmpp/pubsubclient_unittest.cc deleted file mode 100644 index b3049d809..000000000 --- a/talk/xmpp/pubsubclient_unittest.cc +++ /dev/null @@ -1,271 +0,0 @@ -// Copyright 2011 Google Inc. All Rights Reserved - - -#include <string> - -#include "webrtc/libjingle/xmllite/qname.h" -#include "webrtc/libjingle/xmllite/xmlelement.h" -#include "webrtc/libjingle/xmpp/constants.h" -#include "webrtc/libjingle/xmpp/fakexmppclient.h" -#include "webrtc/libjingle/xmpp/jid.h" -#include "webrtc/libjingle/xmpp/pubsubclient.h" -#include "webrtc/base/faketaskrunner.h" -#include "webrtc/base/gunit.h" -#include "webrtc/base/sigslot.h" - -struct HandledPubSubItem { - std::string itemid; - std::string payload; -}; - -class TestPubSubItemsListener : public sigslot::has_slots<> { - public: - TestPubSubItemsListener() : error_count(0) {} - - void OnItems(buzz::PubSubClient*, - const std::vector<buzz::PubSubItem>& items) { - for (std::vector<buzz::PubSubItem>::const_iterator item = items.begin(); - item != items.end(); ++item) { - HandledPubSubItem handled_item; - handled_item.itemid = item->itemid; - if (item->elem->FirstElement() != NULL) { - handled_item.payload = item->elem->FirstElement()->Str(); - } - this->items.push_back(handled_item); - } - } - - void OnRequestError(buzz::PubSubClient* client, - const buzz::XmlElement* stanza) { - error_count++; - } - - void OnPublishResult(buzz::PubSubClient* client, - const std::string& task_id, - const buzz::XmlElement* item) { - result_task_id = task_id; - } - - void OnPublishError(buzz::PubSubClient* client, - const std::string& task_id, - const buzz::XmlElement* item, - const buzz::XmlElement* stanza) { - error_count++; - error_task_id = task_id; - } - - void OnRetractResult(buzz::PubSubClient* client, - const std::string& task_id) { - result_task_id = task_id; - } - - void OnRetractError(buzz::PubSubClient* client, - const std::string& task_id, - const buzz::XmlElement* stanza) { - error_count++; - error_task_id = task_id; - } - - std::vector<HandledPubSubItem> items; - int error_count; - std::string error_task_id; - std::string result_task_id; -}; - -class PubSubClientTest : public testing::Test { - public: - PubSubClientTest() : - pubsubjid("room@domain.com"), - node("topic"), - itemid("key") { - runner.reset(new rtc::FakeTaskRunner()); - xmpp_client = new buzz::FakeXmppClient(runner.get()); - client.reset(new buzz::PubSubClient(xmpp_client, pubsubjid, node)); - listener.reset(new TestPubSubItemsListener()); - client->SignalItems.connect( - listener.get(), &TestPubSubItemsListener::OnItems); - client->SignalRequestError.connect( - listener.get(), &TestPubSubItemsListener::OnRequestError); - client->SignalPublishResult.connect( - listener.get(), &TestPubSubItemsListener::OnPublishResult); - client->SignalPublishError.connect( - listener.get(), &TestPubSubItemsListener::OnPublishError); - client->SignalRetractResult.connect( - listener.get(), &TestPubSubItemsListener::OnRetractResult); - client->SignalRetractError.connect( - listener.get(), &TestPubSubItemsListener::OnRetractError); - } - - rtc::scoped_ptr<rtc::FakeTaskRunner> runner; - // xmpp_client deleted by deleting runner. - buzz::FakeXmppClient* xmpp_client; - rtc::scoped_ptr<buzz::PubSubClient> client; - rtc::scoped_ptr<TestPubSubItemsListener> listener; - buzz::Jid pubsubjid; - std::string node; - std::string itemid; -}; - -TEST_F(PubSubClientTest, TestRequest) { - client->RequestItems(); - - std::string expected_iq = - "<cli:iq type=\"get\" to=\"room@domain.com\" id=\"0\" " - "xmlns:cli=\"jabber:client\">" - "<pub:pubsub xmlns:pub=\"http://jabber.org/protocol/pubsub\">" - "<pub:items node=\"topic\"/>" - "</pub:pubsub>" - "</cli:iq>"; - - ASSERT_EQ(1U, xmpp_client->sent_stanzas().size()); - EXPECT_EQ(expected_iq, xmpp_client->sent_stanzas()[0]->Str()); - - std::string result_iq = - "<iq xmlns='jabber:client' id='0' type='result' from='room@domain.com'>" - " <pubsub xmlns='http://jabber.org/protocol/pubsub'>" - " <items node='topic'>" - " <item id='key0'>" - " <value0a/>" - " </item>" - " <item id='key1'>" - " <value1a/>" - " </item>" - " </items>" - " </pubsub>" - "</iq>"; - - xmpp_client->HandleStanza(buzz::XmlElement::ForStr(result_iq)); - ASSERT_EQ(2U, listener->items.size()); - EXPECT_EQ("key0", listener->items[0].itemid); - EXPECT_EQ("<pub:value0a xmlns:pub=\"http://jabber.org/protocol/pubsub\"/>", - listener->items[0].payload); - EXPECT_EQ("key1", listener->items[1].itemid); - EXPECT_EQ("<pub:value1a xmlns:pub=\"http://jabber.org/protocol/pubsub\"/>", - listener->items[1].payload); - - std::string items_message = - "<message xmlns='jabber:client' from='room@domain.com'>" - " <event xmlns='http://jabber.org/protocol/pubsub#event'>" - " <items node='topic'>" - " <item id='key0'>" - " <value0b/>" - " </item>" - " <item id='key1'>" - " <value1b/>" - " </item>" - " </items>" - " </event>" - "</message>"; - - xmpp_client->HandleStanza(buzz::XmlElement::ForStr(items_message)); - ASSERT_EQ(4U, listener->items.size()); - EXPECT_EQ("key0", listener->items[2].itemid); - EXPECT_EQ("<eve:value0b" - " xmlns:eve=\"http://jabber.org/protocol/pubsub#event\"/>", - listener->items[2].payload); - EXPECT_EQ("key1", listener->items[3].itemid); - EXPECT_EQ("<eve:value1b" - " xmlns:eve=\"http://jabber.org/protocol/pubsub#event\"/>", - listener->items[3].payload); -} - -TEST_F(PubSubClientTest, TestRequestError) { - std::string result_iq = - "<iq xmlns='jabber:client' id='0' type='error' from='room@domain.com'>" - " <error type='auth'>" - " <forbidden xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>" - " </error>" - "</iq>"; - - client->RequestItems(); - xmpp_client->HandleStanza(buzz::XmlElement::ForStr(result_iq)); - EXPECT_EQ(1, listener->error_count); -} - -TEST_F(PubSubClientTest, TestPublish) { - buzz::XmlElement* payload = - new buzz::XmlElement(buzz::QName(buzz::NS_PUBSUB, "value")); - - std::string task_id; - client->PublishItem(itemid, payload, &task_id); - - std::string expected_iq = - "<cli:iq type=\"set\" to=\"room@domain.com\" id=\"0\" " - "xmlns:cli=\"jabber:client\">" - "<pubsub xmlns=\"http://jabber.org/protocol/pubsub\">" - "<publish node=\"topic\">" - "<item id=\"key\">" - "<value/>" - "</item>" - "</publish>" - "</pubsub>" - "</cli:iq>"; - - ASSERT_EQ(1U, xmpp_client->sent_stanzas().size()); - EXPECT_EQ(expected_iq, xmpp_client->sent_stanzas()[0]->Str()); - - std::string result_iq = - "<iq xmlns='jabber:client' id='0' type='result' from='room@domain.com'/>"; - - xmpp_client->HandleStanza(buzz::XmlElement::ForStr(result_iq)); - EXPECT_EQ(task_id, listener->result_task_id); -} - -TEST_F(PubSubClientTest, TestPublishError) { - buzz::XmlElement* payload = - new buzz::XmlElement(buzz::QName(buzz::NS_PUBSUB, "value")); - - std::string task_id; - client->PublishItem(itemid, payload, &task_id); - - std::string result_iq = - "<iq xmlns='jabber:client' id='0' type='error' from='room@domain.com'>" - " <error type='auth'>" - " <forbidden xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>" - " </error>" - "</iq>"; - - xmpp_client->HandleStanza(buzz::XmlElement::ForStr(result_iq)); - EXPECT_EQ(1, listener->error_count); - EXPECT_EQ(task_id, listener->error_task_id); -} - -TEST_F(PubSubClientTest, TestRetract) { - std::string task_id; - client->RetractItem(itemid, &task_id); - - std::string expected_iq = - "<cli:iq type=\"set\" to=\"room@domain.com\" id=\"0\" " - "xmlns:cli=\"jabber:client\">" - "<pubsub xmlns=\"http://jabber.org/protocol/pubsub\">" - "<retract node=\"topic\" notify=\"true\">" - "<item id=\"key\"/>" - "</retract>" - "</pubsub>" - "</cli:iq>"; - - ASSERT_EQ(1U, xmpp_client->sent_stanzas().size()); - EXPECT_EQ(expected_iq, xmpp_client->sent_stanzas()[0]->Str()); - - std::string result_iq = - "<iq xmlns='jabber:client' id='0' type='result' from='room@domain.com'/>"; - - xmpp_client->HandleStanza(buzz::XmlElement::ForStr(result_iq)); - EXPECT_EQ(task_id, listener->result_task_id); -} - -TEST_F(PubSubClientTest, TestRetractError) { - std::string task_id; - client->RetractItem(itemid, &task_id); - - std::string result_iq = - "<iq xmlns='jabber:client' id='0' type='error' from='room@domain.com'>" - " <error type='auth'>" - " <forbidden xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>" - " </error>" - "</iq>"; - - xmpp_client->HandleStanza(buzz::XmlElement::ForStr(result_iq)); - EXPECT_EQ(1, listener->error_count); - EXPECT_EQ(task_id, listener->error_task_id); -} diff --git a/talk/xmpp/pubsubstateclient.cc b/talk/xmpp/pubsubstateclient.cc deleted file mode 100644 index 2ed7b20c9..000000000 --- a/talk/xmpp/pubsubstateclient.cc +++ /dev/null @@ -1,42 +0,0 @@ -/* - * libjingle - * Copyright 2011, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "webrtc/libjingle/xmpp/pubsubstateclient.h" - -namespace buzz { - -std::string PublishedNickKeySerializer::GetKey( - const std::string& publisher_nick, const std::string& published_nick) { - return published_nick; -} - -std::string PublisherAndPublishedNicksKeySerializer::GetKey( - const std::string& publisher_nick, const std::string& published_nick) { - return publisher_nick + ":" + published_nick; -} - -} // namespace buzz diff --git a/talk/xmpp/pubsubstateclient.h b/talk/xmpp/pubsubstateclient.h deleted file mode 100644 index 79b1329e9..000000000 --- a/talk/xmpp/pubsubstateclient.h +++ /dev/null @@ -1,287 +0,0 @@ -/* - * libjingle - * Copyright 2011, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef TALK_XMPP_PUBSUBSTATECLIENT_H_ -#define TALK_XMPP_PUBSUBSTATECLIENT_H_ - -#include <map> -#include <string> -#include <vector> - -#include "webrtc/libjingle/xmllite/qname.h" -#include "webrtc/libjingle/xmllite/xmlelement.h" -#include "webrtc/libjingle/xmpp/constants.h" -#include "webrtc/libjingle/xmpp/jid.h" -#include "webrtc/libjingle/xmpp/pubsubclient.h" -#include "webrtc/base/scoped_ptr.h" -#include "webrtc/base/sigslot.h" -#include "webrtc/base/sigslotrepeater.h" - -namespace buzz { - -// To handle retracts correctly, we need to remember certain details -// about an item. We could just cache the entire XML element, but -// that would take more memory and require re-parsing. -struct StateItemInfo { - std::string published_nick; - std::string publisher_nick; -}; - -// Represents a PubSub state change. Usually, the key is the nick, -// but not always. It's a per-state-type thing. Look below on how keys are -// computed. -template <typename C> -struct PubSubStateChange { - // The nick of the user changing the state. - std::string publisher_nick; - // The nick of the user whose state is changing. - std::string published_nick; - C old_state; - C new_state; -}; - -// Knows how to handle specific states and XML. -template <typename C> -class PubSubStateSerializer { - public: - virtual ~PubSubStateSerializer() {} - virtual XmlElement* Write(const QName& state_name, const C& state) = 0; - virtual void Parse(const XmlElement* state_elem, C* state_out) = 0; -}; - -// Knows how to create "keys" for states, which determines their -// uniqueness. Most states are per-nick, but block is -// per-blocker-and-blockee. This is independent of itemid, especially -// in the case of presenter state. -class PubSubStateKeySerializer { - public: - virtual ~PubSubStateKeySerializer() {} - virtual std::string GetKey(const std::string& publisher_nick, - const std::string& published_nick) = 0; -}; - -class PublishedNickKeySerializer : public PubSubStateKeySerializer { - public: - virtual std::string GetKey(const std::string& publisher_nick, - const std::string& published_nick); -}; - -class PublisherAndPublishedNicksKeySerializer - : public PubSubStateKeySerializer { - public: - virtual std::string GetKey(const std::string& publisher_nick, - const std::string& published_nick); -}; - -// Adapts PubSubClient to be specifically suited for pub sub call -// states. Signals state changes and keeps track of keys, which are -// normally nicks. -template <typename C> -class PubSubStateClient : public sigslot::has_slots<> { - public: - // Gets ownership of the serializers, but not the client. - PubSubStateClient(const std::string& publisher_nick, - PubSubClient* client, - const QName& state_name, - C default_state, - PubSubStateKeySerializer* key_serializer, - PubSubStateSerializer<C>* state_serializer) - : publisher_nick_(publisher_nick), - client_(client), - state_name_(state_name), - default_state_(default_state) { - key_serializer_.reset(key_serializer); - state_serializer_.reset(state_serializer); - client_->SignalItems.connect( - this, &PubSubStateClient<C>::OnItems); - client_->SignalPublishResult.connect( - this, &PubSubStateClient<C>::OnPublishResult); - client_->SignalPublishError.connect( - this, &PubSubStateClient<C>::OnPublishError); - client_->SignalRetractResult.connect( - this, &PubSubStateClient<C>::OnRetractResult); - client_->SignalRetractError.connect( - this, &PubSubStateClient<C>::OnRetractError); - } - - virtual ~PubSubStateClient() {} - - virtual void Publish(const std::string& published_nick, - const C& state, - std::string* task_id_out) { - std::string key = key_serializer_->GetKey(publisher_nick_, published_nick); - std::string itemid = state_name_.LocalPart() + ":" + key; - if (StatesEqual(state, default_state_)) { - client_->RetractItem(itemid, task_id_out); - } else { - XmlElement* state_elem = state_serializer_->Write(state_name_, state); - state_elem->AddAttr(QN_NICK, published_nick); - client_->PublishItem(itemid, state_elem, task_id_out); - } - } - - sigslot::signal1<const PubSubStateChange<C>&> SignalStateChange; - // Signal (task_id, item). item is NULL for retract. - sigslot::signal2<const std::string&, - const XmlElement*> SignalPublishResult; - // Signal (task_id, item, error stanza). item is NULL for retract. - sigslot::signal3<const std::string&, - const XmlElement*, - const XmlElement*> SignalPublishError; - - protected: - // return false if retracted item (no info or state given) - virtual bool ParseStateItem(const PubSubItem& item, - StateItemInfo* info_out, - C* state_out) { - const XmlElement* state_elem = item.elem->FirstNamed(state_name_); - if (state_elem == NULL) { - return false; - } - - info_out->publisher_nick = - client_->GetPublisherNickFromPubSubItem(item.elem); - info_out->published_nick = state_elem->Attr(QN_NICK); - state_serializer_->Parse(state_elem, state_out); - return true; - } - - virtual bool StatesEqual(const C& state1, const C& state2) { - return state1 == state2; - } - - PubSubClient* client() { return client_; } - const QName& state_name() { return state_name_; } - - private: - void OnItems(PubSubClient* pub_sub_client, - const std::vector<PubSubItem>& items) { - for (std::vector<PubSubItem>::const_iterator item = items.begin(); - item != items.end(); ++item) { - OnItem(*item); - } - } - - void OnItem(const PubSubItem& item) { - const std::string& itemid = item.itemid; - StateItemInfo info; - C new_state; - - bool retracted = !ParseStateItem(item, &info, &new_state); - if (retracted) { - bool known_itemid = - (info_by_itemid_.find(itemid) != info_by_itemid_.end()); - if (!known_itemid) { - // Nothing to retract, and nothing to publish. - // Probably a different state type. - return; - } else { - info = info_by_itemid_[itemid]; - info_by_itemid_.erase(itemid); - new_state = default_state_; - } - } else { - // TODO: Assert new key matches the known key. It - // shouldn't change! - info_by_itemid_[itemid] = info; - } - - std::string key = key_serializer_->GetKey( - info.publisher_nick, info.published_nick); - bool has_old_state = (state_by_key_.find(key) != state_by_key_.end()); - C old_state = has_old_state ? state_by_key_[key] : default_state_; - if ((retracted && !has_old_state) || StatesEqual(new_state, old_state)) { - // Nothing change, so don't bother signalling. - return; - } - - if (retracted || StatesEqual(new_state, default_state_)) { - // We treat a default state similar to a retract. - state_by_key_.erase(key); - } else { - state_by_key_[key] = new_state; - } - - PubSubStateChange<C> change; - if (!retracted) { - // Retracts do not have publisher information. - change.publisher_nick = info.publisher_nick; - } - change.published_nick = info.published_nick; - change.old_state = old_state; - change.new_state = new_state; - SignalStateChange(change); - } - - void OnPublishResult(PubSubClient* pub_sub_client, - const std::string& task_id, - const XmlElement* item) { - SignalPublishResult(task_id, item); - } - - void OnPublishError(PubSubClient* pub_sub_client, - const std::string& task_id, - const buzz::XmlElement* item, - const buzz::XmlElement* stanza) { - SignalPublishError(task_id, item, stanza); - } - - void OnRetractResult(PubSubClient* pub_sub_client, - const std::string& task_id) { - // There's no point in differentiating between publish and retract - // errors, so we simplify by making them both signal a publish - // result. - const XmlElement* item = NULL; - SignalPublishResult(task_id, item); - } - - void OnRetractError(PubSubClient* pub_sub_client, - const std::string& task_id, - const buzz::XmlElement* stanza) { - // There's no point in differentiating between publish and retract - // errors, so we simplify by making them both signal a publish - // error. - const XmlElement* item = NULL; - SignalPublishError(task_id, item, stanza); - } - - std::string publisher_nick_; - PubSubClient* client_; - const QName state_name_; - C default_state_; - rtc::scoped_ptr<PubSubStateKeySerializer> key_serializer_; - rtc::scoped_ptr<PubSubStateSerializer<C> > state_serializer_; - // key => state - std::map<std::string, C> state_by_key_; - // itemid => StateItemInfo - std::map<std::string, StateItemInfo> info_by_itemid_; - - DISALLOW_COPY_AND_ASSIGN(PubSubStateClient); -}; -} // namespace buzz - -#endif // TALK_XMPP_PUBSUBSTATECLIENT_H_ diff --git a/talk/xmpp/pubsubtasks.cc b/talk/xmpp/pubsubtasks.cc deleted file mode 100644 index 091a7ad96..000000000 --- a/talk/xmpp/pubsubtasks.cc +++ /dev/null @@ -1,221 +0,0 @@ -/* - * libjingle - * Copyright 2011, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "webrtc/libjingle/xmpp/pubsubtasks.h" - -#include <string> -#include <vector> - -#include "webrtc/libjingle/xmpp/constants.h" -#include "webrtc/libjingle/xmpp/receivetask.h" - -// An implementation of the tasks for XEP-0060 -// (http://xmpp.org/extensions/xep-0060.html). - -namespace buzz { - -namespace { - -bool IsPubSubEventItemsElem(const XmlElement* stanza, - const std::string& expected_node) { - if (stanza->Name() != QN_MESSAGE) { - return false; - } - - const XmlElement* event_elem = stanza->FirstNamed(QN_PUBSUB_EVENT); - if (event_elem == NULL) { - return false; - } - - const XmlElement* items_elem = event_elem->FirstNamed(QN_PUBSUB_EVENT_ITEMS); - if (items_elem == NULL) { - return false; - } - - const std::string& actual_node = items_elem->Attr(QN_NODE); - return (actual_node == expected_node); -} - - -// Creates <pubsub node="node"><items></pubsub> -XmlElement* CreatePubSubItemsElem(const std::string& node) { - XmlElement* items_elem = new XmlElement(QN_PUBSUB_ITEMS, false); - items_elem->AddAttr(QN_NODE, node); - XmlElement* pubsub_elem = new XmlElement(QN_PUBSUB, false); - pubsub_elem->AddElement(items_elem); - return pubsub_elem; -} - -// Creates <pubsub node="node"><publish><item id="itemid">payload</item>... -// Takes ownership of payload. -XmlElement* CreatePubSubPublishItemElem( - const std::string& node, - const std::string& itemid, - const std::vector<XmlElement*>& children) { - XmlElement* pubsub_elem = new XmlElement(QN_PUBSUB, true); - XmlElement* publish_elem = new XmlElement(QN_PUBSUB_PUBLISH, false); - publish_elem->AddAttr(QN_NODE, node); - XmlElement* item_elem = new XmlElement(QN_PUBSUB_ITEM, false); - item_elem->AddAttr(QN_ID, itemid); - for (std::vector<XmlElement*>::const_iterator child = children.begin(); - child != children.end(); ++child) { - item_elem->AddElement(*child); - } - publish_elem->AddElement(item_elem); - pubsub_elem->AddElement(publish_elem); - return pubsub_elem; -} - -// Creates <pubsub node="node"><publish><item id="itemid">payload</item>... -// Takes ownership of payload. -XmlElement* CreatePubSubRetractItemElem(const std::string& node, - const std::string& itemid) { - XmlElement* pubsub_elem = new XmlElement(QN_PUBSUB, true); - XmlElement* retract_elem = new XmlElement(QN_PUBSUB_RETRACT, false); - retract_elem->AddAttr(QN_NODE, node); - retract_elem->AddAttr(QN_NOTIFY, "true"); - XmlElement* item_elem = new XmlElement(QN_PUBSUB_ITEM, false); - item_elem->AddAttr(QN_ID, itemid); - retract_elem->AddElement(item_elem); - pubsub_elem->AddElement(retract_elem); - return pubsub_elem; -} - -void ParseItem(const XmlElement* item_elem, - std::vector<PubSubItem>* items) { - PubSubItem item; - item.itemid = item_elem->Attr(QN_ID); - item.elem = item_elem; - items->push_back(item); -} - -// Right now, <retract>s are treated the same as items with empty -// payloads. We may want to change it in the future, but right now -// it's sufficient for our needs. -void ParseRetract(const XmlElement* retract_elem, - std::vector<PubSubItem>* items) { - ParseItem(retract_elem, items); -} - -void ParseEventItemsElem(const XmlElement* stanza, - std::vector<PubSubItem>* items) { - const XmlElement* event_elem = stanza->FirstNamed(QN_PUBSUB_EVENT); - if (event_elem != NULL) { - const XmlElement* items_elem = - event_elem->FirstNamed(QN_PUBSUB_EVENT_ITEMS); - if (items_elem != NULL) { - for (const XmlElement* item_elem = - items_elem->FirstNamed(QN_PUBSUB_EVENT_ITEM); - item_elem != NULL; - item_elem = item_elem->NextNamed(QN_PUBSUB_EVENT_ITEM)) { - ParseItem(item_elem, items); - } - for (const XmlElement* retract_elem = - items_elem->FirstNamed(QN_PUBSUB_EVENT_RETRACT); - retract_elem != NULL; - retract_elem = retract_elem->NextNamed(QN_PUBSUB_EVENT_RETRACT)) { - ParseRetract(retract_elem, items); - } - } - } -} - -void ParsePubSubItemsElem(const XmlElement* stanza, - std::vector<PubSubItem>* items) { - const XmlElement* pubsub_elem = stanza->FirstNamed(QN_PUBSUB); - if (pubsub_elem != NULL) { - const XmlElement* items_elem = pubsub_elem->FirstNamed(QN_PUBSUB_ITEMS); - if (items_elem != NULL) { - for (const XmlElement* item_elem = items_elem->FirstNamed(QN_PUBSUB_ITEM); - item_elem != NULL; - item_elem = item_elem->NextNamed(QN_PUBSUB_ITEM)) { - ParseItem(item_elem, items); - } - } - } -} - -} // namespace - -PubSubRequestTask::PubSubRequestTask(XmppTaskParentInterface* parent, - const Jid& pubsubjid, - const std::string& node) - : IqTask(parent, STR_GET, pubsubjid, CreatePubSubItemsElem(node)) { -} - -void PubSubRequestTask::HandleResult(const XmlElement* stanza) { - std::vector<PubSubItem> items; - ParsePubSubItemsElem(stanza, &items); - SignalResult(this, items); -} - -int PubSubReceiveTask::ProcessStart() { - if (SignalUpdate.is_empty()) { - return STATE_DONE; - } - return ReceiveTask::ProcessStart(); -} - -bool PubSubReceiveTask::WantsStanza(const XmlElement* stanza) { - return MatchStanzaFrom(stanza, pubsubjid_) && - IsPubSubEventItemsElem(stanza, node_) && !SignalUpdate.is_empty(); -} - -void PubSubReceiveTask::ReceiveStanza(const XmlElement* stanza) { - std::vector<PubSubItem> items; - ParseEventItemsElem(stanza, &items); - SignalUpdate(this, items); -} - -PubSubPublishTask::PubSubPublishTask(XmppTaskParentInterface* parent, - const Jid& pubsubjid, - const std::string& node, - const std::string& itemid, - const std::vector<XmlElement*>& children) - : IqTask(parent, STR_SET, pubsubjid, - CreatePubSubPublishItemElem(node, itemid, children)), - itemid_(itemid) { -} - -void PubSubPublishTask::HandleResult(const XmlElement* stanza) { - SignalResult(this); -} - -PubSubRetractTask::PubSubRetractTask(XmppTaskParentInterface* parent, - const Jid& pubsubjid, - const std::string& node, - const std::string& itemid) - : IqTask(parent, STR_SET, pubsubjid, - CreatePubSubRetractItemElem(node, itemid)), - itemid_(itemid) { -} - -void PubSubRetractTask::HandleResult(const XmlElement* stanza) { - SignalResult(this); -} - -} // namespace buzz diff --git a/talk/xmpp/pubsubtasks.h b/talk/xmpp/pubsubtasks.h deleted file mode 100644 index 280c61309..000000000 --- a/talk/xmpp/pubsubtasks.h +++ /dev/null @@ -1,131 +0,0 @@ -/* - * libjingle - * Copyright 2011, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef TALK_XMPP_PUBSUBTASKS_H_ -#define TALK_XMPP_PUBSUBTASKS_H_ - -#include <vector> - -#include "webrtc/libjingle/xmpp/iqtask.h" -#include "webrtc/libjingle/xmpp/receivetask.h" -#include "webrtc/base/sigslot.h" - -namespace buzz { - -// A PubSub itemid + payload. Useful for signaling items. -struct PubSubItem { - std::string itemid; - // The entire <item>, owned by the stanza handler. To keep a - // reference after handling, make a copy. - const XmlElement* elem; -}; - -// An IqTask which gets a <pubsub><items> for a particular jid and -// node, parses the items in the response and signals the items. -class PubSubRequestTask : public IqTask { - public: - PubSubRequestTask(XmppTaskParentInterface* parent, - const Jid& pubsubjid, - const std::string& node); - - sigslot::signal2<PubSubRequestTask*, - const std::vector<PubSubItem>&> SignalResult; - // SignalError inherited by IqTask. - private: - virtual void HandleResult(const XmlElement* stanza); -}; - -// A ReceiveTask which listens for <event><items> of a particular -// pubsub JID and node and then signals them items. -class PubSubReceiveTask : public ReceiveTask { - public: - PubSubReceiveTask(XmppTaskParentInterface* parent, - const Jid& pubsubjid, - const std::string& node) - : ReceiveTask(parent), - pubsubjid_(pubsubjid), - node_(node) { - } - - virtual int ProcessStart(); - sigslot::signal2<PubSubReceiveTask*, - const std::vector<PubSubItem>&> SignalUpdate; - - protected: - virtual bool WantsStanza(const XmlElement* stanza); - virtual void ReceiveStanza(const XmlElement* stanza); - - private: - Jid pubsubjid_; - std::string node_; -}; - -// An IqTask which publishes a <pubsub><publish><item> to a particular -// pubsub jid and node. -class PubSubPublishTask : public IqTask { - public: - // Takes ownership of children - PubSubPublishTask(XmppTaskParentInterface* parent, - const Jid& pubsubjid, - const std::string& node, - const std::string& itemid, - const std::vector<XmlElement*>& children); - - const std::string& itemid() const { return itemid_; } - - sigslot::signal1<PubSubPublishTask*> SignalResult; - - private: - // SignalError inherited by IqTask. - virtual void HandleResult(const XmlElement* stanza); - - std::string itemid_; -}; - -// An IqTask which publishes a <pubsub><publish><retract> to a particular -// pubsub jid and node. -class PubSubRetractTask : public IqTask { - public: - PubSubRetractTask(XmppTaskParentInterface* parent, - const Jid& pubsubjid, - const std::string& node, - const std::string& itemid); - - const std::string& itemid() const { return itemid_; } - - sigslot::signal1<PubSubRetractTask*> SignalResult; - - private: - // SignalError inherited by IqTask. - virtual void HandleResult(const XmlElement* stanza); - - std::string itemid_; -}; - -} // namespace buzz - -#endif // TALK_XMPP_PUBSUBTASKS_H_ diff --git a/talk/xmpp/pubsubtasks_unittest.cc b/talk/xmpp/pubsubtasks_unittest.cc deleted file mode 100644 index 7ea21e73d..000000000 --- a/talk/xmpp/pubsubtasks_unittest.cc +++ /dev/null @@ -1,273 +0,0 @@ -// Copyright 2011 Google Inc. All Rights Reserved - - -#include <string> - -#include "webrtc/libjingle/xmllite/qname.h" -#include "webrtc/libjingle/xmllite/xmlelement.h" -#include "webrtc/libjingle/xmpp/constants.h" -#include "webrtc/libjingle/xmpp/fakexmppclient.h" -#include "webrtc/libjingle/xmpp/iqtask.h" -#include "webrtc/libjingle/xmpp/jid.h" -#include "webrtc/libjingle/xmpp/pubsubtasks.h" -#include "webrtc/base/faketaskrunner.h" -#include "webrtc/base/gunit.h" -#include "webrtc/base/sigslot.h" - -struct HandledPubSubItem { - std::string itemid; - std::string payload; -}; - -class TestPubSubTasksListener : public sigslot::has_slots<> { - public: - TestPubSubTasksListener() : result_count(0), error_count(0) {} - - void OnReceiveUpdate(buzz::PubSubReceiveTask* task, - const std::vector<buzz::PubSubItem>& items) { - OnItems(items); - } - - void OnRequestResult(buzz::PubSubRequestTask* task, - const std::vector<buzz::PubSubItem>& items) { - OnItems(items); - } - - void OnItems(const std::vector<buzz::PubSubItem>& items) { - for (std::vector<buzz::PubSubItem>::const_iterator item = items.begin(); - item != items.end(); ++item) { - HandledPubSubItem handled_item; - handled_item.itemid = item->itemid; - if (item->elem->FirstElement() != NULL) { - handled_item.payload = item->elem->FirstElement()->Str(); - } - this->items.push_back(handled_item); - } - } - - void OnPublishResult(buzz::PubSubPublishTask* task) { - ++result_count; - } - - void OnRetractResult(buzz::PubSubRetractTask* task) { - ++result_count; - } - - void OnError(buzz::IqTask* task, const buzz::XmlElement* stanza) { - ++error_count; - } - - std::vector<HandledPubSubItem> items; - int result_count; - int error_count; -}; - -class PubSubTasksTest : public testing::Test { - public: - PubSubTasksTest() : - pubsubjid("room@domain.com"), - node("topic"), - itemid("key") { - runner.reset(new rtc::FakeTaskRunner()); - client = new buzz::FakeXmppClient(runner.get()); - listener.reset(new TestPubSubTasksListener()); - } - - rtc::scoped_ptr<rtc::FakeTaskRunner> runner; - // Client deleted by deleting runner. - buzz::FakeXmppClient* client; - rtc::scoped_ptr<TestPubSubTasksListener> listener; - buzz::Jid pubsubjid; - std::string node; - std::string itemid; -}; - -TEST_F(PubSubTasksTest, TestRequest) { - buzz::PubSubRequestTask* task = - new buzz::PubSubRequestTask(client, pubsubjid, node); - task->SignalResult.connect( - listener.get(), &TestPubSubTasksListener::OnRequestResult); - task->Start(); - - std::string expected_iq = - "<cli:iq type=\"get\" to=\"room@domain.com\" id=\"0\" " - "xmlns:cli=\"jabber:client\">" - "<pub:pubsub xmlns:pub=\"http://jabber.org/protocol/pubsub\">" - "<pub:items node=\"topic\"/>" - "</pub:pubsub>" - "</cli:iq>"; - - ASSERT_EQ(1U, client->sent_stanzas().size()); - EXPECT_EQ(expected_iq, client->sent_stanzas()[0]->Str()); - - std::string result_iq = - "<iq xmlns='jabber:client' id='0' type='result' from='room@domain.com'>" - " <pubsub xmlns='http://jabber.org/protocol/pubsub'>" - " <items node='topic'>" - " <item id='key0'>" - " <value0/>" - " </item>" - " <item id='key1'>" - " <value1/>" - " </item>" - " </items>" - " </pubsub>" - "</iq>"; - - client->HandleStanza(buzz::XmlElement::ForStr(result_iq)); - - ASSERT_EQ(2U, listener->items.size()); - EXPECT_EQ("key0", listener->items[0].itemid); - EXPECT_EQ("<pub:value0 xmlns:pub=\"http://jabber.org/protocol/pubsub\"/>", - listener->items[0].payload); - EXPECT_EQ("key1", listener->items[1].itemid); - EXPECT_EQ("<pub:value1 xmlns:pub=\"http://jabber.org/protocol/pubsub\"/>", - listener->items[1].payload); -} - -TEST_F(PubSubTasksTest, TestRequestError) { - std::string result_iq = - "<iq xmlns='jabber:client' id='0' type='error' from='room@domain.com'>" - " <error type='auth'>" - " <forbidden xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>" - " </error>" - "</iq>"; - - buzz::PubSubRequestTask* task = - new buzz::PubSubRequestTask(client, pubsubjid, node); - task->SignalResult.connect( - listener.get(), &TestPubSubTasksListener::OnRequestResult); - task->SignalError.connect( - listener.get(), &TestPubSubTasksListener::OnError); - task->Start(); - client->HandleStanza(buzz::XmlElement::ForStr(result_iq)); - - EXPECT_EQ(0, listener->result_count); - EXPECT_EQ(1, listener->error_count); -} - -TEST_F(PubSubTasksTest, TestReceive) { - std::string items_message = - "<message xmlns='jabber:client' from='room@domain.com'>" - " <event xmlns='http://jabber.org/protocol/pubsub#event'>" - " <items node='topic'>" - " <item id='key0'>" - " <value0/>" - " </item>" - " <item id='key1'>" - " <value1/>" - " </item>" - " </items>" - " </event>" - "</message>"; - - buzz::PubSubReceiveTask* task = - new buzz::PubSubReceiveTask(client, pubsubjid, node); - task->SignalUpdate.connect( - listener.get(), &TestPubSubTasksListener::OnReceiveUpdate); - task->Start(); - client->HandleStanza(buzz::XmlElement::ForStr(items_message)); - - ASSERT_EQ(2U, listener->items.size()); - EXPECT_EQ("key0", listener->items[0].itemid); - EXPECT_EQ( - "<eve:value0 xmlns:eve=\"http://jabber.org/protocol/pubsub#event\"/>", - listener->items[0].payload); - EXPECT_EQ("key1", listener->items[1].itemid); - EXPECT_EQ( - "<eve:value1 xmlns:eve=\"http://jabber.org/protocol/pubsub#event\"/>", - listener->items[1].payload); -} - -TEST_F(PubSubTasksTest, TestPublish) { - buzz::XmlElement* payload = - new buzz::XmlElement(buzz::QName(buzz::NS_PUBSUB, "value")); - std::string expected_iq = - "<cli:iq type=\"set\" to=\"room@domain.com\" id=\"0\" " - "xmlns:cli=\"jabber:client\">" - "<pubsub xmlns=\"http://jabber.org/protocol/pubsub\">" - "<publish node=\"topic\">" - "<item id=\"key\">" - "<value/>" - "</item>" - "</publish>" - "</pubsub>" - "</cli:iq>"; - - std::vector<buzz::XmlElement*> children; - children.push_back(payload); - buzz::PubSubPublishTask* task = - new buzz::PubSubPublishTask(client, pubsubjid, node, itemid, children); - task->SignalResult.connect( - listener.get(), &TestPubSubTasksListener::OnPublishResult); - task->Start(); - - ASSERT_EQ(1U, client->sent_stanzas().size()); - EXPECT_EQ(expected_iq, client->sent_stanzas()[0]->Str()); - - std::string result_iq = - "<iq xmlns='jabber:client' id='0' type='result' from='room@domain.com'/>"; - - client->HandleStanza(buzz::XmlElement::ForStr(result_iq)); - - EXPECT_EQ(1, listener->result_count); - EXPECT_EQ(0, listener->error_count); -} - -TEST_F(PubSubTasksTest, TestPublishError) { - buzz::XmlElement* payload = - new buzz::XmlElement(buzz::QName(buzz::NS_PUBSUB, "value")); - - std::vector<buzz::XmlElement*> children; - children.push_back(payload); - buzz::PubSubPublishTask* task = - new buzz::PubSubPublishTask(client, pubsubjid, node, itemid, children); - task->SignalResult.connect( - listener.get(), &TestPubSubTasksListener::OnPublishResult); - task->SignalError.connect( - listener.get(), &TestPubSubTasksListener::OnError); - task->Start(); - - std::string result_iq = - "<iq xmlns='jabber:client' id='0' type='error' from='room@domain.com'>" - " <error type='auth'>" - " <forbidden xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>" - " </error>" - "</iq>"; - - client->HandleStanza(buzz::XmlElement::ForStr(result_iq)); - - EXPECT_EQ(0, listener->result_count); - EXPECT_EQ(1, listener->error_count); -} - -TEST_F(PubSubTasksTest, TestRetract) { - buzz::PubSubRetractTask* task = - new buzz::PubSubRetractTask(client, pubsubjid, node, itemid); - task->SignalResult.connect( - listener.get(), &TestPubSubTasksListener::OnRetractResult); - task->SignalError.connect( - listener.get(), &TestPubSubTasksListener::OnError); - task->Start(); - - std::string expected_iq = - "<cli:iq type=\"set\" to=\"room@domain.com\" id=\"0\" " - "xmlns:cli=\"jabber:client\">" - "<pubsub xmlns=\"http://jabber.org/protocol/pubsub\">" - "<retract node=\"topic\" notify=\"true\">" - "<item id=\"key\"/>" - "</retract>" - "</pubsub>" - "</cli:iq>"; - - ASSERT_EQ(1U, client->sent_stanzas().size()); - EXPECT_EQ(expected_iq, client->sent_stanzas()[0]->Str()); - - std::string result_iq = - "<iq xmlns='jabber:client' id='0' type='result' from='room@domain.com'/>"; - - client->HandleStanza(buzz::XmlElement::ForStr(result_iq)); - - EXPECT_EQ(1, listener->result_count); - EXPECT_EQ(0, listener->error_count); -} diff --git a/talk/xmpp/receivetask.cc b/talk/xmpp/receivetask.cc deleted file mode 100644 index 4c4fae5b6..000000000 --- a/talk/xmpp/receivetask.cc +++ /dev/null @@ -1,51 +0,0 @@ -/* - * libjingle - * Copyright 2011, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "webrtc/libjingle/xmpp/constants.h" -#include "webrtc/libjingle/xmpp/receivetask.h" - -namespace buzz { - -bool ReceiveTask::HandleStanza(const XmlElement* stanza) { - if (WantsStanza(stanza)) { - QueueStanza(stanza); - return true; - } - - return false; -} - -int ReceiveTask::ProcessStart() { - const XmlElement* stanza = NextStanza(); - if (stanza == NULL) - return STATE_BLOCKED; - - ReceiveStanza(stanza); - return STATE_START; -} - -} // namespace buzz diff --git a/talk/xmpp/receivetask.h b/talk/xmpp/receivetask.h deleted file mode 100644 index 7055339e2..000000000 --- a/talk/xmpp/receivetask.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * libjingle - * Copyright 2011, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef TALK_XMPP_RECEIVETASK_H_ -#define TALK_XMPP_RECEIVETASK_H_ - -#include "webrtc/libjingle/xmpp/xmpptask.h" - -namespace buzz { - -// A base class for receiving stanzas. Override WantsStanza to -// indicate that a stanza should be received and ReceiveStanza to -// process it. Once started, ReceiveStanza will be called for all -// stanzas that return true when passed to WantsStanza. This saves -// you from having to remember how to setup the queueing and the task -// states, etc. -class ReceiveTask : public XmppTask { - public: - explicit ReceiveTask(XmppTaskParentInterface* parent) : - XmppTask(parent, XmppEngine::HL_TYPE) {} - virtual int ProcessStart(); - - protected: - virtual bool HandleStanza(const XmlElement* stanza); - - // Return true if the stanza should be received. - virtual bool WantsStanza(const XmlElement* stanza) = 0; - // Process the received stanza. - virtual void ReceiveStanza(const XmlElement* stanza) = 0; -}; - -} // namespace buzz - -#endif // TALK_XMPP_RECEIVETASK_H_ diff --git a/talk/xmpp/rostermodule.h b/talk/xmpp/rostermodule.h deleted file mode 100644 index 9ae7f70cc..000000000 --- a/talk/xmpp/rostermodule.h +++ /dev/null @@ -1,348 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef TALK_XMPP_ROSTERMODULE_H_ -#define TALK_XMPP_ROSTERMODULE_H_ - -#include "webrtc/libjingle/xmpp/module.h" - -namespace buzz { - -class XmppRosterModule; - -// The main way you initialize and use the module would be like this: -// XmppRosterModule *roster_module = XmppRosterModule::Create(); -// roster_module->RegisterEngine(engine); -// roster_module->BroadcastPresence(); -// roster_module->RequestRosterUpdate(); - -//! This enum captures the valid values for the show attribute in a presence -//! stanza -enum XmppPresenceShow -{ - XMPP_PRESENCE_CHAT = 0, - XMPP_PRESENCE_DEFAULT = 1, - XMPP_PRESENCE_AWAY = 2, - XMPP_PRESENCE_XA = 3, - XMPP_PRESENCE_DND = 4, -}; - -//! These are the valid subscription states in a roster contact. This -//! represents the combination of the subscription and ask attributes -enum XmppSubscriptionState -{ - XMPP_SUBSCRIPTION_NONE = 0, - XMPP_SUBSCRIPTION_NONE_ASKED = 1, - XMPP_SUBSCRIPTION_TO = 2, - XMPP_SUBSCRIPTION_FROM = 3, - XMPP_SUBSCRIPTION_FROM_ASKED = 4, - XMPP_SUBSCRIPTION_BOTH = 5, -}; - -//! These represent the valid types of presence stanzas for managing -//! subscriptions -enum XmppSubscriptionRequestType -{ - XMPP_REQUEST_SUBSCRIBE = 0, - XMPP_REQUEST_UNSUBSCRIBE = 1, - XMPP_REQUEST_SUBSCRIBED = 2, - XMPP_REQUEST_UNSUBSCRIBED = 3, -}; - -enum XmppPresenceAvailable { - XMPP_PRESENCE_UNAVAILABLE = 0, - XMPP_PRESENCE_AVAILABLE = 1, - XMPP_PRESENCE_ERROR = 2, -}; - -enum XmppPresenceConnectionStatus { - XMPP_CONNECTION_STATUS_UNKNOWN = 0, - // Status set by the server while the user is being rung. - XMPP_CONNECTION_STATUS_CONNECTING = 1, - // Status set by the client when the user has accepted the ring but before - // the client has joined the call. - XMPP_CONNECTION_STATUS_JOINING = 2, - // Status set by the client as part of joining the call. - XMPP_CONNECTION_STATUS_CONNECTED = 3, - XMPP_CONNECTION_STATUS_HANGUP = 4, -}; - -//! Presence Information -//! This class stores both presence information for outgoing presence and is -//! returned by methods in XmppRosterModule to represent recieved incoming -//! presence information. When this class is writeable (non-const) then each -//! update to any property will set the inner xml. Setting the raw_xml will -//! rederive all of the other properties. -class XmppPresence { -public: - virtual ~XmppPresence() {} - - //! Create a new Presence - //! This is typically only used when sending a directed presence - static XmppPresence* Create(); - - //! The Jid of for the presence information. - //! Typically this will be a full Jid with resource specified. - virtual const Jid jid() const = 0; - - //! Is the contact available? - virtual XmppPresenceAvailable available() const = 0; - - //! Sets if the user is available or not - virtual XmppReturnStatus set_available(XmppPresenceAvailable available) = 0; - - //! The show value of the presence info - virtual XmppPresenceShow presence_show() const = 0; - - //! Set the presence show value - virtual XmppReturnStatus set_presence_show(XmppPresenceShow show) = 0; - - //! The Priority of the presence info - virtual int priority() const = 0; - - //! Set the priority of the presence - virtual XmppReturnStatus set_priority(int priority) = 0; - - //! The plain text status of the presence info. - //! If there are multiple status because of language, this will either be a - //! status that is not tagged for language or the first available - virtual const std::string status() const = 0; - - //! Sets the status for the presence info. - //! If there is more than one status present already then this will remove - //! them all and replace it with one status element we no specified language - virtual XmppReturnStatus set_status(const std::string& status) = 0; - - //! The connection status - virtual XmppPresenceConnectionStatus connection_status() const = 0; - - //! The focus obfuscated GAIA id - virtual const std::string google_user_id() const = 0; - - //! The nickname in the presence - virtual const std::string nickname() const = 0; - - //! The raw xml of the presence update - virtual const XmlElement* raw_xml() const = 0; - - //! Sets the raw presence stanza for the presence update - //! This will cause all other data items in this structure to be rederived - virtual XmppReturnStatus set_raw_xml(const XmlElement * xml) = 0; -}; - -//! A contact as given by the server -class XmppRosterContact { -public: - virtual ~XmppRosterContact() {} - - //! Create a new roster contact - //! This is typically only used when doing a roster update/add - static XmppRosterContact* Create(); - - //! The jid for the contact. - //! Typically this will be a bare Jid. - virtual const Jid jid() const = 0; - - //! Sets the jid for the roster contact update - virtual XmppReturnStatus set_jid(const Jid& jid) = 0; - - //! The name (nickname) stored for this contact - virtual const std::string name() const = 0; - - //! Sets the name - virtual XmppReturnStatus set_name(const std::string& name) = 0; - - //! The Presence subscription state stored on the server for this contact - //! This is never settable and will be ignored when generating a roster - //! add/update request - virtual XmppSubscriptionState subscription_state() const = 0; - - //! The number of Groups applied to this contact - virtual size_t GetGroupCount() const = 0; - - //! Gets a Group applied to the contact based on index. - //! range - virtual const std::string GetGroup(size_t index) const = 0; - - //! Adds a group to this contact. - //! This will return a bad argument error if the group is already there. - virtual XmppReturnStatus AddGroup(const std::string& group) = 0; - - //! Removes a group from the contact. - //! This will return an error if the group cannot be found in the group list. - virtual XmppReturnStatus RemoveGroup(const std::string& group) = 0; - - //! The raw xml for this roster contact - virtual const XmlElement* raw_xml() const = 0; - - //! Sets the raw presence stanza for the contact update/add - //! This will cause all other data items in this structure to be rederived - virtual XmppReturnStatus set_raw_xml(const XmlElement * xml) = 0; -}; - -//! The XmppRosterHandler is an interface for callbacks from the module -class XmppRosterHandler { -public: - virtual ~XmppRosterHandler() {} - - //! A request for a subscription has come in. - //! Typically, the UI will ask the user if it is okay to let the requester - //! get presence notifications for the user. The response is send back - //! by calling ApproveSubscriber or CancelSubscriber. - virtual void SubscriptionRequest(XmppRosterModule* roster, - const Jid& requesting_jid, - XmppSubscriptionRequestType type, - const XmlElement* raw_xml) = 0; - - //! Some type of presence error has occured - virtual void SubscriptionError(XmppRosterModule* roster, - const Jid& from, - const XmlElement* raw_xml) = 0; - - virtual void RosterError(XmppRosterModule* roster, - const XmlElement* raw_xml) = 0; - - //! New presence information has come in - //! The user is notified with the presence object directly. This info is also - //! added to the store accessable from the engine. - virtual void IncomingPresenceChanged(XmppRosterModule* roster, - const XmppPresence* presence) = 0; - - //! A contact has changed - //! This indicates that the data for a contact may have changed. No - //! contacts have been added or removed. - virtual void ContactChanged(XmppRosterModule* roster, - const XmppRosterContact* old_contact, - size_t index) = 0; - - //! A set of contacts have been added - //! These contacts may have been added in response to the original roster - //! request or due to a "roster push" from the server. - virtual void ContactsAdded(XmppRosterModule* roster, - size_t index, size_t number) = 0; - - //! A contact has been removed - //! This contact has been removed form the list. - virtual void ContactRemoved(XmppRosterModule* roster, - const XmppRosterContact* removed_contact, - size_t index) = 0; - -}; - -//! An XmppModule for handle roster and presence functionality -class XmppRosterModule : public XmppModule { -public: - //! Creates a new XmppRosterModule - static XmppRosterModule * Create(); - virtual ~XmppRosterModule() {} - - //! Sets the roster handler (callbacks) for the module - virtual XmppReturnStatus set_roster_handler(XmppRosterHandler * handler) = 0; - - //! Gets the roster handler for the module - virtual XmppRosterHandler* roster_handler() = 0; - - // USER PRESENCE STATE ------------------------------------------------------- - - //! Gets the aggregate outgoing presence - //! This object is non-const and be edited directly. No update is sent - //! to the server until a Broadcast is sent - virtual XmppPresence* outgoing_presence() = 0; - - //! Broadcasts that the user is available. - //! Nothing with respect to presence is sent until this is called. - virtual XmppReturnStatus BroadcastPresence() = 0; - - //! Sends a directed presence to a Jid - //! Note that the client doesn't store where directed presence notifications - //! have been sent. The server can keep the appropriate state - virtual XmppReturnStatus SendDirectedPresence(const XmppPresence* presence, - const Jid& to_jid) = 0; - - // INCOMING PRESENCE STATUS -------------------------------------------------- - - //! Returns the number of incoming presence data recorded - virtual size_t GetIncomingPresenceCount() = 0; - - //! Returns an incoming presence datum based on index - virtual const XmppPresence* GetIncomingPresence(size_t index) = 0; - - //! Gets the number of presence data for a bare Jid - //! There may be a datum per resource - virtual size_t GetIncomingPresenceForJidCount(const Jid& jid) = 0; - - //! Returns a single presence data for a Jid based on index - virtual const XmppPresence* GetIncomingPresenceForJid(const Jid& jid, - size_t index) = 0; - - // ROSTER MANAGEMENT --------------------------------------------------------- - - //! Requests an update of the roster from the server - //! This must be called to initialize the client side cache of the roster - //! After this is sent the server should keep this module apprised of any - //! changes. - virtual XmppReturnStatus RequestRosterUpdate() = 0; - - //! Returns the number of contacts in the roster - virtual size_t GetRosterContactCount() = 0; - - //! Returns a contact by index - virtual const XmppRosterContact* GetRosterContact(size_t index) = 0; - - //! Finds a contact by Jid - virtual const XmppRosterContact* FindRosterContact(const Jid& jid) = 0; - - //! Send a request to the server to add a contact - //! Note that the contact won't show up in the roster until the server can - //! respond. This happens async when the socket is being serviced - virtual XmppReturnStatus RequestRosterChange( - const XmppRosterContact* contact) = 0; - - //! Request that the server remove a contact - //! The jabber protocol specifies that the server should also cancel any - //! subscriptions when this is done. Like adding, this contact won't be - //! removed until the server responds. - virtual XmppReturnStatus RequestRosterRemove(const Jid& jid) = 0; - - // SUBSCRIPTION MANAGEMENT --------------------------------------------------- - - //! Request a subscription to presence notifications form a Jid - virtual XmppReturnStatus RequestSubscription(const Jid& jid) = 0; - - //! Cancel a subscription to presence notifications from a Jid - virtual XmppReturnStatus CancelSubscription(const Jid& jid) = 0; - - //! Approve a request to deliver presence notifications to a jid - virtual XmppReturnStatus ApproveSubscriber(const Jid& jid) = 0; - - //! Deny or cancel presence notification deliver to a jid - virtual XmppReturnStatus CancelSubscriber(const Jid& jid) = 0; -}; - -} - -#endif // TALK_XMPP_ROSTERMODULE_H_ diff --git a/talk/xmpp/rostermodule_unittest.cc b/talk/xmpp/rostermodule_unittest.cc deleted file mode 100644 index fb82546c8..000000000 --- a/talk/xmpp/rostermodule_unittest.cc +++ /dev/null @@ -1,849 +0,0 @@ -/* - * libjingle - * Copyright 2004, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <iostream> -#include <sstream> -#include <string> - -#include "webrtc/libjingle/xmllite/xmlelement.h" -#include "webrtc/libjingle/xmpp/constants.h" -#include "webrtc/libjingle/xmpp/rostermodule.h" -#include "webrtc/libjingle/xmpp/util_unittest.h" -#include "webrtc/libjingle/xmpp/xmppengine.h" -#include "webrtc/base/gunit.h" -#include "webrtc/base/scoped_ptr.h" - -#define TEST_OK(x) EXPECT_EQ((x),XMPP_RETURN_OK) -#define TEST_BADARGUMENT(x) EXPECT_EQ((x),XMPP_RETURN_BADARGUMENT) - - -namespace buzz { - -class RosterModuleTest; - -static void -WriteString(std::ostream& os, const std::string& str) { - os<<str; -} - -static void -WriteSubscriptionState(std::ostream& os, XmppSubscriptionState state) -{ - switch (state) { - case XMPP_SUBSCRIPTION_NONE: - os<<"none"; - break; - case XMPP_SUBSCRIPTION_NONE_ASKED: - os<<"none_asked"; - break; - case XMPP_SUBSCRIPTION_TO: - os<<"to"; - break; - case XMPP_SUBSCRIPTION_FROM: - os<<"from"; - break; - case XMPP_SUBSCRIPTION_FROM_ASKED: - os<<"from_asked"; - break; - case XMPP_SUBSCRIPTION_BOTH: - os<<"both"; - break; - default: - os<<"unknown"; - break; - } -} - -static void -WriteSubscriptionRequestType(std::ostream& os, - XmppSubscriptionRequestType type) { - switch(type) { - case XMPP_REQUEST_SUBSCRIBE: - os<<"subscribe"; - break; - case XMPP_REQUEST_UNSUBSCRIBE: - os<<"unsubscribe"; - break; - case XMPP_REQUEST_SUBSCRIBED: - os<<"subscribed"; - break; - case XMPP_REQUEST_UNSUBSCRIBED: - os<<"unsubscribe"; - break; - default: - os<<"unknown"; - break; - } -} - -static void -WritePresenceShow(std::ostream& os, XmppPresenceShow show) { - switch(show) { - case XMPP_PRESENCE_AWAY: - os<<"away"; - break; - case XMPP_PRESENCE_CHAT: - os<<"chat"; - break; - case XMPP_PRESENCE_DND: - os<<"dnd"; - break; - case XMPP_PRESENCE_XA: - os<<"xa"; - break; - case XMPP_PRESENCE_DEFAULT: - os<<"[default]"; - break; - default: - os<<"[unknown]"; - break; - } -} - -static void -WritePresence(std::ostream& os, const XmppPresence* presence) { - if (presence == NULL) { - os<<"NULL"; - return; - } - - os<<"[Presence jid:"; - WriteString(os, presence->jid().Str()); - os<<" available:"<<presence->available(); - os<<" presence_show:"; - WritePresenceShow(os, presence->presence_show()); - os<<" priority:"<<presence->priority(); - os<<" status:"; - WriteString(os, presence->status()); - os<<"]"<<presence->raw_xml()->Str(); -} - -static void -WriteContact(std::ostream& os, const XmppRosterContact* contact) { - if (contact == NULL) { - os<<"NULL"; - return; - } - - os<<"[Contact jid:"; - WriteString(os, contact->jid().Str()); - os<<" name:"; - WriteString(os, contact->name()); - os<<" subscription_state:"; - WriteSubscriptionState(os, contact->subscription_state()); - os<<" groups:["; - for(size_t i=0; i < contact->GetGroupCount(); ++i) { - os<<(i==0?"":", "); - WriteString(os, contact->GetGroup(i)); - } - os<<"]]"<<contact->raw_xml()->Str(); -} - -//! This session handler saves all calls to a string. These are events and -//! data delivered form the engine to application code. -class XmppTestRosterHandler : public XmppRosterHandler { -public: - XmppTestRosterHandler() {} - virtual ~XmppTestRosterHandler() {} - - virtual void SubscriptionRequest(XmppRosterModule*, - const Jid& requesting_jid, - XmppSubscriptionRequestType type, - const XmlElement* raw_xml) { - ss_<<"[SubscriptionRequest Jid:" << requesting_jid.Str()<<" type:"; - WriteSubscriptionRequestType(ss_, type); - ss_<<"]"<<raw_xml->Str(); - } - - //! Some type of presence error has occured - virtual void SubscriptionError(XmppRosterModule*, - const Jid& from, - const XmlElement* raw_xml) { - ss_<<"[SubscriptionError from:"<<from.Str()<<"]"<<raw_xml->Str(); - } - - virtual void RosterError(XmppRosterModule*, - const XmlElement* raw_xml) { - ss_<<"[RosterError]"<<raw_xml->Str(); - } - - //! New presence information has come in - //! The user is notified with the presence object directly. This info is also - //! added to the store accessable from the engine. - virtual void IncomingPresenceChanged(XmppRosterModule*, - const XmppPresence* presence) { - ss_<<"[IncomingPresenceChanged presence:"; - WritePresence(ss_, presence); - ss_<<"]"; - } - - //! A contact has changed - //! This indicates that the data for a contact may have changed. No - //! contacts have been added or removed. - virtual void ContactChanged(XmppRosterModule* roster, - const XmppRosterContact* old_contact, - size_t index) { - ss_<<"[ContactChanged old_contact:"; - WriteContact(ss_, old_contact); - ss_<<" index:"<<index<<" new_contact:"; - WriteContact(ss_, roster->GetRosterContact(index)); - ss_<<"]"; - } - - //! A set of contacts have been added - //! These contacts may have been added in response to the original roster - //! request or due to a "roster push" from the server. - virtual void ContactsAdded(XmppRosterModule* roster, - size_t index, size_t number) { - ss_<<"[ContactsAdded index:"<<index<<" number:"<<number; - for (size_t i = 0; i < number; ++i) { - ss_<<" "<<(index+i)<<":"; - WriteContact(ss_, roster->GetRosterContact(index+i)); - } - ss_<<"]"; - } - - //! A contact has been removed - //! This contact has been removed form the list. - virtual void ContactRemoved(XmppRosterModule*, - const XmppRosterContact* removed_contact, - size_t index) { - ss_<<"[ContactRemoved old_contact:"; - WriteContact(ss_, removed_contact); - ss_<<" index:"<<index<<"]"; - } - - std::string Str() { - return ss_.str(); - } - - std::string StrClear() { - std::string result = ss_.str(); - ss_.str(""); - return result; - } - -private: - std::stringstream ss_; -}; - -//! This is the class that holds all of the unit test code for the -//! roster module -class RosterModuleTest : public testing::Test { -public: - RosterModuleTest() {} - static void RunLogin(RosterModuleTest* obj, XmppEngine* engine, - XmppTestHandler* handler) { - // Needs to be similar to XmppEngineTest::RunLogin - } -}; - -TEST_F(RosterModuleTest, TestPresence) { - XmlElement* status = new XmlElement(QN_GOOGLE_PSTN_CONFERENCE_STATUS); - status->AddAttr(QN_STATUS, STR_PSTN_CONFERENCE_STATUS_CONNECTING); - XmlElement presence_xml(QN_PRESENCE); - presence_xml.AddElement(status); - rtc::scoped_ptr<XmppPresence> presence(XmppPresence::Create()); - presence->set_raw_xml(&presence_xml); - EXPECT_EQ(presence->connection_status(), XMPP_CONNECTION_STATUS_CONNECTING); -} - -TEST_F(RosterModuleTest, TestOutgoingPresence) { - std::stringstream dump; - - rtc::scoped_ptr<XmppEngine> engine(XmppEngine::Create()); - XmppTestHandler handler(engine.get()); - XmppTestRosterHandler roster_handler; - - rtc::scoped_ptr<XmppRosterModule> roster(XmppRosterModule::Create()); - roster->set_roster_handler(&roster_handler); - - // Configure the roster module - roster->RegisterEngine(engine.get()); - - // Set up callbacks - engine->SetOutputHandler(&handler); - engine->AddStanzaHandler(&handler); - engine->SetSessionHandler(&handler); - - // Set up minimal login info - engine->SetUser(Jid("david@my-server")); - // engine->SetPassword("david"); - - // Do the whole login handshake - RunLogin(this, engine.get(), &handler); - EXPECT_EQ("", handler.OutputActivity()); - - // Set some presence and broadcast it - TEST_OK(roster->outgoing_presence()-> - set_available(XMPP_PRESENCE_AVAILABLE)); - TEST_OK(roster->outgoing_presence()->set_priority(-37)); - TEST_OK(roster->outgoing_presence()->set_presence_show(XMPP_PRESENCE_DND)); - TEST_OK(roster->outgoing_presence()-> - set_status("I'm off to the races!<>&")); - TEST_OK(roster->BroadcastPresence()); - - EXPECT_EQ(roster_handler.StrClear(), ""); - EXPECT_EQ(handler.OutputActivity(), - "<presence>" - "<priority>-37</priority>" - "<show>dnd</show>" - "<status>I'm off to the races!<>&</status>" - "</presence>"); - EXPECT_EQ(handler.SessionActivity(), ""); - - // Try some more - TEST_OK(roster->outgoing_presence()-> - set_available(XMPP_PRESENCE_UNAVAILABLE)); - TEST_OK(roster->outgoing_presence()->set_priority(0)); - TEST_OK(roster->outgoing_presence()->set_presence_show(XMPP_PRESENCE_XA)); - TEST_OK(roster->outgoing_presence()->set_status("Gone fishin'")); - TEST_OK(roster->BroadcastPresence()); - - EXPECT_EQ(roster_handler.StrClear(), ""); - EXPECT_EQ(handler.OutputActivity(), - "<presence type=\"unavailable\">" - "<show>xa</show>" - "<status>Gone fishin'</status>" - "</presence>"); - EXPECT_EQ(handler.SessionActivity(), ""); - - // Okay -- we are back on - TEST_OK(roster->outgoing_presence()-> - set_available(XMPP_PRESENCE_AVAILABLE)); - TEST_BADARGUMENT(roster->outgoing_presence()->set_priority(128)); - TEST_OK(roster->outgoing_presence()-> - set_presence_show(XMPP_PRESENCE_DEFAULT)); - TEST_OK(roster->outgoing_presence()->set_status("Cookin' wit gas")); - TEST_OK(roster->BroadcastPresence()); - - EXPECT_EQ(roster_handler.StrClear(), ""); - EXPECT_EQ(handler.OutputActivity(), - "<presence>" - "<status>Cookin' wit gas</status>" - "</presence>"); - EXPECT_EQ(handler.SessionActivity(), ""); - - // Set it via XML - XmlElement presence_input(QN_PRESENCE); - presence_input.AddAttr(QN_TYPE, "unavailable"); - presence_input.AddElement(new XmlElement(QN_PRIORITY)); - presence_input.AddText("42", 1); - presence_input.AddElement(new XmlElement(QN_STATUS)); - presence_input.AddAttr(QN_XML_LANG, "es", 1); - presence_input.AddText("Hola Amigos!", 1); - presence_input.AddElement(new XmlElement(QN_STATUS)); - presence_input.AddText("Hey there, friend!", 1); - TEST_OK(roster->outgoing_presence()->set_raw_xml(&presence_input)); - TEST_OK(roster->BroadcastPresence()); - - WritePresence(dump, roster->outgoing_presence()); - EXPECT_EQ(dump.str(), - "[Presence jid: available:0 presence_show:[default] " - "priority:42 status:Hey there, friend!]" - "<cli:presence type=\"unavailable\" xmlns:cli=\"jabber:client\">" - "<cli:priority>42</cli:priority>" - "<cli:status xml:lang=\"es\">Hola Amigos!</cli:status>" - "<cli:status>Hey there, friend!</cli:status>" - "</cli:presence>"); - dump.str(""); - EXPECT_EQ(roster_handler.StrClear(), ""); - EXPECT_EQ(handler.OutputActivity(), - "<presence type=\"unavailable\">" - "<priority>42</priority>" - "<status xml:lang=\"es\">Hola Amigos!</status>" - "<status>Hey there, friend!</status>" - "</presence>"); - EXPECT_EQ(handler.SessionActivity(), ""); - - // Construct a directed presence - rtc::scoped_ptr<XmppPresence> directed_presence(XmppPresence::Create()); - TEST_OK(directed_presence->set_available(XMPP_PRESENCE_AVAILABLE)); - TEST_OK(directed_presence->set_priority(120)); - TEST_OK(directed_presence->set_status("*very* available")); - TEST_OK(roster->SendDirectedPresence(directed_presence.get(), - Jid("myhoney@honey.net"))); - - EXPECT_EQ(roster_handler.StrClear(), ""); - EXPECT_EQ(handler.OutputActivity(), - "<presence to=\"myhoney@honey.net\">" - "<priority>120</priority>" - "<status>*very* available</status>" - "</presence>"); - EXPECT_EQ(handler.SessionActivity(), ""); -} - -TEST_F(RosterModuleTest, TestIncomingPresence) { - rtc::scoped_ptr<XmppEngine> engine(XmppEngine::Create()); - XmppTestHandler handler(engine.get()); - XmppTestRosterHandler roster_handler; - - rtc::scoped_ptr<XmppRosterModule> roster(XmppRosterModule::Create()); - roster->set_roster_handler(&roster_handler); - - // Configure the roster module - roster->RegisterEngine(engine.get()); - - // Set up callbacks - engine->SetOutputHandler(&handler); - engine->AddStanzaHandler(&handler); - engine->SetSessionHandler(&handler); - - // Set up minimal login info - engine->SetUser(Jid("david@my-server")); - // engine->SetPassword("david"); - - // Do the whole login handshake - RunLogin(this, engine.get(), &handler); - EXPECT_EQ("", handler.OutputActivity()); - - // Load up with a bunch of data - std::string input; - input = "<presence from='maude@example.net/studio' " - "to='david@my-server/test'/>" - "<presence from='walter@example.net/home' " - "to='david@my-server/test'>" - "<priority>-10</priority>" - "<show>xa</show>" - "<status>Off bowling</status>" - "</presence>" - "<presence from='walter@example.net/alley' " - "to='david@my-server/test'>" - "<priority>20</priority>" - "<status>Looking for toes...</status>" - "</presence>" - "<presence from='donny@example.net/alley' " - "to='david@my-server/test'>" - "<priority>10</priority>" - "<status>Throwing rocks</status>" - "</presence>"; - TEST_OK(engine->HandleInput(input.c_str(), input.length())); - - EXPECT_EQ(roster_handler.StrClear(), - "[IncomingPresenceChanged " - "presence:[Presence jid:maude@example.net/studio available:1 " - "presence_show:[default] priority:0 status:]" - "<cli:presence from=\"maude@example.net/studio\" " - "to=\"david@my-server/test\" " - "xmlns:cli=\"jabber:client\"/>]" - "[IncomingPresenceChanged " - "presence:[Presence jid:walter@example.net/home available:1 " - "presence_show:xa priority:-10 status:Off bowling]" - "<cli:presence from=\"walter@example.net/home\" " - "to=\"david@my-server/test\" " - "xmlns:cli=\"jabber:client\">" - "<cli:priority>-10</cli:priority>" - "<cli:show>xa</cli:show>" - "<cli:status>Off bowling</cli:status>" - "</cli:presence>]" - "[IncomingPresenceChanged " - "presence:[Presence jid:walter@example.net/alley available:1 " - "presence_show:[default] " - "priority:20 status:Looking for toes...]" - "<cli:presence from=\"walter@example.net/alley\" " - "to=\"david@my-server/test\" " - "xmlns:cli=\"jabber:client\">" - "<cli:priority>20</cli:priority>" - "<cli:status>Looking for toes...</cli:status>" - "</cli:presence>]" - "[IncomingPresenceChanged " - "presence:[Presence jid:donny@example.net/alley available:1 " - "presence_show:[default] priority:10 status:Throwing rocks]" - "<cli:presence from=\"donny@example.net/alley\" " - "to=\"david@my-server/test\" " - "xmlns:cli=\"jabber:client\">" - "<cli:priority>10</cli:priority>" - "<cli:status>Throwing rocks</cli:status>" - "</cli:presence>]"); - EXPECT_EQ(handler.OutputActivity(), ""); - handler.SessionActivity(); // Ignore the session output - - // Now look at the data structure we've built - EXPECT_EQ(roster->GetIncomingPresenceCount(), static_cast<size_t>(4)); - EXPECT_EQ(roster->GetIncomingPresenceForJidCount(Jid("maude@example.net")), - static_cast<size_t>(1)); - EXPECT_EQ(roster->GetIncomingPresenceForJidCount(Jid("walter@example.net")), - static_cast<size_t>(2)); - - const XmppPresence * presence; - presence = roster->GetIncomingPresenceForJid(Jid("walter@example.net"), 1); - - std::stringstream dump; - WritePresence(dump, presence); - EXPECT_EQ(dump.str(), - "[Presence jid:walter@example.net/alley available:1 " - "presence_show:[default] priority:20 status:Looking for toes...]" - "<cli:presence from=\"walter@example.net/alley\" " - "to=\"david@my-server/test\" " - "xmlns:cli=\"jabber:client\">" - "<cli:priority>20</cli:priority>" - "<cli:status>Looking for toes...</cli:status>" - "</cli:presence>"); - dump.str(""); - - // Maude took off... - input = "<presence from='maude@example.net/studio' " - "to='david@my-server/test' " - "type='unavailable'>" - "<status>Stealing my rug back</status>" - "<priority>-10</priority>" - "</presence>"; - TEST_OK(engine->HandleInput(input.c_str(), input.length())); - - EXPECT_EQ(roster_handler.StrClear(), - "[IncomingPresenceChanged " - "presence:[Presence jid:maude@example.net/studio available:0 " - "presence_show:[default] priority:-10 " - "status:Stealing my rug back]" - "<cli:presence from=\"maude@example.net/studio\" " - "to=\"david@my-server/test\" type=\"unavailable\" " - "xmlns:cli=\"jabber:client\">" - "<cli:status>Stealing my rug back</cli:status>" - "<cli:priority>-10</cli:priority>" - "</cli:presence>]"); - EXPECT_EQ(handler.OutputActivity(), ""); - handler.SessionActivity(); // Ignore the session output -} - -TEST_F(RosterModuleTest, TestPresenceSubscription) { - rtc::scoped_ptr<XmppEngine> engine(XmppEngine::Create()); - XmppTestHandler handler(engine.get()); - XmppTestRosterHandler roster_handler; - - rtc::scoped_ptr<XmppRosterModule> roster(XmppRosterModule::Create()); - roster->set_roster_handler(&roster_handler); - - // Configure the roster module - roster->RegisterEngine(engine.get()); - - // Set up callbacks - engine->SetOutputHandler(&handler); - engine->AddStanzaHandler(&handler); - engine->SetSessionHandler(&handler); - - // Set up minimal login info - engine->SetUser(Jid("david@my-server")); - // engine->SetPassword("david"); - - // Do the whole login handshake - RunLogin(this, engine.get(), &handler); - EXPECT_EQ("", handler.OutputActivity()); - - // Test incoming requests - std::string input; - input = - "<presence from='maude@example.net' type='subscribe'/>" - "<presence from='maude@example.net' type='unsubscribe'/>" - "<presence from='maude@example.net' type='subscribed'/>" - "<presence from='maude@example.net' type='unsubscribed'/>"; - TEST_OK(engine->HandleInput(input.c_str(), input.length())); - - EXPECT_EQ(roster_handler.StrClear(), - "[SubscriptionRequest Jid:maude@example.net type:subscribe]" - "<cli:presence from=\"maude@example.net\" type=\"subscribe\" " - "xmlns:cli=\"jabber:client\"/>" - "[SubscriptionRequest Jid:maude@example.net type:unsubscribe]" - "<cli:presence from=\"maude@example.net\" type=\"unsubscribe\" " - "xmlns:cli=\"jabber:client\"/>" - "[SubscriptionRequest Jid:maude@example.net type:subscribed]" - "<cli:presence from=\"maude@example.net\" type=\"subscribed\" " - "xmlns:cli=\"jabber:client\"/>" - "[SubscriptionRequest Jid:maude@example.net type:unsubscribe]" - "<cli:presence from=\"maude@example.net\" type=\"unsubscribed\" " - "xmlns:cli=\"jabber:client\"/>"); - EXPECT_EQ(handler.OutputActivity(), ""); - handler.SessionActivity(); // Ignore the session output - - TEST_OK(roster->RequestSubscription(Jid("maude@example.net"))); - TEST_OK(roster->CancelSubscription(Jid("maude@example.net"))); - TEST_OK(roster->ApproveSubscriber(Jid("maude@example.net"))); - TEST_OK(roster->CancelSubscriber(Jid("maude@example.net"))); - - EXPECT_EQ(roster_handler.StrClear(), ""); - EXPECT_EQ(handler.OutputActivity(), - "<presence to=\"maude@example.net\" type=\"subscribe\"/>" - "<presence to=\"maude@example.net\" type=\"unsubscribe\"/>" - "<presence to=\"maude@example.net\" type=\"subscribed\"/>" - "<presence to=\"maude@example.net\" type=\"unsubscribed\"/>"); - EXPECT_EQ(handler.SessionActivity(), ""); -} - -TEST_F(RosterModuleTest, TestRosterReceive) { - rtc::scoped_ptr<XmppEngine> engine(XmppEngine::Create()); - XmppTestHandler handler(engine.get()); - XmppTestRosterHandler roster_handler; - - rtc::scoped_ptr<XmppRosterModule> roster(XmppRosterModule::Create()); - roster->set_roster_handler(&roster_handler); - - // Configure the roster module - roster->RegisterEngine(engine.get()); - - // Set up callbacks - engine->SetOutputHandler(&handler); - engine->AddStanzaHandler(&handler); - engine->SetSessionHandler(&handler); - - // Set up minimal login info - engine->SetUser(Jid("david@my-server")); - // engine->SetPassword("david"); - - // Do the whole login handshake - RunLogin(this, engine.get(), &handler); - EXPECT_EQ("", handler.OutputActivity()); - - // Request a roster update - TEST_OK(roster->RequestRosterUpdate()); - - EXPECT_EQ(roster_handler.StrClear(),""); - EXPECT_EQ(handler.OutputActivity(), - "<iq type=\"get\" id=\"2\">" - "<query xmlns=\"jabber:iq:roster\"/>" - "</iq>"); - EXPECT_EQ(handler.SessionActivity(), ""); - - // Prime the roster with a starting set - std::string input = - "<iq to='david@myserver/test' type='result' id='2'>" - "<query xmlns='jabber:iq:roster'>" - "<item jid='maude@example.net' " - "name='Maude Lebowski' " - "subscription='none' " - "ask='subscribe'>" - "<group>Business Partners</group>" - "</item>" - "<item jid='walter@example.net' " - "name='Walter Sobchak' " - "subscription='both'>" - "<group>Friends</group>" - "<group>Bowling Team</group>" - "<group>Bowling League</group>" - "</item>" - "<item jid='donny@example.net' " - "name='Donny' " - "subscription='both'>" - "<group>Friends</group>" - "<group>Bowling Team</group>" - "<group>Bowling League</group>" - "</item>" - "<item jid='jeffrey@example.net' " - "name='The Big Lebowski' " - "subscription='to'>" - "<group>Business Partners</group>" - "</item>" - "<item jid='jesus@example.net' " - "name='Jesus Quintana' " - "subscription='from'>" - "<group>Bowling League</group>" - "</item>" - "</query>" - "</iq>"; - - TEST_OK(engine->HandleInput(input.c_str(), input.length())); - - EXPECT_EQ(roster_handler.StrClear(), - "[ContactsAdded index:0 number:5 " - "0:[Contact jid:maude@example.net name:Maude Lebowski " - "subscription_state:none_asked " - "groups:[Business Partners]]" - "<ros:item jid=\"maude@example.net\" name=\"Maude Lebowski\" " - "subscription=\"none\" ask=\"subscribe\" " - "xmlns:ros=\"jabber:iq:roster\">" - "<ros:group>Business Partners</ros:group>" - "</ros:item> " - "1:[Contact jid:walter@example.net name:Walter Sobchak " - "subscription_state:both " - "groups:[Friends, Bowling Team, Bowling League]]" - "<ros:item jid=\"walter@example.net\" name=\"Walter Sobchak\" " - "subscription=\"both\" " - "xmlns:ros=\"jabber:iq:roster\">" - "<ros:group>Friends</ros:group>" - "<ros:group>Bowling Team</ros:group>" - "<ros:group>Bowling League</ros:group>" - "</ros:item> " - "2:[Contact jid:donny@example.net name:Donny " - "subscription_state:both " - "groups:[Friends, Bowling Team, Bowling League]]" - "<ros:item jid=\"donny@example.net\" name=\"Donny\" " - "subscription=\"both\" " - "xmlns:ros=\"jabber:iq:roster\">" - "<ros:group>Friends</ros:group>" - "<ros:group>Bowling Team</ros:group>" - "<ros:group>Bowling League</ros:group>" - "</ros:item> " - "3:[Contact jid:jeffrey@example.net name:The Big Lebowski " - "subscription_state:to " - "groups:[Business Partners]]" - "<ros:item jid=\"jeffrey@example.net\" name=\"The Big Lebowski\" " - "subscription=\"to\" " - "xmlns:ros=\"jabber:iq:roster\">" - "<ros:group>Business Partners</ros:group>" - "</ros:item> " - "4:[Contact jid:jesus@example.net name:Jesus Quintana " - "subscription_state:from groups:[Bowling League]]" - "<ros:item jid=\"jesus@example.net\" name=\"Jesus Quintana\" " - "subscription=\"from\" xmlns:ros=\"jabber:iq:roster\">" - "<ros:group>Bowling League</ros:group>" - "</ros:item>]"); - EXPECT_EQ(handler.OutputActivity(), ""); - EXPECT_EQ(handler.SessionActivity(), ""); - - // Request that someone be added - rtc::scoped_ptr<XmppRosterContact> contact(XmppRosterContact::Create()); - TEST_OK(contact->set_jid(Jid("brandt@example.net"))); - TEST_OK(contact->set_name("Brandt")); - TEST_OK(contact->AddGroup("Business Partners")); - TEST_OK(contact->AddGroup("Watchers")); - TEST_OK(contact->AddGroup("Friends")); - TEST_OK(contact->RemoveGroup("Friends")); // Maybe not... - TEST_OK(roster->RequestRosterChange(contact.get())); - - EXPECT_EQ(roster_handler.StrClear(), ""); - EXPECT_EQ(handler.OutputActivity(), - "<iq type=\"set\" id=\"3\">" - "<query xmlns=\"jabber:iq:roster\">" - "<item jid=\"brandt@example.net\" " - "name=\"Brandt\">" - "<group>Business Partners</group>" - "<group>Watchers</group>" - "</item>" - "</query>" - "</iq>"); - EXPECT_EQ(handler.SessionActivity(), ""); - - // Get the push from the server - input = - "<iq type='result' to='david@my-server/test' id='3'/>" - "<iq type='set' id='server_1'>" - "<query xmlns='jabber:iq:roster'>" - "<item jid='brandt@example.net' " - "name='Brandt' " - "subscription='none'>" - "<group>Business Partners</group>" - "<group>Watchers</group>" - "</item>" - "</query>" - "</iq>"; - TEST_OK(engine->HandleInput(input.c_str(), input.length())); - - EXPECT_EQ(roster_handler.StrClear(), - "[ContactsAdded index:5 number:1 " - "5:[Contact jid:brandt@example.net name:Brandt " - "subscription_state:none " - "groups:[Business Partners, Watchers]]" - "<ros:item jid=\"brandt@example.net\" name=\"Brandt\" " - "subscription=\"none\" " - "xmlns:ros=\"jabber:iq:roster\">" - "<ros:group>Business Partners</ros:group>" - "<ros:group>Watchers</ros:group>" - "</ros:item>]"); - EXPECT_EQ(handler.OutputActivity(), - "<iq type=\"result\" id=\"server_1\"/>"); - EXPECT_EQ(handler.SessionActivity(), ""); - - // Get a contact update - input = - "<iq type='set' id='server_2'>" - "<query xmlns='jabber:iq:roster'>" - "<item jid='walter@example.net' " - "name='Walter Sobchak' " - "subscription='both'>" - "<group>Friends</group>" - "<group>Bowling Team</group>" - "<group>Bowling League</group>" - "<group>Not wrong, just an...</group>" - "</item>" - "</query>" - "</iq>"; - - TEST_OK(engine->HandleInput(input.c_str(), input.length())); - - EXPECT_EQ(roster_handler.StrClear(), - "[ContactChanged " - "old_contact:[Contact jid:walter@example.net name:Walter Sobchak " - "subscription_state:both " - "groups:[Friends, Bowling Team, Bowling League]]" - "<ros:item jid=\"walter@example.net\" name=\"Walter Sobchak\" " - "subscription=\"both\" xmlns:ros=\"jabber:iq:roster\">" - "<ros:group>Friends</ros:group>" - "<ros:group>Bowling Team</ros:group>" - "<ros:group>Bowling League</ros:group>" - "</ros:item> " - "index:1 " - "new_contact:[Contact jid:walter@example.net name:Walter Sobchak " - "subscription_state:both " - "groups:[Friends, Bowling Team, Bowling League, " - "Not wrong, just an...]]" - "<ros:item jid=\"walter@example.net\" name=\"Walter Sobchak\" " - "subscription=\"both\" xmlns:ros=\"jabber:iq:roster\">" - "<ros:group>Friends</ros:group>" - "<ros:group>Bowling Team</ros:group>" - "<ros:group>Bowling League</ros:group>" - "<ros:group>Not wrong, just an...</ros:group>" - "</ros:item>]"); - EXPECT_EQ(handler.OutputActivity(), - "<iq type=\"result\" id=\"server_2\"/>"); - EXPECT_EQ(handler.SessionActivity(), ""); - - // Remove a contact - TEST_OK(roster->RequestRosterRemove(Jid("jesus@example.net"))); - - EXPECT_EQ(roster_handler.StrClear(), ""); - EXPECT_EQ(handler.OutputActivity(), - "<iq type=\"set\" id=\"4\">" - "<query xmlns=\"jabber:iq:roster\" jid=\"jesus@example.net\" " - "subscription=\"remove\"/>" - "</iq>"); - EXPECT_EQ(handler.SessionActivity(), ""); - - // Response from the server - input = - "<iq type='result' to='david@my-server/test' id='4'/>" - "<iq type='set' id='server_3'>" - "<query xmlns='jabber:iq:roster'>" - "<item jid='jesus@example.net' " - "subscription='remove'>" - "</item>" - "</query>" - "</iq>"; - TEST_OK(engine->HandleInput(input.c_str(), input.length())); - - EXPECT_EQ(roster_handler.StrClear(), - "[ContactRemoved " - "old_contact:[Contact jid:jesus@example.net name:Jesus Quintana " - "subscription_state:from groups:[Bowling League]]" - "<ros:item jid=\"jesus@example.net\" name=\"Jesus Quintana\" " - "subscription=\"from\" " - "xmlns:ros=\"jabber:iq:roster\">" - "<ros:group>Bowling League</ros:group>" - "</ros:item> index:4]"); - EXPECT_EQ(handler.OutputActivity(), - "<iq type=\"result\" id=\"server_3\"/>"); - EXPECT_EQ(handler.SessionActivity(), ""); -} - -} diff --git a/talk/xmpp/rostermoduleimpl.cc b/talk/xmpp/rostermoduleimpl.cc deleted file mode 100644 index 8841db6f4..000000000 --- a/talk/xmpp/rostermoduleimpl.cc +++ /dev/null @@ -1,1081 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <algorithm> -#include <iostream> -#include <map> -#include <sstream> -#include <string> -#include <vector> -#include "webrtc/libjingle/xmpp/constants.h" -#include "webrtc/libjingle/xmpp/rostermoduleimpl.h" -#include "webrtc/base/common.h" -#include "webrtc/base/stringencode.h" - -namespace buzz { - -// enum prase and persist helpers ---------------------------------------------- -static bool -StringToPresenceShow(const std::string& input, XmppPresenceShow* show) { - // If this becomes a perf issue we can use a hash or a map here - if (STR_SHOW_AWAY == input) - *show = XMPP_PRESENCE_AWAY; - else if (STR_SHOW_DND == input) - *show = XMPP_PRESENCE_DND; - else if (STR_SHOW_XA == input) - *show = XMPP_PRESENCE_XA; - else if (STR_SHOW_CHAT == input) - *show = XMPP_PRESENCE_CHAT; - else if (STR_EMPTY == input) - *show = XMPP_PRESENCE_DEFAULT; - else - return false; - - return true; -} - -static bool -PresenceShowToString(XmppPresenceShow show, const char** output) { - switch(show) { - case XMPP_PRESENCE_AWAY: - *output = STR_SHOW_AWAY; - return true; - case XMPP_PRESENCE_CHAT: - *output = STR_SHOW_CHAT; - return true; - case XMPP_PRESENCE_XA: - *output = STR_SHOW_XA; - return true; - case XMPP_PRESENCE_DND: - *output = STR_SHOW_DND; - return true; - case XMPP_PRESENCE_DEFAULT: - *output = STR_EMPTY; - return true; - } - - *output = STR_EMPTY; - return false; -} - -static bool -StringToSubscriptionState(const std::string& subscription, - const std::string& ask, - XmppSubscriptionState* state) -{ - if (ask == "subscribe") - { - if (subscription == "none") { - *state = XMPP_SUBSCRIPTION_NONE_ASKED; - return true; - } - if (subscription == "from") { - *state = XMPP_SUBSCRIPTION_FROM_ASKED; - return true; - } - } else if (ask == STR_EMPTY) - { - if (subscription == "none") { - *state = XMPP_SUBSCRIPTION_NONE; - return true; - } - if (subscription == "from") { - *state = XMPP_SUBSCRIPTION_FROM; - return true; - } - if (subscription == "to") { - *state = XMPP_SUBSCRIPTION_TO; - return true; - } - if (subscription == "both") { - *state = XMPP_SUBSCRIPTION_BOTH; - return true; - } - } - - return false; -} - -static bool -StringToSubscriptionRequestType(const std::string& string, - XmppSubscriptionRequestType* type) -{ - if (string == "subscribe") - *type = XMPP_REQUEST_SUBSCRIBE; - else if (string == "unsubscribe") - *type = XMPP_REQUEST_UNSUBSCRIBE; - else if (string == "subscribed") - *type = XMPP_REQUEST_SUBSCRIBED; - else if (string == "unsubscribed") - *type = XMPP_REQUEST_UNSUBSCRIBED; - else - return false; - return true; -} - -// XmppPresenceImpl class ------------------------------------------------------ -XmppPresence* -XmppPresence::Create() { - return new XmppPresenceImpl(); -} - -XmppPresenceImpl::XmppPresenceImpl() { -} - -const Jid -XmppPresenceImpl::jid() const { - if (!raw_xml_) - return Jid(); - - return Jid(raw_xml_->Attr(QN_FROM)); -} - -XmppPresenceAvailable -XmppPresenceImpl::available() const { - if (!raw_xml_) - return XMPP_PRESENCE_UNAVAILABLE; - - if (raw_xml_->Attr(QN_TYPE) == "unavailable") - return XMPP_PRESENCE_UNAVAILABLE; - else if (raw_xml_->Attr(QN_TYPE) == "error") - return XMPP_PRESENCE_ERROR; - else - return XMPP_PRESENCE_AVAILABLE; -} - -XmppReturnStatus -XmppPresenceImpl::set_available(XmppPresenceAvailable available) { - if (!raw_xml_) - CreateRawXmlSkeleton(); - - if (available == XMPP_PRESENCE_AVAILABLE) - raw_xml_->ClearAttr(QN_TYPE); - else if (available == XMPP_PRESENCE_UNAVAILABLE) - raw_xml_->SetAttr(QN_TYPE, "unavailable"); - else if (available == XMPP_PRESENCE_ERROR) - raw_xml_->SetAttr(QN_TYPE, "error"); - return XMPP_RETURN_OK; -} - -XmppPresenceShow -XmppPresenceImpl::presence_show() const { - if (!raw_xml_) - return XMPP_PRESENCE_DEFAULT; - - XmppPresenceShow show = XMPP_PRESENCE_DEFAULT; - StringToPresenceShow(raw_xml_->TextNamed(QN_SHOW), &show); - return show; -} - -XmppReturnStatus -XmppPresenceImpl::set_presence_show(XmppPresenceShow show) { - if (!raw_xml_) - CreateRawXmlSkeleton(); - - const char* show_string; - - if(!PresenceShowToString(show, &show_string)) - return XMPP_RETURN_BADARGUMENT; - - raw_xml_->ClearNamedChildren(QN_SHOW); - - if (show!=XMPP_PRESENCE_DEFAULT) { - raw_xml_->AddElement(new XmlElement(QN_SHOW)); - raw_xml_->AddText(show_string, 1); - } - - return XMPP_RETURN_OK; -} - -int -XmppPresenceImpl::priority() const { - if (!raw_xml_) - return 0; - - int raw_priority = 0; - if (!rtc::FromString(raw_xml_->TextNamed(QN_PRIORITY), &raw_priority)) - raw_priority = 0; - if (raw_priority < -128) - raw_priority = -128; - if (raw_priority > 127) - raw_priority = 127; - - return raw_priority; -} - -XmppReturnStatus -XmppPresenceImpl::set_priority(int priority) { - if (!raw_xml_) - CreateRawXmlSkeleton(); - - if (priority < -128 || priority > 127) - return XMPP_RETURN_BADARGUMENT; - - raw_xml_->ClearNamedChildren(QN_PRIORITY); - if (0 != priority) { - std::string priority_string; - if (rtc::ToString(priority, &priority_string)) { - raw_xml_->AddElement(new XmlElement(QN_PRIORITY)); - raw_xml_->AddText(priority_string, 1); - } - } - - return XMPP_RETURN_OK; -} - -const std::string -XmppPresenceImpl::status() const { - if (!raw_xml_) - return STR_EMPTY; - - XmlElement* status_element; - XmlElement* element; - - // Search for a status element with no xml:lang attribute on it. if we can't - // find that then just return the first status element in the stanza. - for (status_element = element = raw_xml_->FirstNamed(QN_STATUS); - element; - element = element->NextNamed(QN_STATUS)) { - if (!element->HasAttr(QN_XML_LANG)) { - status_element = element; - break; - } - } - - if (status_element) { - return status_element->BodyText(); - } - - return STR_EMPTY; -} - -XmppReturnStatus -XmppPresenceImpl::set_status(const std::string& status) { - if (!raw_xml_) - CreateRawXmlSkeleton(); - - raw_xml_->ClearNamedChildren(QN_STATUS); - - if (status != STR_EMPTY) { - raw_xml_->AddElement(new XmlElement(QN_STATUS)); - raw_xml_->AddText(status, 1); - } - - return XMPP_RETURN_OK; -} - -XmppPresenceConnectionStatus -XmppPresenceImpl::connection_status() const { - if (!raw_xml_) - return XMPP_CONNECTION_STATUS_UNKNOWN; - - XmlElement* con = raw_xml_->FirstNamed(QN_GOOGLE_PSTN_CONFERENCE_STATUS); - if (con) { - std::string status = con->Attr(QN_ATTR_STATUS); - if (status == STR_PSTN_CONFERENCE_STATUS_CONNECTING) - return XMPP_CONNECTION_STATUS_CONNECTING; - else if (status == STR_PSTN_CONFERENCE_STATUS_CONNECTED) - return XMPP_CONNECTION_STATUS_CONNECTED; - else if (status == STR_PSTN_CONFERENCE_STATUS_JOINING) - return XMPP_CONNECTION_STATUS_JOINING; - else if (status == STR_PSTN_CONFERENCE_STATUS_HANGUP) - return XMPP_CONNECTION_STATUS_HANGUP; - } - - return XMPP_CONNECTION_STATUS_CONNECTED; -} - -const std::string -XmppPresenceImpl::google_user_id() const { - if (!raw_xml_) - return std::string(); - - XmlElement* muc_user_x = raw_xml_->FirstNamed(QN_MUC_USER_X); - if (muc_user_x) { - XmlElement* muc_user_item = muc_user_x->FirstNamed(QN_MUC_USER_ITEM); - if (muc_user_item) { - return muc_user_item->Attr(QN_GOOGLE_USER_ID); - } - } - - return std::string(); -} - -const std::string -XmppPresenceImpl::nickname() const { - if (!raw_xml_) - return std::string(); - - XmlElement* nickname = raw_xml_->FirstNamed(QN_NICKNAME); - if (nickname) { - return nickname->BodyText(); - } - - return std::string(); -} - -const XmlElement* -XmppPresenceImpl::raw_xml() const { - if (!raw_xml_) - const_cast<XmppPresenceImpl*>(this)->CreateRawXmlSkeleton(); - return raw_xml_.get(); -} - -XmppReturnStatus -XmppPresenceImpl::set_raw_xml(const XmlElement * xml) { - if (!xml || - xml->Name() != QN_PRESENCE) - return XMPP_RETURN_BADARGUMENT; - - raw_xml_.reset(new XmlElement(*xml)); - return XMPP_RETURN_OK; -} - -void -XmppPresenceImpl::CreateRawXmlSkeleton() { - raw_xml_.reset(new XmlElement(QN_PRESENCE)); -} - -// XmppRosterContactImpl ------------------------------------------------------- -XmppRosterContact* -XmppRosterContact::Create() { - return new XmppRosterContactImpl(); -} - -XmppRosterContactImpl::XmppRosterContactImpl() { - ResetGroupCache(); -} - -void -XmppRosterContactImpl::SetXmlFromWire(const XmlElement* xml) { - ResetGroupCache(); - if (xml) - raw_xml_.reset(new XmlElement(*xml)); - else - raw_xml_.reset(NULL); -} - -void -XmppRosterContactImpl::ResetGroupCache() { - group_count_ = -1; - group_index_returned_ = -1; - group_returned_ = NULL; -} - -const Jid -XmppRosterContactImpl::jid() const { - return Jid(raw_xml_->Attr(QN_JID)); -} - -XmppReturnStatus -XmppRosterContactImpl::set_jid(const Jid& jid) -{ - if (!raw_xml_) - CreateRawXmlSkeleton(); - - if (!jid.IsValid()) - return XMPP_RETURN_BADARGUMENT; - - raw_xml_->SetAttr(QN_JID, jid.Str()); - - return XMPP_RETURN_OK; -} - -const std::string -XmppRosterContactImpl::name() const { - return raw_xml_->Attr(QN_NAME); -} - -XmppReturnStatus -XmppRosterContactImpl::set_name(const std::string& name) { - if (!raw_xml_) - CreateRawXmlSkeleton(); - - if (name == STR_EMPTY) - raw_xml_->ClearAttr(QN_NAME); - else - raw_xml_->SetAttr(QN_NAME, name); - - return XMPP_RETURN_OK; -} - -XmppSubscriptionState -XmppRosterContactImpl::subscription_state() const { - if (!raw_xml_) - return XMPP_SUBSCRIPTION_NONE; - - XmppSubscriptionState state = XMPP_SUBSCRIPTION_NONE; - - if (StringToSubscriptionState(raw_xml_->Attr(QN_SUBSCRIPTION), - raw_xml_->Attr(QN_ASK), - &state)) - return state; - - return XMPP_SUBSCRIPTION_NONE; -} - -size_t -XmppRosterContactImpl::GetGroupCount() const { - if (!raw_xml_) - return 0; - - if (-1 == group_count_) { - XmlElement *group_element = raw_xml_->FirstNamed(QN_ROSTER_GROUP); - int group_count = 0; - while(group_element) { - group_count++; - group_element = group_element->NextNamed(QN_ROSTER_GROUP); - } - - ASSERT(group_count > 0); // protect the cast - XmppRosterContactImpl * me = const_cast<XmppRosterContactImpl*>(this); - me->group_count_ = group_count; - } - - return group_count_; -} - -const std::string -XmppRosterContactImpl::GetGroup(size_t index) const { - if (index >= GetGroupCount()) - return STR_EMPTY; - - // We cache the last group index and element that we returned. This way - // going through the groups in order is order n and not n^2. This could be - // enhanced if necessary by starting at the cached value if the index asked - // is after the cached one. - if (group_index_returned_ >= 0 && - index == static_cast<size_t>(group_index_returned_) + 1) - { - XmppRosterContactImpl * me = const_cast<XmppRosterContactImpl*>(this); - me->group_returned_ = group_returned_->NextNamed(QN_ROSTER_GROUP); - ASSERT(group_returned_ != NULL); - me->group_index_returned_++; - } else if (group_index_returned_ < 0 || - static_cast<size_t>(group_index_returned_) != index) { - XmlElement * group_element = raw_xml_->FirstNamed(QN_ROSTER_GROUP); - size_t group_index = 0; - while(group_index < index) { - ASSERT(group_element != NULL); - group_index++; - group_element = group_element->NextNamed(QN_ROSTER_GROUP); - } - - XmppRosterContactImpl * me = const_cast<XmppRosterContactImpl*>(this); - me->group_index_returned_ = static_cast<int>(group_index); - me->group_returned_ = group_element; - } - - return group_returned_->BodyText(); -} - -XmppReturnStatus -XmppRosterContactImpl::AddGroup(const std::string& group) { - if (group == STR_EMPTY) - return XMPP_RETURN_BADARGUMENT; - - if (!raw_xml_) - CreateRawXmlSkeleton(); - - if (FindGroup(group, NULL, NULL)) - return XMPP_RETURN_OK; - - raw_xml_->AddElement(new XmlElement(QN_ROSTER_GROUP)); - raw_xml_->AddText(group, 1); - ++group_count_; - - return XMPP_RETURN_OK; -} - -XmppReturnStatus -XmppRosterContactImpl::RemoveGroup(const std::string& group) { - if (group == STR_EMPTY) - return XMPP_RETURN_BADARGUMENT; - - if (!raw_xml_) - return XMPP_RETURN_OK; - - XmlChild * child_before; - if (FindGroup(group, NULL, &child_before)) { - raw_xml_->RemoveChildAfter(child_before); - ResetGroupCache(); - } - return XMPP_RETURN_OK; -} - -bool -XmppRosterContactImpl::FindGroup(const std::string& group, - XmlElement** element, - XmlChild** child_before) { - XmlChild * prev_child = NULL; - XmlChild * next_child; - XmlChild * child; - for (child = raw_xml_->FirstChild(); child; child = next_child) { - next_child = child->NextChild(); - if (!child->IsText() && - child->AsElement()->Name() == QN_ROSTER_GROUP && - child->AsElement()->BodyText() == group) { - if (element) - *element = child->AsElement(); - if (child_before) - *child_before = prev_child; - return true; - } - prev_child = child; - } - - return false; -} - -const XmlElement* -XmppRosterContactImpl::raw_xml() const { - if (!raw_xml_) - const_cast<XmppRosterContactImpl*>(this)->CreateRawXmlSkeleton(); - return raw_xml_.get(); -} - -XmppReturnStatus -XmppRosterContactImpl::set_raw_xml(const XmlElement* xml) { - if (!xml || - xml->Name() != QN_ROSTER_ITEM || - xml->HasAttr(QN_SUBSCRIPTION) || - xml->HasAttr(QN_ASK)) - return XMPP_RETURN_BADARGUMENT; - - ResetGroupCache(); - - raw_xml_.reset(new XmlElement(*xml)); - - return XMPP_RETURN_OK; -} - -void -XmppRosterContactImpl::CreateRawXmlSkeleton() { - raw_xml_.reset(new XmlElement(QN_ROSTER_ITEM)); -} - -// XmppRosterModuleImpl -------------------------------------------------------- -XmppRosterModule * -XmppRosterModule::Create() { - return new XmppRosterModuleImpl(); -} - -XmppRosterModuleImpl::XmppRosterModuleImpl() : - roster_handler_(NULL), - incoming_presence_map_(new JidPresenceVectorMap()), - incoming_presence_vector_(new PresenceVector()), - contacts_(new ContactVector()) { - -} - -XmppRosterModuleImpl::~XmppRosterModuleImpl() { - DeleteIncomingPresence(); - DeleteContacts(); -} - -XmppReturnStatus -XmppRosterModuleImpl::set_roster_handler(XmppRosterHandler * handler) { - roster_handler_ = handler; - return XMPP_RETURN_OK; -} - -XmppRosterHandler* -XmppRosterModuleImpl::roster_handler() { - return roster_handler_; -} - -XmppPresence* -XmppRosterModuleImpl::outgoing_presence() { - return &outgoing_presence_; -} - -XmppReturnStatus -XmppRosterModuleImpl::BroadcastPresence() { - // Scrub the outgoing presence - const XmlElement* element = outgoing_presence_.raw_xml(); - - ASSERT(!element->HasAttr(QN_TO) && - !element->HasAttr(QN_FROM) && - (element->Attr(QN_TYPE) == STR_EMPTY || - element->Attr(QN_TYPE) == "unavailable")); - - if (!engine()) - return XMPP_RETURN_BADSTATE; - - return engine()->SendStanza(element); -} - -XmppReturnStatus -XmppRosterModuleImpl::SendDirectedPresence(const XmppPresence* presence, - const Jid& to_jid) { - if (!presence) - return XMPP_RETURN_BADARGUMENT; - - if (!engine()) - return XMPP_RETURN_BADSTATE; - - XmlElement element(*(presence->raw_xml())); - - if (element.Name() != QN_PRESENCE || - element.HasAttr(QN_TO) || - element.HasAttr(QN_FROM)) - return XMPP_RETURN_BADARGUMENT; - - if (element.HasAttr(QN_TYPE)) { - if (element.Attr(QN_TYPE) != STR_EMPTY && - element.Attr(QN_TYPE) != "unavailable") { - return XMPP_RETURN_BADARGUMENT; - } - } - - element.SetAttr(QN_TO, to_jid.Str()); - - return engine()->SendStanza(&element); -} - -size_t -XmppRosterModuleImpl::GetIncomingPresenceCount() { - return incoming_presence_vector_->size(); -} - -const XmppPresence* -XmppRosterModuleImpl::GetIncomingPresence(size_t index) { - if (index >= incoming_presence_vector_->size()) - return NULL; - return (*incoming_presence_vector_)[index]; -} - -size_t -XmppRosterModuleImpl::GetIncomingPresenceForJidCount(const Jid& jid) -{ - // find the vector in the map - JidPresenceVectorMap::iterator pos; - pos = incoming_presence_map_->find(jid); - if (pos == incoming_presence_map_->end()) - return 0; - - ASSERT(pos->second != NULL); - - return pos->second->size(); -} - -const XmppPresence* -XmppRosterModuleImpl::GetIncomingPresenceForJid(const Jid& jid, - size_t index) { - JidPresenceVectorMap::iterator pos; - pos = incoming_presence_map_->find(jid); - if (pos == incoming_presence_map_->end()) - return NULL; - - ASSERT(pos->second != NULL); - - if (index >= pos->second->size()) - return NULL; - - return (*pos->second)[index]; -} - -XmppReturnStatus -XmppRosterModuleImpl::RequestRosterUpdate() { - if (!engine()) - return XMPP_RETURN_BADSTATE; - - XmlElement roster_get(QN_IQ); - roster_get.AddAttr(QN_TYPE, "get"); - roster_get.AddAttr(QN_ID, engine()->NextId()); - roster_get.AddElement(new XmlElement(QN_ROSTER_QUERY, true)); - return engine()->SendIq(&roster_get, this, NULL); -} - -size_t -XmppRosterModuleImpl::GetRosterContactCount() { - return contacts_->size(); -} - -const XmppRosterContact* -XmppRosterModuleImpl::GetRosterContact(size_t index) { - if (index >= contacts_->size()) - return NULL; - return (*contacts_)[index]; -} - -class RosterPredicate { -public: - explicit RosterPredicate(const Jid& jid) : jid_(jid) { - } - - bool operator() (XmppRosterContactImpl *& contact) { - return contact->jid() == jid_; - } - -private: - Jid jid_; -}; - -const XmppRosterContact* -XmppRosterModuleImpl::FindRosterContact(const Jid& jid) { - ContactVector::iterator pos; - - pos = std::find_if(contacts_->begin(), - contacts_->end(), - RosterPredicate(jid)); - if (pos == contacts_->end()) - return NULL; - - return *pos; -} - -XmppReturnStatus -XmppRosterModuleImpl::RequestRosterChange( - const XmppRosterContact* contact) { - if (!contact) - return XMPP_RETURN_BADARGUMENT; - - Jid jid = contact->jid(); - - if (!jid.IsValid()) - return XMPP_RETURN_BADARGUMENT; - - if (!engine()) - return XMPP_RETURN_BADSTATE; - - const XmlElement* contact_xml = contact->raw_xml(); - if (contact_xml->Name() != QN_ROSTER_ITEM || - contact_xml->HasAttr(QN_SUBSCRIPTION) || - contact_xml->HasAttr(QN_ASK)) - return XMPP_RETURN_BADARGUMENT; - - XmlElement roster_add(QN_IQ); - roster_add.AddAttr(QN_TYPE, "set"); - roster_add.AddAttr(QN_ID, engine()->NextId()); - roster_add.AddElement(new XmlElement(QN_ROSTER_QUERY, true)); - roster_add.AddElement(new XmlElement(*contact_xml), 1); - - return engine()->SendIq(&roster_add, this, NULL); -} - -XmppReturnStatus -XmppRosterModuleImpl::RequestRosterRemove(const Jid& jid) { - if (!jid.IsValid()) - return XMPP_RETURN_BADARGUMENT; - - if (!engine()) - return XMPP_RETURN_BADSTATE; - - XmlElement roster_add(QN_IQ); - roster_add.AddAttr(QN_TYPE, "set"); - roster_add.AddAttr(QN_ID, engine()->NextId()); - roster_add.AddElement(new XmlElement(QN_ROSTER_QUERY, true)); - roster_add.AddAttr(QN_JID, jid.Str(), 1); - roster_add.AddAttr(QN_SUBSCRIPTION, "remove", 1); - - return engine()->SendIq(&roster_add, this, NULL); -} - -XmppReturnStatus -XmppRosterModuleImpl::RequestSubscription(const Jid& jid) { - return SendSubscriptionRequest(jid, "subscribe"); -} - -XmppReturnStatus -XmppRosterModuleImpl::CancelSubscription(const Jid& jid) { - return SendSubscriptionRequest(jid, "unsubscribe"); -} - -XmppReturnStatus -XmppRosterModuleImpl::ApproveSubscriber(const Jid& jid) { - return SendSubscriptionRequest(jid, "subscribed"); -} - -XmppReturnStatus -XmppRosterModuleImpl::CancelSubscriber(const Jid& jid) { - return SendSubscriptionRequest(jid, "unsubscribed"); -} - -void -XmppRosterModuleImpl::IqResponse(XmppIqCookie, const XmlElement * stanza) { - // The only real Iq response that we expect to recieve are initial roster - // population - if (stanza->Attr(QN_TYPE) == "error") - { - if (roster_handler_) - roster_handler_->RosterError(this, stanza); - - return; - } - - ASSERT(stanza->Attr(QN_TYPE) == "result"); - - InternalRosterItems(stanza); -} - -bool -XmppRosterModuleImpl::HandleStanza(const XmlElement * stanza) -{ - ASSERT(engine() != NULL); - - // There are two types of stanzas that we care about: presence and roster push - // Iqs - if (stanza->Name() == QN_PRESENCE) { - const std::string& jid_string = stanza->Attr(QN_FROM); - Jid jid(jid_string); - - if (!jid.IsValid()) - return false; // if the Jid isn't valid, don't process - - const std::string& type = stanza->Attr(QN_TYPE); - XmppSubscriptionRequestType request_type; - if (StringToSubscriptionRequestType(type, &request_type)) - InternalSubscriptionRequest(jid, stanza, request_type); - else if (type == "unavailable" || type == STR_EMPTY) - InternalIncomingPresence(jid, stanza); - else if (type == "error") - InternalIncomingPresenceError(jid, stanza); - else - return false; - - return true; - } else if (stanza->Name() == QN_IQ) { - const XmlElement * roster_query = stanza->FirstNamed(QN_ROSTER_QUERY); - if (!roster_query || stanza->Attr(QN_TYPE) != "set") - return false; - - InternalRosterItems(stanza); - - // respond to the IQ - XmlElement result(QN_IQ); - result.AddAttr(QN_TYPE, "result"); - result.AddAttr(QN_TO, stanza->Attr(QN_FROM)); - result.AddAttr(QN_ID, stanza->Attr(QN_ID)); - - engine()->SendStanza(&result); - return true; - } - - return false; -} - -void -XmppRosterModuleImpl::DeleteIncomingPresence() { - // Clear out the vector of all presence notifications - { - PresenceVector::iterator pos; - for (pos = incoming_presence_vector_->begin(); - pos < incoming_presence_vector_->end(); - ++pos) { - XmppPresenceImpl * presence = *pos; - *pos = NULL; - delete presence; - } - incoming_presence_vector_->clear(); - } - - // Clear out all of the small presence vectors per Jid - { - JidPresenceVectorMap::iterator pos; - for (pos = incoming_presence_map_->begin(); - pos != incoming_presence_map_->end(); - ++pos) { - PresenceVector* presence_vector = pos->second; - pos->second = NULL; - delete presence_vector; - } - incoming_presence_map_->clear(); - } -} - -void -XmppRosterModuleImpl::DeleteContacts() { - ContactVector::iterator pos; - for (pos = contacts_->begin(); - pos < contacts_->end(); - ++pos) { - XmppRosterContact* contact = *pos; - *pos = NULL; - delete contact; - } - contacts_->clear(); -} - -XmppReturnStatus -XmppRosterModuleImpl::SendSubscriptionRequest(const Jid& jid, - const std::string& type) { - if (!jid.IsValid()) - return XMPP_RETURN_BADARGUMENT; - - if (!engine()) - return XMPP_RETURN_BADSTATE; - - XmlElement presence_request(QN_PRESENCE); - presence_request.AddAttr(QN_TO, jid.Str()); - presence_request.AddAttr(QN_TYPE, type); - - return engine()->SendStanza(&presence_request); -} - - -void -XmppRosterModuleImpl::InternalSubscriptionRequest(const Jid& jid, - const XmlElement* stanza, - XmppSubscriptionRequestType - request_type) { - if (roster_handler_) - roster_handler_->SubscriptionRequest(this, jid, request_type, stanza); -} - -class PresencePredicate { -public: - explicit PresencePredicate(const Jid& jid) : jid_(jid) { - } - - bool operator() (XmppPresenceImpl *& contact) { - return contact->jid() == jid_; - } - -private: - Jid jid_; -}; - -void -XmppRosterModuleImpl::InternalIncomingPresence(const Jid& jid, - const XmlElement* stanza) { - bool added = false; - Jid bare_jid = jid.BareJid(); - - // First add the presence to the map - JidPresenceVectorMap::iterator pos; - pos = incoming_presence_map_->find(jid.BareJid()); - if (pos == incoming_presence_map_->end()) { - // Insert a new entry into the map. Get the position of this new entry - pos = (incoming_presence_map_->insert( - std::make_pair(bare_jid, new PresenceVector()))).first; - } - - PresenceVector * presence_vector = pos->second; - ASSERT(presence_vector != NULL); - - // Try to find this jid in the bare jid bucket - PresenceVector::iterator presence_pos; - XmppPresenceImpl* presence; - presence_pos = std::find_if(presence_vector->begin(), - presence_vector->end(), - PresencePredicate(jid)); - - // Update/add it to the bucket - if (presence_pos == presence_vector->end()) { - presence = new XmppPresenceImpl(); - if (XMPP_RETURN_OK == presence->set_raw_xml(stanza)) { - added = true; - presence_vector->push_back(presence); - } else { - delete presence; - presence = NULL; - } - } else { - presence = *presence_pos; - presence->set_raw_xml(stanza); - } - - // now add to the comprehensive vector - if (added) - incoming_presence_vector_->push_back(presence); - - // Call back to the user with the changed presence information - if (roster_handler_) - roster_handler_->IncomingPresenceChanged(this, presence); -} - - -void -XmppRosterModuleImpl::InternalIncomingPresenceError(const Jid& jid, - const XmlElement* stanza) { - if (roster_handler_) - roster_handler_->SubscriptionError(this, jid, stanza); -} - -void -XmppRosterModuleImpl::InternalRosterItems(const XmlElement* stanza) { - const XmlElement* result_data = stanza->FirstNamed(QN_ROSTER_QUERY); - if (!result_data) - return; // unknown stuff in result! - - bool all_new = contacts_->empty(); - - for (const XmlElement* roster_item = result_data->FirstNamed(QN_ROSTER_ITEM); - roster_item; - roster_item = roster_item->NextNamed(QN_ROSTER_ITEM)) - { - const std::string& jid_string = roster_item->Attr(QN_JID); - Jid jid(jid_string); - if (!jid.IsValid()) - continue; - - // This algorithm is N^2 on the number of incoming contacts after the - // initial load. There is no way to do this faster without allowing - // duplicates, introducing more data structures or write a custom data - // structure. We'll see if this becomes a perf problem and fix it if it - // does. - ContactVector::iterator pos = contacts_->end(); - - if (!all_new) { - pos = std::find_if(contacts_->begin(), - contacts_->end(), - RosterPredicate(jid)); - } - - if (pos != contacts_->end()) { // Update/remove a current contact - if (roster_item->Attr(QN_SUBSCRIPTION) == "remove") { - XmppRosterContact* contact = *pos; - contacts_->erase(pos); - if (roster_handler_) - roster_handler_->ContactRemoved(this, contact, - std::distance(contacts_->begin(), pos)); - delete contact; - } else { - XmppRosterContact* old_contact = *pos; - *pos = new XmppRosterContactImpl(); - (*pos)->SetXmlFromWire(roster_item); - if (roster_handler_) - roster_handler_->ContactChanged(this, old_contact, - std::distance(contacts_->begin(), pos)); - delete old_contact; - } - } else { // Add a new contact - XmppRosterContactImpl* contact = new XmppRosterContactImpl(); - contact->SetXmlFromWire(roster_item); - contacts_->push_back(contact); - if (roster_handler_ && !all_new) - roster_handler_->ContactsAdded(this, contacts_->size() - 1, 1); - } - } - - // Send a consolidated update if all contacts are new - if (roster_handler_ && all_new) - roster_handler_->ContactsAdded(this, 0, contacts_->size()); -} - -} diff --git a/talk/xmpp/rostermoduleimpl.h b/talk/xmpp/rostermoduleimpl.h deleted file mode 100644 index efef5eda4..000000000 --- a/talk/xmpp/rostermoduleimpl.h +++ /dev/null @@ -1,302 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef TALK_XMPP_XMPPTHREAD_H_ -#define TALK_XMPP_XMPPTHREAD_H_ - -#include "webrtc/libjingle/xmpp/moduleimpl.h" -#include "webrtc/libjingle/xmpp/rostermodule.h" - -namespace buzz { - -//! Presence Information -//! This class stores both presence information for outgoing presence and is -//! returned by methods in XmppRosterModule to represent received incoming -//! presence information. When this class is writeable (non-const) then each -//! update to any property will set the inner xml. Setting the raw_xml will -//! rederive all of the other properties. -class XmppPresenceImpl : public XmppPresence { -public: - virtual ~XmppPresenceImpl() {} - - //! The from Jid of for the presence information. - //! Typically this will be a full Jid with resource specified. For outgoing - //! presence this should remain JID_NULL and will be scrubbed from the - //! stanza when being sent. - virtual const Jid jid() const; - - //! Is the contact available? - virtual XmppPresenceAvailable available() const; - - //! Sets if the user is available or not - virtual XmppReturnStatus set_available(XmppPresenceAvailable available); - - //! The show value of the presence info - virtual XmppPresenceShow presence_show() const; - - //! Set the presence show value - virtual XmppReturnStatus set_presence_show(XmppPresenceShow show); - - //! The Priority of the presence info - virtual int priority() const; - - //! Set the priority of the presence - virtual XmppReturnStatus set_priority(int priority); - - //! The plain text status of the presence info. - //! If there are multiple status because of language, this will either be a - //! status that is not tagged for language or the first available - virtual const std::string status() const; - - //! Sets the status for the presence info. - //! If there is more than one status present already then this will remove - //! them all and replace it with one status element we no specified language - virtual XmppReturnStatus set_status(const std::string& status); - - //! The connection status - virtual XmppPresenceConnectionStatus connection_status() const; - - //! The focus obfuscated GAIA id - virtual const std::string google_user_id() const; - - //! The nickname in the presence - virtual const std::string nickname() const; - - //! The raw xml of the presence update - virtual const XmlElement* raw_xml() const; - - //! Sets the raw presence stanza for the presence update - //! This will cause all other data items in this structure to be rederived - virtual XmppReturnStatus set_raw_xml(const XmlElement * xml); - -private: - XmppPresenceImpl(); - - friend class XmppPresence; - friend class XmppRosterModuleImpl; - - void CreateRawXmlSkeleton(); - - // Store everything in the XML element. If this becomes a perf issue we can - // cache the data. - rtc::scoped_ptr<XmlElement> raw_xml_; -}; - -//! A contact as given by the server -class XmppRosterContactImpl : public XmppRosterContact { -public: - virtual ~XmppRosterContactImpl() {} - - //! The jid for the contact. - //! Typically this will be a bare Jid. - virtual const Jid jid() const; - - //! Sets the jid for the roster contact update - virtual XmppReturnStatus set_jid(const Jid& jid); - - //! The name (nickname) stored for this contact - virtual const std::string name() const; - - //! Sets the name - virtual XmppReturnStatus set_name(const std::string& name); - - //! The Presence subscription state stored on the server for this contact - //! This is never settable and will be ignored when generating a roster - //! add/update request - virtual XmppSubscriptionState subscription_state() const; - - //! The number of Groups applied to this contact - virtual size_t GetGroupCount() const; - - //! Gets a Group applied to the contact based on index. - virtual const std::string GetGroup(size_t index) const; - - //! Adds a group to this contact. - //! This will return a no error if the group is already present. - virtual XmppReturnStatus AddGroup(const std::string& group); - - //! Removes a group from the contact. - //! This will return no error if the group isn't there - virtual XmppReturnStatus RemoveGroup(const std::string& group); - - //! The raw xml for this roster contact - virtual const XmlElement* raw_xml() const; - - //! Sets the raw presence stanza for the presence update - //! This will cause all other data items in this structure to be rederived - virtual XmppReturnStatus set_raw_xml(const XmlElement * xml); - -private: - XmppRosterContactImpl(); - - void CreateRawXmlSkeleton(); - void SetXmlFromWire(const XmlElement * xml); - void ResetGroupCache(); - - bool FindGroup(const std::string& group, - XmlElement** element, - XmlChild** child_before); - - - friend class XmppRosterContact; - friend class XmppRosterModuleImpl; - - int group_count_; - int group_index_returned_; - XmlElement * group_returned_; - rtc::scoped_ptr<XmlElement> raw_xml_; -}; - -//! An XmppModule for handle roster and presence functionality -class XmppRosterModuleImpl : public XmppModuleImpl, - public XmppRosterModule, public XmppIqHandler { -public: - virtual ~XmppRosterModuleImpl(); - - IMPLEMENT_XMPPMODULE - - //! Sets the roster handler (callbacks) for the module - virtual XmppReturnStatus set_roster_handler(XmppRosterHandler * handler); - - //! Gets the roster handler for the module - virtual XmppRosterHandler* roster_handler(); - - // USER PRESENCE STATE ------------------------------------------------------- - - //! Gets the aggregate outgoing presence - //! This object is non-const and be edited directly. No update is sent - //! to the server until a Broadcast is sent - virtual XmppPresence* outgoing_presence(); - - //! Broadcasts that the user is available. - //! Nothing with respect to presence is sent until this is called. - virtual XmppReturnStatus BroadcastPresence(); - - //! Sends a directed presence to a Jid - //! Note that the client doesn't store where directed presence notifications - //! have been sent. The server can keep the appropriate state - virtual XmppReturnStatus SendDirectedPresence(const XmppPresence* presence, - const Jid& to_jid); - - // INCOMING PRESENCE STATUS -------------------------------------------------- - - //! Returns the number of incoming presence data recorded - virtual size_t GetIncomingPresenceCount(); - - //! Returns an incoming presence datum based on index - virtual const XmppPresence* GetIncomingPresence(size_t index); - - //! Gets the number of presence data for a bare Jid - //! There may be a datum per resource - virtual size_t GetIncomingPresenceForJidCount(const Jid& jid); - - //! Returns a single presence data for a Jid based on index - virtual const XmppPresence* GetIncomingPresenceForJid(const Jid& jid, - size_t index); - - // ROSTER MANAGEMENT --------------------------------------------------------- - - //! Requests an update of the roster from the server - //! This must be called to initialize the client side cache of the roster - //! After this is sent the server should keep this module apprised of any - //! changes. - virtual XmppReturnStatus RequestRosterUpdate(); - - //! Returns the number of contacts in the roster - virtual size_t GetRosterContactCount(); - - //! Returns a contact by index - virtual const XmppRosterContact* GetRosterContact(size_t index); - - //! Finds a contact by Jid - virtual const XmppRosterContact* FindRosterContact(const Jid& jid); - - //! Send a request to the server to add a contact - //! Note that the contact won't show up in the roster until the server can - //! respond. This happens async when the socket is being serviced - virtual XmppReturnStatus RequestRosterChange( - const XmppRosterContact* contact); - - //! Request that the server remove a contact - //! The jabber protocol specifies that the server should also cancel any - //! subscriptions when this is done. Like adding, this contact won't be - //! removed until the server responds. - virtual XmppReturnStatus RequestRosterRemove(const Jid& jid); - - // SUBSCRIPTION MANAGEMENT --------------------------------------------------- - - //! Request a subscription to presence notifications form a Jid - virtual XmppReturnStatus RequestSubscription(const Jid& jid); - - //! Cancel a subscription to presence notifications from a Jid - virtual XmppReturnStatus CancelSubscription(const Jid& jid); - - //! Approve a request to deliver presence notifications to a jid - virtual XmppReturnStatus ApproveSubscriber(const Jid& jid); - - //! Deny or cancel presence notification deliver to a jid - virtual XmppReturnStatus CancelSubscriber(const Jid& jid); - - // XmppIqHandler IMPLEMENTATION ---------------------------------------------- - virtual void IqResponse(XmppIqCookie cookie, const XmlElement * stanza); - -protected: - // XmppModuleImpl OVERRIDES -------------------------------------------------- - virtual bool HandleStanza(const XmlElement *); - - // PRIVATE DATA -------------------------------------------------------------- -private: - friend class XmppRosterModule; - XmppRosterModuleImpl(); - - // Helper functions - void DeleteIncomingPresence(); - void DeleteContacts(); - XmppReturnStatus SendSubscriptionRequest(const Jid& jid, - const std::string& type); - void InternalSubscriptionRequest(const Jid& jid, const XmlElement* stanza, - XmppSubscriptionRequestType request_type); - void InternalIncomingPresence(const Jid& jid, const XmlElement* stanza); - void InternalIncomingPresenceError(const Jid& jid, const XmlElement* stanza); - void InternalRosterItems(const XmlElement* stanza); - - // Member data - XmppPresenceImpl outgoing_presence_; - XmppRosterHandler* roster_handler_; - - typedef std::vector<XmppPresenceImpl*> PresenceVector; - typedef std::map<Jid, PresenceVector*> JidPresenceVectorMap; - rtc::scoped_ptr<JidPresenceVectorMap> incoming_presence_map_; - rtc::scoped_ptr<PresenceVector> incoming_presence_vector_; - - typedef std::vector<XmppRosterContactImpl*> ContactVector; - rtc::scoped_ptr<ContactVector> contacts_; -}; - -} - -#endif // TALK_XMPP_XMPPTHREAD_H_ diff --git a/talk/xmpp/saslcookiemechanism.h b/talk/xmpp/saslcookiemechanism.h deleted file mode 100644 index 0f193f243..000000000 --- a/talk/xmpp/saslcookiemechanism.h +++ /dev/null @@ -1,86 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef TALK_XMPP_SASLCOOKIEMECHANISM_H_ -#define TALK_XMPP_SASLCOOKIEMECHANISM_H_ - -#include "webrtc/libjingle/xmllite/qname.h" -#include "webrtc/libjingle/xmllite/xmlelement.h" -#include "webrtc/libjingle/xmpp/constants.h" -#include "webrtc/libjingle/xmpp/saslmechanism.h" - -namespace buzz { - -class SaslCookieMechanism : public SaslMechanism { - -public: - SaslCookieMechanism(const std::string & mechanism, - const std::string & username, - const std::string & cookie, - const std::string & token_service) - : mechanism_(mechanism), - username_(username), - cookie_(cookie), - token_service_(token_service) {} - - SaslCookieMechanism(const std::string & mechanism, - const std::string & username, - const std::string & cookie) - : mechanism_(mechanism), - username_(username), - cookie_(cookie), - token_service_("") {} - - virtual std::string GetMechanismName() { return mechanism_; } - - virtual XmlElement * StartSaslAuth() { - // send initial request - XmlElement * el = new XmlElement(QN_SASL_AUTH, true); - el->AddAttr(QN_MECHANISM, mechanism_); - if (!token_service_.empty()) { - el->AddAttr(QN_GOOGLE_AUTH_SERVICE, token_service_); - } - - std::string credential; - credential.append("\0", 1); - credential.append(username_); - credential.append("\0", 1); - credential.append(cookie_); - el->AddText(Base64Encode(credential)); - return el; - } - -private: - std::string mechanism_; - std::string username_; - std::string cookie_; - std::string token_service_; -}; - -} - -#endif // TALK_XMPP_SASLCOOKIEMECHANISM_H_ diff --git a/talk/xmpp/saslhandler.h b/talk/xmpp/saslhandler.h deleted file mode 100644 index a4a73e4b3..000000000 --- a/talk/xmpp/saslhandler.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef TALK_XMPP_SASLHANDLER_H_ -#define TALK_XMPP_SASLHANDLER_H_ - -#include <string> -#include <vector> - -namespace buzz { - -class XmlElement; -class SaslMechanism; - -// Creates mechanisms to deal with a given mechanism -class SaslHandler { - -public: - - // Intended to be subclassed - virtual ~SaslHandler() {} - - // Should pick the best method according to this handler - // returns the empty string if none are suitable - virtual std::string ChooseBestSaslMechanism(const std::vector<std::string> & mechanisms, bool encrypted) = 0; - - // Creates a SaslMechanism for the given mechanism name (you own it - // once you get it). - // If not handled, return NULL. - virtual SaslMechanism * CreateSaslMechanism(const std::string & mechanism) = 0; -}; - -} - -#endif // TALK_XMPP_SASLHANDLER_H_ diff --git a/talk/xmpp/saslmechanism.cc b/talk/xmpp/saslmechanism.cc deleted file mode 100644 index 9fb01bc30..000000000 --- a/talk/xmpp/saslmechanism.cc +++ /dev/null @@ -1,72 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "webrtc/libjingle/xmllite/xmlelement.h" -#include "webrtc/libjingle/xmpp/constants.h" -#include "webrtc/libjingle/xmpp/saslmechanism.h" -#include "webrtc/base/base64.h" - -using rtc::Base64; - -namespace buzz { - -XmlElement * -SaslMechanism::StartSaslAuth() { - return new XmlElement(QN_SASL_AUTH, true); -} - -XmlElement * -SaslMechanism::HandleSaslChallenge(const XmlElement * challenge) { - return new XmlElement(QN_SASL_ABORT, true); -} - -void -SaslMechanism::HandleSaslSuccess(const XmlElement * success) { -} - -void -SaslMechanism::HandleSaslFailure(const XmlElement * failure) { -} - -std::string -SaslMechanism::Base64Encode(const std::string & plain) { - return Base64::Encode(plain); -} - -std::string -SaslMechanism::Base64Decode(const std::string & encoded) { - return Base64::Decode(encoded, Base64::DO_LAX); -} - -std::string -SaslMechanism::Base64EncodeFromArray(const char * plain, size_t length) { - std::string result; - Base64::EncodeFromArray(plain, length, &result); - return result; -} - -} diff --git a/talk/xmpp/saslmechanism.h b/talk/xmpp/saslmechanism.h deleted file mode 100644 index ee419d1c7..000000000 --- a/talk/xmpp/saslmechanism.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef TALK_XMPP_SASLMECHANISM_H_ -#define TALK_XMPP_SASLMECHANISM_H_ - -#include <string> - -namespace buzz { - -class XmlElement; - - -// Defines a mechnanism to do SASL authentication. -// Subclass instances should have a self-contained way to present -// credentials. -class SaslMechanism { - -public: - - // Intended to be subclassed - virtual ~SaslMechanism() {} - - // Should return the name of the SASL mechanism, e.g., "PLAIN" - virtual std::string GetMechanismName() = 0; - - // Should generate the initial "auth" request. Default is just <auth/>. - virtual XmlElement * StartSaslAuth(); - - // Should respond to a SASL "<challenge>" request. Default is - // to abort (for mechanisms that do not do challenge-response) - virtual XmlElement * HandleSaslChallenge(const XmlElement * challenge); - - // Notification of a SASL "<success>". Sometimes information - // is passed on success. - virtual void HandleSaslSuccess(const XmlElement * success); - - // Notification of a SASL "<failure>". Sometimes information - // for the user is passed on failure. - virtual void HandleSaslFailure(const XmlElement * failure); - -protected: - static std::string Base64Encode(const std::string & plain); - static std::string Base64Decode(const std::string & encoded); - static std::string Base64EncodeFromArray(const char * plain, size_t length); -}; - -} - -#endif // TALK_XMPP_SASLMECHANISM_H_ diff --git a/talk/xmpp/saslplainmechanism.h b/talk/xmpp/saslplainmechanism.h deleted file mode 100644 index c9d428e71..000000000 --- a/talk/xmpp/saslplainmechanism.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef TALK_XMPP_SASLPLAINMECHANISM_H_ -#define TALK_XMPP_SASLPLAINMECHANISM_H_ - -#include "webrtc/libjingle/xmpp/saslmechanism.h" -#include "webrtc/base/cryptstring.h" - -namespace buzz { - -class SaslPlainMechanism : public SaslMechanism { - -public: - SaslPlainMechanism(const buzz::Jid user_jid, const rtc::CryptString & password) : - user_jid_(user_jid), password_(password) {} - - virtual std::string GetMechanismName() { return "PLAIN"; } - - virtual XmlElement * StartSaslAuth() { - // send initial request - XmlElement * el = new XmlElement(QN_SASL_AUTH, true); - el->AddAttr(QN_MECHANISM, "PLAIN"); - - rtc::FormatCryptString credential; - credential.Append("\0", 1); - credential.Append(user_jid_.node()); - credential.Append("\0", 1); - credential.Append(&password_); - el->AddText(Base64EncodeFromArray(credential.GetData(), credential.GetLength())); - return el; - } - -private: - Jid user_jid_; - rtc::CryptString password_; -}; - -} - -#endif // TALK_XMPP_SASLPLAINMECHANISM_H_ diff --git a/talk/xmpp/util_unittest.cc b/talk/xmpp/util_unittest.cc deleted file mode 100644 index d245efe1d..000000000 --- a/talk/xmpp/util_unittest.cc +++ /dev/null @@ -1,102 +0,0 @@ -// Copyright 2004 Google, Inc. All Rights Reserved. -// Author: Joe Beda - -#include <iostream> -#include <sstream> -#include <string> -#include "webrtc/libjingle/xmllite/xmlelement.h" -#include "webrtc/libjingle/xmpp/util_unittest.h" -#include "webrtc/libjingle/xmpp/xmppengine.h" -#include "webrtc/base/gunit.h" - -namespace buzz { - -void XmppTestHandler::WriteOutput(const char * bytes, size_t len) { - output_ << std::string(bytes, len); -} - -void XmppTestHandler::StartTls(const std::string & cname) { - output_ << "[START-TLS " << cname << "]"; -} - -void XmppTestHandler::CloseConnection() { - output_ << "[CLOSED]"; -} - -void XmppTestHandler::OnStateChange(int state) { - switch (static_cast<XmppEngine::State>(state)) { - case XmppEngine::STATE_START: - session_ << "[START]"; - break; - case XmppEngine::STATE_OPENING: - session_ << "[OPENING]"; - break; - case XmppEngine::STATE_OPEN: - session_ << "[OPEN]"; - break; - case XmppEngine::STATE_CLOSED: - session_ << "[CLOSED]"; - switch (engine_->GetError(NULL)) { - case XmppEngine::ERROR_NONE: - // do nothing - break; - case XmppEngine::ERROR_XML: - session_ << "[ERROR-XML]"; - break; - case XmppEngine::ERROR_STREAM: - session_ << "[ERROR-STREAM]"; - break; - case XmppEngine::ERROR_VERSION: - session_ << "[ERROR-VERSION]"; - break; - case XmppEngine::ERROR_UNAUTHORIZED: - session_ << "[ERROR-UNAUTHORIZED]"; - break; - case XmppEngine::ERROR_TLS: - session_ << "[ERROR-TLS]"; - break; - case XmppEngine::ERROR_AUTH: - session_ << "[ERROR-AUTH]"; - break; - case XmppEngine::ERROR_BIND: - session_ << "[ERROR-BIND]"; - break; - case XmppEngine::ERROR_CONNECTION_CLOSED: - session_ << "[ERROR-CONNECTION-CLOSED]"; - break; - case XmppEngine::ERROR_DOCUMENT_CLOSED: - session_ << "[ERROR-DOCUMENT-CLOSED]"; - break; - default: - break; - } - break; - default: - break; - } -} - -bool XmppTestHandler::HandleStanza(const XmlElement * stanza) { - stanza_ << stanza->Str(); - return true; -} - -std::string XmppTestHandler::OutputActivity() { - std::string result = output_.str(); - output_.str(""); - return result; -} - -std::string XmppTestHandler::SessionActivity() { - std::string result = session_.str(); - session_.str(""); - return result; -} - -std::string XmppTestHandler::StanzaActivity() { - std::string result = stanza_.str(); - stanza_.str(""); - return result; -} - -} // namespace buzz diff --git a/talk/xmpp/util_unittest.h b/talk/xmpp/util_unittest.h deleted file mode 100644 index 806b505d4..000000000 --- a/talk/xmpp/util_unittest.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef TALK_XMPP_UTIL_UNITTEST_H_ -#define TALK_XMPP_UTIL_UNITTEST_H_ - -#include <sstream> -#include <string> -#include "webrtc/libjingle/xmpp/xmppengine.h" - -namespace buzz { - -// This class captures callbacks from engine. -class XmppTestHandler : public XmppOutputHandler, public XmppSessionHandler, - public XmppStanzaHandler { - public: - explicit XmppTestHandler(XmppEngine* engine) : engine_(engine) {} - virtual ~XmppTestHandler() {} - - void SetEngine(XmppEngine* engine); - - // Output handler - virtual void WriteOutput(const char * bytes, size_t len); - virtual void StartTls(const std::string & cname); - virtual void CloseConnection(); - - // Session handler - virtual void OnStateChange(int state); - - // Stanza handler - virtual bool HandleStanza(const XmlElement* stanza); - - std::string OutputActivity(); - std::string SessionActivity(); - std::string StanzaActivity(); - - private: - XmppEngine* engine_; - std::stringstream output_; - std::stringstream session_; - std::stringstream stanza_; -}; - -} // namespace buzz - -inline std::ostream& operator<<(std::ostream& os, const buzz::Jid& jid) { - os << jid.Str(); - return os; -} - -#endif // TALK_XMPP_UTIL_UNITTEST_H_ diff --git a/talk/xmpp/xmppauth.cc b/talk/xmpp/xmppauth.cc deleted file mode 100644 index 255f3a7ef..000000000 --- a/talk/xmpp/xmppauth.cc +++ /dev/null @@ -1,105 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "webrtc/libjingle/xmpp/xmppauth.h" - -#include <algorithm> - -#include "webrtc/libjingle/xmpp/constants.h" -#include "webrtc/libjingle/xmpp/saslcookiemechanism.h" -#include "webrtc/libjingle/xmpp/saslplainmechanism.h" - -XmppAuth::XmppAuth() : done_(false) { -} - -XmppAuth::~XmppAuth() { -} - -void XmppAuth::StartPreXmppAuth(const buzz::Jid& jid, - const rtc::SocketAddress& server, - const rtc::CryptString& pass, - const std::string& auth_mechanism, - const std::string& auth_token) { - jid_ = jid; - passwd_ = pass; - auth_mechanism_ = auth_mechanism; - auth_token_ = auth_token; - done_ = true; - - SignalAuthDone(); -} - -static bool contains(const std::vector<std::string>& strings, - const std::string& string) { - return std::find(strings.begin(), strings.end(), string) != strings.end(); -} - -std::string XmppAuth::ChooseBestSaslMechanism( - const std::vector<std::string>& mechanisms, - bool encrypted) { - // First try Oauth2. - if (GetAuthMechanism() == buzz::AUTH_MECHANISM_OAUTH2 && - contains(mechanisms, buzz::AUTH_MECHANISM_OAUTH2)) { - return buzz::AUTH_MECHANISM_OAUTH2; - } - - // A token is the weakest auth - 15s, service-limited, so prefer it. - if (GetAuthMechanism() == buzz::AUTH_MECHANISM_GOOGLE_TOKEN && - contains(mechanisms, buzz::AUTH_MECHANISM_GOOGLE_TOKEN)) { - return buzz::AUTH_MECHANISM_GOOGLE_TOKEN; - } - - // A cookie is the next weakest - 14 days. - if (GetAuthMechanism() == buzz::AUTH_MECHANISM_GOOGLE_COOKIE && - contains(mechanisms, buzz::AUTH_MECHANISM_GOOGLE_COOKIE)) { - return buzz::AUTH_MECHANISM_GOOGLE_COOKIE; - } - - // As a last resort, use plain authentication. - if (contains(mechanisms, buzz::AUTH_MECHANISM_PLAIN)) { - return buzz::AUTH_MECHANISM_PLAIN; - } - - // No good mechanism found - return ""; -} - -buzz::SaslMechanism* XmppAuth::CreateSaslMechanism( - const std::string& mechanism) { - if (mechanism == buzz::AUTH_MECHANISM_OAUTH2) { - return new buzz::SaslCookieMechanism( - mechanism, jid_.Str(), auth_token_, "oauth2"); - } else if (mechanism == buzz::AUTH_MECHANISM_GOOGLE_TOKEN) { - return new buzz::SaslCookieMechanism(mechanism, jid_.Str(), auth_token_); - // } else if (mechanism == buzz::AUTH_MECHANISM_GOOGLE_COOKIE) { - // return new buzz::SaslCookieMechanism(mechanism, jid.Str(), sid_); - } else if (mechanism == buzz::AUTH_MECHANISM_PLAIN) { - return new buzz::SaslPlainMechanism(jid_, passwd_); - } else { - return NULL; - } -} diff --git a/talk/xmpp/xmppauth.h b/talk/xmpp/xmppauth.h deleted file mode 100644 index 9fabd5ea8..000000000 --- a/talk/xmpp/xmppauth.h +++ /dev/null @@ -1,78 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef TALK_XMPP_XMPPAUTH_H_ -#define TALK_XMPP_XMPPAUTH_H_ - -#include <vector> - -#include "webrtc/libjingle/xmpp/jid.h" -#include "webrtc/libjingle/xmpp/prexmppauth.h" -#include "webrtc/libjingle/xmpp/saslhandler.h" -#include "webrtc/base/cryptstring.h" -#include "webrtc/base/sigslot.h" - -class XmppAuth: public buzz::PreXmppAuth { -public: - XmppAuth(); - virtual ~XmppAuth(); - - // TODO: Just have one "secret" that is either pass or - // token? - virtual void StartPreXmppAuth(const buzz::Jid& jid, - const rtc::SocketAddress& server, - const rtc::CryptString& pass, - const std::string& auth_mechanism, - const std::string& auth_token); - - virtual bool IsAuthDone() const { return done_; } - virtual bool IsAuthorized() const { return true; } - virtual bool HadError() const { return false; } - virtual int GetError() const { return 0; } - virtual buzz::CaptchaChallenge GetCaptchaChallenge() const { - return buzz::CaptchaChallenge(); - } - virtual std::string GetAuthMechanism() const { return auth_mechanism_; } - virtual std::string GetAuthToken() const { return auth_token_; } - - virtual std::string ChooseBestSaslMechanism( - const std::vector<std::string>& mechanisms, - bool encrypted); - - virtual buzz::SaslMechanism * CreateSaslMechanism( - const std::string& mechanism); - -private: - buzz::Jid jid_; - rtc::CryptString passwd_; - std::string auth_mechanism_; - std::string auth_token_; - bool done_; -}; - -#endif // TALK_XMPP_XMPPAUTH_H_ - diff --git a/talk/xmpp/xmppclient.cc b/talk/xmpp/xmppclient.cc deleted file mode 100644 index 66d1e970e..000000000 --- a/talk/xmpp/xmppclient.cc +++ /dev/null @@ -1,441 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "webrtc/libjingle/xmpp/xmppclient.h" - -#include "webrtc/libjingle/xmpp/constants.h" -#include "webrtc/libjingle/xmpp/plainsaslhandler.h" -#include "webrtc/libjingle/xmpp/prexmppauth.h" -#include "webrtc/libjingle/xmpp/saslplainmechanism.h" -#include "webrtc/base/logging.h" -#include "webrtc/base/scoped_ptr.h" -#include "webrtc/base/sigslot.h" -#include "webrtc/base/stringutils.h" -#include "xmpptask.h" - -namespace buzz { - -class XmppClient::Private : - public sigslot::has_slots<>, - public XmppSessionHandler, - public XmppOutputHandler { -public: - - explicit Private(XmppClient* client) : - client_(client), - socket_(), - engine_(), - proxy_port_(0), - pre_engine_error_(XmppEngine::ERROR_NONE), - pre_engine_subcode_(0), - signal_closed_(false), - allow_plain_(false) {} - - virtual ~Private() { - // We need to disconnect from socket_ before engine_ is destructed (by - // the auto-generated destructor code). - ResetSocket(); - } - - // the owner - XmppClient* const client_; - - // the two main objects - rtc::scoped_ptr<AsyncSocket> socket_; - rtc::scoped_ptr<XmppEngine> engine_; - rtc::scoped_ptr<PreXmppAuth> pre_auth_; - rtc::CryptString pass_; - std::string auth_mechanism_; - std::string auth_token_; - rtc::SocketAddress server_; - std::string proxy_host_; - int proxy_port_; - XmppEngine::Error pre_engine_error_; - int pre_engine_subcode_; - CaptchaChallenge captcha_challenge_; - bool signal_closed_; - bool allow_plain_; - - void ResetSocket() { - if (socket_) { - socket_->SignalConnected.disconnect(this); - socket_->SignalRead.disconnect(this); - socket_->SignalClosed.disconnect(this); - socket_.reset(NULL); - } - } - - // implementations of interfaces - void OnStateChange(int state); - void WriteOutput(const char* bytes, size_t len); - void StartTls(const std::string& domainname); - void CloseConnection(); - - // slots for socket signals - void OnSocketConnected(); - void OnSocketRead(); - void OnSocketClosed(); -}; - -bool IsTestServer(const std::string& server_name, - const std::string& test_server_domain) { - return (!test_server_domain.empty() && - rtc::ends_with(server_name.c_str(), - test_server_domain.c_str())); -} - -XmppReturnStatus XmppClient::Connect( - const XmppClientSettings& settings, - const std::string& lang, AsyncSocket* socket, PreXmppAuth* pre_auth) { - if (socket == NULL) - return XMPP_RETURN_BADARGUMENT; - if (d_->socket_) - return XMPP_RETURN_BADSTATE; - - d_->socket_.reset(socket); - - d_->socket_->SignalConnected.connect(d_.get(), &Private::OnSocketConnected); - d_->socket_->SignalRead.connect(d_.get(), &Private::OnSocketRead); - d_->socket_->SignalClosed.connect(d_.get(), &Private::OnSocketClosed); - - d_->engine_.reset(XmppEngine::Create()); - d_->engine_->SetSessionHandler(d_.get()); - d_->engine_->SetOutputHandler(d_.get()); - if (!settings.resource().empty()) { - d_->engine_->SetRequestedResource(settings.resource()); - } - d_->engine_->SetTls(settings.use_tls()); - - // The talk.google.com server returns a certificate with common-name: - // CN="gmail.com" for @gmail.com accounts, - // CN="googlemail.com" for @googlemail.com accounts, - // CN="talk.google.com" for other accounts (such as @example.com), - // so we tweak the tls server setting for those other accounts to match the - // returned certificate CN of "talk.google.com". - // For other servers, we leave the strings empty, which causes the jid's - // domain to be used. We do the same for gmail.com and googlemail.com as the - // returned CN matches the account domain in those cases. - std::string server_name = settings.server().HostAsURIString(); - if (server_name == buzz::STR_TALK_GOOGLE_COM || - server_name == buzz::STR_TALKX_L_GOOGLE_COM || - server_name == buzz::STR_XMPP_GOOGLE_COM || - server_name == buzz::STR_XMPPX_L_GOOGLE_COM || - IsTestServer(server_name, settings.test_server_domain())) { - if (settings.host() != STR_GMAIL_COM && - settings.host() != STR_GOOGLEMAIL_COM) { - d_->engine_->SetTlsServer("", STR_TALK_GOOGLE_COM); - } - } - - // Set language - d_->engine_->SetLanguage(lang); - - d_->engine_->SetUser(buzz::Jid(settings.user(), settings.host(), STR_EMPTY)); - - d_->pass_ = settings.pass(); - d_->auth_mechanism_ = settings.auth_mechanism(); - d_->auth_token_ = settings.auth_token(); - d_->server_ = settings.server(); - d_->proxy_host_ = settings.proxy_host(); - d_->proxy_port_ = settings.proxy_port(); - d_->allow_plain_ = settings.allow_plain(); - d_->pre_auth_.reset(pre_auth); - - return XMPP_RETURN_OK; -} - -XmppEngine::State XmppClient::GetState() const { - if (!d_->engine_) - return XmppEngine::STATE_NONE; - return d_->engine_->GetState(); -} - -XmppEngine::Error XmppClient::GetError(int* subcode) { - if (subcode) { - *subcode = 0; - } - if (!d_->engine_) - return XmppEngine::ERROR_NONE; - if (d_->pre_engine_error_ != XmppEngine::ERROR_NONE) { - if (subcode) { - *subcode = d_->pre_engine_subcode_; - } - return d_->pre_engine_error_; - } - return d_->engine_->GetError(subcode); -} - -const XmlElement* XmppClient::GetStreamError() { - if (!d_->engine_) { - return NULL; - } - return d_->engine_->GetStreamError(); -} - -CaptchaChallenge XmppClient::GetCaptchaChallenge() { - if (!d_->engine_) - return CaptchaChallenge(); - return d_->captcha_challenge_; -} - -std::string XmppClient::GetAuthMechanism() { - if (!d_->engine_) - return ""; - return d_->auth_mechanism_; -} - -std::string XmppClient::GetAuthToken() { - if (!d_->engine_) - return ""; - return d_->auth_token_; -} - -int XmppClient::ProcessStart() { - // Should not happen, but was observed in crash reports - if (!d_->socket_) { - LOG(LS_ERROR) << "socket_ already reset"; - return STATE_DONE; - } - - if (d_->pre_auth_) { - d_->pre_auth_->SignalAuthDone.connect(this, &XmppClient::OnAuthDone); - d_->pre_auth_->StartPreXmppAuth( - d_->engine_->GetUser(), d_->server_, d_->pass_, - d_->auth_mechanism_, d_->auth_token_); - d_->pass_.Clear(); // done with this; - return STATE_PRE_XMPP_LOGIN; - } - else { - d_->engine_->SetSaslHandler(new PlainSaslHandler( - d_->engine_->GetUser(), d_->pass_, d_->allow_plain_)); - d_->pass_.Clear(); // done with this; - return STATE_START_XMPP_LOGIN; - } -} - -void XmppClient::OnAuthDone() { - Wake(); -} - -int XmppClient::ProcessTokenLogin() { - // Should not happen, but was observed in crash reports - if (!d_->socket_) { - LOG(LS_ERROR) << "socket_ already reset"; - return STATE_DONE; - } - - // Don't know how this could happen, but crash reports show it as NULL - if (!d_->pre_auth_) { - d_->pre_engine_error_ = XmppEngine::ERROR_AUTH; - EnsureClosed(); - return STATE_ERROR; - } - - // Wait until pre authentication is done is done - if (!d_->pre_auth_->IsAuthDone()) - return STATE_BLOCKED; - - if (!d_->pre_auth_->IsAuthorized()) { - // maybe split out a case when gaia is down? - if (d_->pre_auth_->HadError()) { - d_->pre_engine_error_ = XmppEngine::ERROR_AUTH; - d_->pre_engine_subcode_ = d_->pre_auth_->GetError(); - } - else { - d_->pre_engine_error_ = XmppEngine::ERROR_UNAUTHORIZED; - d_->pre_engine_subcode_ = 0; - d_->captcha_challenge_ = d_->pre_auth_->GetCaptchaChallenge(); - } - d_->pre_auth_.reset(NULL); // done with this - EnsureClosed(); - return STATE_ERROR; - } - - // Save auth token as a result - - d_->auth_mechanism_ = d_->pre_auth_->GetAuthMechanism(); - d_->auth_token_ = d_->pre_auth_->GetAuthToken(); - - // transfer ownership of pre_auth_ to engine - d_->engine_->SetSaslHandler(d_->pre_auth_.release()); - return STATE_START_XMPP_LOGIN; -} - -int XmppClient::ProcessStartXmppLogin() { - // Should not happen, but was observed in crash reports - if (!d_->socket_) { - LOG(LS_ERROR) << "socket_ already reset"; - return STATE_DONE; - } - - // Done with pre-connect tasks - connect! - if (!d_->socket_->Connect(d_->server_)) { - EnsureClosed(); - return STATE_ERROR; - } - - return STATE_RESPONSE; -} - -int XmppClient::ProcessResponse() { - // Hang around while we are connected. - if (!delivering_signal_ && - (!d_->engine_ || d_->engine_->GetState() == XmppEngine::STATE_CLOSED)) - return STATE_DONE; - return STATE_BLOCKED; -} - -XmppReturnStatus XmppClient::Disconnect() { - if (!d_->socket_) - return XMPP_RETURN_BADSTATE; - Abort(); - d_->engine_->Disconnect(); - d_->ResetSocket(); - return XMPP_RETURN_OK; -} - -XmppClient::XmppClient(TaskParent* parent) - : XmppTaskParentInterface(parent), - delivering_signal_(false), - valid_(false) { - d_.reset(new Private(this)); - valid_ = true; -} - -XmppClient::~XmppClient() { - valid_ = false; -} - -const Jid& XmppClient::jid() const { - return d_->engine_->FullJid(); -} - - -std::string XmppClient::NextId() { - return d_->engine_->NextId(); -} - -XmppReturnStatus XmppClient::SendStanza(const XmlElement* stanza) { - return d_->engine_->SendStanza(stanza); -} - -XmppReturnStatus XmppClient::SendStanzaError( - const XmlElement* old_stanza, XmppStanzaError xse, - const std::string& message) { - return d_->engine_->SendStanzaError(old_stanza, xse, message); -} - -XmppReturnStatus XmppClient::SendRaw(const std::string& text) { - return d_->engine_->SendRaw(text); -} - -XmppEngine* XmppClient::engine() { - return d_->engine_.get(); -} - -void XmppClient::Private::OnSocketConnected() { - engine_->Connect(); -} - -void XmppClient::Private::OnSocketRead() { - char bytes[4096]; - size_t bytes_read; - for (;;) { - // Should not happen, but was observed in crash reports - if (!socket_) { - LOG(LS_ERROR) << "socket_ already reset"; - return; - } - - if (!socket_->Read(bytes, sizeof(bytes), &bytes_read)) { - // TODO: deal with error information - return; - } - - if (bytes_read == 0) - return; - -//#ifdef _DEBUG - client_->SignalLogInput(bytes, static_cast<int>(bytes_read)); -//#endif - - engine_->HandleInput(bytes, bytes_read); - } -} - -void XmppClient::Private::OnSocketClosed() { - int code = socket_->GetError(); - engine_->ConnectionClosed(code); -} - -void XmppClient::Private::OnStateChange(int state) { - if (state == XmppEngine::STATE_CLOSED) { - client_->EnsureClosed(); - } - else { - client_->SignalStateChange((XmppEngine::State)state); - } - client_->Wake(); -} - -void XmppClient::Private::WriteOutput(const char* bytes, size_t len) { -//#ifdef _DEBUG - client_->SignalLogOutput(bytes, static_cast<int>(len)); -//#endif - - socket_->Write(bytes, len); - // TODO: deal with error information -} - -void XmppClient::Private::StartTls(const std::string& domain) { -#if defined(FEATURE_ENABLE_SSL) - socket_->StartTls(domain); -#endif -} - -void XmppClient::Private::CloseConnection() { - socket_->Close(); -} - -void XmppClient::AddXmppTask(XmppTask* task, XmppEngine::HandlerLevel level) { - d_->engine_->AddStanzaHandler(task, level); -} - -void XmppClient::RemoveXmppTask(XmppTask* task) { - d_->engine_->RemoveStanzaHandler(task); -} - -void XmppClient::EnsureClosed() { - if (!d_->signal_closed_) { - d_->signal_closed_ = true; - delivering_signal_ = true; - SignalStateChange(XmppEngine::STATE_CLOSED); - delivering_signal_ = false; - } -} - -} // namespace buzz diff --git a/talk/xmpp/xmppclient.h b/talk/xmpp/xmppclient.h deleted file mode 100644 index 74e403053..000000000 --- a/talk/xmpp/xmppclient.h +++ /dev/null @@ -1,165 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef TALK_XMPP_XMPPCLIENT_H_ -#define TALK_XMPP_XMPPCLIENT_H_ - -#include <string> -#include "webrtc/libjingle/xmpp/asyncsocket.h" -#include "webrtc/libjingle/xmpp/xmppclientsettings.h" -#include "webrtc/libjingle/xmpp/xmppengine.h" -#include "webrtc/libjingle/xmpp/xmpptask.h" -#include "webrtc/base/basicdefs.h" -#include "webrtc/base/sigslot.h" -#include "webrtc/base/task.h" - -namespace buzz { - -class PreXmppAuth; -class CaptchaChallenge; - -// Just some non-colliding number. Could have picked "1". -#define XMPP_CLIENT_TASK_CODE 0x366c1e47 - -///////////////////////////////////////////////////////////////////// -// -// XMPPCLIENT -// -///////////////////////////////////////////////////////////////////// -// -// See Task first. XmppClient is a parent task for XmppTasks. -// -// XmppClient is a task which is designed to be the parent task for -// all tasks that depend on a single Xmpp connection. If you want to, -// for example, listen for subscription requests forever, then your -// listener should be a task that is a child of the XmppClient that owns -// the connection you are using. XmppClient has all the utility methods -// that basically drill through to XmppEngine. -// -// XmppClient is just a wrapper for XmppEngine, and if I were writing it -// all over again, I would make XmppClient == XmppEngine. Why? -// XmppEngine needs tasks too, for example it has an XmppLoginTask which -// should just be the same kind of Task instead of an XmppEngine specific -// thing. It would help do certain things like GAIA auth cleaner. -// -///////////////////////////////////////////////////////////////////// - -class XmppClient : public XmppTaskParentInterface, - public XmppClientInterface, - public sigslot::has_slots<> -{ -public: - explicit XmppClient(rtc::TaskParent * parent); - virtual ~XmppClient(); - - XmppReturnStatus Connect(const XmppClientSettings & settings, - const std::string & lang, - AsyncSocket * socket, - PreXmppAuth * preauth); - - virtual int ProcessStart(); - virtual int ProcessResponse(); - XmppReturnStatus Disconnect(); - - sigslot::signal1<XmppEngine::State> SignalStateChange; - XmppEngine::Error GetError(int *subcode); - - // When there is a <stream:error> stanza, return the stanza - // so that they can be handled. - const XmlElement *GetStreamError(); - - // When there is an authentication error, we may have captcha info - // that the user can use to unlock their account - CaptchaChallenge GetCaptchaChallenge(); - - // When authentication is successful, this returns the service token - // (if we used GAIA authentication) - std::string GetAuthMechanism(); - std::string GetAuthToken(); - - XmppReturnStatus SendRaw(const std::string & text); - - XmppEngine* engine(); - - sigslot::signal2<const char *, int> SignalLogInput; - sigslot::signal2<const char *, int> SignalLogOutput; - - // As XmppTaskParentIntreface - virtual XmppClientInterface* GetClient() { return this; } - - // As XmppClientInterface - virtual XmppEngine::State GetState() const; - virtual const Jid& jid() const; - virtual std::string NextId(); - virtual XmppReturnStatus SendStanza(const XmlElement *stanza); - virtual XmppReturnStatus SendStanzaError(const XmlElement * pelOriginal, - XmppStanzaError code, - const std::string & text); - virtual void AddXmppTask(XmppTask *, XmppEngine::HandlerLevel); - virtual void RemoveXmppTask(XmppTask *); - - private: - friend class XmppTask; - - void OnAuthDone(); - - // Internal state management - enum { - STATE_PRE_XMPP_LOGIN = STATE_NEXT, - STATE_START_XMPP_LOGIN = STATE_NEXT + 1, - }; - int Process(int state) { - switch (state) { - case STATE_PRE_XMPP_LOGIN: return ProcessTokenLogin(); - case STATE_START_XMPP_LOGIN: return ProcessStartXmppLogin(); - default: return Task::Process(state); - } - } - - std::string GetStateName(int state) const { - switch (state) { - case STATE_PRE_XMPP_LOGIN: return "PRE_XMPP_LOGIN"; - case STATE_START_XMPP_LOGIN: return "START_XMPP_LOGIN"; - default: return Task::GetStateName(state); - } - } - - int ProcessTokenLogin(); - int ProcessStartXmppLogin(); - void EnsureClosed(); - - class Private; - friend class Private; - rtc::scoped_ptr<Private> d_; - - bool delivering_signal_; - bool valid_; -}; - -} - -#endif // TALK_XMPP_XMPPCLIENT_H_ diff --git a/talk/xmpp/xmppclientsettings.h b/talk/xmpp/xmppclientsettings.h deleted file mode 100644 index 04acf36f3..000000000 --- a/talk/xmpp/xmppclientsettings.h +++ /dev/null @@ -1,128 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef TALK_XMPP_XMPPCLIENTSETTINGS_H_ -#define TALK_XMPP_XMPPCLIENTSETTINGS_H_ - -#include "webrtc/p2p/base/port.h" -#include "webrtc/libjingle/xmpp/xmppengine.h" -#include "webrtc/base/cryptstring.h" - -namespace buzz { - -class XmppUserSettings { - public: - XmppUserSettings() - : use_tls_(buzz::TLS_DISABLED), - allow_plain_(false) { - } - - void set_user(const std::string& user) { user_ = user; } - void set_host(const std::string& host) { host_ = host; } - void set_pass(const rtc::CryptString& pass) { pass_ = pass; } - void set_auth_token(const std::string& mechanism, - const std::string& token) { - auth_mechanism_ = mechanism; - auth_token_ = token; - } - void set_resource(const std::string& resource) { resource_ = resource; } - void set_use_tls(const TlsOptions use_tls) { use_tls_ = use_tls; } - void set_allow_plain(bool f) { allow_plain_ = f; } - void set_test_server_domain(const std::string& test_server_domain) { - test_server_domain_ = test_server_domain; - } - void set_token_service(const std::string& token_service) { - token_service_ = token_service; - } - - const std::string& user() const { return user_; } - const std::string& host() const { return host_; } - const rtc::CryptString& pass() const { return pass_; } - const std::string& auth_mechanism() const { return auth_mechanism_; } - const std::string& auth_token() const { return auth_token_; } - const std::string& resource() const { return resource_; } - TlsOptions use_tls() const { return use_tls_; } - bool allow_plain() const { return allow_plain_; } - const std::string& test_server_domain() const { return test_server_domain_; } - const std::string& token_service() const { return token_service_; } - - private: - std::string user_; - std::string host_; - rtc::CryptString pass_; - std::string auth_mechanism_; - std::string auth_token_; - std::string resource_; - TlsOptions use_tls_; - bool allow_plain_; - std::string test_server_domain_; - std::string token_service_; -}; - -class XmppClientSettings : public XmppUserSettings { - public: - XmppClientSettings() - : protocol_(cricket::PROTO_TCP), - proxy_(rtc::PROXY_NONE), - proxy_port_(80), - use_proxy_auth_(false) { - } - - void set_server(const rtc::SocketAddress& server) { - server_ = server; - } - void set_protocol(cricket::ProtocolType protocol) { protocol_ = protocol; } - void set_proxy(rtc::ProxyType f) { proxy_ = f; } - void set_proxy_host(const std::string& host) { proxy_host_ = host; } - void set_proxy_port(int port) { proxy_port_ = port; }; - void set_use_proxy_auth(bool f) { use_proxy_auth_ = f; } - void set_proxy_user(const std::string& user) { proxy_user_ = user; } - void set_proxy_pass(const rtc::CryptString& pass) { proxy_pass_ = pass; } - - const rtc::SocketAddress& server() const { return server_; } - cricket::ProtocolType protocol() const { return protocol_; } - rtc::ProxyType proxy() const { return proxy_; } - const std::string& proxy_host() const { return proxy_host_; } - int proxy_port() const { return proxy_port_; } - bool use_proxy_auth() const { return use_proxy_auth_; } - const std::string& proxy_user() const { return proxy_user_; } - const rtc::CryptString& proxy_pass() const { return proxy_pass_; } - - private: - rtc::SocketAddress server_; - cricket::ProtocolType protocol_; - rtc::ProxyType proxy_; - std::string proxy_host_; - int proxy_port_; - bool use_proxy_auth_; - std::string proxy_user_; - rtc::CryptString proxy_pass_; -}; - -} - -#endif // TALK_XMPP_XMPPCLIENT_H_ diff --git a/talk/xmpp/xmppengine.h b/talk/xmpp/xmppengine.h deleted file mode 100644 index 1806ba9da..000000000 --- a/talk/xmpp/xmppengine.h +++ /dev/null @@ -1,349 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef TALK_XMPP_XMPPENGINE_H_ -#define TALK_XMPP_XMPPENGINE_H_ - -// also part of the API -#include "webrtc/libjingle/xmllite/qname.h" -#include "webrtc/libjingle/xmllite/xmlelement.h" -#include "webrtc/libjingle/xmpp/jid.h" - - -namespace buzz { - -class XmppEngine; -class SaslHandler; -typedef void * XmppIqCookie; - -//! XMPP stanza error codes. -//! Used in XmppEngine.SendStanzaError(). -enum XmppStanzaError { - XSE_BAD_REQUEST, - XSE_CONFLICT, - XSE_FEATURE_NOT_IMPLEMENTED, - XSE_FORBIDDEN, - XSE_GONE, - XSE_INTERNAL_SERVER_ERROR, - XSE_ITEM_NOT_FOUND, - XSE_JID_MALFORMED, - XSE_NOT_ACCEPTABLE, - XSE_NOT_ALLOWED, - XSE_PAYMENT_REQUIRED, - XSE_RECIPIENT_UNAVAILABLE, - XSE_REDIRECT, - XSE_REGISTRATION_REQUIRED, - XSE_SERVER_NOT_FOUND, - XSE_SERVER_TIMEOUT, - XSE_RESOURCE_CONSTRAINT, - XSE_SERVICE_UNAVAILABLE, - XSE_SUBSCRIPTION_REQUIRED, - XSE_UNDEFINED_CONDITION, - XSE_UNEXPECTED_REQUEST, -}; - -// XmppReturnStatus -// This is used by API functions to synchronously return status. -enum XmppReturnStatus { - XMPP_RETURN_OK, - XMPP_RETURN_BADARGUMENT, - XMPP_RETURN_BADSTATE, - XMPP_RETURN_PENDING, - XMPP_RETURN_UNEXPECTED, - XMPP_RETURN_NOTYETIMPLEMENTED, -}; - -// TlsOptions -// This is used by API to identify TLS setting. -enum TlsOptions { - TLS_DISABLED, - TLS_ENABLED, - TLS_REQUIRED -}; - -//! Callback for socket output for an XmppEngine connection. -//! Register via XmppEngine.SetOutputHandler. An XmppEngine -//! can call back to this handler while it is processing -//! Connect, SendStanza, SendIq, Disconnect, or HandleInput. -class XmppOutputHandler { -public: - virtual ~XmppOutputHandler() {} - - //! Deliver the specified bytes to the XMPP socket. - virtual void WriteOutput(const char * bytes, size_t len) = 0; - - //! Initiate TLS encryption on the socket. - //! The implementation must verify that the SSL - //! certificate matches the given domainname. - virtual void StartTls(const std::string & domainname) = 0; - - //! Called when engine wants the connecton closed. - virtual void CloseConnection() = 0; -}; - -//! Callback to deliver engine state change notifications -//! to the object managing the engine. -class XmppSessionHandler { -public: - virtual ~XmppSessionHandler() {} - //! Called when engine changes state. Argument is new state. - virtual void OnStateChange(int state) = 0; -}; - -//! Callback to deliver stanzas to an Xmpp application module. -//! Register via XmppEngine.SetDefaultSessionHandler or via -//! XmppEngine.AddSessionHAndler. -class XmppStanzaHandler { -public: - virtual ~XmppStanzaHandler() {} - //! Process the given stanza. - //! The handler must return true if it has handled the stanza. - //! A false return value causes the stanza to be passed on to - //! the next registered handler. - virtual bool HandleStanza(const XmlElement * stanza) = 0; -}; - -//! Callback to deliver iq responses (results and errors). -//! Register while sending an iq via XmppEngine.SendIq. -//! Iq responses are routed to matching XmppIqHandlers in preference -//! to sending to any registered SessionHandlers. -class XmppIqHandler { -public: - virtual ~XmppIqHandler() {} - //! Called to handle the iq response. - //! The response may be either a result or an error, and will have - //! an 'id' that matches the request and a 'from' that matches the - //! 'to' of the request. Called no more than once; once this is - //! called, the handler is automatically unregistered. - virtual void IqResponse(XmppIqCookie cookie, const XmlElement * pelStanza) = 0; -}; - -//! The XMPP connection engine. -//! This engine implements the client side of the 'core' XMPP protocol. -//! To use it, register an XmppOutputHandler to handle socket output -//! and pass socket input to HandleInput. Then application code can -//! set up the connection with a user, password, and other settings, -//! and then call Connect() to initiate the connection. -//! An application can listen for events and receive stanzas by -//! registering an XmppStanzaHandler via AddStanzaHandler(). -class XmppEngine { -public: - static XmppEngine * Create(); - virtual ~XmppEngine() {} - - //! Error codes. See GetError(). - enum Error { - ERROR_NONE = 0, //!< No error - ERROR_XML, //!< Malformed XML or encoding error - ERROR_STREAM, //!< XMPP stream error - see GetStreamError() - ERROR_VERSION, //!< XMPP version error - ERROR_UNAUTHORIZED, //!< User is not authorized (rejected credentials) - ERROR_TLS, //!< TLS could not be negotiated - ERROR_AUTH, //!< Authentication could not be negotiated - ERROR_BIND, //!< Resource or session binding could not be negotiated - ERROR_CONNECTION_CLOSED,//!< Connection closed by output handler. - ERROR_DOCUMENT_CLOSED, //!< Closed by </stream:stream> - ERROR_SOCKET, //!< Socket error - ERROR_NETWORK_TIMEOUT, //!< Some sort of timeout (eg., we never got the roster) - ERROR_MISSING_USERNAME //!< User has a Google Account but no nickname - }; - - //! States. See GetState(). - enum State { - STATE_NONE = 0, //!< Nonexistent state - STATE_START, //!< Initial state. - STATE_OPENING, //!< Exchanging stream headers, authenticating and so on. - STATE_OPEN, //!< Authenticated and bound. - STATE_CLOSED, //!< Session closed, possibly due to error. - }; - - // SOCKET INPUT AND OUTPUT ------------------------------------------------ - - //! Registers the handler for socket output - virtual XmppReturnStatus SetOutputHandler(XmppOutputHandler *pxoh) = 0; - - //! Provides socket input to the engine - virtual XmppReturnStatus HandleInput(const char * bytes, size_t len) = 0; - - //! Advises the engine that the socket has closed - virtual XmppReturnStatus ConnectionClosed(int subcode) = 0; - - // SESSION SETUP --------------------------------------------------------- - - //! Indicates the (bare) JID for the user to use. - virtual XmppReturnStatus SetUser(const Jid & jid)= 0; - - //! Get the login (bare) JID. - virtual const Jid & GetUser() = 0; - - //! Provides different methods for credentials for login. - //! Takes ownership of this object; deletes when login is done - virtual XmppReturnStatus SetSaslHandler(SaslHandler * h) = 0; - - //! Sets whether TLS will be used within the connection (default true). - virtual XmppReturnStatus SetTls(TlsOptions useTls) = 0; - - //! Sets an alternate domain from which we allows TLS certificates. - //! This is for use in the case where a we want to allow a proxy to - //! serve up its own certificate rather than one owned by the underlying - //! domain. - virtual XmppReturnStatus SetTlsServer(const std::string & proxy_hostname, - const std::string & proxy_domain) = 0; - - //! Gets whether TLS will be used within the connection. - virtual TlsOptions GetTls() = 0; - - //! Sets the request resource name, if any (optional). - //! Note that the resource name may be overridden by the server; after - //! binding, the actual resource name is available as part of FullJid(). - virtual XmppReturnStatus SetRequestedResource(const std::string& resource) = 0; - - //! Gets the request resource name. - virtual const std::string & GetRequestedResource() = 0; - - //! Sets language - virtual void SetLanguage(const std::string & lang) = 0; - - // SESSION MANAGEMENT --------------------------------------------------- - - //! Set callback for state changes. - virtual XmppReturnStatus SetSessionHandler(XmppSessionHandler* handler) = 0; - - //! Initiates the XMPP connection. - //! After supplying connection settings, call this once to initiate, - //! (optionally) encrypt, authenticate, and bind the connection. - virtual XmppReturnStatus Connect() = 0; - - //! The current engine state. - virtual State GetState() = 0; - - //! Returns true if the connection is encrypted (under TLS) - virtual bool IsEncrypted() = 0; - - //! The error code. - //! Consult this after XmppOutputHandler.OnClose(). - virtual Error GetError(int *subcode) = 0; - - //! The stream:error stanza, when the error is XmppEngine::ERROR_STREAM. - //! Notice the stanza returned is owned by the XmppEngine and - //! is deleted when the engine is destroyed. - virtual const XmlElement * GetStreamError() = 0; - - //! Closes down the connection. - //! Sends CloseConnection to output, and disconnects and registered - //! session handlers. After Disconnect completes, it is guaranteed - //! that no further callbacks will be made. - virtual XmppReturnStatus Disconnect() = 0; - - // APPLICATION USE ------------------------------------------------------- - - enum HandlerLevel { - HL_NONE = 0, - HL_PEEK, //!< Sees messages before all other processing; cannot abort - HL_SINGLE, //!< Watches for a single message, e.g., by id and sender - HL_SENDER, //!< Watches for a type of message from a specific sender - HL_TYPE, //!< Watches a type of message, e.g., all groupchat msgs - HL_ALL, //!< Watches all messages - gets last shot - HL_COUNT, //!< Count of handler levels - }; - - //! Adds a listener for session events. - //! Stanza delivery is chained to session handlers; the first to - //! return 'true' is the last to get each stanza. - virtual XmppReturnStatus AddStanzaHandler(XmppStanzaHandler* handler, HandlerLevel level = HL_PEEK) = 0; - - //! Removes a listener for session events. - virtual XmppReturnStatus RemoveStanzaHandler(XmppStanzaHandler* handler) = 0; - - //! Sends a stanza to the server. - virtual XmppReturnStatus SendStanza(const XmlElement * pelStanza) = 0; - - //! Sends raw text to the server - virtual XmppReturnStatus SendRaw(const std::string & text) = 0; - - //! Sends an iq to the server, and registers a callback for the result. - //! Returns the cookie passed to the result handler. - virtual XmppReturnStatus SendIq(const XmlElement* pelStanza, - XmppIqHandler* iq_handler, - XmppIqCookie* cookie) = 0; - - //! Unregisters an iq callback handler given its cookie. - //! No callback will come to this handler after it's unregistered. - virtual XmppReturnStatus RemoveIqHandler(XmppIqCookie cookie, - XmppIqHandler** iq_handler) = 0; - - - //! Forms and sends an error in response to the given stanza. - //! Swaps to and from, sets type to "error", and adds error information - //! based on the passed code. Text is optional and may be STR_EMPTY. - virtual XmppReturnStatus SendStanzaError(const XmlElement * pelOriginal, - XmppStanzaError code, - const std::string & text) = 0; - - //! The fullly bound JID. - //! This JID is only valid after binding has succeeded. If the value - //! is JID_NULL, the binding has not succeeded. - virtual const Jid & FullJid() = 0; - - //! The next unused iq id for this connection. - //! Call this when building iq stanzas, to ensure that each iq - //! gets its own unique id. - virtual std::string NextId() = 0; - -}; - -} - - -// Move these to a better location - -#define XMPP_FAILED(x) \ - ( (x) == buzz::XMPP_RETURN_OK ? false : true) \ - - -#define XMPP_SUCCEEDED(x) \ - ( (x) == buzz::XMPP_RETURN_OK ? true : false) \ - -#define IFR(x) \ - do { \ - xmpp_status = (x); \ - if (XMPP_FAILED(xmpp_status)) { \ - return xmpp_status; \ - } \ - } while (false) \ - - -#define IFC(x) \ - do { \ - xmpp_status = (x); \ - if (XMPP_FAILED(xmpp_status)) { \ - goto Cleanup; \ - } \ - } while (false) \ - - -#endif // TALK_XMPP_XMPPENGINE_H_ diff --git a/talk/xmpp/xmppengine_unittest.cc b/talk/xmpp/xmppengine_unittest.cc deleted file mode 100644 index 6b0dc9670..000000000 --- a/talk/xmpp/xmppengine_unittest.cc +++ /dev/null @@ -1,318 +0,0 @@ -// Copyright 2004 Google Inc. All Rights Reserved -// Author: David Bau - -#include <iostream> -#include <sstream> -#include <string> -#include "webrtc/libjingle/xmllite/xmlelement.h" -#include "webrtc/libjingle/xmpp/constants.h" -#include "webrtc/libjingle/xmpp/plainsaslhandler.h" -#include "webrtc/libjingle/xmpp/saslplainmechanism.h" -#include "webrtc/libjingle/xmpp/util_unittest.h" -#include "webrtc/libjingle/xmpp/xmppengine.h" -#include "webrtc/base/common.h" -#include "webrtc/base/gunit.h" - -using buzz::Jid; -using buzz::QName; -using buzz::XmlElement; -using buzz::XmppEngine; -using buzz::XmppIqCookie; -using buzz::XmppIqHandler; -using buzz::XmppTestHandler; -using buzz::QN_ID; -using buzz::QN_IQ; -using buzz::QN_TYPE; -using buzz::QN_ROSTER_QUERY; -using buzz::XMPP_RETURN_OK; -using buzz::XMPP_RETURN_BADARGUMENT; - -// XmppEngineTestIqHandler -// This class grabs the response to an IQ stanza and stores it in a string. -class XmppEngineTestIqHandler : public XmppIqHandler { - public: - virtual void IqResponse(XmppIqCookie, const XmlElement * stanza) { - ss_ << stanza->Str(); - } - - std::string IqResponseActivity() { - std::string result = ss_.str(); - ss_.str(""); - return result; - } - - private: - std::stringstream ss_; -}; - -class XmppEngineTest : public testing::Test { - public: - XmppEngine* engine() { return engine_.get(); } - XmppTestHandler* handler() { return handler_.get(); } - virtual void SetUp() { - engine_.reset(XmppEngine::Create()); - handler_.reset(new XmppTestHandler(engine_.get())); - - Jid jid("david@my-server"); - rtc::InsecureCryptStringImpl pass; - pass.password() = "david"; - engine_->SetSessionHandler(handler_.get()); - engine_->SetOutputHandler(handler_.get()); - engine_->AddStanzaHandler(handler_.get()); - engine_->SetUser(jid); - engine_->SetSaslHandler( - new buzz::PlainSaslHandler(jid, rtc::CryptString(pass), true)); - } - virtual void TearDown() { - handler_.reset(); - engine_.reset(); - } - void RunLogin(); - - private: - rtc::scoped_ptr<XmppEngine> engine_; - rtc::scoped_ptr<XmppTestHandler> handler_; -}; - -void XmppEngineTest::RunLogin() { - // Connect - EXPECT_EQ(XmppEngine::STATE_START, engine()->GetState()); - engine()->Connect(); - EXPECT_EQ(XmppEngine::STATE_OPENING, engine()->GetState()); - - EXPECT_EQ("[OPENING]", handler_->SessionActivity()); - - EXPECT_EQ("<stream:stream to=\"my-server\" xml:lang=\"*\" version=\"1.0\" " - "xmlns:stream=\"http://etherx.jabber.org/streams\" " - "xmlns=\"jabber:client\">\r\n", handler_->OutputActivity()); - - std::string input = - "<stream:stream id=\"a5f2d8c9\" version=\"1.0\" " - "xmlns:stream=\"http://etherx.jabber.org/streams\" " - "xmlns=\"jabber:client\">"; - engine()->HandleInput(input.c_str(), input.length()); - - input = - "<stream:features>" - "<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'>" - "<required/>" - "</starttls>" - "<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>" - "<mechanism>DIGEST-MD5</mechanism>" - "<mechanism>PLAIN</mechanism>" - "</mechanisms>" - "</stream:features>"; - engine()->HandleInput(input.c_str(), input.length()); - EXPECT_EQ("<starttls xmlns=\"urn:ietf:params:xml:ns:xmpp-tls\"/>", - handler_->OutputActivity()); - - EXPECT_EQ("", handler_->SessionActivity()); - EXPECT_EQ("", handler_->StanzaActivity()); - - input = "<proceed xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>"; - engine()->HandleInput(input.c_str(), input.length()); - EXPECT_EQ("[START-TLS my-server]" - "<stream:stream to=\"my-server\" xml:lang=\"*\" " - "version=\"1.0\" xmlns:stream=\"http://etherx.jabber.org/streams\" " - "xmlns=\"jabber:client\">\r\n", handler_->OutputActivity()); - - EXPECT_EQ("", handler_->SessionActivity()); - EXPECT_EQ("", handler_->StanzaActivity()); - - input = "<stream:stream id=\"01234567\" version=\"1.0\" " - "xmlns:stream=\"http://etherx.jabber.org/streams\" " - "xmlns=\"jabber:client\">"; - engine()->HandleInput(input.c_str(), input.length()); - - input = - "<stream:features>" - "<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>" - "<mechanism>DIGEST-MD5</mechanism>" - "<mechanism>PLAIN</mechanism>" - "</mechanisms>" - "</stream:features>"; - engine()->HandleInput(input.c_str(), input.length()); - EXPECT_EQ("<auth xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\" " - "mechanism=\"PLAIN\" " - "auth:allow-non-google-login=\"true\" " - "auth:client-uses-full-bind-result=\"true\" " - "xmlns:auth=\"http://www.google.com/talk/protocol/auth\"" - ">AGRhdmlkAGRhdmlk</auth>", - handler_->OutputActivity()); - - EXPECT_EQ("", handler_->SessionActivity()); - EXPECT_EQ("", handler_->StanzaActivity()); - - input = "<success xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/>"; - engine()->HandleInput(input.c_str(), input.length()); - EXPECT_EQ("<stream:stream to=\"my-server\" xml:lang=\"*\" version=\"1.0\" " - "xmlns:stream=\"http://etherx.jabber.org/streams\" " - "xmlns=\"jabber:client\">\r\n", handler_->OutputActivity()); - - EXPECT_EQ("", handler_->SessionActivity()); - EXPECT_EQ("", handler_->StanzaActivity()); - - input = "<stream:stream id=\"01234567\" version=\"1.0\" " - "xmlns:stream=\"http://etherx.jabber.org/streams\" " - "xmlns=\"jabber:client\">"; - engine()->HandleInput(input.c_str(), input.length()); - - input = "<stream:features>" - "<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'/>" - "<session xmlns='urn:ietf:params:xml:ns:xmpp-session'/>" - "</stream:features>"; - engine()->HandleInput(input.c_str(), input.length()); - EXPECT_EQ("<iq type=\"set\" id=\"0\">" - "<bind xmlns=\"urn:ietf:params:xml:ns:xmpp-bind\"/></iq>", - handler_->OutputActivity()); - - EXPECT_EQ("", handler_->SessionActivity()); - EXPECT_EQ("", handler_->StanzaActivity()); - - input = "<iq type='result' id='0'>" - "<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'><jid>" - "david@my-server/test</jid></bind></iq>"; - engine()->HandleInput(input.c_str(), input.length()); - - EXPECT_EQ("<iq type=\"set\" id=\"1\">" - "<session xmlns=\"urn:ietf:params:xml:ns:xmpp-session\"/></iq>", - handler_->OutputActivity()); - - EXPECT_EQ("", handler_->SessionActivity()); - EXPECT_EQ("", handler_->StanzaActivity()); - - input = "<iq type='result' id='1'/>"; - engine()->HandleInput(input.c_str(), input.length()); - - EXPECT_EQ("[OPEN]", handler_->SessionActivity()); - EXPECT_EQ("", handler_->StanzaActivity()); - EXPECT_EQ(Jid("david@my-server/test"), engine()->FullJid()); -} - -// TestSuccessfulLogin() -// This function simply tests to see if a login works. This includes -// encryption and authentication -TEST_F(XmppEngineTest, TestSuccessfulLoginAndDisconnect) { - RunLogin(); - engine()->Disconnect(); - EXPECT_EQ("</stream:stream>[CLOSED]", handler()->OutputActivity()); - EXPECT_EQ("[CLOSED]", handler()->SessionActivity()); - EXPECT_EQ("", handler()->StanzaActivity()); -} - -TEST_F(XmppEngineTest, TestSuccessfulLoginAndConnectionClosed) { - RunLogin(); - engine()->ConnectionClosed(0); - EXPECT_EQ("[CLOSED]", handler()->OutputActivity()); - EXPECT_EQ("[CLOSED][ERROR-CONNECTION-CLOSED]", handler()->SessionActivity()); - EXPECT_EQ("", handler()->StanzaActivity()); -} - - -// TestNotXmpp() -// This tests the error case when connecting to a non XMPP service -TEST_F(XmppEngineTest, TestNotXmpp) { - // Connect - engine()->Connect(); - EXPECT_EQ("<stream:stream to=\"my-server\" xml:lang=\"*\" version=\"1.0\" " - "xmlns:stream=\"http://etherx.jabber.org/streams\" " - "xmlns=\"jabber:client\">\r\n", handler()->OutputActivity()); - - // Send garbage response (courtesy of apache) - std::string input = "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">"; - engine()->HandleInput(input.c_str(), input.length()); - - EXPECT_EQ("[CLOSED]", handler()->OutputActivity()); - EXPECT_EQ("[OPENING][CLOSED][ERROR-XML]", handler()->SessionActivity()); - EXPECT_EQ("", handler()->StanzaActivity()); -} - -// TestPassthrough() -// This tests that arbitrary stanzas can be passed to the server through -// the engine. -TEST_F(XmppEngineTest, TestPassthrough) { - // Queue up an app stanza - XmlElement application_stanza(QName("test", "app-stanza")); - application_stanza.AddText("this-is-a-test"); - engine()->SendStanza(&application_stanza); - - // Do the whole login handshake - RunLogin(); - - EXPECT_EQ("<test:app-stanza xmlns:test=\"test\">this-is-a-test" - "</test:app-stanza>", handler()->OutputActivity()); - - // do another stanza - XmlElement roster_get(QN_IQ); - roster_get.AddAttr(QN_TYPE, "get"); - roster_get.AddAttr(QN_ID, engine()->NextId()); - roster_get.AddElement(new XmlElement(QN_ROSTER_QUERY, true)); - engine()->SendStanza(&roster_get); - EXPECT_EQ("<iq type=\"get\" id=\"2\"><query xmlns=\"jabber:iq:roster\"/>" - "</iq>", handler()->OutputActivity()); - - // now say the server ends the stream - engine()->HandleInput("</stream:stream>", 16); - EXPECT_EQ("[CLOSED][ERROR-DOCUMENT-CLOSED]", handler()->SessionActivity()); - EXPECT_EQ("[CLOSED]", handler()->OutputActivity()); - EXPECT_EQ("", handler()->StanzaActivity()); -} - -// TestIqCallback() -// This tests the routing of Iq stanzas and responses. -TEST_F(XmppEngineTest, TestIqCallback) { - XmppEngineTestIqHandler iq_response; - XmppIqCookie cookie; - - // Do the whole login handshake - RunLogin(); - - // Build an iq request - XmlElement roster_get(QN_IQ); - roster_get.AddAttr(QN_TYPE, "get"); - roster_get.AddAttr(QN_ID, engine()->NextId()); - roster_get.AddElement(new XmlElement(QN_ROSTER_QUERY, true)); - engine()->SendIq(&roster_get, &iq_response, &cookie); - EXPECT_EQ("<iq type=\"get\" id=\"2\"><query xmlns=\"jabber:iq:roster\"/>" - "</iq>", handler()->OutputActivity()); - EXPECT_EQ("", handler()->SessionActivity()); - EXPECT_EQ("", handler()->StanzaActivity()); - EXPECT_EQ("", iq_response.IqResponseActivity()); - - // now say the server responds to the iq - std::string input = "<iq type='result' id='2'>" - "<query xmlns='jabber:iq:roster'><item>foo</item>" - "</query></iq>"; - engine()->HandleInput(input.c_str(), input.length()); - EXPECT_EQ("", handler()->OutputActivity()); - EXPECT_EQ("", handler()->SessionActivity()); - EXPECT_EQ("", handler()->StanzaActivity()); - EXPECT_EQ("<cli:iq type=\"result\" id=\"2\" xmlns:cli=\"jabber:client\">" - "<query xmlns=\"jabber:iq:roster\"><item>foo</item></query>" - "</cli:iq>", iq_response.IqResponseActivity()); - - EXPECT_EQ(XMPP_RETURN_BADARGUMENT, engine()->RemoveIqHandler(cookie, NULL)); - - // Do it again with another id to test cancel - roster_get.SetAttr(QN_ID, engine()->NextId()); - engine()->SendIq(&roster_get, &iq_response, &cookie); - EXPECT_EQ("<iq type=\"get\" id=\"3\"><query xmlns=\"jabber:iq:roster\"/>" - "</iq>", handler()->OutputActivity()); - EXPECT_EQ("", handler()->SessionActivity()); - EXPECT_EQ("", handler()->StanzaActivity()); - EXPECT_EQ("", iq_response.IqResponseActivity()); - - // cancel the handler this time - EXPECT_EQ(XMPP_RETURN_OK, engine()->RemoveIqHandler(cookie, NULL)); - - // now say the server responds to the iq: the iq handler should not get it. - input = "<iq type='result' id='3'><query xmlns='jabber:iq:roster'><item>bar" - "</item></query></iq>"; - engine()->HandleInput(input.c_str(), input.length()); - EXPECT_EQ("<cli:iq type=\"result\" id=\"3\" xmlns:cli=\"jabber:client\">" - "<query xmlns=\"jabber:iq:roster\"><item>bar</item></query>" - "</cli:iq>", handler()->StanzaActivity()); - EXPECT_EQ("", iq_response.IqResponseActivity()); - EXPECT_EQ("", handler()->OutputActivity()); - EXPECT_EQ("", handler()->SessionActivity()); -} diff --git a/talk/xmpp/xmppengineimpl.cc b/talk/xmpp/xmppengineimpl.cc deleted file mode 100644 index 98d89e226..000000000 --- a/talk/xmpp/xmppengineimpl.cc +++ /dev/null @@ -1,463 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "webrtc/libjingle/xmpp/xmppengineimpl.h" - -#include <algorithm> -#include <sstream> -#include <vector> - -#include "webrtc/libjingle/xmllite/xmlelement.h" -#include "webrtc/libjingle/xmllite/xmlprinter.h" -#include "webrtc/libjingle/xmpp/constants.h" -#include "webrtc/libjingle/xmpp/saslhandler.h" -#include "webrtc/libjingle/xmpp/xmpplogintask.h" -#include "webrtc/base/common.h" - -namespace buzz { - -XmppEngine* XmppEngine::Create() { - return new XmppEngineImpl(); -} - - -XmppEngineImpl::XmppEngineImpl() - : stanza_parse_handler_(this), - stanza_parser_(&stanza_parse_handler_), - engine_entered_(0), - password_(), - requested_resource_(STR_EMPTY), - tls_option_(buzz::TLS_REQUIRED), - login_task_(new XmppLoginTask(this)), - next_id_(0), - state_(STATE_START), - encrypted_(false), - error_code_(ERROR_NONE), - subcode_(0), - stream_error_(), - raised_reset_(false), - output_handler_(NULL), - session_handler_(NULL), - iq_entries_(new IqEntryVector()), - sasl_handler_(), - output_(new std::stringstream()) { - for (int i = 0; i < HL_COUNT; i+= 1) { - stanza_handlers_[i].reset(new StanzaHandlerVector()); - } - - // Add XMPP namespaces to XML namespaces stack. - xmlns_stack_.AddXmlns("stream", "http://etherx.jabber.org/streams"); - xmlns_stack_.AddXmlns("", "jabber:client"); -} - -XmppEngineImpl::~XmppEngineImpl() { - DeleteIqCookies(); -} - -XmppReturnStatus XmppEngineImpl::SetOutputHandler( - XmppOutputHandler* output_handler) { - if (state_ != STATE_START) - return XMPP_RETURN_BADSTATE; - - output_handler_ = output_handler; - - return XMPP_RETURN_OK; -} - -XmppReturnStatus XmppEngineImpl::SetSessionHandler( - XmppSessionHandler* session_handler) { - if (state_ != STATE_START) - return XMPP_RETURN_BADSTATE; - - session_handler_ = session_handler; - - return XMPP_RETURN_OK; -} - -XmppReturnStatus XmppEngineImpl::HandleInput( - const char* bytes, size_t len) { - if (state_ < STATE_OPENING || state_ > STATE_OPEN) - return XMPP_RETURN_BADSTATE; - - EnterExit ee(this); - - // TODO: The return value of the xml parser is not checked. - stanza_parser_.Parse(bytes, len, false); - - return XMPP_RETURN_OK; -} - -XmppReturnStatus XmppEngineImpl::ConnectionClosed(int subcode) { - if (state_ != STATE_CLOSED) { - EnterExit ee(this); - // If told that connection closed and not already closed, - // then connection was unpexectedly dropped. - if (subcode) { - SignalError(ERROR_SOCKET, subcode); - } else { - SignalError(ERROR_CONNECTION_CLOSED, 0); // no subcode - } - } - return XMPP_RETURN_OK; -} - -XmppReturnStatus XmppEngineImpl::SetTls(TlsOptions use_tls) { - if (state_ != STATE_START) - return XMPP_RETURN_BADSTATE; - tls_option_ = use_tls; - return XMPP_RETURN_OK; -} - -XmppReturnStatus XmppEngineImpl::SetTlsServer( - const std::string& tls_server_hostname, - const std::string& tls_server_domain) { - if (state_ != STATE_START) - return XMPP_RETURN_BADSTATE; - - tls_server_hostname_ = tls_server_hostname; - tls_server_domain_= tls_server_domain; - - return XMPP_RETURN_OK; -} - -TlsOptions XmppEngineImpl::GetTls() { - return tls_option_; -} - -XmppReturnStatus XmppEngineImpl::SetUser(const Jid& jid) { - if (state_ != STATE_START) - return XMPP_RETURN_BADSTATE; - - user_jid_ = jid; - - return XMPP_RETURN_OK; -} - -const Jid& XmppEngineImpl::GetUser() { - return user_jid_; -} - -XmppReturnStatus XmppEngineImpl::SetSaslHandler(SaslHandler* sasl_handler) { - if (state_ != STATE_START) - return XMPP_RETURN_BADSTATE; - - sasl_handler_.reset(sasl_handler); - return XMPP_RETURN_OK; -} - -XmppReturnStatus XmppEngineImpl::SetRequestedResource( - const std::string& resource) { - if (state_ != STATE_START) - return XMPP_RETURN_BADSTATE; - - requested_resource_ = resource; - - return XMPP_RETURN_OK; -} - -const std::string& XmppEngineImpl::GetRequestedResource() { - return requested_resource_; -} - -XmppReturnStatus XmppEngineImpl::AddStanzaHandler( - XmppStanzaHandler* stanza_handler, - XmppEngine::HandlerLevel level) { - if (state_ == STATE_CLOSED) - return XMPP_RETURN_BADSTATE; - - stanza_handlers_[level]->push_back(stanza_handler); - - return XMPP_RETURN_OK; -} - -XmppReturnStatus XmppEngineImpl::RemoveStanzaHandler( - XmppStanzaHandler* stanza_handler) { - bool found = false; - - for (int level = 0; level < HL_COUNT; level += 1) { - StanzaHandlerVector::iterator new_end = - std::remove(stanza_handlers_[level]->begin(), - stanza_handlers_[level]->end(), - stanza_handler); - - if (new_end != stanza_handlers_[level]->end()) { - stanza_handlers_[level]->erase(new_end, stanza_handlers_[level]->end()); - found = true; - } - } - - if (!found) - return XMPP_RETURN_BADARGUMENT; - - return XMPP_RETURN_OK; -} - -XmppReturnStatus XmppEngineImpl::Connect() { - if (state_ != STATE_START) - return XMPP_RETURN_BADSTATE; - - EnterExit ee(this); - - // get the login task started - state_ = STATE_OPENING; - if (login_task_) { - login_task_->IncomingStanza(NULL, false); - if (login_task_->IsDone()) - login_task_.reset(); - } - - return XMPP_RETURN_OK; -} - -XmppReturnStatus XmppEngineImpl::SendStanza(const XmlElement* element) { - if (state_ == STATE_CLOSED) - return XMPP_RETURN_BADSTATE; - - EnterExit ee(this); - - if (login_task_) { - // still handshaking - then outbound stanzas are queued - login_task_->OutgoingStanza(element); - } else { - // handshake done - send straight through - InternalSendStanza(element); - } - - return XMPP_RETURN_OK; -} - -XmppReturnStatus XmppEngineImpl::SendRaw(const std::string& text) { - if (state_ == STATE_CLOSED || login_task_) - return XMPP_RETURN_BADSTATE; - - EnterExit ee(this); - - (*output_) << text; - - return XMPP_RETURN_OK; -} - -std::string XmppEngineImpl::NextId() { - std::stringstream ss; - ss << next_id_++; - return ss.str(); -} - -XmppReturnStatus XmppEngineImpl::Disconnect() { - if (state_ != STATE_CLOSED) { - EnterExit ee(this); - if (state_ == STATE_OPEN) - *output_ << "</stream:stream>"; - state_ = STATE_CLOSED; - } - - return XMPP_RETURN_OK; -} - -void XmppEngineImpl::IncomingStart(const XmlElement* start) { - if (HasError() || raised_reset_) - return; - - if (login_task_) { - // start-stream should go to login task - login_task_->IncomingStanza(start, true); - if (login_task_->IsDone()) - login_task_.reset(); - } - else { - // if not logging in, it's an error to see a start - SignalError(ERROR_XML, 0); - } -} - -void XmppEngineImpl::IncomingStanza(const XmlElement* stanza) { - if (HasError() || raised_reset_) - return; - - if (stanza->Name() == QN_STREAM_ERROR) { - // Explicit XMPP stream error - SignalStreamError(stanza); - } else if (login_task_) { - // Handle login handshake - login_task_->IncomingStanza(stanza, false); - if (login_task_->IsDone()) - login_task_.reset(); - } else if (HandleIqResponse(stanza)) { - // iq is handled by above call - } else { - // give every "peek" handler a shot at all stanzas - for (size_t i = 0; i < stanza_handlers_[HL_PEEK]->size(); i += 1) { - (*stanza_handlers_[HL_PEEK])[i]->HandleStanza(stanza); - } - - // give other handlers a shot in precedence order, stopping after handled - for (int level = HL_SINGLE; level <= HL_ALL; level += 1) { - for (size_t i = 0; i < stanza_handlers_[level]->size(); i += 1) { - if ((*stanza_handlers_[level])[i]->HandleStanza(stanza)) - return; - } - } - - // If nobody wants to handle a stanza then send back an error. - // Only do this for IQ stanzas as messages should probably just be dropped - // and presence stanzas should certainly be dropped. - std::string type = stanza->Attr(QN_TYPE); - if (stanza->Name() == QN_IQ && - !(type == "error" || type == "result")) { - SendStanzaError(stanza, XSE_FEATURE_NOT_IMPLEMENTED, STR_EMPTY); - } - } -} - -void XmppEngineImpl::IncomingEnd(bool isError) { - if (HasError() || raised_reset_) - return; - - SignalError(isError ? ERROR_XML : ERROR_DOCUMENT_CLOSED, 0); -} - -void XmppEngineImpl::InternalSendStart(const std::string& to) { - std::string hostname = tls_server_hostname_; - if (hostname.empty()) - hostname = to; - - // If not language is specified, the spec says use * - std::string lang = lang_; - if (lang.length() == 0) - lang = "*"; - - // send stream-beginning - // note, we put a \r\n at tne end fo the first line to cause non-XMPP - // line-oriented servers (e.g., Apache) to reveal themselves more quickly. - *output_ << "<stream:stream to=\"" << hostname << "\" " - << "xml:lang=\"" << lang << "\" " - << "version=\"1.0\" " - << "xmlns:stream=\"http://etherx.jabber.org/streams\" " - << "xmlns=\"jabber:client\">\r\n"; -} - -void XmppEngineImpl::InternalSendStanza(const XmlElement* element) { - // It should really never be necessary to set a FROM attribute on a stanza. - // It is implied by the bind on the stream and if you get it wrong - // (by flipping from/to on a message?) the server will close the stream. - ASSERT(!element->HasAttr(QN_FROM)); - - XmlPrinter::PrintXml(output_.get(), element, &xmlns_stack_); -} - -std::string XmppEngineImpl::ChooseBestSaslMechanism( - const std::vector<std::string>& mechanisms, bool encrypted) { - return sasl_handler_->ChooseBestSaslMechanism(mechanisms, encrypted); -} - -SaslMechanism* XmppEngineImpl::GetSaslMechanism(const std::string& name) { - return sasl_handler_->CreateSaslMechanism(name); -} - -void XmppEngineImpl::SignalBound(const Jid& fullJid) { - if (state_ == STATE_OPENING) { - bound_jid_ = fullJid; - state_ = STATE_OPEN; - } -} - -void XmppEngineImpl::SignalStreamError(const XmlElement* stream_error) { - if (state_ != STATE_CLOSED) { - stream_error_.reset(new XmlElement(*stream_error)); - SignalError(ERROR_STREAM, 0); - } -} - -void XmppEngineImpl::SignalError(Error error_code, int sub_code) { - if (state_ != STATE_CLOSED) { - error_code_ = error_code; - subcode_ = sub_code; - state_ = STATE_CLOSED; - } -} - -bool XmppEngineImpl::HasError() { - return error_code_ != ERROR_NONE; -} - -void XmppEngineImpl::StartTls(const std::string& domain) { - if (output_handler_) { - // As substitute for the real (login jid's) domain, we permit - // verifying a tls_server_domain_ instead, if one was passed. - // This allows us to avoid running a proxy that needs to handle - // valuable certificates. - output_handler_->StartTls( - tls_server_domain_.empty() ? domain : tls_server_domain_); - encrypted_ = true; - } -} - -XmppEngineImpl::EnterExit::EnterExit(XmppEngineImpl* engine) - : engine_(engine), - state_(engine->state_) { - engine->engine_entered_ += 1; -} - -XmppEngineImpl::EnterExit::~EnterExit() { - XmppEngineImpl* engine = engine_; - - engine->engine_entered_ -= 1; - - bool closing = (engine->state_ != state_ && - engine->state_ == STATE_CLOSED); - bool flushing = closing || (engine->engine_entered_ == 0); - - if (engine->output_handler_ && flushing) { - std::string output = engine->output_->str(); - if (output.length() > 0) - engine->output_handler_->WriteOutput(output.c_str(), output.length()); - engine->output_->str(""); - - if (closing) { - engine->output_handler_->CloseConnection(); - engine->output_handler_ = 0; - } - } - - if (engine->engine_entered_) - return; - - if (engine->raised_reset_) { - engine->stanza_parser_.Reset(); - engine->raised_reset_ = false; - } - - if (engine->session_handler_) { - if (engine->state_ != state_) - engine->session_handler_->OnStateChange(engine->state_); - // Note: Handling of OnStateChange(CLOSED) should allow for the - // deletion of the engine, so no members should be accessed - // after this line. - } -} - -} // namespace buzz diff --git a/talk/xmpp/xmppengineimpl.h b/talk/xmpp/xmppengineimpl.h deleted file mode 100644 index a3da795ab..000000000 --- a/talk/xmpp/xmppengineimpl.h +++ /dev/null @@ -1,282 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef TALK_XMPP_XMPPENGINEIMPL_H_ -#define TALK_XMPP_XMPPENGINEIMPL_H_ - -#include <sstream> -#include <vector> -#include "webrtc/libjingle/xmpp/xmppengine.h" -#include "webrtc/libjingle/xmpp/xmppstanzaparser.h" - -namespace buzz { - -class XmppLoginTask; -class XmppEngine; -class XmppIqEntry; -class SaslHandler; -class SaslMechanism; - -//! The XMPP connection engine. -//! This engine implements the client side of the 'core' XMPP protocol. -//! To use it, register an XmppOutputHandler to handle socket output -//! and pass socket input to HandleInput. Then application code can -//! set up the connection with a user, password, and other settings, -//! and then call Connect() to initiate the connection. -//! An application can listen for events and receive stanzas by -//! registering an XmppStanzaHandler via AddStanzaHandler(). -class XmppEngineImpl : public XmppEngine { - public: - XmppEngineImpl(); - virtual ~XmppEngineImpl(); - - // SOCKET INPUT AND OUTPUT ------------------------------------------------ - - //! Registers the handler for socket output - virtual XmppReturnStatus SetOutputHandler(XmppOutputHandler *pxoh); - - //! Provides socket input to the engine - virtual XmppReturnStatus HandleInput(const char* bytes, size_t len); - - //! Advises the engine that the socket has closed - virtual XmppReturnStatus ConnectionClosed(int subcode); - - // SESSION SETUP --------------------------------------------------------- - - //! Indicates the (bare) JID for the user to use. - virtual XmppReturnStatus SetUser(const Jid& jid); - - //! Get the login (bare) JID. - virtual const Jid& GetUser(); - - //! Indicates the autentication to use. Takes ownership of the object. - virtual XmppReturnStatus SetSaslHandler(SaslHandler* sasl_handler); - - //! Sets whether TLS will be used within the connection (default true). - virtual XmppReturnStatus SetTls(TlsOptions use_tls); - - //! Sets an alternate domain from which we allows TLS certificates. - //! This is for use in the case where a we want to allow a proxy to - //! serve up its own certificate rather than one owned by the underlying - //! domain. - virtual XmppReturnStatus SetTlsServer(const std::string& proxy_hostname, - const std::string& proxy_domain); - - //! Gets whether TLS will be used within the connection. - virtual TlsOptions GetTls(); - - //! Sets the request resource name, if any (optional). - //! Note that the resource name may be overridden by the server; after - //! binding, the actual resource name is available as part of FullJid(). - virtual XmppReturnStatus SetRequestedResource(const std::string& resource); - - //! Gets the request resource name. - virtual const std::string& GetRequestedResource(); - - //! Sets language - virtual void SetLanguage(const std::string& lang) { - lang_ = lang; - } - - // SESSION MANAGEMENT --------------------------------------------------- - - //! Set callback for state changes. - virtual XmppReturnStatus SetSessionHandler(XmppSessionHandler* handler); - - //! Initiates the XMPP connection. - //! After supplying connection settings, call this once to initiate, - //! (optionally) encrypt, authenticate, and bind the connection. - virtual XmppReturnStatus Connect(); - - //! The current engine state. - virtual State GetState() { return state_; } - - //! Returns true if the connection is encrypted (under TLS) - virtual bool IsEncrypted() { return encrypted_; } - - //! The error code. - //! Consult this after XmppOutputHandler.OnClose(). - virtual Error GetError(int *subcode) { - if (subcode) { - *subcode = subcode_; - } - return error_code_; - } - - //! The stream:error stanza, when the error is XmppEngine::ERROR_STREAM. - //! Notice the stanza returned is owned by the XmppEngine and - //! is deleted when the engine is destroyed. - virtual const XmlElement* GetStreamError() { return stream_error_.get(); } - - //! Closes down the connection. - //! Sends CloseConnection to output, and disconnects and registered - //! session handlers. After Disconnect completes, it is guaranteed - //! that no further callbacks will be made. - virtual XmppReturnStatus Disconnect(); - - // APPLICATION USE ------------------------------------------------------- - - //! Adds a listener for session events. - //! Stanza delivery is chained to session handlers; the first to - //! return 'true' is the last to get each stanza. - virtual XmppReturnStatus AddStanzaHandler(XmppStanzaHandler* handler, - XmppEngine::HandlerLevel level); - - //! Removes a listener for session events. - virtual XmppReturnStatus RemoveStanzaHandler(XmppStanzaHandler* handler); - - //! Sends a stanza to the server. - virtual XmppReturnStatus SendStanza(const XmlElement* stanza); - - //! Sends raw text to the server - virtual XmppReturnStatus SendRaw(const std::string& text); - - //! Sends an iq to the server, and registers a callback for the result. - //! Returns the cookie passed to the result handler. - virtual XmppReturnStatus SendIq(const XmlElement* stanza, - XmppIqHandler* iq_handler, - XmppIqCookie* cookie); - - //! Unregisters an iq callback handler given its cookie. - //! No callback will come to this handler after it's unregistered. - virtual XmppReturnStatus RemoveIqHandler(XmppIqCookie cookie, - XmppIqHandler** iq_handler); - - //! Forms and sends an error in response to the given stanza. - //! Swaps to and from, sets type to "error", and adds error information - //! based on the passed code. Text is optional and may be STR_EMPTY. - virtual XmppReturnStatus SendStanzaError(const XmlElement* pelOriginal, - XmppStanzaError code, - const std::string& text); - - //! The fullly bound JID. - //! This JID is only valid after binding has succeeded. If the value - //! is JID_NULL, the binding has not succeeded. - virtual const Jid& FullJid() { return bound_jid_; } - - //! The next unused iq id for this connection. - //! Call this when building iq stanzas, to ensure that each iq - //! gets its own unique id. - virtual std::string NextId(); - - private: - friend class XmppLoginTask; - friend class XmppIqEntry; - - void IncomingStanza(const XmlElement *stanza); - void IncomingStart(const XmlElement *stanza); - void IncomingEnd(bool isError); - - void InternalSendStart(const std::string& domainName); - void InternalSendStanza(const XmlElement* stanza); - std::string ChooseBestSaslMechanism( - const std::vector<std::string>& mechanisms, bool encrypted); - SaslMechanism* GetSaslMechanism(const std::string& name); - void SignalBound(const Jid& fullJid); - void SignalStreamError(const XmlElement* streamError); - void SignalError(Error errorCode, int subCode); - bool HasError(); - void DeleteIqCookies(); - bool HandleIqResponse(const XmlElement* element); - void StartTls(const std::string& domain); - void RaiseReset() { raised_reset_ = true; } - - class StanzaParseHandler : public XmppStanzaParseHandler { - public: - StanzaParseHandler(XmppEngineImpl* outer) : outer_(outer) {} - virtual ~StanzaParseHandler() {} - - virtual void StartStream(const XmlElement* stream) { - outer_->IncomingStart(stream); - } - virtual void Stanza(const XmlElement* stanza) { - outer_->IncomingStanza(stanza); - } - virtual void EndStream() { - outer_->IncomingEnd(false); - } - virtual void XmlError() { - outer_->IncomingEnd(true); - } - - private: - XmppEngineImpl* const outer_; - }; - - class EnterExit { - public: - EnterExit(XmppEngineImpl* engine); - ~EnterExit(); - private: - XmppEngineImpl* engine_; - State state_; - }; - - friend class StanzaParseHandler; - friend class EnterExit; - - StanzaParseHandler stanza_parse_handler_; - XmppStanzaParser stanza_parser_; - - // state - int engine_entered_; - Jid user_jid_; - std::string password_; - std::string requested_resource_; - TlsOptions tls_option_; - std::string tls_server_hostname_; - std::string tls_server_domain_; - rtc::scoped_ptr<XmppLoginTask> login_task_; - std::string lang_; - - int next_id_; - Jid bound_jid_; - State state_; - bool encrypted_; - Error error_code_; - int subcode_; - rtc::scoped_ptr<XmlElement> stream_error_; - bool raised_reset_; - XmppOutputHandler* output_handler_; - XmppSessionHandler* session_handler_; - - XmlnsStack xmlns_stack_; - - typedef std::vector<XmppStanzaHandler*> StanzaHandlerVector; - rtc::scoped_ptr<StanzaHandlerVector> stanza_handlers_[HL_COUNT]; - - typedef std::vector<XmppIqEntry*> IqEntryVector; - rtc::scoped_ptr<IqEntryVector> iq_entries_; - - rtc::scoped_ptr<SaslHandler> sasl_handler_; - - rtc::scoped_ptr<std::stringstream> output_; -}; - -} // namespace buzz - -#endif // TALK_XMPP_XMPPENGINEIMPL_H_ diff --git a/talk/xmpp/xmppengineimpl_iq.cc b/talk/xmpp/xmppengineimpl_iq.cc deleted file mode 100644 index d48f021b4..000000000 --- a/talk/xmpp/xmppengineimpl_iq.cc +++ /dev/null @@ -1,277 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <algorithm> -#include <vector> -#include "webrtc/libjingle/xmpp/constants.h" -#include "webrtc/libjingle/xmpp/xmppengineimpl.h" -#include "webrtc/base/common.h" - -namespace buzz { - -class XmppIqEntry { - XmppIqEntry(const std::string & id, const std::string & to, - XmppEngine * pxce, XmppIqHandler * iq_handler) : - id_(id), - to_(to), - engine_(pxce), - iq_handler_(iq_handler) { - } - -private: - friend class XmppEngineImpl; - - const std::string id_; - const std::string to_; - XmppEngine * const engine_; - XmppIqHandler * const iq_handler_; -}; - - -XmppReturnStatus -XmppEngineImpl::SendIq(const XmlElement * element, XmppIqHandler * iq_handler, - XmppIqCookie* cookie) { - if (state_ == STATE_CLOSED) - return XMPP_RETURN_BADSTATE; - if (NULL == iq_handler) - return XMPP_RETURN_BADARGUMENT; - if (!element || element->Name() != QN_IQ) - return XMPP_RETURN_BADARGUMENT; - - const std::string& type = element->Attr(QN_TYPE); - if (type != "get" && type != "set") - return XMPP_RETURN_BADARGUMENT; - - if (!element->HasAttr(QN_ID)) - return XMPP_RETURN_BADARGUMENT; - const std::string& id = element->Attr(QN_ID); - - XmppIqEntry * iq_entry = new XmppIqEntry(id, - element->Attr(QN_TO), - this, iq_handler); - iq_entries_->push_back(iq_entry); - SendStanza(element); - - if (cookie) - *cookie = iq_entry; - - return XMPP_RETURN_OK; -} - - -XmppReturnStatus -XmppEngineImpl::RemoveIqHandler(XmppIqCookie cookie, - XmppIqHandler ** iq_handler) { - - std::vector<XmppIqEntry*, std::allocator<XmppIqEntry*> >::iterator pos; - - pos = std::find(iq_entries_->begin(), - iq_entries_->end(), - reinterpret_cast<XmppIqEntry*>(cookie)); - - if (pos == iq_entries_->end()) - return XMPP_RETURN_BADARGUMENT; - - XmppIqEntry* entry = *pos; - iq_entries_->erase(pos); - if (iq_handler) - *iq_handler = entry->iq_handler_; - delete entry; - - return XMPP_RETURN_OK; -} - -void -XmppEngineImpl::DeleteIqCookies() { - for (size_t i = 0; i < iq_entries_->size(); i += 1) { - XmppIqEntry * iq_entry_ = (*iq_entries_)[i]; - (*iq_entries_)[i] = NULL; - delete iq_entry_; - } - iq_entries_->clear(); -} - -static void -AecImpl(XmlElement * error_element, const QName & name, - const char * type, const char * code) { - error_element->AddElement(new XmlElement(QN_ERROR)); - error_element->AddAttr(QN_CODE, code, 1); - error_element->AddAttr(QN_TYPE, type, 1); - error_element->AddElement(new XmlElement(name, true), 1); -} - - -static void -AddErrorCode(XmlElement * error_element, XmppStanzaError code) { - switch (code) { - case XSE_BAD_REQUEST: - AecImpl(error_element, QN_STANZA_BAD_REQUEST, "modify", "400"); - break; - case XSE_CONFLICT: - AecImpl(error_element, QN_STANZA_CONFLICT, "cancel", "409"); - break; - case XSE_FEATURE_NOT_IMPLEMENTED: - AecImpl(error_element, QN_STANZA_FEATURE_NOT_IMPLEMENTED, - "cancel", "501"); - break; - case XSE_FORBIDDEN: - AecImpl(error_element, QN_STANZA_FORBIDDEN, "auth", "403"); - break; - case XSE_GONE: - AecImpl(error_element, QN_STANZA_GONE, "modify", "302"); - break; - case XSE_INTERNAL_SERVER_ERROR: - AecImpl(error_element, QN_STANZA_INTERNAL_SERVER_ERROR, "wait", "500"); - break; - case XSE_ITEM_NOT_FOUND: - AecImpl(error_element, QN_STANZA_ITEM_NOT_FOUND, "cancel", "404"); - break; - case XSE_JID_MALFORMED: - AecImpl(error_element, QN_STANZA_JID_MALFORMED, "modify", "400"); - break; - case XSE_NOT_ACCEPTABLE: - AecImpl(error_element, QN_STANZA_NOT_ACCEPTABLE, "cancel", "406"); - break; - case XSE_NOT_ALLOWED: - AecImpl(error_element, QN_STANZA_NOT_ALLOWED, "cancel", "405"); - break; - case XSE_PAYMENT_REQUIRED: - AecImpl(error_element, QN_STANZA_PAYMENT_REQUIRED, "auth", "402"); - break; - case XSE_RECIPIENT_UNAVAILABLE: - AecImpl(error_element, QN_STANZA_RECIPIENT_UNAVAILABLE, "wait", "404"); - break; - case XSE_REDIRECT: - AecImpl(error_element, QN_STANZA_REDIRECT, "modify", "302"); - break; - case XSE_REGISTRATION_REQUIRED: - AecImpl(error_element, QN_STANZA_REGISTRATION_REQUIRED, "auth", "407"); - break; - case XSE_SERVER_NOT_FOUND: - AecImpl(error_element, QN_STANZA_REMOTE_SERVER_NOT_FOUND, - "cancel", "404"); - break; - case XSE_SERVER_TIMEOUT: - AecImpl(error_element, QN_STANZA_REMOTE_SERVER_TIMEOUT, "wait", "502"); - break; - case XSE_RESOURCE_CONSTRAINT: - AecImpl(error_element, QN_STANZA_RESOURCE_CONSTRAINT, "wait", "500"); - break; - case XSE_SERVICE_UNAVAILABLE: - AecImpl(error_element, QN_STANZA_SERVICE_UNAVAILABLE, "cancel", "503"); - break; - case XSE_SUBSCRIPTION_REQUIRED: - AecImpl(error_element, QN_STANZA_SUBSCRIPTION_REQUIRED, "auth", "407"); - break; - case XSE_UNDEFINED_CONDITION: - AecImpl(error_element, QN_STANZA_UNDEFINED_CONDITION, "wait", "500"); - break; - case XSE_UNEXPECTED_REQUEST: - AecImpl(error_element, QN_STANZA_UNEXPECTED_REQUEST, "wait", "400"); - break; - } -} - - -XmppReturnStatus -XmppEngineImpl::SendStanzaError(const XmlElement * element_original, - XmppStanzaError code, - const std::string & text) { - - if (state_ == STATE_CLOSED) - return XMPP_RETURN_BADSTATE; - - XmlElement error_element(element_original->Name()); - error_element.AddAttr(QN_TYPE, "error"); - - // copy attrs, copy 'from' to 'to' and strip 'from' - for (const XmlAttr * attribute = element_original->FirstAttr(); - attribute; attribute = attribute->NextAttr()) { - QName name = attribute->Name(); - if (name == QN_TO) - continue; // no need to put a from attr. Server will stamp stanza - else if (name == QN_FROM) - name = QN_TO; - else if (name == QN_TYPE) - continue; - error_element.AddAttr(name, attribute->Value()); - } - - // copy children - for (const XmlChild * child = element_original->FirstChild(); - child; - child = child->NextChild()) { - if (child->IsText()) { - error_element.AddText(child->AsText()->Text()); - } else { - error_element.AddElement(new XmlElement(*(child->AsElement()))); - } - } - - // add error information - AddErrorCode(&error_element, code); - if (text != STR_EMPTY) { - XmlElement * text_element = new XmlElement(QN_STANZA_TEXT, true); - text_element->AddText(text); - error_element.AddElement(text_element); - } - - SendStanza(&error_element); - - return XMPP_RETURN_OK; -} - - -bool -XmppEngineImpl::HandleIqResponse(const XmlElement * element) { - if (iq_entries_->empty()) - return false; - if (element->Name() != QN_IQ) - return false; - std::string type = element->Attr(QN_TYPE); - if (type != "result" && type != "error") - return false; - if (!element->HasAttr(QN_ID)) - return false; - std::string id = element->Attr(QN_ID); - std::string from = element->Attr(QN_FROM); - - for (std::vector<XmppIqEntry *>::iterator it = iq_entries_->begin(); - it != iq_entries_->end(); it += 1) { - XmppIqEntry * iq_entry = *it; - if (iq_entry->id_ == id && iq_entry->to_ == from) { - iq_entries_->erase(it); - iq_entry->iq_handler_->IqResponse(iq_entry, element); - delete iq_entry; - return true; - } - } - - return false; -} - -} diff --git a/talk/xmpp/xmpplogintask.cc b/talk/xmpp/xmpplogintask.cc deleted file mode 100644 index 7788c0d60..000000000 --- a/talk/xmpp/xmpplogintask.cc +++ /dev/null @@ -1,397 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "webrtc/libjingle/xmpp/xmpplogintask.h" - -#include <string> -#include <vector> - -#include "webrtc/libjingle/xmllite/xmlelement.h" -#include "webrtc/libjingle/xmpp/constants.h" -#include "webrtc/libjingle/xmpp/jid.h" -#include "webrtc/libjingle/xmpp/saslmechanism.h" -#include "webrtc/libjingle/xmpp/xmppengineimpl.h" -#include "webrtc/base/base64.h" -#include "webrtc/base/common.h" - -using rtc::ConstantLabel; - -namespace buzz { - -#ifdef _DEBUG -const ConstantLabel XmppLoginTask::LOGINTASK_STATES[] = { - KLABEL(LOGINSTATE_INIT), - KLABEL(LOGINSTATE_STREAMSTART_SENT), - KLABEL(LOGINSTATE_STARTED_XMPP), - KLABEL(LOGINSTATE_TLS_INIT), - KLABEL(LOGINSTATE_AUTH_INIT), - KLABEL(LOGINSTATE_BIND_INIT), - KLABEL(LOGINSTATE_TLS_REQUESTED), - KLABEL(LOGINSTATE_SASL_RUNNING), - KLABEL(LOGINSTATE_BIND_REQUESTED), - KLABEL(LOGINSTATE_SESSION_REQUESTED), - KLABEL(LOGINSTATE_DONE), - LASTLABEL -}; -#endif // _DEBUG -XmppLoginTask::XmppLoginTask(XmppEngineImpl * pctx) : - pctx_(pctx), - authNeeded_(true), - allowNonGoogleLogin_(true), - state_(LOGINSTATE_INIT), - pelStanza_(NULL), - isStart_(false), - iqId_(STR_EMPTY), - pelFeatures_(), - fullJid_(STR_EMPTY), - streamId_(STR_EMPTY), - pvecQueuedStanzas_(new std::vector<XmlElement *>()), - sasl_mech_() { -} - -XmppLoginTask::~XmppLoginTask() { - for (size_t i = 0; i < pvecQueuedStanzas_->size(); i += 1) - delete (*pvecQueuedStanzas_)[i]; -} - -void -XmppLoginTask::IncomingStanza(const XmlElement *element, bool isStart) { - pelStanza_ = element; - isStart_ = isStart; - Advance(); - pelStanza_ = NULL; - isStart_ = false; -} - -const XmlElement * -XmppLoginTask::NextStanza() { - const XmlElement * result = pelStanza_; - pelStanza_ = NULL; - return result; -} - -bool -XmppLoginTask::Advance() { - - for (;;) { - - const XmlElement * element = NULL; - -#if _DEBUG - LOG(LS_VERBOSE) << "XmppLoginTask::Advance - " - << rtc::ErrorName(state_, LOGINTASK_STATES); -#endif // _DEBUG - - switch (state_) { - - case LOGINSTATE_INIT: { - pctx_->RaiseReset(); - pelFeatures_.reset(NULL); - - // The proper domain to verify against is the real underlying - // domain - i.e., the domain that owns the JID. Our XmppEngineImpl - // also allows matching against a proxy domain instead, if it is told - // to do so - see the implementation of XmppEngineImpl::StartTls and - // XmppEngine::SetTlsServerDomain to see how you can use that feature - pctx_->InternalSendStart(pctx_->user_jid_.domain()); - state_ = LOGINSTATE_STREAMSTART_SENT; - break; - } - - case LOGINSTATE_STREAMSTART_SENT: { - if (NULL == (element = NextStanza())) - return true; - - if (!isStart_ || !HandleStartStream(element)) - return Failure(XmppEngine::ERROR_VERSION); - - state_ = LOGINSTATE_STARTED_XMPP; - return true; - } - - case LOGINSTATE_STARTED_XMPP: { - if (NULL == (element = NextStanza())) - return true; - - if (!HandleFeatures(element)) - return Failure(XmppEngine::ERROR_VERSION); - - bool tls_present = (GetFeature(QN_TLS_STARTTLS) != NULL); - // Error if TLS required but not present. - if (pctx_->tls_option_ == buzz::TLS_REQUIRED && !tls_present) { - return Failure(XmppEngine::ERROR_TLS); - } - // Use TLS if required or enabled, and also available - if ((pctx_->tls_option_ == buzz::TLS_REQUIRED || - pctx_->tls_option_ == buzz::TLS_ENABLED) && tls_present) { - state_ = LOGINSTATE_TLS_INIT; - continue; - } - - if (authNeeded_) { - state_ = LOGINSTATE_AUTH_INIT; - continue; - } - - state_ = LOGINSTATE_BIND_INIT; - continue; - } - - case LOGINSTATE_TLS_INIT: { - const XmlElement * pelTls = GetFeature(QN_TLS_STARTTLS); - if (!pelTls) - return Failure(XmppEngine::ERROR_TLS); - - XmlElement el(QN_TLS_STARTTLS, true); - pctx_->InternalSendStanza(&el); - state_ = LOGINSTATE_TLS_REQUESTED; - continue; - } - - case LOGINSTATE_TLS_REQUESTED: { - if (NULL == (element = NextStanza())) - return true; - if (element->Name() != QN_TLS_PROCEED) - return Failure(XmppEngine::ERROR_TLS); - - // The proper domain to verify against is the real underlying - // domain - i.e., the domain that owns the JID. Our XmppEngineImpl - // also allows matching against a proxy domain instead, if it is told - // to do so - see the implementation of XmppEngineImpl::StartTls and - // XmppEngine::SetTlsServerDomain to see how you can use that feature - pctx_->StartTls(pctx_->user_jid_.domain()); - pctx_->tls_option_ = buzz::TLS_ENABLED; - state_ = LOGINSTATE_INIT; - continue; - } - - case LOGINSTATE_AUTH_INIT: { - const XmlElement * pelSaslAuth = GetFeature(QN_SASL_MECHANISMS); - if (!pelSaslAuth) { - return Failure(XmppEngine::ERROR_AUTH); - } - - // Collect together the SASL auth mechanisms presented by the server - std::vector<std::string> mechanisms; - for (const XmlElement * pelMech = - pelSaslAuth->FirstNamed(QN_SASL_MECHANISM); - pelMech; - pelMech = pelMech->NextNamed(QN_SASL_MECHANISM)) { - - mechanisms.push_back(pelMech->BodyText()); - } - - // Given all the mechanisms, choose the best - std::string choice(pctx_->ChooseBestSaslMechanism(mechanisms, pctx_->IsEncrypted())); - if (choice.empty()) { - return Failure(XmppEngine::ERROR_AUTH); - } - - // No recognized auth mechanism - that's an error - sasl_mech_.reset(pctx_->GetSaslMechanism(choice)); - if (!sasl_mech_) { - return Failure(XmppEngine::ERROR_AUTH); - } - - // OK, let's start it. - XmlElement * auth = sasl_mech_->StartSaslAuth(); - if (auth == NULL) { - return Failure(XmppEngine::ERROR_AUTH); - } - if (allowNonGoogleLogin_) { - // Setting the following two attributes is required to support - // non-google ids. - - // Allow login with non-google id accounts. - auth->SetAttr(QN_GOOGLE_ALLOW_NON_GOOGLE_ID_XMPP_LOGIN, "true"); - - // Allow login with either the non-google id or the friendly email. - auth->SetAttr(QN_GOOGLE_AUTH_CLIENT_USES_FULL_BIND_RESULT, "true"); - } - - pctx_->InternalSendStanza(auth); - delete auth; - state_ = LOGINSTATE_SASL_RUNNING; - continue; - } - - case LOGINSTATE_SASL_RUNNING: { - if (NULL == (element = NextStanza())) - return true; - if (element->Name().Namespace() != NS_SASL) - return Failure(XmppEngine::ERROR_AUTH); - if (element->Name() == QN_SASL_CHALLENGE) { - XmlElement * response = sasl_mech_->HandleSaslChallenge(element); - if (response == NULL) { - return Failure(XmppEngine::ERROR_AUTH); - } - pctx_->InternalSendStanza(response); - delete response; - state_ = LOGINSTATE_SASL_RUNNING; - continue; - } - if (element->Name() != QN_SASL_SUCCESS) { - return Failure(XmppEngine::ERROR_UNAUTHORIZED); - } - - // Authenticated! - authNeeded_ = false; - state_ = LOGINSTATE_INIT; - continue; - } - - case LOGINSTATE_BIND_INIT: { - const XmlElement * pelBindFeature = GetFeature(QN_BIND_BIND); - const XmlElement * pelSessionFeature = GetFeature(QN_SESSION_SESSION); - if (!pelBindFeature || !pelSessionFeature) - return Failure(XmppEngine::ERROR_BIND); - - XmlElement iq(QN_IQ); - iq.AddAttr(QN_TYPE, "set"); - - iqId_ = pctx_->NextId(); - iq.AddAttr(QN_ID, iqId_); - iq.AddElement(new XmlElement(QN_BIND_BIND, true)); - - if (pctx_->requested_resource_ != STR_EMPTY) { - iq.AddElement(new XmlElement(QN_BIND_RESOURCE), 1); - iq.AddText(pctx_->requested_resource_, 2); - } - pctx_->InternalSendStanza(&iq); - state_ = LOGINSTATE_BIND_REQUESTED; - continue; - } - - case LOGINSTATE_BIND_REQUESTED: { - if (NULL == (element = NextStanza())) - return true; - - if (element->Name() != QN_IQ || element->Attr(QN_ID) != iqId_ || - element->Attr(QN_TYPE) == "get" || element->Attr(QN_TYPE) == "set") - return true; - - if (element->Attr(QN_TYPE) != "result" || element->FirstElement() == NULL || - element->FirstElement()->Name() != QN_BIND_BIND) - return Failure(XmppEngine::ERROR_BIND); - - fullJid_ = Jid(element->FirstElement()->TextNamed(QN_BIND_JID)); - if (!fullJid_.IsFull()) { - return Failure(XmppEngine::ERROR_BIND); - } - - // now request session - XmlElement iq(QN_IQ); - iq.AddAttr(QN_TYPE, "set"); - - iqId_ = pctx_->NextId(); - iq.AddAttr(QN_ID, iqId_); - iq.AddElement(new XmlElement(QN_SESSION_SESSION, true)); - pctx_->InternalSendStanza(&iq); - - state_ = LOGINSTATE_SESSION_REQUESTED; - continue; - } - - case LOGINSTATE_SESSION_REQUESTED: { - if (NULL == (element = NextStanza())) - return true; - if (element->Name() != QN_IQ || element->Attr(QN_ID) != iqId_ || - element->Attr(QN_TYPE) == "get" || element->Attr(QN_TYPE) == "set") - return false; - - if (element->Attr(QN_TYPE) != "result") - return Failure(XmppEngine::ERROR_BIND); - - pctx_->SignalBound(fullJid_); - FlushQueuedStanzas(); - state_ = LOGINSTATE_DONE; - return true; - } - - case LOGINSTATE_DONE: - return false; - } - } -} - -bool -XmppLoginTask::HandleStartStream(const XmlElement *element) { - - if (element->Name() != QN_STREAM_STREAM) - return false; - - if (element->Attr(QN_XMLNS) != "jabber:client") - return false; - - if (element->Attr(QN_VERSION) != "1.0") - return false; - - if (!element->HasAttr(QN_ID)) - return false; - - streamId_ = element->Attr(QN_ID); - - return true; -} - -bool -XmppLoginTask::HandleFeatures(const XmlElement *element) { - if (element->Name() != QN_STREAM_FEATURES) - return false; - - pelFeatures_.reset(new XmlElement(*element)); - return true; -} - -const XmlElement * -XmppLoginTask::GetFeature(const QName & name) { - return pelFeatures_->FirstNamed(name); -} - -bool -XmppLoginTask::Failure(XmppEngine::Error reason) { - state_ = LOGINSTATE_DONE; - pctx_->SignalError(reason, 0); - return false; -} - -void -XmppLoginTask::OutgoingStanza(const XmlElement * element) { - XmlElement * pelCopy = new XmlElement(*element); - pvecQueuedStanzas_->push_back(pelCopy); -} - -void -XmppLoginTask::FlushQueuedStanzas() { - for (size_t i = 0; i < pvecQueuedStanzas_->size(); i += 1) { - pctx_->InternalSendStanza((*pvecQueuedStanzas_)[i]); - delete (*pvecQueuedStanzas_)[i]; - } - pvecQueuedStanzas_->clear(); -} - -} diff --git a/talk/xmpp/xmpplogintask.h b/talk/xmpp/xmpplogintask.h deleted file mode 100644 index 631ebdfe4..000000000 --- a/talk/xmpp/xmpplogintask.h +++ /dev/null @@ -1,104 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef TALK_XMPP_LOGINTASK_H_ -#define TALK_XMPP_LOGINTASK_H_ - -#include <string> -#include <vector> - -#include "webrtc/libjingle/xmpp/jid.h" -#include "webrtc/libjingle/xmpp/xmppengine.h" -#include "webrtc/base/logging.h" -#include "webrtc/base/scoped_ptr.h" - -namespace buzz { - -class XmlElement; -class XmppEngineImpl; -class SaslMechanism; - - -// TODO: Rename to LoginTask. -class XmppLoginTask { - -public: - XmppLoginTask(XmppEngineImpl *pctx); - ~XmppLoginTask(); - - bool IsDone() - { return state_ == LOGINSTATE_DONE; } - void IncomingStanza(const XmlElement * element, bool isStart); - void OutgoingStanza(const XmlElement *element); - void set_allow_non_google_login(bool b) - { allowNonGoogleLogin_ = b; } - -private: - enum LoginTaskState { - LOGINSTATE_INIT = 0, - LOGINSTATE_STREAMSTART_SENT, - LOGINSTATE_STARTED_XMPP, - LOGINSTATE_TLS_INIT, - LOGINSTATE_AUTH_INIT, - LOGINSTATE_BIND_INIT, - LOGINSTATE_TLS_REQUESTED, - LOGINSTATE_SASL_RUNNING, - LOGINSTATE_BIND_REQUESTED, - LOGINSTATE_SESSION_REQUESTED, - LOGINSTATE_DONE, - }; - - const XmlElement * NextStanza(); - bool Advance(); - bool HandleStartStream(const XmlElement * element); - bool HandleFeatures(const XmlElement * element); - const XmlElement * GetFeature(const QName & name); - bool Failure(XmppEngine::Error reason); - void FlushQueuedStanzas(); - - XmppEngineImpl * pctx_; - bool authNeeded_; - bool allowNonGoogleLogin_; - LoginTaskState state_; - const XmlElement * pelStanza_; - bool isStart_; - std::string iqId_; - rtc::scoped_ptr<XmlElement> pelFeatures_; - Jid fullJid_; - std::string streamId_; - rtc::scoped_ptr<std::vector<XmlElement *> > pvecQueuedStanzas_; - - rtc::scoped_ptr<SaslMechanism> sasl_mech_; - -#ifdef _DEBUG - static const rtc::ConstantLabel LOGINTASK_STATES[]; -#endif // _DEBUG -}; - -} - -#endif // TALK_XMPP_LOGINTASK_H_ diff --git a/talk/xmpp/xmpplogintask_unittest.cc b/talk/xmpp/xmpplogintask_unittest.cc deleted file mode 100644 index 82973c46d..000000000 --- a/talk/xmpp/xmpplogintask_unittest.cc +++ /dev/null @@ -1,614 +0,0 @@ -// Copyright 2004 Google Inc. All Rights Reserved - - -#include <iostream> -#include <sstream> -#include <string> -#include "webrtc/libjingle/xmllite/xmlelement.h" -#include "webrtc/libjingle/xmpp/constants.h" -#include "webrtc/libjingle/xmpp/plainsaslhandler.h" -#include "webrtc/libjingle/xmpp/saslplainmechanism.h" -#include "webrtc/libjingle/xmpp/util_unittest.h" -#include "webrtc/libjingle/xmpp/xmppengine.h" -#include "webrtc/base/common.h" -#include "webrtc/base/cryptstring.h" -#include "webrtc/base/gunit.h" - -using buzz::Jid; -using buzz::QName; -using buzz::XmlElement; -using buzz::XmppEngine; -using buzz::XmppTestHandler; - -enum XlttStage { - XLTT_STAGE_CONNECT = 0, - XLTT_STAGE_STREAMSTART, - XLTT_STAGE_TLS_FEATURES, - XLTT_STAGE_TLS_PROCEED, - XLTT_STAGE_ENCRYPTED_START, - XLTT_STAGE_AUTH_FEATURES, - XLTT_STAGE_AUTH_SUCCESS, - XLTT_STAGE_AUTHENTICATED_START, - XLTT_STAGE_BIND_FEATURES, - XLTT_STAGE_BIND_SUCCESS, - XLTT_STAGE_SESSION_SUCCESS, -}; - -class XmppLoginTaskTest : public testing::Test { - public: - XmppEngine* engine() { return engine_.get(); } - XmppTestHandler* handler() { return handler_.get(); } - virtual void SetUp() { - engine_.reset(XmppEngine::Create()); - handler_.reset(new XmppTestHandler(engine_.get())); - - Jid jid("david@my-server"); - rtc::InsecureCryptStringImpl pass; - pass.password() = "david"; - engine_->SetSessionHandler(handler_.get()); - engine_->SetOutputHandler(handler_.get()); - engine_->AddStanzaHandler(handler_.get()); - engine_->SetUser(jid); - engine_->SetSaslHandler( - new buzz::PlainSaslHandler(jid, rtc::CryptString(pass), true)); - } - virtual void TearDown() { - handler_.reset(); - engine_.reset(); - } - void RunPartialLogin(XlttStage startstage, XlttStage endstage); - void SetTlsOptions(buzz::TlsOptions option); - - private: - rtc::scoped_ptr<XmppEngine> engine_; - rtc::scoped_ptr<XmppTestHandler> handler_; -}; - -void XmppLoginTaskTest::SetTlsOptions(buzz::TlsOptions option) { - engine_->SetTls(option); -} -void XmppLoginTaskTest::RunPartialLogin(XlttStage startstage, - XlttStage endstage) { - std::string input; - - switch (startstage) { - case XLTT_STAGE_CONNECT: { - engine_->Connect(); - XmlElement appStanza(QName("test", "app-stanza")); - appStanza.AddText("this-is-a-test"); - engine_->SendStanza(&appStanza); - - EXPECT_EQ("<stream:stream to=\"my-server\" xml:lang=\"*\" " - "version=\"1.0\" xmlns:stream=\"http://etherx.jabber.org/streams\" " - "xmlns=\"jabber:client\">\r\n", handler_->OutputActivity()); - EXPECT_EQ("[OPENING]", handler_->SessionActivity()); - EXPECT_EQ("", handler_->StanzaActivity()); - if (endstage == XLTT_STAGE_CONNECT) - return; - } - - case XLTT_STAGE_STREAMSTART: { - input = "<stream:stream id=\"a5f2d8c9\" version=\"1.0\" " - "xmlns:stream=\"http://etherx.jabber.org/streams\" " - "xmlns=\"jabber:client\">"; - engine_->HandleInput(input.c_str(), input.length()); - EXPECT_EQ("", handler_->StanzaActivity()); - EXPECT_EQ("", handler_->SessionActivity()); - EXPECT_EQ("", handler_->OutputActivity()); - if (endstage == XLTT_STAGE_STREAMSTART) - return; - } - - case XLTT_STAGE_TLS_FEATURES: { - input = "<stream:features>" - "<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>" - "</stream:features>"; - engine_->HandleInput(input.c_str(), input.length()); - EXPECT_EQ("<starttls xmlns=\"urn:ietf:params:xml:ns:xmpp-tls\"/>", - handler_->OutputActivity()); - EXPECT_EQ("", handler_->StanzaActivity()); - EXPECT_EQ("", handler_->SessionActivity()); - if (endstage == XLTT_STAGE_TLS_FEATURES) - return; - } - - case XLTT_STAGE_TLS_PROCEED: { - input = std::string("<proceed xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>"); - engine_->HandleInput(input.c_str(), input.length()); - EXPECT_EQ("[START-TLS my-server]" - "<stream:stream to=\"my-server\" xml:lang=\"*\" " - "version=\"1.0\" xmlns:stream=\"http://etherx.jabber.org/streams\" " - "xmlns=\"jabber:client\">\r\n", handler_->OutputActivity()); - EXPECT_EQ("", handler_->StanzaActivity()); - EXPECT_EQ("", handler_->SessionActivity()); - if (endstage == XLTT_STAGE_TLS_PROCEED) - return; - } - - case XLTT_STAGE_ENCRYPTED_START: { - input = std::string("<stream:stream id=\"01234567\" version=\"1.0\" " - "xmlns:stream=\"http://etherx.jabber.org/streams\" " - "xmlns=\"jabber:client\">"); - engine_->HandleInput(input.c_str(), input.length()); - EXPECT_EQ("", handler_->StanzaActivity()); - EXPECT_EQ("", handler_->SessionActivity()); - EXPECT_EQ("", handler_->OutputActivity()); - if (endstage == XLTT_STAGE_ENCRYPTED_START) - return; - } - - case XLTT_STAGE_AUTH_FEATURES: { - input = "<stream:features>" - "<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>" - "<mechanism>DIGEST-MD5</mechanism>" - "<mechanism>PLAIN</mechanism>" - "</mechanisms>" - "</stream:features>"; - engine_->HandleInput(input.c_str(), input.length()); - EXPECT_EQ("<auth xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\" " - "mechanism=\"PLAIN\" " - "auth:allow-non-google-login=\"true\" " - "auth:client-uses-full-bind-result=\"true\" " - "xmlns:auth=\"http://www.google.com/talk/protocol/auth\"" - ">AGRhdmlkAGRhdmlk</auth>", - handler_->OutputActivity()); - EXPECT_EQ("", handler_->StanzaActivity()); - EXPECT_EQ("", handler_->SessionActivity()); - if (endstage == XLTT_STAGE_AUTH_FEATURES) - return; - } - - case XLTT_STAGE_AUTH_SUCCESS: { - input = "<success xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/>"; - engine_->HandleInput(input.c_str(), input.length()); - EXPECT_EQ("<stream:stream to=\"my-server\" xml:lang=\"*\" " - "version=\"1.0\" xmlns:stream=\"http://etherx.jabber.org/streams\" " - "xmlns=\"jabber:client\">\r\n", handler_->OutputActivity()); - EXPECT_EQ("", handler_->StanzaActivity()); - EXPECT_EQ("", handler_->SessionActivity()); - if (endstage == XLTT_STAGE_AUTH_SUCCESS) - return; - } - - case XLTT_STAGE_AUTHENTICATED_START: { - input = std::string("<stream:stream id=\"01234567\" version=\"1.0\" " - "xmlns:stream=\"http://etherx.jabber.org/streams\" " - "xmlns=\"jabber:client\">"); - engine_->HandleInput(input.c_str(), input.length()); - EXPECT_EQ("", handler_->StanzaActivity()); - EXPECT_EQ("", handler_->SessionActivity()); - EXPECT_EQ("", handler_->OutputActivity()); - if (endstage == XLTT_STAGE_AUTHENTICATED_START) - return; - } - - case XLTT_STAGE_BIND_FEATURES: { - input = "<stream:features>" - "<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'/>" - "<session xmlns='urn:ietf:params:xml:ns:xmpp-session'/>" - "</stream:features>"; - engine_->HandleInput(input.c_str(), input.length()); - EXPECT_EQ("<iq type=\"set\" id=\"0\">" - "<bind xmlns=\"urn:ietf:params:xml:ns:xmpp-bind\"/></iq>", - handler_->OutputActivity()); - EXPECT_EQ("", handler_->StanzaActivity()); - EXPECT_EQ("", handler_->SessionActivity()); - if (endstage == XLTT_STAGE_BIND_FEATURES) - return; - } - - case XLTT_STAGE_BIND_SUCCESS: { - input = "<iq type='result' id='0'>" - "<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'>" - "<jid>david@my-server/test</jid></bind></iq>"; - engine_->HandleInput(input.c_str(), input.length()); - EXPECT_EQ("<iq type=\"set\" id=\"1\">" - "<session xmlns=\"urn:ietf:params:xml:ns:xmpp-session\"/></iq>", - handler_->OutputActivity()); - EXPECT_EQ("", handler_->StanzaActivity()); - EXPECT_EQ("", handler_->SessionActivity()); - if (endstage == XLTT_STAGE_BIND_SUCCESS) - return; - } - - case XLTT_STAGE_SESSION_SUCCESS: { - input = "<iq type='result' id='1'/>"; - engine_->HandleInput(input.c_str(), input.length()); - EXPECT_EQ("<test:app-stanza xmlns:test=\"test\">this-is-a-test" - "</test:app-stanza>", handler_->OutputActivity()); - EXPECT_EQ("[OPEN]", handler_->SessionActivity()); - EXPECT_EQ("", handler_->StanzaActivity()); - if (endstage == XLTT_STAGE_SESSION_SUCCESS) - return; - } - } -} - -TEST_F(XmppLoginTaskTest, TestUtf8Good) { - RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_CONNECT); - - std::string input = "<?xml version='1.0' encoding='UTF-8'?>" - "<stream:stream id=\"a5f2d8c9\" version=\"1.0\" " - "xmlns:stream=\"http://etherx.jabber.org/streams\" " - "xmlns=\"jabber:client\">"; - engine()->HandleInput(input.c_str(), input.length()); - EXPECT_EQ("", handler()->OutputActivity()); - EXPECT_EQ("", handler()->SessionActivity()); - EXPECT_EQ("", handler()->StanzaActivity()); -} - -TEST_F(XmppLoginTaskTest, TestNonUtf8Bad) { - RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_CONNECT); - - std::string input = "<?xml version='1.0' encoding='ISO-8859-1'?>" - "<stream:stream id=\"a5f2d8c9\" version=\"1.0\" " - "xmlns:stream=\"http://etherx.jabber.org/streams\" " - "xmlns=\"jabber:client\">"; - engine()->HandleInput(input.c_str(), input.length()); - EXPECT_EQ("[CLOSED]", handler()->OutputActivity()); - EXPECT_EQ("[CLOSED][ERROR-XML]", handler()->SessionActivity()); - EXPECT_EQ("", handler()->StanzaActivity()); -} - -TEST_F(XmppLoginTaskTest, TestNoFeatures) { - RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_STREAMSTART); - - std::string input = "<iq type='get' id='1'/>"; - engine()->HandleInput(input.c_str(), input.length()); - - EXPECT_EQ("[CLOSED]", handler()->OutputActivity()); - EXPECT_EQ("[CLOSED][ERROR-VERSION]", handler()->SessionActivity()); - EXPECT_EQ("", handler()->StanzaActivity()); -} - -TEST_F(XmppLoginTaskTest, TestTlsRequiredNotPresent) { - RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_STREAMSTART); - - std::string input = "<stream:features>" - "<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>" - "<mechanism>DIGEST-MD5</mechanism>" - "<mechanism>PLAIN</mechanism>" - "</mechanisms>" - "</stream:features>"; - engine()->HandleInput(input.c_str(), input.length()); - - EXPECT_EQ("[CLOSED]", handler()->OutputActivity()); - EXPECT_EQ("[CLOSED][ERROR-TLS]", handler()->SessionActivity()); - EXPECT_EQ("", handler()->StanzaActivity()); -} - -TEST_F(XmppLoginTaskTest, TestTlsRequeiredAndPresent) { - RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_STREAMSTART); - - std::string input = "<stream:features>" - "<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'>" - "<required/>" - "</starttls>" - "<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>" - "<mechanism>X-GOOGLE-TOKEN</mechanism>" - "<mechanism>PLAIN</mechanism>" - "<mechanism>X-OAUTH2</mechanism>" - "</mechanisms>" - "</stream:features>"; - engine()->HandleInput(input.c_str(), input.length()); - - EXPECT_EQ("<starttls xmlns=\"urn:ietf:params:xml:ns:xmpp-tls\"/>", - handler()->OutputActivity()); - EXPECT_EQ("", handler()->SessionActivity()); - EXPECT_EQ("", handler()->StanzaActivity()); -} - -TEST_F(XmppLoginTaskTest, TestTlsEnabledNotPresent) { - SetTlsOptions(buzz::TLS_ENABLED); - RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_STREAMSTART); - - std::string input = "<stream:features>" - "<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>" - "<mechanism>DIGEST-MD5</mechanism>" - "<mechanism>PLAIN</mechanism>" - "</mechanisms>" - "</stream:features>"; - engine()->HandleInput(input.c_str(), input.length()); - - EXPECT_EQ("<auth xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\" " - "mechanism=\"PLAIN\" auth:allow-non-google-login=\"true\" " - "auth:client-uses-full-bind-result=\"true\" " - "xmlns:auth=\"http://www.google.com/talk/protocol/auth\"" - ">AGRhdmlkAGRhdmlk</auth>", handler()->OutputActivity()); - EXPECT_EQ("", handler()->SessionActivity()); - EXPECT_EQ("", handler()->StanzaActivity()); -} - -TEST_F(XmppLoginTaskTest, TestTlsEnabledAndPresent) { - SetTlsOptions(buzz::TLS_ENABLED); - RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_STREAMSTART); - - std::string input = "<stream:features>" - "<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>" - "<mechanism>X-GOOGLE-TOKEN</mechanism>" - "<mechanism>PLAIN</mechanism>" - "<mechanism>X-OAUTH2</mechanism>" - "</mechanisms>" - "</stream:features>"; - engine()->HandleInput(input.c_str(), input.length()); - - EXPECT_EQ("<auth xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\" " - "mechanism=\"PLAIN\" auth:allow-non-google-login=\"true\" " - "auth:client-uses-full-bind-result=\"true\" " - "xmlns:auth=\"http://www.google.com/talk/protocol/auth\"" - ">AGRhdmlkAGRhdmlk</auth>", handler()->OutputActivity()); - EXPECT_EQ("", handler()->SessionActivity()); - EXPECT_EQ("", handler()->StanzaActivity()); -} - -TEST_F(XmppLoginTaskTest, TestTlsDisabledNotPresent) { - SetTlsOptions(buzz::TLS_DISABLED); - RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_STREAMSTART); - - std::string input = "<stream:features>" - "<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>" - "<mechanism>DIGEST-MD5</mechanism>" - "<mechanism>PLAIN</mechanism>" - "</mechanisms>" - "</stream:features>"; - engine()->HandleInput(input.c_str(), input.length()); - - EXPECT_EQ("<auth xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\" " - "mechanism=\"PLAIN\" auth:allow-non-google-login=\"true\" " - "auth:client-uses-full-bind-result=\"true\" " - "xmlns:auth=\"http://www.google.com/talk/protocol/auth\"" - ">AGRhdmlkAGRhdmlk</auth>", handler()->OutputActivity()); - EXPECT_EQ("", handler()->SessionActivity()); - EXPECT_EQ("", handler()->StanzaActivity()); -} - -TEST_F(XmppLoginTaskTest, TestTlsDisabledAndPresent) { - SetTlsOptions(buzz::TLS_DISABLED); - RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_STREAMSTART); - - std::string input = "<stream:features>" - "<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>" - "<mechanism>X-GOOGLE-TOKEN</mechanism>" - "<mechanism>PLAIN</mechanism>" - "<mechanism>X-OAUTH2</mechanism>" - "</mechanisms>" - "</stream:features>"; - engine()->HandleInput(input.c_str(), input.length()); - - EXPECT_EQ("<auth xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\" " - "mechanism=\"PLAIN\" auth:allow-non-google-login=\"true\" " - "auth:client-uses-full-bind-result=\"true\" " - "xmlns:auth=\"http://www.google.com/talk/protocol/auth\"" - ">AGRhdmlkAGRhdmlk</auth>", handler()->OutputActivity()); - EXPECT_EQ("", handler()->SessionActivity()); - EXPECT_EQ("", handler()->StanzaActivity()); -} - -TEST_F(XmppLoginTaskTest, TestTlsFailure) { - RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_TLS_FEATURES); - - std::string input = "<failure xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>"; - engine()->HandleInput(input.c_str(), input.length()); - - EXPECT_EQ("[CLOSED]", handler()->OutputActivity()); - EXPECT_EQ("[CLOSED][ERROR-TLS]", handler()->SessionActivity()); - EXPECT_EQ("", handler()->StanzaActivity()); -} - -TEST_F(XmppLoginTaskTest, TestTlsBadStream) { - RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_TLS_PROCEED); - - std::string input = "<wrongtag>"; - engine()->HandleInput(input.c_str(), input.length()); - - EXPECT_EQ("[CLOSED]", handler()->OutputActivity()); - EXPECT_EQ("[CLOSED][ERROR-VERSION]", handler()->SessionActivity()); - EXPECT_EQ("", handler()->StanzaActivity()); -} - -TEST_F(XmppLoginTaskTest, TestMissingSaslPlain) { - RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_ENCRYPTED_START); - - std::string input = "<stream:features>" - "<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>" - "<mechanism>DIGEST-MD5</mechanism>" - "</mechanisms>" - "</stream:features>"; - engine()->HandleInput(input.c_str(), input.length()); - - EXPECT_EQ("[CLOSED]", handler()->OutputActivity()); - EXPECT_EQ("[CLOSED][ERROR-AUTH]", handler()->SessionActivity()); - EXPECT_EQ("", handler()->StanzaActivity()); -} - -TEST_F(XmppLoginTaskTest, TestWrongPassword) { - RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_AUTH_FEATURES); - - std::string input = "<failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/>"; - engine()->HandleInput(input.c_str(), input.length()); - - EXPECT_EQ("[CLOSED]", handler()->OutputActivity()); - EXPECT_EQ("[CLOSED][ERROR-UNAUTHORIZED]", handler()->SessionActivity()); - EXPECT_EQ("", handler()->StanzaActivity()); -} - -TEST_F(XmppLoginTaskTest, TestAuthBadStream) { - RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_AUTH_SUCCESS); - - std::string input = "<wrongtag>"; - engine()->HandleInput(input.c_str(), input.length()); - - EXPECT_EQ("[CLOSED]", handler()->OutputActivity()); - EXPECT_EQ("[CLOSED][ERROR-VERSION]", handler()->SessionActivity()); - EXPECT_EQ("", handler()->StanzaActivity()); -} - -TEST_F(XmppLoginTaskTest, TestMissingBindFeature) { - RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_AUTHENTICATED_START); - - std::string input = "<stream:features>" - "<session xmlns='urn:ietf:params:xml:ns:xmpp-session'/>" - "</stream:features>"; - engine()->HandleInput(input.c_str(), input.length()); - - EXPECT_EQ("[CLOSED]", handler()->OutputActivity()); - EXPECT_EQ("[CLOSED][ERROR-BIND]", handler()->SessionActivity()); -} - -TEST_F(XmppLoginTaskTest, TestMissingSessionFeature) { - RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_AUTHENTICATED_START); - - std::string input = "<stream:features>" - "<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'/>" - "</stream:features>"; - engine()->HandleInput(input.c_str(), input.length()); - - EXPECT_EQ("[CLOSED]", handler()->OutputActivity()); - EXPECT_EQ("[CLOSED][ERROR-BIND]", handler()->SessionActivity()); - EXPECT_EQ("", handler()->StanzaActivity()); -} - -/* TODO: Handle this case properly inside XmppLoginTask. -TEST_F(XmppLoginTaskTest, TestBindFailure1) { - // check wrong JID - RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_BIND_FEATURES); - - std::string input = "<iq type='result' id='0'>" - "<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'>" - "<jid>davey@my-server/test</jid></bind></iq>"; - engine()->HandleInput(input.c_str(), input.length()); - - EXPECT_EQ("[CLOSED]", handler()->OutputActivity()); - EXPECT_EQ("[CLOSED][ERROR-BIND]", handler()->SessionActivity()); - EXPECT_EQ("", handler()->StanzaActivity()); -} -*/ - -TEST_F(XmppLoginTaskTest, TestBindFailure2) { - // check missing JID - RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_BIND_FEATURES); - - std::string input = "<iq type='result' id='0'>" - "<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'/></iq>"; - engine()->HandleInput(input.c_str(), input.length()); - - EXPECT_EQ("[CLOSED]", handler()->OutputActivity()); - EXPECT_EQ("[CLOSED][ERROR-BIND]", handler()->SessionActivity()); - EXPECT_EQ("", handler()->StanzaActivity()); -} - -TEST_F(XmppLoginTaskTest, TestBindFailure3) { - // check plain failure - RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_BIND_FEATURES); - - std::string input = "<iq type='error' id='0'/>"; - engine()->HandleInput(input.c_str(), input.length()); - - EXPECT_EQ("[CLOSED]", handler()->OutputActivity()); - EXPECT_EQ("[CLOSED][ERROR-BIND]", handler()->SessionActivity()); - EXPECT_EQ("", handler()->StanzaActivity()); -} - -TEST_F(XmppLoginTaskTest, TestBindFailure4) { - // check wrong id to ignore - RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_BIND_FEATURES); - - std::string input = "<iq type='error' id='1'/>"; - engine()->HandleInput(input.c_str(), input.length()); - - // continue after an ignored iq - RunPartialLogin(XLTT_STAGE_BIND_SUCCESS, XLTT_STAGE_SESSION_SUCCESS); -} - -TEST_F(XmppLoginTaskTest, TestSessionFailurePlain1) { - RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_BIND_SUCCESS); - - std::string input = "<iq type='error' id='1'/>"; - engine()->HandleInput(input.c_str(), input.length()); - - EXPECT_EQ("[CLOSED]", handler()->OutputActivity()); - EXPECT_EQ("[CLOSED][ERROR-BIND]", handler()->SessionActivity()); -} - -TEST_F(XmppLoginTaskTest, TestSessionFailurePlain2) { - RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_BIND_SUCCESS); - - // check reverse iq to ignore - // TODO: consider queueing or passing through? - std::string input = "<iq type='get' id='1'/>"; - engine()->HandleInput(input.c_str(), input.length()); - - EXPECT_EQ("", handler()->OutputActivity()); - EXPECT_EQ("", handler()->SessionActivity()); - - // continue after an ignored iq - RunPartialLogin(XLTT_STAGE_SESSION_SUCCESS, XLTT_STAGE_SESSION_SUCCESS); -} - -TEST_F(XmppLoginTaskTest, TestBadXml) { - int errorKind = 0; - for (XlttStage stage = XLTT_STAGE_CONNECT; - stage <= XLTT_STAGE_SESSION_SUCCESS; - stage = static_cast<XlttStage>(stage + 1)) { - RunPartialLogin(XLTT_STAGE_CONNECT, stage); - - std::string input; - switch (errorKind++ % 5) { - case 0: input = "&syntax;"; break; - case 1: input = "<nons:iq/>"; break; - case 2: input = "<iq a='b' a='dupe'/>"; break; - case 3: input = "<>"; break; - case 4: input = "<iq a='<wrong>'>"; break; - } - - engine()->HandleInput(input.c_str(), input.length()); - - EXPECT_EQ("[CLOSED]", handler()->OutputActivity()); - EXPECT_EQ("[CLOSED][ERROR-XML]", handler()->SessionActivity()); - - TearDown(); - SetUp(); - } -} - -TEST_F(XmppLoginTaskTest, TestStreamError) { - for (XlttStage stage = XLTT_STAGE_CONNECT; - stage <= XLTT_STAGE_SESSION_SUCCESS; - stage = static_cast<XlttStage>(stage + 1)) { - switch (stage) { - case XLTT_STAGE_CONNECT: - case XLTT_STAGE_TLS_PROCEED: - case XLTT_STAGE_AUTH_SUCCESS: - continue; - default: - break; - } - - RunPartialLogin(XLTT_STAGE_CONNECT, stage); - - std::string input = "<stream:error>" - "<xml-not-well-formed xmlns='urn:ietf:params:xml:ns:xmpp-streams'/>" - "<text xml:lang='en' xmlns='urn:ietf:params:xml:ns:xmpp-streams'>" - "Some special application diagnostic information!" - "</text>" - "<escape-your-data xmlns='application-ns'/>" - "</stream:error>"; - - engine()->HandleInput(input.c_str(), input.length()); - - EXPECT_EQ("[CLOSED]", handler()->OutputActivity()); - EXPECT_EQ("[CLOSED][ERROR-STREAM]", handler()->SessionActivity()); - - EXPECT_EQ("<str:error xmlns:str=\"http://etherx.jabber.org/streams\">" - "<xml-not-well-formed xmlns=\"urn:ietf:params:xml:ns:xmpp-streams\"/>" - "<text xml:lang=\"en\" xmlns=\"urn:ietf:params:xml:ns:xmpp-streams\">" - "Some special application diagnostic information!" - "</text>" - "<escape-your-data xmlns=\"application-ns\"/>" - "</str:error>", engine()->GetStreamError()->Str()); - - TearDown(); - SetUp(); - } -} - diff --git a/talk/xmpp/xmpppump.cc b/talk/xmpp/xmpppump.cc deleted file mode 100644 index e9e7823a4..000000000 --- a/talk/xmpp/xmpppump.cc +++ /dev/null @@ -1,84 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "webrtc/libjingle/xmpp/xmpppump.h" - -#include "webrtc/libjingle/xmpp/xmppauth.h" - -namespace buzz { - -XmppPump::XmppPump(XmppPumpNotify * notify) { - state_ = buzz::XmppEngine::STATE_NONE; - notify_ = notify; - client_ = new buzz::XmppClient(this); // NOTE: deleted by TaskRunner -} - -void XmppPump::DoLogin(const buzz::XmppClientSettings & xcs, - buzz::AsyncSocket* socket, - buzz::PreXmppAuth* auth) { - OnStateChange(buzz::XmppEngine::STATE_START); - if (!AllChildrenDone()) { - client_->SignalStateChange.connect(this, &XmppPump::OnStateChange); - client_->Connect(xcs, "", socket, auth); - client_->Start(); - } -} - -void XmppPump::DoDisconnect() { - if (!AllChildrenDone()) - client_->Disconnect(); - OnStateChange(buzz::XmppEngine::STATE_CLOSED); -} - -void XmppPump::OnStateChange(buzz::XmppEngine::State state) { - if (state_ == state) - return; - state_ = state; - if (notify_ != NULL) - notify_->OnStateChange(state); -} - -void XmppPump::WakeTasks() { - rtc::Thread::Current()->Post(this); -} - -int64 XmppPump::CurrentTime() { - return (int64)rtc::Time(); -} - -void XmppPump::OnMessage(rtc::Message *pmsg) { - RunTasks(); -} - -buzz::XmppReturnStatus XmppPump::SendStanza(const buzz::XmlElement *stanza) { - if (!AllChildrenDone()) - return client_->SendStanza(stanza); - return buzz::XMPP_RETURN_BADSTATE; -} - -} // namespace buzz - diff --git a/talk/xmpp/xmpppump.h b/talk/xmpp/xmpppump.h deleted file mode 100644 index 082afb9db..000000000 --- a/talk/xmpp/xmpppump.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef TALK_XMPP_XMPPPUMP_H_ -#define TALK_XMPP_XMPPPUMP_H_ - -#include "webrtc/libjingle/xmpp/xmppclient.h" -#include "webrtc/libjingle/xmpp/xmppengine.h" -#include "webrtc/libjingle/xmpp/xmpptask.h" -#include "webrtc/base/messagequeue.h" -#include "webrtc/base/taskrunner.h" -#include "webrtc/base/thread.h" -#include "webrtc/base/timeutils.h" - -namespace buzz { - -// Simple xmpp pump - -class XmppPumpNotify { -public: - virtual ~XmppPumpNotify() {} - virtual void OnStateChange(buzz::XmppEngine::State state) = 0; -}; - -class XmppPump : public rtc::MessageHandler, public rtc::TaskRunner { -public: - XmppPump(buzz::XmppPumpNotify * notify = NULL); - - buzz::XmppClient *client() { return client_; } - - void DoLogin(const buzz::XmppClientSettings & xcs, - buzz::AsyncSocket* socket, - buzz::PreXmppAuth* auth); - void DoDisconnect(); - - void OnStateChange(buzz::XmppEngine::State state); - - void WakeTasks(); - - int64 CurrentTime(); - - void OnMessage(rtc::Message *pmsg); - - buzz::XmppReturnStatus SendStanza(const buzz::XmlElement *stanza); - -private: - buzz::XmppClient *client_; - buzz::XmppEngine::State state_; - buzz::XmppPumpNotify *notify_; -}; - -} // namespace buzz - -#endif // TALK_XMPP_XMPPPUMP_H_ - diff --git a/talk/xmpp/xmppsocket.cc b/talk/xmpp/xmppsocket.cc deleted file mode 100644 index 67240ba96..000000000 --- a/talk/xmpp/xmppsocket.cc +++ /dev/null @@ -1,262 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "xmppsocket.h" - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <errno.h> -#include "webrtc/base/basicdefs.h" -#include "webrtc/base/logging.h" -#include "webrtc/base/thread.h" -#ifdef FEATURE_ENABLE_SSL -#include "webrtc/base/ssladapter.h" -#endif - -#ifdef USE_SSLSTREAM -#include "webrtc/base/socketstream.h" -#ifdef FEATURE_ENABLE_SSL -#include "webrtc/base/sslstreamadapter.h" -#endif // FEATURE_ENABLE_SSL -#endif // USE_SSLSTREAM - -namespace buzz { - -XmppSocket::XmppSocket(buzz::TlsOptions tls) : cricket_socket_(NULL), - tls_(tls) { - state_ = buzz::AsyncSocket::STATE_CLOSED; -} - -void XmppSocket::CreateCricketSocket(int family) { - rtc::Thread* pth = rtc::Thread::Current(); - if (family == AF_UNSPEC) { - family = AF_INET; - } - rtc::AsyncSocket* socket = - pth->socketserver()->CreateAsyncSocket(family, SOCK_STREAM); -#ifndef USE_SSLSTREAM -#ifdef FEATURE_ENABLE_SSL - if (tls_ != buzz::TLS_DISABLED) { - socket = rtc::SSLAdapter::Create(socket); - } -#endif // FEATURE_ENABLE_SSL - cricket_socket_ = socket; - cricket_socket_->SignalReadEvent.connect(this, &XmppSocket::OnReadEvent); - cricket_socket_->SignalWriteEvent.connect(this, &XmppSocket::OnWriteEvent); - cricket_socket_->SignalConnectEvent.connect(this, - &XmppSocket::OnConnectEvent); - cricket_socket_->SignalCloseEvent.connect(this, &XmppSocket::OnCloseEvent); -#else // USE_SSLSTREAM - cricket_socket_ = socket; - stream_ = new rtc::SocketStream(cricket_socket_); -#ifdef FEATURE_ENABLE_SSL - if (tls_ != buzz::TLS_DISABLED) - stream_ = rtc::SSLStreamAdapter::Create(stream_); -#endif // FEATURE_ENABLE_SSL - stream_->SignalEvent.connect(this, &XmppSocket::OnEvent); -#endif // USE_SSLSTREAM -} - -XmppSocket::~XmppSocket() { - Close(); -#ifndef USE_SSLSTREAM - delete cricket_socket_; -#else // USE_SSLSTREAM - delete stream_; -#endif // USE_SSLSTREAM -} - -#ifndef USE_SSLSTREAM -void XmppSocket::OnReadEvent(rtc::AsyncSocket * socket) { - SignalRead(); -} - -void XmppSocket::OnWriteEvent(rtc::AsyncSocket * socket) { - // Write bytes if there are any - while (buffer_.Length() != 0) { - int written = cricket_socket_->Send(buffer_.Data(), buffer_.Length()); - if (written > 0) { - buffer_.Consume(written); - continue; - } - if (!cricket_socket_->IsBlocking()) - LOG(LS_ERROR) << "Send error: " << cricket_socket_->GetError(); - return; - } -} - -void XmppSocket::OnConnectEvent(rtc::AsyncSocket * socket) { -#if defined(FEATURE_ENABLE_SSL) - if (state_ == buzz::AsyncSocket::STATE_TLS_CONNECTING) { - state_ = buzz::AsyncSocket::STATE_TLS_OPEN; - SignalSSLConnected(); - OnWriteEvent(cricket_socket_); - return; - } -#endif // !defined(FEATURE_ENABLE_SSL) - state_ = buzz::AsyncSocket::STATE_OPEN; - SignalConnected(); -} - -void XmppSocket::OnCloseEvent(rtc::AsyncSocket * socket, int error) { - SignalCloseEvent(error); -} - -#else // USE_SSLSTREAM - -void XmppSocket::OnEvent(rtc::StreamInterface* stream, - int events, int err) { - if ((events & rtc::SE_OPEN)) { -#if defined(FEATURE_ENABLE_SSL) - if (state_ == buzz::AsyncSocket::STATE_TLS_CONNECTING) { - state_ = buzz::AsyncSocket::STATE_TLS_OPEN; - SignalSSLConnected(); - events |= rtc::SE_WRITE; - } else -#endif - { - state_ = buzz::AsyncSocket::STATE_OPEN; - SignalConnected(); - } - } - if ((events & rtc::SE_READ)) - SignalRead(); - if ((events & rtc::SE_WRITE)) { - // Write bytes if there are any - while (buffer_.Length() != 0) { - rtc::StreamResult result; - size_t written; - int error; - result = stream_->Write(buffer_.Data(), buffer_.Length(), - &written, &error); - if (result == rtc::SR_ERROR) { - LOG(LS_ERROR) << "Send error: " << error; - return; - } - if (result == rtc::SR_BLOCK) - return; - ASSERT(result == rtc::SR_SUCCESS); - ASSERT(written > 0); - buffer_.Shift(written); - } - } - if ((events & rtc::SE_CLOSE)) - SignalCloseEvent(err); -} -#endif // USE_SSLSTREAM - -buzz::AsyncSocket::State XmppSocket::state() { - return state_; -} - -buzz::AsyncSocket::Error XmppSocket::error() { - return buzz::AsyncSocket::ERROR_NONE; -} - -int XmppSocket::GetError() { - return 0; -} - -bool XmppSocket::Connect(const rtc::SocketAddress& addr) { - if (cricket_socket_ == NULL) { - CreateCricketSocket(addr.family()); - } - if (cricket_socket_->Connect(addr) < 0) { - return cricket_socket_->IsBlocking(); - } - return true; -} - -bool XmppSocket::Read(char * data, size_t len, size_t* len_read) { -#ifndef USE_SSLSTREAM - int read = cricket_socket_->Recv(data, len); - if (read > 0) { - *len_read = (size_t)read; - return true; - } -#else // USE_SSLSTREAM - rtc::StreamResult result = stream_->Read(data, len, len_read, NULL); - if (result == rtc::SR_SUCCESS) - return true; -#endif // USE_SSLSTREAM - return false; -} - -bool XmppSocket::Write(const char * data, size_t len) { - buffer_.WriteBytes(data, len); -#ifndef USE_SSLSTREAM - OnWriteEvent(cricket_socket_); -#else // USE_SSLSTREAM - OnEvent(stream_, rtc::SE_WRITE, 0); -#endif // USE_SSLSTREAM - return true; -} - -bool XmppSocket::Close() { - if (state_ != buzz::AsyncSocket::STATE_OPEN) - return false; -#ifndef USE_SSLSTREAM - if (cricket_socket_->Close() == 0) { - state_ = buzz::AsyncSocket::STATE_CLOSED; - SignalClosed(); - return true; - } - return false; -#else // USE_SSLSTREAM - state_ = buzz::AsyncSocket::STATE_CLOSED; - stream_->Close(); - SignalClosed(); - return true; -#endif // USE_SSLSTREAM -} - -bool XmppSocket::StartTls(const std::string & domainname) { -#if defined(FEATURE_ENABLE_SSL) - if (tls_ == buzz::TLS_DISABLED) - return false; -#ifndef USE_SSLSTREAM - rtc::SSLAdapter* ssl_adapter = - static_cast<rtc::SSLAdapter *>(cricket_socket_); - if (ssl_adapter->StartSSL(domainname.c_str(), false) != 0) - return false; -#else // USE_SSLSTREAM - rtc::SSLStreamAdapter* ssl_stream = - static_cast<rtc::SSLStreamAdapter *>(stream_); - if (ssl_stream->StartSSLWithServer(domainname.c_str()) != 0) - return false; -#endif // USE_SSLSTREAM - state_ = buzz::AsyncSocket::STATE_TLS_CONNECTING; - return true; -#else // !defined(FEATURE_ENABLE_SSL) - return false; -#endif // !defined(FEATURE_ENABLE_SSL) -} - -} // namespace buzz - diff --git a/talk/xmpp/xmppsocket.h b/talk/xmpp/xmppsocket.h deleted file mode 100644 index 240bbe97d..000000000 --- a/talk/xmpp/xmppsocket.h +++ /dev/null @@ -1,89 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef TALK_XMPP_XMPPSOCKET_H_ -#define TALK_XMPP_XMPPSOCKET_H_ - -#include "webrtc/libjingle/xmpp/asyncsocket.h" -#include "webrtc/libjingle/xmpp/xmppengine.h" -#include "webrtc/base/asyncsocket.h" -#include "webrtc/base/bytebuffer.h" -#include "webrtc/base/sigslot.h" - -// The below define selects the SSLStreamAdapter implementation for -// SSL, as opposed to the SSLAdapter socket adapter. -// #define USE_SSLSTREAM - -namespace rtc { - class StreamInterface; - class SocketAddress; -}; -extern rtc::AsyncSocket* cricket_socket_; - -namespace buzz { - -class XmppSocket : public buzz::AsyncSocket, public sigslot::has_slots<> { -public: - XmppSocket(buzz::TlsOptions tls); - ~XmppSocket(); - - virtual buzz::AsyncSocket::State state(); - virtual buzz::AsyncSocket::Error error(); - virtual int GetError(); - - virtual bool Connect(const rtc::SocketAddress& addr); - virtual bool Read(char * data, size_t len, size_t* len_read); - virtual bool Write(const char * data, size_t len); - virtual bool Close(); - virtual bool StartTls(const std::string & domainname); - - sigslot::signal1<int> SignalCloseEvent; - -private: - void CreateCricketSocket(int family); -#ifndef USE_SSLSTREAM - void OnReadEvent(rtc::AsyncSocket * socket); - void OnWriteEvent(rtc::AsyncSocket * socket); - void OnConnectEvent(rtc::AsyncSocket * socket); - void OnCloseEvent(rtc::AsyncSocket * socket, int error); -#else // USE_SSLSTREAM - void OnEvent(rtc::StreamInterface* stream, int events, int err); -#endif // USE_SSLSTREAM - - rtc::AsyncSocket * cricket_socket_; -#ifdef USE_SSLSTREAM - rtc::StreamInterface *stream_; -#endif // USE_SSLSTREAM - buzz::AsyncSocket::State state_; - rtc::ByteBuffer buffer_; - buzz::TlsOptions tls_; -}; - -} // namespace buzz - -#endif // TALK_XMPP_XMPPSOCKET_H_ - diff --git a/talk/xmpp/xmppstanzaparser.cc b/talk/xmpp/xmppstanzaparser.cc deleted file mode 100644 index a4ca2ed7c..000000000 --- a/talk/xmpp/xmppstanzaparser.cc +++ /dev/null @@ -1,106 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "webrtc/libjingle/xmpp/xmppstanzaparser.h" - -#include "webrtc/libjingle/xmllite/xmlelement.h" -#include "webrtc/libjingle/xmpp/constants.h" -#include "webrtc/base/common.h" -#ifdef EXPAT_RELATIVE_PATH -#include "expat.h" -#else -#include "third_party/expat/v2_0_1/Source/lib/expat.h" -#endif - -namespace buzz { - -XmppStanzaParser::XmppStanzaParser(XmppStanzaParseHandler *psph) : - psph_(psph), - innerHandler_(this), - parser_(&innerHandler_), - depth_(0), - builder_() { -} - -void -XmppStanzaParser::Reset() { - parser_.Reset(); - depth_ = 0; - builder_.Reset(); -} - -void -XmppStanzaParser::IncomingStartElement( - XmlParseContext * pctx, const char * name, const char ** atts) { - if (depth_++ == 0) { - XmlElement * pelStream = XmlBuilder::BuildElement(pctx, name, atts); - if (pelStream == NULL) { - pctx->RaiseError(XML_ERROR_SYNTAX); - return; - } - psph_->StartStream(pelStream); - delete pelStream; - return; - } - - builder_.StartElement(pctx, name, atts); -} - -void -XmppStanzaParser::IncomingCharacterData( - XmlParseContext * pctx, const char * text, int len) { - if (depth_ > 1) { - builder_.CharacterData(pctx, text, len); - } -} - -void -XmppStanzaParser::IncomingEndElement( - XmlParseContext * pctx, const char * name) { - if (--depth_ == 0) { - psph_->EndStream(); - return; - } - - builder_.EndElement(pctx, name); - - if (depth_ == 1) { - XmlElement *element = builder_.CreateElement(); - psph_->Stanza(element); - delete element; - } -} - -void -XmppStanzaParser::IncomingError( - XmlParseContext * pctx, XML_Error errCode) { - RTC_UNUSED(pctx); - RTC_UNUSED(errCode); - psph_->XmlError(); -} - -} diff --git a/talk/xmpp/xmppstanzaparser.h b/talk/xmpp/xmppstanzaparser.h deleted file mode 100644 index ffb32753f..000000000 --- a/talk/xmpp/xmppstanzaparser.h +++ /dev/null @@ -1,97 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef TALK_XMPP_XMPPSTANZAPARSER_H_ -#define TALK_XMPP_XMPPSTANZAPARSER_H_ - -#include "webrtc/libjingle/xmllite/xmlbuilder.h" -#include "webrtc/libjingle/xmllite/xmlparser.h" - - -namespace buzz { - -class XmlElement; - -class XmppStanzaParseHandler { -public: - virtual ~XmppStanzaParseHandler() {} - virtual void StartStream(const XmlElement * pelStream) = 0; - virtual void Stanza(const XmlElement * pelStanza) = 0; - virtual void EndStream() = 0; - virtual void XmlError() = 0; -}; - -class XmppStanzaParser { -public: - XmppStanzaParser(XmppStanzaParseHandler *psph); - bool Parse(const char * data, size_t len, bool isFinal) - { return parser_.Parse(data, len, isFinal); } - void Reset(); - -private: - class ParseHandler : public XmlParseHandler { - public: - ParseHandler(XmppStanzaParser * outer) : outer_(outer) {} - virtual void StartElement(XmlParseContext * pctx, - const char * name, const char ** atts) - { outer_->IncomingStartElement(pctx, name, atts); } - virtual void EndElement(XmlParseContext * pctx, - const char * name) - { outer_->IncomingEndElement(pctx, name); } - virtual void CharacterData(XmlParseContext * pctx, - const char * text, int len) - { outer_->IncomingCharacterData(pctx, text, len); } - virtual void Error(XmlParseContext * pctx, - XML_Error errCode) - { outer_->IncomingError(pctx, errCode); } - private: - XmppStanzaParser * const outer_; - }; - - friend class ParseHandler; - - void IncomingStartElement(XmlParseContext * pctx, - const char * name, const char ** atts); - void IncomingEndElement(XmlParseContext * pctx, - const char * name); - void IncomingCharacterData(XmlParseContext * pctx, - const char * text, int len); - void IncomingError(XmlParseContext * pctx, - XML_Error errCode); - - XmppStanzaParseHandler * psph_; - ParseHandler innerHandler_; - XmlParser parser_; - int depth_; - XmlBuilder builder_; - - }; - - -} - -#endif // TALK_XMPP_XMPPSTANZAPARSER_H_ diff --git a/talk/xmpp/xmppstanzaparser_unittest.cc b/talk/xmpp/xmppstanzaparser_unittest.cc deleted file mode 100644 index 433de5e2e..000000000 --- a/talk/xmpp/xmppstanzaparser_unittest.cc +++ /dev/null @@ -1,168 +0,0 @@ -// Copyright 2004 Google Inc. All Rights Reserved - - -#include <iostream> -#include <sstream> -#include <string> -#include "webrtc/libjingle/xmllite/xmlelement.h" -#include "webrtc/libjingle/xmpp/xmppstanzaparser.h" -#include "webrtc/base/common.h" -#include "webrtc/base/gunit.h" - -using buzz::QName; -using buzz::XmlElement; -using buzz::XmppStanzaParser; -using buzz::XmppStanzaParseHandler; - -class XmppStanzaParserTestHandler : public XmppStanzaParseHandler { - public: - virtual void StartStream(const XmlElement * element) { - ss_ << "START" << element->Str(); - } - virtual void Stanza(const XmlElement * element) { - ss_ << "STANZA" << element->Str(); - } - virtual void EndStream() { - ss_ << "END"; - } - virtual void XmlError() { - ss_ << "ERROR"; - } - - std::string Str() { - return ss_.str(); - } - - std::string StrClear() { - std::string result = ss_.str(); - ss_.str(""); - return result; - } - - private: - std::stringstream ss_; -}; - - -TEST(XmppStanzaParserTest, TestTrivial) { - XmppStanzaParserTestHandler handler; - XmppStanzaParser parser(&handler); - std::string fragment; - - fragment = "<trivial/>"; - parser.Parse(fragment.c_str(), fragment.length(), false); - EXPECT_EQ("START<trivial/>END", handler.StrClear()); -} - -TEST(XmppStanzaParserTest, TestStanzaAtATime) { - XmppStanzaParserTestHandler handler; - XmppStanzaParser parser(&handler); - std::string fragment; - - fragment = "<stream:stream id='abc' xmlns='j:c' xmlns:stream='str'>"; - parser.Parse(fragment.c_str(), fragment.length(), false); - EXPECT_EQ("START<stream:stream id=\"abc\" xmlns=\"j:c\" " - "xmlns:stream=\"str\"/>", handler.StrClear()); - - fragment = "<message type='foo'><body>hello</body></message>"; - parser.Parse(fragment.c_str(), fragment.length(), false); - EXPECT_EQ("STANZA<c:message type=\"foo\" xmlns:c=\"j:c\">" - "<c:body>hello</c:body></c:message>", handler.StrClear()); - - fragment = " SOME TEXT TO IGNORE "; - parser.Parse(fragment.c_str(), fragment.length(), false); - EXPECT_EQ("", handler.StrClear()); - - fragment = "<iq type='set' id='123'><abc xmlns='def'/></iq>"; - parser.Parse(fragment.c_str(), fragment.length(), false); - EXPECT_EQ("STANZA<c:iq type=\"set\" id=\"123\" xmlns:c=\"j:c\">" - "<abc xmlns=\"def\"/></c:iq>", handler.StrClear()); - - fragment = "</stream:stream>"; - parser.Parse(fragment.c_str(), fragment.length(), false); - EXPECT_EQ("END", handler.StrClear()); -} - -TEST(XmppStanzaParserTest, TestFragmentedStanzas) { - XmppStanzaParserTestHandler handler; - XmppStanzaParser parser(&handler); - std::string fragment; - - fragment = "<stream:stream id='abc' xmlns='j:c' xml"; - parser.Parse(fragment.c_str(), fragment.length(), false); - EXPECT_EQ("", handler.StrClear()); - - fragment = "ns:stream='str'><message type='foo'><body>hel"; - parser.Parse(fragment.c_str(), fragment.length(), false); - EXPECT_EQ("START<stream:stream id=\"abc\" xmlns=\"j:c\" " - "xmlns:stream=\"str\"/>", handler.StrClear()); - - fragment = "lo</body></message> IGNORE ME <iq type='set' id='123'>" - "<abc xmlns='def'/></iq></st"; - parser.Parse(fragment.c_str(), fragment.length(), false); - EXPECT_EQ("STANZA<c:message type=\"foo\" xmlns:c=\"j:c\">" - "<c:body>hello</c:body></c:message>STANZA<c:iq type=\"set\" id=\"123\" " - "xmlns:c=\"j:c\"><abc xmlns=\"def\"/></c:iq>", handler.StrClear()); - - fragment = "ream:stream>"; - parser.Parse(fragment.c_str(), fragment.length(), false); - EXPECT_EQ("END", handler.StrClear()); -} - -TEST(XmppStanzaParserTest, TestReset) { - XmppStanzaParserTestHandler handler; - XmppStanzaParser parser(&handler); - std::string fragment; - - fragment = "<stream:stream id='abc' xmlns='j:c' xml"; - parser.Parse(fragment.c_str(), fragment.length(), false); - EXPECT_EQ("", handler.StrClear()); - - parser.Reset(); - fragment = "<stream:stream id='abc' xmlns='j:c' xml"; - parser.Parse(fragment.c_str(), fragment.length(), false); - EXPECT_EQ("", handler.StrClear()); - - fragment = "ns:stream='str'><message type='foo'><body>hel"; - parser.Parse(fragment.c_str(), fragment.length(), false); - EXPECT_EQ("START<stream:stream id=\"abc\" xmlns=\"j:c\" " - "xmlns:stream=\"str\"/>", handler.StrClear()); - parser.Reset(); - - fragment = "<stream:stream id='abc' xmlns='j:c' xmlns:stream='str'>"; - parser.Parse(fragment.c_str(), fragment.length(), false); - EXPECT_EQ("START<stream:stream id=\"abc\" xmlns=\"j:c\" " - "xmlns:stream=\"str\"/>", handler.StrClear()); - - fragment = "<message type='foo'><body>hello</body></message>"; - parser.Parse(fragment.c_str(), fragment.length(), false); - EXPECT_EQ("STANZA<c:message type=\"foo\" xmlns:c=\"j:c\">" - "<c:body>hello</c:body></c:message>", handler.StrClear()); -} - -TEST(XmppStanzaParserTest, TestError) { - XmppStanzaParserTestHandler handler; - XmppStanzaParser parser(&handler); - std::string fragment; - - fragment = "<-foobar/>"; - parser.Parse(fragment.c_str(), fragment.length(), false); - EXPECT_EQ("ERROR", handler.StrClear()); - - parser.Reset(); - fragment = "<stream:stream/>"; - parser.Parse(fragment.c_str(), fragment.length(), false); - EXPECT_EQ("ERROR", handler.StrClear()); - parser.Reset(); - - fragment = "ns:stream='str'><message type='foo'><body>hel"; - parser.Parse(fragment.c_str(), fragment.length(), false); - EXPECT_EQ("ERROR", handler.StrClear()); - parser.Reset(); - - fragment = "<stream:stream xmlns:stream='st' xmlns='jc'>" - "<foo/><bar><st:foobar/></bar>"; - parser.Parse(fragment.c_str(), fragment.length(), false); - EXPECT_EQ("START<stream:stream xmlns:stream=\"st\" xmlns=\"jc\"/>STANZA" - "<jc:foo xmlns:jc=\"jc\"/>ERROR", handler.StrClear()); -} diff --git a/talk/xmpp/xmpptask.cc b/talk/xmpp/xmpptask.cc deleted file mode 100644 index 31aba621b..000000000 --- a/talk/xmpp/xmpptask.cc +++ /dev/null @@ -1,175 +0,0 @@ -/* - * libjingle - * Copyright 2004--2006, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "webrtc/libjingle/xmpp/constants.h" -#include "webrtc/libjingle/xmpp/xmppclient.h" -#include "webrtc/libjingle/xmpp/xmppengine.h" -#include "webrtc/libjingle/xmpp/xmpptask.h" - -namespace buzz { - -XmppClientInterface::XmppClientInterface() { -} - -XmppClientInterface::~XmppClientInterface() { -} - -XmppTask::XmppTask(XmppTaskParentInterface* parent, - XmppEngine::HandlerLevel level) - : XmppTaskBase(parent), stopped_(false) { -#ifdef _DEBUG - debug_force_timeout_ = false; -#endif - - id_ = GetClient()->NextId(); - GetClient()->AddXmppTask(this, level); - GetClient()->SignalDisconnected.connect(this, &XmppTask::OnDisconnect); -} - -XmppTask::~XmppTask() { - StopImpl(); -} - -void XmppTask::StopImpl() { - while (NextStanza() != NULL) {} - if (!stopped_) { - GetClient()->RemoveXmppTask(this); - GetClient()->SignalDisconnected.disconnect(this); - stopped_ = true; - } -} - -XmppReturnStatus XmppTask::SendStanza(const XmlElement* stanza) { - if (stopped_) - return XMPP_RETURN_BADSTATE; - return GetClient()->SendStanza(stanza); -} - -XmppReturnStatus XmppTask::SendStanzaError(const XmlElement* element_original, - XmppStanzaError code, - const std::string& text) { - if (stopped_) - return XMPP_RETURN_BADSTATE; - return GetClient()->SendStanzaError(element_original, code, text); -} - -void XmppTask::Stop() { - StopImpl(); - Task::Stop(); -} - -void XmppTask::OnDisconnect() { - Error(); -} - -void XmppTask::QueueStanza(const XmlElement* stanza) { -#ifdef _DEBUG - if (debug_force_timeout_) - return; -#endif - - stanza_queue_.push_back(new XmlElement(*stanza)); - Wake(); -} - -const XmlElement* XmppTask::NextStanza() { - XmlElement* result = NULL; - if (!stanza_queue_.empty()) { - result = stanza_queue_.front(); - stanza_queue_.pop_front(); - } - next_stanza_.reset(result); - return result; -} - -XmlElement* XmppTask::MakeIq(const std::string& type, - const buzz::Jid& to, - const std::string& id) { - XmlElement* result = new XmlElement(QN_IQ); - if (!type.empty()) - result->AddAttr(QN_TYPE, type); - if (!to.IsEmpty()) - result->AddAttr(QN_TO, to.Str()); - if (!id.empty()) - result->AddAttr(QN_ID, id); - return result; -} - -XmlElement* XmppTask::MakeIqResult(const XmlElement * query) { - XmlElement* result = new XmlElement(QN_IQ); - result->AddAttr(QN_TYPE, STR_RESULT); - if (query->HasAttr(QN_FROM)) { - result->AddAttr(QN_TO, query->Attr(QN_FROM)); - } - result->AddAttr(QN_ID, query->Attr(QN_ID)); - return result; -} - -bool XmppTask::MatchResponseIq(const XmlElement* stanza, - const Jid& to, - const std::string& id) { - if (stanza->Name() != QN_IQ) - return false; - - if (stanza->Attr(QN_ID) != id) - return false; - - return MatchStanzaFrom(stanza, to); -} - -bool XmppTask::MatchStanzaFrom(const XmlElement* stanza, - const Jid& to) { - Jid from(stanza->Attr(QN_FROM)); - if (from == to) - return true; - - // We address the server as "", check if we are doing so here. - if (!to.IsEmpty()) - return false; - - // It is legal for the server to identify itself with "domain" or - // "myself@domain" - Jid me = GetClient()->jid(); - return (from == Jid(me.domain())) || (from == me.BareJid()); -} - -bool XmppTask::MatchRequestIq(const XmlElement* stanza, - const std::string& type, - const QName& qn) { - if (stanza->Name() != QN_IQ) - return false; - - if (stanza->Attr(QN_TYPE) != type) - return false; - - if (stanza->FirstNamed(qn) == NULL) - return false; - - return true; -} - -} diff --git a/talk/xmpp/xmpptask.h b/talk/xmpp/xmpptask.h deleted file mode 100644 index a8d1124f5..000000000 --- a/talk/xmpp/xmpptask.h +++ /dev/null @@ -1,189 +0,0 @@ -/* - * libjingle - * Copyright 2004--2006, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef TALK_XMPP_XMPPTASK_H_ -#define TALK_XMPP_XMPPTASK_H_ - -#include <deque> -#include <string> -#include "webrtc/libjingle/xmpp/xmppengine.h" -#include "webrtc/base/sigslot.h" -#include "webrtc/base/task.h" -#include "webrtc/base/taskparent.h" - -namespace buzz { - -///////////////////////////////////////////////////////////////////// -// -// XMPPTASK -// -///////////////////////////////////////////////////////////////////// -// -// See Task and XmppClient first. -// -// XmppTask is a task that is designed to go underneath XmppClient and be -// useful there. It has a way of finding its XmppClient parent so you -// can have it nested arbitrarily deep under an XmppClient and it can -// still find the XMPP services. -// -// Tasks register themselves to listen to particular kinds of stanzas -// that are sent out by the client. Rather than processing stanzas -// right away, they should decide if they own the sent stanza, -// and if so, queue it and Wake() the task, or if a stanza does not belong -// to you, return false right away so the next XmppTask can take a crack. -// This technique (synchronous recognize, but asynchronous processing) -// allows you to have arbitrary logic for recognizing stanzas yet still, -// for example, disconnect a client while processing a stanza - -// without reentrancy problems. -// -///////////////////////////////////////////////////////////////////// - -class XmppTask; - -// XmppClientInterface is an abstract interface for sending and -// handling stanzas. It can be implemented for unit tests or -// different network environments. It will usually be implemented by -// XmppClient. -class XmppClientInterface { - public: - XmppClientInterface(); - virtual ~XmppClientInterface(); - - virtual XmppEngine::State GetState() const = 0; - virtual const Jid& jid() const = 0; - virtual std::string NextId() = 0; - virtual XmppReturnStatus SendStanza(const XmlElement* stanza) = 0; - virtual XmppReturnStatus SendStanzaError(const XmlElement* original_stanza, - XmppStanzaError error_code, - const std::string& message) = 0; - virtual void AddXmppTask(XmppTask* task, XmppEngine::HandlerLevel level) = 0; - virtual void RemoveXmppTask(XmppTask* task) = 0; - sigslot::signal0<> SignalDisconnected; - - DISALLOW_EVIL_CONSTRUCTORS(XmppClientInterface); -}; - -// XmppTaskParentInterface is the interface require for any parent of -// an XmppTask. It needs, for example, a way to get an -// XmppClientInterface. - -// We really ought to inherit from a TaskParentInterface, but we tried -// that and it's way too complicated to change -// Task/TaskParent/TaskRunner. For now, this works. -class XmppTaskParentInterface : public rtc::Task { - public: - explicit XmppTaskParentInterface(rtc::TaskParent* parent) - : Task(parent) { - } - virtual ~XmppTaskParentInterface() {} - - virtual XmppClientInterface* GetClient() = 0; - - DISALLOW_EVIL_CONSTRUCTORS(XmppTaskParentInterface); -}; - -class XmppTaskBase : public XmppTaskParentInterface { - public: - explicit XmppTaskBase(XmppTaskParentInterface* parent) - : XmppTaskParentInterface(parent), - parent_(parent) { - } - virtual ~XmppTaskBase() {} - - virtual XmppClientInterface* GetClient() { - return parent_->GetClient(); - } - - protected: - XmppTaskParentInterface* parent_; - - DISALLOW_EVIL_CONSTRUCTORS(XmppTaskBase); -}; - -class XmppTask : public XmppTaskBase, - public XmppStanzaHandler, - public sigslot::has_slots<> -{ - public: - XmppTask(XmppTaskParentInterface* parent, - XmppEngine::HandlerLevel level = XmppEngine::HL_NONE); - virtual ~XmppTask(); - - std::string task_id() const { return id_; } - void set_task_id(std::string id) { id_ = id; } - -#ifdef _DEBUG - void set_debug_force_timeout(const bool f) { debug_force_timeout_ = f; } -#endif - - virtual bool HandleStanza(const XmlElement* stanza) { return false; } - - protected: - XmppReturnStatus SendStanza(const XmlElement* stanza); - XmppReturnStatus SetResult(const std::string& code); - XmppReturnStatus SendStanzaError(const XmlElement* element_original, - XmppStanzaError code, - const std::string& text); - - virtual void Stop(); - virtual void OnDisconnect(); - - virtual void QueueStanza(const XmlElement* stanza); - const XmlElement* NextStanza(); - - bool MatchStanzaFrom(const XmlElement* stanza, const Jid& match_jid); - - bool MatchResponseIq(const XmlElement* stanza, const Jid& to, - const std::string& task_id); - - static bool MatchRequestIq(const XmlElement* stanza, const std::string& type, - const QName& qn); - static XmlElement *MakeIqResult(const XmlElement* query); - static XmlElement *MakeIq(const std::string& type, - const Jid& to, const std::string& task_id); - - // Returns true if the task is under the specified rate limit and updates the - // rate limit accordingly - bool VerifyTaskRateLimit(const std::string task_name, int max_count, - int per_x_seconds); - -private: - void StopImpl(); - - bool stopped_; - std::deque<XmlElement*> stanza_queue_; - rtc::scoped_ptr<XmlElement> next_stanza_; - std::string id_; - -#ifdef _DEBUG - bool debug_force_timeout_; -#endif -}; - -} // namespace buzz - -#endif // TALK_XMPP_XMPPTASK_H_ diff --git a/talk/xmpp/xmppthread.cc b/talk/xmpp/xmppthread.cc deleted file mode 100644 index ad9246b1b..000000000 --- a/talk/xmpp/xmppthread.cc +++ /dev/null @@ -1,86 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "webrtc/libjingle/xmpp/xmppthread.h" - -#include "webrtc/libjingle/xmpp/xmppauth.h" -#include "webrtc/libjingle/xmpp/xmppclientsettings.h" - -namespace buzz { -namespace { - -const uint32 MSG_LOGIN = 1; -const uint32 MSG_DISCONNECT = 2; - -struct LoginData: public rtc::MessageData { - LoginData(const buzz::XmppClientSettings& s) : xcs(s) {} - virtual ~LoginData() {} - - buzz::XmppClientSettings xcs; -}; - -} // namespace - -XmppThread::XmppThread() { - pump_ = new buzz::XmppPump(this); -} - -XmppThread::~XmppThread() { - Stop(); - delete pump_; -} - -void XmppThread::ProcessMessages(int cms) { - rtc::Thread::ProcessMessages(cms); -} - -void XmppThread::Login(const buzz::XmppClientSettings& xcs) { - Post(this, MSG_LOGIN, new LoginData(xcs)); -} - -void XmppThread::Disconnect() { - Post(this, MSG_DISCONNECT); -} - -void XmppThread::OnStateChange(buzz::XmppEngine::State state) { -} - -void XmppThread::OnMessage(rtc::Message* pmsg) { - if (pmsg->message_id == MSG_LOGIN) { - ASSERT(pmsg->pdata != NULL); - LoginData* data = reinterpret_cast<LoginData*>(pmsg->pdata); - pump_->DoLogin(data->xcs, new XmppSocket(buzz::TLS_DISABLED), - new XmppAuth()); - delete data; - } else if (pmsg->message_id == MSG_DISCONNECT) { - pump_->DoDisconnect(); - } else { - ASSERT(false); - } -} - -} // namespace buzz diff --git a/talk/xmpp/xmppthread.h b/talk/xmpp/xmppthread.h deleted file mode 100644 index 5a77f0094..000000000 --- a/talk/xmpp/xmppthread.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef TALK_XMPP_XMPPTHREAD_H_ -#define TALK_XMPP_XMPPTHREAD_H_ - -#include "webrtc/libjingle/xmpp/xmppclientsettings.h" -#include "webrtc/libjingle/xmpp/xmppengine.h" -#include "webrtc/libjingle/xmpp/xmpppump.h" -#include "webrtc/libjingle/xmpp/xmppsocket.h" -#include "webrtc/base/thread.h" - -namespace buzz { - -class XmppThread: - public rtc::Thread, buzz::XmppPumpNotify, rtc::MessageHandler { -public: - XmppThread(); - ~XmppThread(); - - buzz::XmppClient* client() { return pump_->client(); } - - void ProcessMessages(int cms); - - void Login(const buzz::XmppClientSettings & xcs); - void Disconnect(); - -private: - buzz::XmppPump* pump_; - - void OnStateChange(buzz::XmppEngine::State state); - void OnMessage(rtc::Message* pmsg); -}; - -} // namespace buzz - -#endif // TALK_XMPP_XMPPTHREAD_H_ -