EMANE  1.2.1
flowcontrolmanager.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2013-2014,2016 - Adjacent Link LLC, Bridgewater, New
3  * Jersey
4  * Copyright (c) 2010 - DRS CenGen, LLC, Columbia, Maryland
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  * notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above copyright
14  * notice, this list of conditions and the following disclaimer in
15  * the documentation and/or other materials provided with the
16  * distribution.
17  * * Neither the name of DRS CenGen, LLC nor the names of its
18  * contributors may be used to endorse or promote products derived
19  * from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  */
34 
36 
37 #include <mutex>
38 
39 class EMANE::FlowControlManager::Implementation
40 {
41 public:
42 Implementation(EMANE::DownstreamTransport & transport):
43  rTransport_(transport),
44  u16TokensAvailable_{},
45  u16TotalTokensAvailable_{},
46  u16ShadowTokenCount_{},
47  u16LastTokensUpdate_{},
48  bAckPending_{true}{}
49 
50  ~Implementation(){}
51 
52  void start(std::uint16_t u16TotalTokensAvailable)
53  {
54  std::lock_guard<std::mutex> m(mutex_);
55 
56  u16TotalTokensAvailable_ = u16TotalTokensAvailable;
57  u16TokensAvailable_ = u16TotalTokensAvailable;
58 
59  sendFlowControlResponseMessage();
60  }
61 
62  void stop()
63  {
64  std::lock_guard<std::mutex> m(mutex_);
65 
66  u16TotalTokensAvailable_ = 0;
67  u16TokensAvailable_ = 0;
68  u16ShadowTokenCount_ = 0;
69  }
70 
71  std::pair<std::uint16_t,bool> addToken(std::uint16_t u16Tokens)
72  {
73  std::lock_guard<std::mutex> m(mutex_);
74 
75  // get add tokens status
76  const bool bStatus = ((u16TokensAvailable_ + u16Tokens) <= u16TotalTokensAvailable_);
77 
78  // have room to add all requested tokens
79  if(bStatus == true)
80  {
81  // update tokens available
82  u16TokensAvailable_ += u16Tokens;
83  }
84 
85  // check shadow count, send update if tokens are available
86  if((u16ShadowTokenCount_ == 0) && (u16TokensAvailable_ > 0))
87  {
88  sendFlowControlResponseMessage();
89  }
90 
91  return {u16TokensAvailable_,bStatus};
92  }
93 
94  std::pair<std::uint16_t,bool> removeToken()
95  {
96  std::lock_guard<std::mutex> m(mutex_);
97 
98  bool bStatus;
99 
100  // ack pending, no action
101  if(bAckPending_ == true)
102  {
103  bStatus = false;
104  }
105  else
106  {
107  // no tokens available
108  if(u16TokensAvailable_ == 0)
109  {
110  bStatus = false;
111  }
112  else
113  {
114  // decrement tokens available
115  --u16TokensAvailable_;
116  --u16ShadowTokenCount_;
117 
118  bStatus = true;
119  }
120  }
121 
122  return {u16TokensAvailable_,bStatus};
123  }
124 
125  void processFlowControlMessage(const Controls::FlowControlControlMessage * pMsg)
126  {
127  std::lock_guard<std::mutex> m(mutex_);
128 
129  if(!bAckPending_)
130  {
131  // upstream layer start or restart condition
132  // detected
133  sendFlowControlResponseMessage();
134  }
135  else
136  {
137  // a proper acknowledgment echos the token account will allow
138  // traffic to flow
139  if(pMsg->getTokens() == u16LastTokensUpdate_)
140  {
141  bAckPending_ = false;
142  }
143  else
144  {
145  // upstream layer missed the initial token message
146  // so we received a message with an incorrect number token
147  // count - resend a reponse
148  sendFlowControlResponseMessage();
149  }
150  }
151  }
152 
153 private:
154 
155  DownstreamTransport & rTransport_;
156 
157  std::mutex mutex_;
158 
159  std::uint16_t u16TokensAvailable_;
160 
161  std::uint16_t u16TotalTokensAvailable_;
162 
163  std::uint16_t u16ShadowTokenCount_;
164 
165  std::uint16_t u16LastTokensUpdate_;
166 
167  bool bAckPending_;
168 
169  // precondition - mutex is locked
170  void sendFlowControlResponseMessage()
171  {
172  rTransport_.sendUpstreamControl({Controls::FlowControlControlMessage::create(u16TokensAvailable_)});
173 
174  u16ShadowTokenCount_ = u16TokensAvailable_;
175 
176  u16LastTokensUpdate_ = u16TokensAvailable_;
177 
178  bAckPending_ = true;
179  }
180 };
181 
182 
184  pImpl_{new Implementation{transport}}
185 {}
186 
188 
189 void EMANE::FlowControlManager::start(std::uint16_t u16TotalTokensAvailable)
190 {
191  pImpl_->start(u16TotalTokensAvailable);
192 }
193 
195 {
196  pImpl_->stop();
197 }
198 
199 std::pair<std::uint16_t,bool> EMANE::FlowControlManager::addToken(std::uint16_t u16Tokens)
200 {
201  return pImpl_->addToken(u16Tokens);
202 }
203 
204 std::pair<std::uint16_t,bool> EMANE::FlowControlManager::removeToken()
205 {
206  return pImpl_->removeToken();
207 }
208 
210 {
211  pImpl_->processFlowControlMessage(pMsg);
212 }
std::pair< std::uint16_t, bool > addToken(std::uint16_t u16Tokens=1)
FlowControlManager(EMANE::DownstreamTransport &transport)
void start(std::uint16_t u16TotalTokensAvailable)
static FlowControlControlMessage * create(const Serialization &serialization)
void processFlowControlMessage(const Controls::FlowControlControlMessage *pMsg)
Flow Control Control Messages are sent between a MAC layer and a transport in order to communicate da...
std::pair< std::uint16_t, bool > removeToken()
DownstreamTransport allows for processing downstream data and control messages.