blob: bae4fb2f6f07759bd6b7fa612f76927c8156b46c [file] [log] [blame]
Giulio Grassi624f6c62014-02-18 19:42:14 +01001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
Junxiao Shi08d07a72014-06-09 23:17:57 -07003 * Copyright (c) 2014, Regents of the University of California,
4 * Arizona Board of Regents,
5 * Colorado State University,
6 * University Pierre & Marie Curie, Sorbonne University,
7 * Washington University in St. Louis,
8 * Beijing Institute of Technology,
9 * The University of Memphis
Alexander Afanasyev9bcbc7c2014-04-06 19:37:37 -070010 *
11 * This file is part of NFD (Named Data Networking Forwarding Daemon).
12 * See AUTHORS.md for complete list of NFD authors and contributors.
13 *
14 * NFD is free software: you can redistribute it and/or modify it under the terms
15 * of the GNU General Public License as published by the Free Software Foundation,
16 * either version 3 of the License, or (at your option) any later version.
17 *
18 * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
19 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
20 * PURPOSE. See the GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License along with
23 * NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
Alexander Afanasyevcd591e12014-06-18 16:35:16 -070024 */
Giulio Grassi624f6c62014-02-18 19:42:14 +010025
Alexander Afanasyev613e2a92014-04-15 13:36:58 -070026#ifndef NFD_DAEMON_FACE_DATAGRAM_FACE_HPP
27#define NFD_DAEMON_FACE_DATAGRAM_FACE_HPP
Giulio Grassi624f6c62014-02-18 19:42:14 +010028
29#include "face.hpp"
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -060030#include "core/logger.hpp"
Giulio Grassi624f6c62014-02-18 19:42:14 +010031
32namespace nfd {
33
Alexander Afanasyevcd591e12014-06-18 16:35:16 -070034class Unicast {};
35class Multicast {};
36
37template<class Protocol, class Type = Unicast>
Giulio Grassi624f6c62014-02-18 19:42:14 +010038class DatagramFace : public Face
39{
40public:
Davide Pesaventod8d4d982014-03-21 18:47:58 +010041 typedef Protocol protocol;
Alexander Afanasyev355c0662014-03-20 18:08:17 -070042
43 /** \brief Construct datagram face
44 *
Alexander Afanasyev355c0662014-03-20 18:08:17 -070045 * \param socket Protocol-specific socket for the created face
46 * \param isOnDemand If true, the face can be closed after it remains
Davide Pesaventod8d4d982014-03-21 18:47:58 +010047 * unused for a certain amount of time
Alexander Afanasyev355c0662014-03-20 18:08:17 -070048 */
Junxiao Shi79494162014-04-02 18:25:11 -070049 DatagramFace(const FaceUri& remoteUri, const FaceUri& localUri,
Giulio Grassi69871f02014-03-09 16:14:44 +010050 const shared_ptr<typename protocol::socket>& socket,
Alexander Afanasyev355c0662014-03-20 18:08:17 -070051 bool isOnDemand);
Giulio Grassi624f6c62014-02-18 19:42:14 +010052
53 virtual
54 ~DatagramFace();
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -060055
Giulio Grassi624f6c62014-02-18 19:42:14 +010056 // from Face
57 virtual void
58 sendInterest(const Interest& interest);
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -060059
Giulio Grassi624f6c62014-02-18 19:42:14 +010060 virtual void
61 sendData(const Data& data);
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -060062
Giulio Grassi624f6c62014-02-18 19:42:14 +010063 virtual void
64 close();
65
66 void
67 handleSend(const boost::system::error_code& error,
68 const Block& wire);
69
70 void
71 handleReceive(const boost::system::error_code& error,
72 size_t nBytesReceived);
73
Giulio Grassi69871f02014-03-09 16:14:44 +010074 /**
75 * \brief Set m_hasBeenUsedRecently to false
76 */
77 void
78 resetRecentUsage();
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -060079
Giulio Grassi69871f02014-03-09 16:14:44 +010080 bool
81 hasBeenUsedRecently() const;
Alexander Afanasyev355c0662014-03-20 18:08:17 -070082
83 void
84 setOnDemand(bool isOnDemand);
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -060085
Giulio Grassi624f6c62014-02-18 19:42:14 +010086protected:
Giulio Grassi624f6c62014-02-18 19:42:14 +010087 void
88 receiveDatagram(const uint8_t* buffer,
89 size_t nBytesReceived,
90 const boost::system::error_code& error);
91
92 void
93 keepFaceAliveUntilAllHandlersExecuted(const shared_ptr<Face>& face);
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -060094
Giulio Grassi624f6c62014-02-18 19:42:14 +010095 void
96 closeSocket();
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -060097
Giulio Grassi624f6c62014-02-18 19:42:14 +010098protected:
99 shared_ptr<typename protocol::socket> m_socket;
100 uint8_t m_inputBuffer[MAX_NDN_PACKET_SIZE];
Giulio Grassi69871f02014-03-09 16:14:44 +0100101 bool m_hasBeenUsedRecently;
102
Giulio Grassi624f6c62014-02-18 19:42:14 +0100103 NFD_LOG_INCLASS_DECLARE();
Giulio Grassi624f6c62014-02-18 19:42:14 +0100104};
105
Davide Pesavento1bdef282014-04-08 20:59:50 +0200106
Alexander Afanasyevcd591e12014-06-18 16:35:16 -0700107template<class T, class U>
Giulio Grassi624f6c62014-02-18 19:42:14 +0100108inline
Alexander Afanasyevcd591e12014-06-18 16:35:16 -0700109DatagramFace<T, U>::DatagramFace(const FaceUri& remoteUri, const FaceUri& localUri,
110 const shared_ptr<typename DatagramFace::protocol::socket>& socket,
111 bool isOnDemand)
Junxiao Shi79494162014-04-02 18:25:11 -0700112 : Face(remoteUri, localUri)
Alexander Afanasyeva39b90b2014-03-05 15:31:00 +0000113 , m_socket(socket)
Giulio Grassi624f6c62014-02-18 19:42:14 +0100114{
Alexander Afanasyev355c0662014-03-20 18:08:17 -0700115 setOnDemand(isOnDemand);
116
Giulio Grassi624f6c62014-02-18 19:42:14 +0100117 m_socket->async_receive(boost::asio::buffer(m_inputBuffer, MAX_NDN_PACKET_SIZE), 0,
Alexander Afanasyevcd591e12014-06-18 16:35:16 -0700118 bind(&DatagramFace<T, U>::handleReceive, this, _1, _2));
Giulio Grassi624f6c62014-02-18 19:42:14 +0100119}
120
Alexander Afanasyevcd591e12014-06-18 16:35:16 -0700121template<class T, class U>
Giulio Grassi624f6c62014-02-18 19:42:14 +0100122inline
Alexander Afanasyevcd591e12014-06-18 16:35:16 -0700123DatagramFace<T, U>::~DatagramFace()
Giulio Grassi624f6c62014-02-18 19:42:14 +0100124{
125}
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600126
Alexander Afanasyevcd591e12014-06-18 16:35:16 -0700127template<class T, class U>
Giulio Grassi624f6c62014-02-18 19:42:14 +0100128inline void
Alexander Afanasyevcd591e12014-06-18 16:35:16 -0700129DatagramFace<T, U>::sendInterest(const Interest& interest)
Giulio Grassi624f6c62014-02-18 19:42:14 +0100130{
Alexander Afanasyev7e698e62014-03-07 16:48:35 +0000131 this->onSendInterest(interest);
Giulio Grassi624f6c62014-02-18 19:42:14 +0100132 m_socket->async_send(boost::asio::buffer(interest.wireEncode().wire(),
133 interest.wireEncode().size()),
Alexander Afanasyevcd591e12014-06-18 16:35:16 -0700134 bind(&DatagramFace<T, U>::handleSend, this, _1, interest.wireEncode()));
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600135
Giulio Grassi624f6c62014-02-18 19:42:14 +0100136 // anything else should be done here?
137}
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600138
Alexander Afanasyevcd591e12014-06-18 16:35:16 -0700139template<class T, class U>
Giulio Grassi624f6c62014-02-18 19:42:14 +0100140inline void
Alexander Afanasyevcd591e12014-06-18 16:35:16 -0700141DatagramFace<T, U>::sendData(const Data& data)
Giulio Grassi624f6c62014-02-18 19:42:14 +0100142{
Alexander Afanasyev7e698e62014-03-07 16:48:35 +0000143 this->onSendData(data);
Giulio Grassi624f6c62014-02-18 19:42:14 +0100144 m_socket->async_send(boost::asio::buffer(data.wireEncode().wire(),
145 data.wireEncode().size()),
Alexander Afanasyevcd591e12014-06-18 16:35:16 -0700146 bind(&DatagramFace<T, U>::handleSend, this, _1, data.wireEncode()));
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600147
Giulio Grassi624f6c62014-02-18 19:42:14 +0100148 // anything else should be done here?
149}
150
Alexander Afanasyevcd591e12014-06-18 16:35:16 -0700151template<class T, class U>
Giulio Grassi624f6c62014-02-18 19:42:14 +0100152inline void
Alexander Afanasyevcd591e12014-06-18 16:35:16 -0700153DatagramFace<T, U>::handleSend(const boost::system::error_code& error,
154 const Block& wire)
Giulio Grassi624f6c62014-02-18 19:42:14 +0100155{
156 if (error != 0) {
157 if (error == boost::system::errc::operation_canceled) // when socket is closed by someone
158 return;
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600159
Giulio Grassi624f6c62014-02-18 19:42:14 +0100160 if (!m_socket->is_open())
161 {
Junxiao Shi08d07a72014-06-09 23:17:57 -0700162 fail("Tunnel closed");
Giulio Grassi624f6c62014-02-18 19:42:14 +0100163 return;
164 }
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600165
Giulio Grassi624f6c62014-02-18 19:42:14 +0100166 NFD_LOG_WARN("[id:" << this->getId()
167 << ",endpoint:" << m_socket->local_endpoint()
168 << "] Send operation failed, closing socket: "
169 << error.category().message(error.value()));
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600170
Giulio Grassi624f6c62014-02-18 19:42:14 +0100171 closeSocket();
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600172
Giulio Grassi624f6c62014-02-18 19:42:14 +0100173 if (error == boost::asio::error::eof)
174 {
Junxiao Shi08d07a72014-06-09 23:17:57 -0700175 fail("Tunnel closed");
Giulio Grassi624f6c62014-02-18 19:42:14 +0100176 }
177 else
178 {
Junxiao Shi08d07a72014-06-09 23:17:57 -0700179 fail("Send operation failed, closing socket: " +
Giulio Grassi624f6c62014-02-18 19:42:14 +0100180 error.category().message(error.value()));
181 }
182 return;
183 }
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600184
Giulio Grassi624f6c62014-02-18 19:42:14 +0100185 NFD_LOG_TRACE("[id:" << this->getId()
186 << ",endpoint:" << m_socket->local_endpoint()
187 << "] Successfully sent: " << wire.size() << " bytes");
188 // do nothing (needed to retain validity of wire memory block
189}
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600190
Alexander Afanasyevcd591e12014-06-18 16:35:16 -0700191template<class T, class U>
Giulio Grassi624f6c62014-02-18 19:42:14 +0100192inline void
Alexander Afanasyevcd591e12014-06-18 16:35:16 -0700193DatagramFace<T, U>::close()
Giulio Grassi624f6c62014-02-18 19:42:14 +0100194{
195 if (!m_socket->is_open())
196 return;
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600197
Giulio Grassi624f6c62014-02-18 19:42:14 +0100198 NFD_LOG_INFO("[id:" << this->getId()
199 << ",endpoint:" << m_socket->local_endpoint()
200 << "] Close tunnel");
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600201
Giulio Grassi624f6c62014-02-18 19:42:14 +0100202 closeSocket();
Junxiao Shi08d07a72014-06-09 23:17:57 -0700203 fail("Close tunnel");
Giulio Grassi624f6c62014-02-18 19:42:14 +0100204}
205
Alexander Afanasyevcd591e12014-06-18 16:35:16 -0700206template<class T, class U>
Giulio Grassi624f6c62014-02-18 19:42:14 +0100207inline void
Alexander Afanasyevcd591e12014-06-18 16:35:16 -0700208DatagramFace<T, U>::handleReceive(const boost::system::error_code& error,
209 size_t nBytesReceived)
Giulio Grassi624f6c62014-02-18 19:42:14 +0100210{
Alexander Afanasyev7e698e62014-03-07 16:48:35 +0000211 NFD_LOG_DEBUG("handleReceive: " << nBytesReceived);
Giulio Grassi624f6c62014-02-18 19:42:14 +0100212 receiveDatagram(m_inputBuffer, nBytesReceived, error);
Giulio Grassi69871f02014-03-09 16:14:44 +0100213 if (m_socket->is_open())
214 m_socket->async_receive(boost::asio::buffer(m_inputBuffer, MAX_NDN_PACKET_SIZE), 0,
Alexander Afanasyevcd591e12014-06-18 16:35:16 -0700215 bind(&DatagramFace<T, U>::handleReceive, this, _1, _2));
Giulio Grassi624f6c62014-02-18 19:42:14 +0100216}
217
Alexander Afanasyevcd591e12014-06-18 16:35:16 -0700218template<class T, class U>
Giulio Grassi624f6c62014-02-18 19:42:14 +0100219inline void
Alexander Afanasyevcd591e12014-06-18 16:35:16 -0700220DatagramFace<T, U>::receiveDatagram(const uint8_t* buffer,
221 size_t nBytesReceived,
222 const boost::system::error_code& error)
Giulio Grassi624f6c62014-02-18 19:42:14 +0100223{
224 if (error != 0 || nBytesReceived == 0) {
225 if (error == boost::system::errc::operation_canceled) // when socket is closed by someone
226 return;
227
228 // this should be unnecessary, but just in case
229 if (!m_socket->is_open())
230 {
Junxiao Shi08d07a72014-06-09 23:17:57 -0700231 fail("Tunnel closed");
Giulio Grassi624f6c62014-02-18 19:42:14 +0100232 return;
233 }
234
235 NFD_LOG_WARN("[id:" << this->getId()
236 << ",endpoint:" << m_socket->local_endpoint()
237 << "] Receive operation failed: "
238 << error.category().message(error.value()));
239
240 closeSocket();
241
242 if (error == boost::asio::error::eof)
243 {
Junxiao Shi08d07a72014-06-09 23:17:57 -0700244 fail("Tunnel closed");
Giulio Grassi624f6c62014-02-18 19:42:14 +0100245 }
246 else
247 {
Junxiao Shi08d07a72014-06-09 23:17:57 -0700248 fail("Receive operation failed, closing socket: " +
Giulio Grassi624f6c62014-02-18 19:42:14 +0100249 error.category().message(error.value()));
250 }
251 return;
252 }
253
254 NFD_LOG_TRACE("[id:" << this->getId()
255 << ",endpoint:" << m_socket->local_endpoint()
256 << "] Received: " << nBytesReceived << " bytes");
257
Alexander Afanasyev5a8d8d82014-03-21 14:08:41 -0700258 Block element;
259 bool isOk = Block::fromBuffer(buffer, nBytesReceived, element);
260 if (!isOk)
261 {
262 NFD_LOG_WARN("[id:" << this->getId()
263 << ",endpoint:" << m_socket->local_endpoint()
264 << "] Failed to parse incoming packet");
265 // This message won't extend the face lifetime
266 return;
267 }
Giulio Grassi624f6c62014-02-18 19:42:14 +0100268
Alexander Afanasyev5a8d8d82014-03-21 14:08:41 -0700269 if (element.size() != nBytesReceived)
270 {
271 NFD_LOG_WARN("[id:" << this->getId()
272 << ",endpoint:" << m_socket->local_endpoint()
273 << "] Received datagram size and decoded "
274 << "element size don't match");
275 // This message won't extend the face lifetime
276 return;
277 }
278
279 if (!this->decodeAndDispatchInput(element))
280 {
281 NFD_LOG_WARN("[id:" << this->getId()
282 << ",endpoint:" << m_socket->local_endpoint()
283 << "] Received unrecognized block of type ["
284 << element.type() << "]");
285 // This message won't extend the face lifetime
286 return;
287 }
288
Giulio Grassi69871f02014-03-09 16:14:44 +0100289 m_hasBeenUsedRecently = true;
Giulio Grassi624f6c62014-02-18 19:42:14 +0100290}
291
292
Alexander Afanasyevcd591e12014-06-18 16:35:16 -0700293template<class T, class U>
Giulio Grassi624f6c62014-02-18 19:42:14 +0100294inline void
Alexander Afanasyevcd591e12014-06-18 16:35:16 -0700295DatagramFace<T, U>::keepFaceAliveUntilAllHandlersExecuted(const shared_ptr<Face>& face)
Giulio Grassi624f6c62014-02-18 19:42:14 +0100296{
297}
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600298
Alexander Afanasyevcd591e12014-06-18 16:35:16 -0700299template<class T, class U>
Giulio Grassi624f6c62014-02-18 19:42:14 +0100300inline void
Alexander Afanasyevcd591e12014-06-18 16:35:16 -0700301DatagramFace<T, U>::closeSocket()
Giulio Grassi624f6c62014-02-18 19:42:14 +0100302{
Giulio Grassi69871f02014-03-09 16:14:44 +0100303 NFD_LOG_DEBUG("closeSocket " << m_socket->local_endpoint());
Giulio Grassi624f6c62014-02-18 19:42:14 +0100304 boost::asio::io_service& io = m_socket->get_io_service();
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600305
Giulio Grassi624f6c62014-02-18 19:42:14 +0100306 // use the non-throwing variants and ignore errors, if any
307 boost::system::error_code error;
308 m_socket->shutdown(protocol::socket::shutdown_both, error);
309 m_socket->close(error);
310 // after this, handlers will be called with an error code
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600311
Giulio Grassi624f6c62014-02-18 19:42:14 +0100312 // ensure that the Face object is alive at least until all pending
313 // handlers are dispatched
Alexander Afanasyevcd591e12014-06-18 16:35:16 -0700314 io.post(bind(&DatagramFace<T, U>::keepFaceAliveUntilAllHandlersExecuted,
Giulio Grassi624f6c62014-02-18 19:42:14 +0100315 this, this->shared_from_this()));
316}
317
Alexander Afanasyevcd591e12014-06-18 16:35:16 -0700318template<class T, class U>
Giulio Grassi69871f02014-03-09 16:14:44 +0100319inline void
Alexander Afanasyevcd591e12014-06-18 16:35:16 -0700320DatagramFace<T, U>::setOnDemand(bool isOnDemand)
Giulio Grassi69871f02014-03-09 16:14:44 +0100321{
Alexander Afanasyev355c0662014-03-20 18:08:17 -0700322 Face::setOnDemand(isOnDemand);
Giulio Grassi69871f02014-03-09 16:14:44 +0100323}
324
Alexander Afanasyevcd591e12014-06-18 16:35:16 -0700325template<class T, class U>
Giulio Grassi69871f02014-03-09 16:14:44 +0100326inline void
Alexander Afanasyevcd591e12014-06-18 16:35:16 -0700327DatagramFace<T, U>::resetRecentUsage()
Giulio Grassi69871f02014-03-09 16:14:44 +0100328{
329 m_hasBeenUsedRecently = false;
330}
331
Alexander Afanasyevcd591e12014-06-18 16:35:16 -0700332template<class T, class U>
Giulio Grassi69871f02014-03-09 16:14:44 +0100333inline bool
Alexander Afanasyevcd591e12014-06-18 16:35:16 -0700334DatagramFace<T, U>::hasBeenUsedRecently() const
Giulio Grassi69871f02014-03-09 16:14:44 +0100335{
336 return m_hasBeenUsedRecently;
337}
338
Giulio Grassi624f6c62014-02-18 19:42:14 +0100339} // namespace nfd
340
Alexander Afanasyev613e2a92014-04-15 13:36:58 -0700341#endif // NFD_DAEMON_FACE_DATAGRAM_FACE_HPP