1// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef REMOTING_SIGNALING_IQ_SENDER_H_
6#define REMOTING_SIGNALING_IQ_SENDER_H_
7
8#include <map>
9#include <string>
10
11#include "base/callback.h"
12#include "base/compiler_specific.h"
13#include "base/gtest_prod_util.h"
14#include "base/memory/scoped_ptr.h"
15#include "base/memory/weak_ptr.h"
16#include "remoting/signaling/signal_strategy.h"
17
18namespace base {
19class TimeDelta;
20}  // namespace base
21
22namespace buzz {
23class XmlElement;
24}  // namespace buzz
25
26namespace remoting {
27
28class IqRequest;
29class SignalStrategy;
30
31// IqSender handles sending iq requests and routing of responses to
32// those requests.
33class IqSender : public SignalStrategy::Listener {
34 public:
35  // Callback that is called when an Iq response is received. Called
36  // with the |response| set to NULL in case of a timeout.
37  typedef base::Callback<void(IqRequest* request,
38                              const buzz::XmlElement* response)> ReplyCallback;
39
40  explicit IqSender(SignalStrategy* signal_strategy);
41  virtual ~IqSender();
42
43  // Send an iq stanza. Returns an IqRequest object that represends
44  // the request. |callback| is called when response to |stanza| is
45  // received. Destroy the returned IqRequest to cancel the callback.
46  // Caller must take ownership of the result. Result must be
47  // destroyed before sender is destroyed.
48  scoped_ptr<IqRequest> SendIq(scoped_ptr<buzz::XmlElement> stanza,
49                               const ReplyCallback& callback);
50
51  // Same as above, but also formats the message.
52  scoped_ptr<IqRequest> SendIq(const std::string& type,
53                               const std::string& addressee,
54                               scoped_ptr<buzz::XmlElement> iq_body,
55                               const ReplyCallback& callback);
56
57  // SignalStrategy::Listener implementation.
58  virtual void OnSignalStrategyStateChange(
59      SignalStrategy::State state) OVERRIDE;
60  virtual bool OnSignalStrategyIncomingStanza(
61      const buzz::XmlElement* stanza) OVERRIDE;
62
63 private:
64  typedef std::map<std::string, IqRequest*> IqRequestMap;
65  friend class IqRequest;
66
67  // Helper function used to create iq stanzas.
68  static scoped_ptr<buzz::XmlElement> MakeIqStanza(
69      const std::string& type,
70      const std::string& addressee,
71      scoped_ptr<buzz::XmlElement> iq_body);
72
73  // Removes |request| from the list of pending requests. Called by IqRequest.
74  void RemoveRequest(IqRequest* request);
75
76  SignalStrategy* signal_strategy_;
77  IqRequestMap requests_;
78
79  DISALLOW_COPY_AND_ASSIGN(IqSender);
80};
81
82// This call must only be used on the thread it was created on.
83class IqRequest : public  base::SupportsWeakPtr<IqRequest> {
84 public:
85  IqRequest(IqSender* sender, const IqSender::ReplyCallback& callback,
86            const std::string& addressee);
87  ~IqRequest();
88
89  // Sets timeout for the request. When the timeout expires the
90  // callback is called with the |response| set to NULL.
91  void SetTimeout(base::TimeDelta timeout);
92
93 private:
94  friend class IqSender;
95
96  void CallCallback(const buzz::XmlElement* stanza);
97  void OnTimeout();
98
99  // Called by IqSender when a response is received.
100  void OnResponse(const buzz::XmlElement* stanza);
101
102  void DeliverResponse(scoped_ptr<buzz::XmlElement> stanza);
103
104  IqSender* sender_;
105  IqSender::ReplyCallback callback_;
106  std::string addressee_;
107
108  DISALLOW_COPY_AND_ASSIGN(IqRequest);
109};
110
111}  // namespace remoting
112
113#endif  // REMOTING_SIGNALING_IQ_SENDER_H_
114