aboutsummaryrefslogtreecommitdiff
path: root/p2p/base/stun_request.h
blob: 6e83be3830fa92557044213a55b02bd26bd98289 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
/*
 *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#ifndef P2P_BASE_STUN_REQUEST_H_
#define P2P_BASE_STUN_REQUEST_H_

#include <stddef.h>
#include <stdint.h>

#include <functional>
#include <map>
#include <memory>
#include <string>

#include "api/task_queue/pending_task_safety_flag.h"
#include "api/task_queue/task_queue_base.h"
#include "api/transport/stun.h"
#include "api/units/time_delta.h"

namespace cricket {

class StunRequest;

const int kAllRequestsForTest = 0;

// Total max timeouts: 39.75 seconds
// For years, this was 9.5 seconds, but for networks that experience moments of
// high RTT (such as 40s on 2G networks), this doesn't work well.
const int STUN_TOTAL_TIMEOUT = 39750;  // milliseconds

// 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(
      webrtc::TaskQueueBase* thread,
      std::function<void(const void*, size_t, StunRequest*)> send_packet);
  ~StunRequestManager();

  // Starts sending the given request (perhaps after a delay).
  void Send(StunRequest* request);
  void SendDelayed(StunRequest* request, int delay);

  // If `msg_type` is kAllRequestsForTest, sends all pending requests right
  // away. Otherwise, sends those that have a matching type right away. Only for
  // testing.
  // TODO(tommi): Remove this method and update tests that use it to simulate
  // production code.
  void FlushForTest(int msg_type);

  // Returns true if at least one request with `msg_type` is scheduled for
  // transmission. For testing only.
  // TODO(tommi): Remove this method and update tests that use it to simulate
  // production code.
  bool HasRequestForTest(int msg_type);

  // 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);

  // Called from a StunRequest when a timeout occurs.
  void OnRequestTimedOut(StunRequest* request);

  bool empty() const;

  webrtc::TaskQueueBase* network_thread() const { return thread_; }

  void SendPacket(const void* data, size_t size, StunRequest* request);

 private:
  typedef std::map<std::string, std::unique_ptr<StunRequest>> RequestMap;

  webrtc::TaskQueueBase* const thread_;
  RequestMap requests_ RTC_GUARDED_BY(thread_);
  const std::function<void(const void*, size_t, StunRequest*)> send_packet_;
};

// Represents an individual request to be sent.  The STUN message can either be
// constructed beforehand or built on demand.
class StunRequest {
 public:
  explicit StunRequest(StunRequestManager& manager);
  StunRequest(StunRequestManager& manager,
              std::unique_ptr<StunMessage> message);
  virtual ~StunRequest();

  // 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() const { return msg_->transaction_id(); }

  // Returns the reduced transaction ID of this request.
  uint32_t reduced_transaction_id() const {
    return msg_->reduced_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)
  int Elapsed() const;

 protected:
  friend class StunRequestManager;

  // Called by StunRequestManager.
  void Send(webrtc::TimeDelta delay);

  // Called from FlushForTest.
  // TODO(tommi): Remove when FlushForTest gets removed.
  void ResetTasksForTest();

  StunMessage* mutable_msg() { return msg_.get(); }

  // Called when the message receives a response or times out.
  virtual void OnResponse(StunMessage* response) {}
  virtual void OnErrorResponse(StunMessage* response) {}
  virtual void OnTimeout() {}
  // Called when the message is sent.
  virtual void OnSent();
  // Returns the next delay for resends in milliseconds.
  virtual int resend_delay();

  webrtc::TaskQueueBase* network_thread() const {
    return manager_.network_thread();
  }

  void set_timed_out();

 private:
  void SendInternal();
  // Calls `PostDelayedTask` to queue up a call to SendInternal after the
  // specified timeout.
  void SendDelayed(webrtc::TimeDelta delay);

  StunRequestManager& manager_;
  const std::unique_ptr<StunMessage> msg_;
  int64_t tstamp_ RTC_GUARDED_BY(network_thread());
  int count_ RTC_GUARDED_BY(network_thread());
  bool timeout_ RTC_GUARDED_BY(network_thread());
  webrtc::ScopedTaskSafety task_safety_{
      webrtc::PendingTaskSafetyFlag::CreateDetachedInactive()};
};

}  // namespace cricket

#endif  // P2P_BASE_STUN_REQUEST_H_