1 /* 2 * libjingle 3 * Copyright 2004--2005, 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 #ifndef _CRICKET_P2P_CLIENT_SESSIONSENDTASK_H_ 29 #define _CRICKET_P2P_CLIENT_SESSIONSENDTASK_H_ 30 31 #include "talk/base/common.h" 32 #include "talk/xmpp/constants.h" 33 #include "talk/xmpp/xmppclient.h" 34 #include "talk/xmpp/xmppengine.h" 35 #include "talk/xmpp/xmpptask.h" 36 #include "talk/p2p/base/sessionmanager.h" 37 38 namespace cricket { 39 40 // The job of this task is to send an IQ stanza out (after stamping it with 41 // an ID attribute) and then wait for a response. If not response happens 42 // within 5 seconds, it will signal failure on a SessionManager. If an error 43 // happens it will also signal failure. If, however, the send succeeds this 44 // task will quietly go away. 45 46 class SessionSendTask : public buzz::XmppTask { 47 public: SessionSendTask(TaskParent * parent,SessionManager * session_manager)48 SessionSendTask(TaskParent *parent, SessionManager *session_manager) 49 : buzz::XmppTask(parent, buzz::XmppEngine::HL_SINGLE), 50 session_manager_(session_manager) { 51 set_timeout_seconds(15); 52 } 53 ~SessionSendTask()54 virtual ~SessionSendTask() { 55 SignalDone(this); 56 } 57 Send(const buzz::XmlElement * stanza)58 void Send(const buzz::XmlElement* stanza) { 59 ASSERT(stanza_.get() == NULL); 60 61 // This should be an IQ of type set, result, or error. In the first case, 62 // we supply an ID. In the others, it should be present. 63 ASSERT(stanza->Name() == buzz::QN_IQ); 64 ASSERT(stanza->HasAttr(buzz::QN_TYPE)); 65 if (stanza->Attr(buzz::QN_TYPE) == "set") { 66 ASSERT(!stanza->HasAttr(buzz::QN_ID)); 67 } else { 68 ASSERT((stanza->Attr(buzz::QN_TYPE) == "result") || 69 (stanza->Attr(buzz::QN_TYPE) == "error")); 70 ASSERT(stanza->HasAttr(buzz::QN_ID)); 71 } 72 73 stanza_.reset(new buzz::XmlElement(*stanza)); 74 if (stanza_->HasAttr(buzz::QN_ID)) { 75 set_task_id(stanza_->Attr(buzz::QN_ID)); 76 } else { 77 stanza_->SetAttr(buzz::QN_ID, task_id()); 78 } 79 } 80 81 sigslot::signal1<SessionSendTask *> SignalDone; 82 83 protected: OnTimeout()84 virtual int OnTimeout() { 85 session_manager_->OnFailedSend(stanza_.get(), NULL); 86 87 return XmppTask::OnTimeout(); 88 } 89 ProcessStart()90 virtual int ProcessStart() { 91 SendStanza(stanza_.get()); 92 if (stanza_->Attr(buzz::QN_TYPE) == buzz::STR_SET) { 93 return STATE_RESPONSE; 94 } else { 95 return STATE_DONE; 96 } 97 } 98 ProcessResponse()99 virtual int ProcessResponse() { 100 if (GetClient()->GetState() != buzz::XmppEngine::STATE_OPEN) { 101 return STATE_DONE; 102 } 103 104 const buzz::XmlElement* next = NextStanza(); 105 if (next == NULL) 106 return STATE_BLOCKED; 107 108 if (next->Attr(buzz::QN_TYPE) == buzz::STR_RESULT) { 109 session_manager_->OnIncomingResponse(stanza_.get(), next); 110 } else { 111 session_manager_->OnFailedSend(stanza_.get(), next); 112 } 113 114 return STATE_DONE; 115 } 116 HandleStanza(const buzz::XmlElement * stanza)117 virtual bool HandleStanza(const buzz::XmlElement *stanza) { 118 if (!MatchResponseIq(stanza, 119 buzz::Jid(stanza_->Attr(buzz::QN_TO)), task_id())) 120 return false; 121 if (stanza->Attr(buzz::QN_TYPE) == buzz::STR_RESULT || 122 stanza->Attr(buzz::QN_TYPE) == buzz::STR_ERROR) { 123 QueueStanza(stanza); 124 return true; 125 } 126 return false; 127 } 128 129 private: 130 SessionManager *session_manager_; 131 talk_base::scoped_ptr<buzz::XmlElement> stanza_; 132 bool timed_out_; 133 }; 134 135 } 136 137 #endif // _CRICKET_P2P_CLIENT_SESSIONSENDTASK_H_ 138