1 /* 2 * libjingle 3 * Copyright 2010, Google Inc. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, 9 * this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright notice, 11 * this list of conditions and the following disclaimer in the documentation 12 * and/or other materials provided with the distribution. 13 * 3. The name of the author may not be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 #include "talk/xmpp/jingleinfotask.h" 29 30 #include "talk/base/socketaddress.h" 31 #include "talk/xmpp/constants.h" 32 #include "talk/xmpp/xmppclient.h" 33 #include "talk/xmpp/xmpptask.h" 34 35 namespace buzz { 36 37 class JingleInfoTask::JingleInfoGetTask : public XmppTask { 38 public: 39 explicit JingleInfoGetTask(XmppTaskParentInterface* parent) 40 : XmppTask(parent, XmppEngine::HL_SINGLE), 41 done_(false) {} 42 43 virtual int ProcessStart() { 44 talk_base::scoped_ptr<XmlElement> get( 45 MakeIq(STR_GET, Jid(), task_id())); 46 get->AddElement(new XmlElement(QN_JINGLE_INFO_QUERY, true)); 47 if (SendStanza(get.get()) != XMPP_RETURN_OK) { 48 return STATE_ERROR; 49 } 50 return STATE_RESPONSE; 51 } 52 virtual int ProcessResponse() { 53 if (done_) 54 return STATE_DONE; 55 return STATE_BLOCKED; 56 } 57 58 protected: 59 virtual bool HandleStanza(const XmlElement * stanza) { 60 if (!MatchResponseIq(stanza, Jid(), task_id())) 61 return false; 62 63 if (stanza->Attr(QN_TYPE) != STR_RESULT) 64 return false; 65 66 // Queue the stanza with the parent so these don't get handled out of order 67 JingleInfoTask* parent = static_cast<JingleInfoTask*>(GetParent()); 68 parent->QueueStanza(stanza); 69 70 // Wake ourselves so we can go into the done state 71 done_ = true; 72 Wake(); 73 return true; 74 } 75 76 bool done_; 77 }; 78 79 80 void JingleInfoTask::RefreshJingleInfoNow() { 81 JingleInfoGetTask* get_task = new JingleInfoGetTask(this); 82 get_task->Start(); 83 } 84 85 bool 86 JingleInfoTask::HandleStanza(const XmlElement * stanza) { 87 if (!MatchRequestIq(stanza, "set", QN_JINGLE_INFO_QUERY)) 88 return false; 89 90 // only respect relay push from the server 91 Jid from(stanza->Attr(QN_FROM)); 92 if (!from.IsEmpty() && 93 !from.BareEquals(GetClient()->jid()) && 94 from != Jid(GetClient()->jid().domain())) 95 return false; 96 97 QueueStanza(stanza); 98 return true; 99 } 100 101 int 102 JingleInfoTask::ProcessStart() { 103 std::vector<std::string> relay_hosts; 104 std::vector<talk_base::SocketAddress> stun_hosts; 105 std::string relay_token; 106 const XmlElement * stanza = NextStanza(); 107 if (stanza == NULL) 108 return STATE_BLOCKED; 109 const XmlElement * query = stanza->FirstNamed(QN_JINGLE_INFO_QUERY); 110 if (query == NULL) 111 return STATE_START; 112 const XmlElement *stun = query->FirstNamed(QN_JINGLE_INFO_STUN); 113 if (stun) { 114 for (const XmlElement *server = stun->FirstNamed(QN_JINGLE_INFO_SERVER); 115 server != NULL; server = server->NextNamed(QN_JINGLE_INFO_SERVER)) { 116 std::string host = server->Attr(QN_JINGLE_INFO_HOST); 117 std::string port = server->Attr(QN_JINGLE_INFO_UDP); 118 if (host != STR_EMPTY && host != STR_EMPTY) { 119 stun_hosts.push_back(talk_base::SocketAddress(host, atoi(port.c_str()))); 120 } 121 } 122 } 123 124 const XmlElement *relay = query->FirstNamed(QN_JINGLE_INFO_RELAY); 125 if (relay) { 126 relay_token = relay->TextNamed(QN_JINGLE_INFO_TOKEN); 127 for (const XmlElement *server = relay->FirstNamed(QN_JINGLE_INFO_SERVER); 128 server != NULL; server = server->NextNamed(QN_JINGLE_INFO_SERVER)) { 129 std::string host = server->Attr(QN_JINGLE_INFO_HOST); 130 if (host != STR_EMPTY) { 131 relay_hosts.push_back(host); 132 } 133 } 134 } 135 SignalJingleInfo(relay_token, relay_hosts, stun_hosts); 136 return STATE_START; 137 } 138 } 139