blob: 1ba6808bdaacba6608e51c23258f7f9c023d0e55 [file] [log] [blame]
Alexander Afanasyev33b72772014-01-26 23:22:58 -08001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
3 * Copyright (C) 2014 Named Data Networking Project
4 * See COPYING for copyright and distribution information.
5 */
6
7#include "forwarder.hpp"
8
Alexander Afanasyev18bbf812014-01-29 01:40:23 -08009namespace nfd {
Alexander Afanasyev33b72772014-01-26 23:22:58 -080010
11Forwarder::Forwarder(boost::asio::io_service& ioService)
Junxiao Shid3c792f2014-01-30 00:46:13 -070012 : m_scheduler(ioService)
Alexander Afanasyev33b72772014-01-26 23:22:58 -080013{
14}
15
16uint64_t
17Forwarder::addFace(const shared_ptr<Face>& face)
18{
19 return -1;
20}
21
22void
23Forwarder::removeFace(const shared_ptr<Face>& face)
24{
25}
26
27void
28Forwarder::onInterest(const Face& face, const Interest& interest)
29{
Junxiao Shid3c792f2014-01-30 00:46:13 -070030 this->onIncomingInterest(const_cast<Face&>(face), interest);
Alexander Afanasyev33b72772014-01-26 23:22:58 -080031}
32
33void
34Forwarder::onData(const Face& face, const Data& data)
35{
Junxiao Shid3c792f2014-01-30 00:46:13 -070036 this->onIncomingData(const_cast<Face&>(face), data);
Alexander Afanasyev33b72772014-01-26 23:22:58 -080037}
38
Junxiao Shid3c792f2014-01-30 00:46:13 -070039void
40Forwarder::onIncomingInterest(Face& inFace, const Interest& interest)
41{
42 // receive Interest
43
44 // PIT insert
45 std::pair<shared_ptr<pit::Entry>, bool>
46 pitInsertResult = m_pit.insert(interest);
47 shared_ptr<pit::Entry> pitEntry = pitInsertResult.first;
48
49 // detect loop and record Nonce
50 bool isLoop = ! pitEntry->addNonce(interest.getNonce());
51 if (isLoop) {
52 // goto Interest loop pipeline
53 this->onInterestLoop(inFace, interest, pitEntry);
54 return;
55 }
56
57 // cancel unsatisfy & straggler timer
58 this->cancelUnsatisfyAndStragglerTimer(pitEntry);
59
60 const pit::InRecordCollection& inRecords = pitEntry->getInRecords();
61 bool isPending = inRecords.begin() == inRecords.end();
62
63 if (!isPending) {
64 // CS lookup
65 const Data* csMatch = m_cs.find(interest);
66 if (csMatch != 0) {
67 // XXX should we lookup PIT for other Interests that also match csMatch?
68
69 // goto outgoing Data pipeline
70 this->onOutgoingData(*csMatch, inFace);
71 return;
72 }
73 }
74
75 // insert InRecord
76 pit::InRecordCollection::iterator inRecordIt =
77 pitEntry->insertOrUpdateInRecord(inFace.shared_from_this(), interest);
78
79 // app chosen nexthops
80 bool isAppChosenNexthops = false; // TODO get from local control header
81 if (isAppChosenNexthops) {
82 // TODO foreach chosen nexthop: goto outgoing Interest pipeline
83 return;
84 }
85
86 // FIB lookup
87 shared_ptr<fib::Entry> fibEntry
88 = m_fib.findLongestPrefixMatch(interest.getName());
89 // TODO use Fib::findParent(pitEntry)
90
91 // dispatch to strategy
92 // TODO
93}
94
95void
96Forwarder::onInterestLoop(Face& inFace, const Interest& interest,
97 shared_ptr<pit::Entry> pitEntry)
98{
99 // do nothing, which means Interest is dropped
100}
101
102void
103Forwarder::onOutgoingInterest(shared_ptr<pit::Entry> pitEntry, Face& outFace)
104{
105 // pick Interest
106 const Interest& interest = pitEntry->getInterest();
107 // TODO pick the last incoming Interest
108
109 // insert OutRecord
110 pit::OutRecordCollection::iterator outRecordIt =
111 pitEntry->insertOrUpdateOutRecord(outFace.shared_from_this(), interest);
112
113 // set PIT unsatisfy timer
114 this->setUnsatisfyTimer(pitEntry);
115
116 // send Interest
117 outFace.sendInterest(interest);
118}
119
120void
121Forwarder::onInterestRebuff(shared_ptr<pit::Entry> pitEntry)
122{
123 // set PIT straggler timer
124 this->setStragglerTimer(pitEntry);
125}
126
127void
128Forwarder::onInterestUnsatisfied(shared_ptr<pit::Entry> pitEntry)
129{
130 // invoke PIT unsatisfied callback
131 // TODO
132
133 // PIT delete
134 m_pit.remove(pitEntry);
135}
136
137void
138Forwarder::onIncomingData(Face& inFace, const Data& data)
139{
140 // receive Data
141
142 // PIT match
143 shared_ptr<pit::DataMatchResult> pitMatches = m_pit.findAllDataMatches(data);
144 if (pitMatches->begin() == pitMatches->end()) {
145 // goto Data unsolicited pipeline
146 this->onDataUnsolicited(inFace, data);
147 return;
148 }
149
150 // CS insert
151 m_cs.insert(data);
152
153 std::set<shared_ptr<Face> > pendingDownstreams;
154 // foreach PitEntry
155 for (pit::DataMatchResult::iterator it = pitMatches->begin();
156 it != pitMatches->end(); ++it) {
157 shared_ptr<pit::Entry> pitEntry = *it;
158
159 // cancel unsatisfy & straggler timer
160 this->cancelUnsatisfyAndStragglerTimer(pitEntry);
161
162 // remember pending downstreams
163 const pit::InRecordCollection& inRecords = pitEntry->getInRecords();
164 for (pit::InRecordCollection::const_iterator it = inRecords.begin();
165 it != inRecords.end(); ++it) {
166 if (it->getExpiry() > time::now()) {
167 pendingDownstreams.insert(it->getFace());
168 }
169 }
170
171 // mark PIT satisfied
172 pitEntry->deleteInRecords();
173 pitEntry->deleteOutRecord(inFace.shared_from_this());
174
175 // set PIT straggler timer
176 this->setStragglerTimer(pitEntry);
177
178 // invoke PIT satisfy callback
179 // TODO
180 }
181
182 // foreach pending downstream
183 for (std::set<shared_ptr<Face> >::iterator it = pendingDownstreams.begin();
184 it != pendingDownstreams.end(); ++it) {
185 // goto outgoing Data pipeline
186 this->onOutgoingData(data, **it);
187 }
188}
189
190void
191Forwarder::onDataUnsolicited(Face& inFace, const Data& data)
192{
193 // accept to cache?
194 bool acceptToCache = false;// TODO decision
195 if (acceptToCache) {
196 // CS insert
197 m_cs.insert(data);
198 }
199}
200
201void
202Forwarder::onOutgoingData(const Data& data, Face& outFace)
203{
204 // traffic manager
205 // pass through
206
207 // send Data
208 outFace.sendData(data);
209}
210
211static inline bool
212compare_InRecord_expiry(const pit::InRecord& a, const pit::InRecord& b)
213{
214 return a.getExpiry() < b.getExpiry();
215}
216
217void
218Forwarder::setUnsatisfyTimer(shared_ptr<pit::Entry> pitEntry)
219{
220 const pit::InRecordCollection& inRecords = pitEntry->getInRecords();
221 pit::InRecordCollection::const_iterator lastExpiring =
222 std::max_element(inRecords.begin(), inRecords.end(),
223 &compare_InRecord_expiry);
224
225 time::Point lastExpiry = lastExpiring->getExpiry();
226 time::Duration lastExpiryFromNow = lastExpiry - time::now();
227 if (lastExpiryFromNow <= time::seconds(0)) {
228 // TODO all InRecords are already expired; will this happen?
229 }
230
231 pitEntry->m_unsatisfyTimer = m_scheduler.scheduleEvent(lastExpiryFromNow,
232 bind(&Forwarder::onInterestUnsatisfied, this, pitEntry));
233}
234
235void
236Forwarder::setStragglerTimer(shared_ptr<pit::Entry> pitEntry)
237{
238 time::Duration stragglerTime = time::milliseconds(100);
239
240 pitEntry->m_stragglerTimer = m_scheduler.scheduleEvent(stragglerTime,
241 bind(&Pit::remove, &m_pit, pitEntry));
242}
243
244void
245Forwarder::cancelUnsatisfyAndStragglerTimer(shared_ptr<pit::Entry> pitEntry)
246{
247 m_scheduler.cancelEvent(pitEntry->m_unsatisfyTimer);
248 m_scheduler.cancelEvent(pitEntry->m_stragglerTimer);
249}
250
251
252
Alexander Afanasyev18bbf812014-01-29 01:40:23 -0800253} // namespace nfd