blob: e6a6929aca5ecc90e5d839c34e337a92d7bb7e99 [file] [log] [blame]
Giulio Grassi624f6c62014-02-18 19:42:14 +01001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
Alexander Afanasyev9bcbc7c2014-04-06 19:37:37 -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 *
10 * This file is part of NFD (Named Data Networking Forwarding Daemon).
11 * See AUTHORS.md for complete list of NFD authors and contributors.
12 *
13 * NFD is free software: you can redistribute it and/or modify it under the terms
14 * of the GNU General Public License as published by the Free Software Foundation,
15 * either version 3 of the License, or (at your option) any later version.
16 *
17 * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
18 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
19 * PURPOSE. See the GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License along with
22 * NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
23 **/
Giulio Grassi624f6c62014-02-18 19:42:14 +010024
Alexander Afanasyev613e2a92014-04-15 13:36:58 -070025#ifndef NFD_DAEMON_FACE_DATAGRAM_FACE_HPP
26#define NFD_DAEMON_FACE_DATAGRAM_FACE_HPP
Giulio Grassi624f6c62014-02-18 19:42:14 +010027
28#include "face.hpp"
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -060029#include "core/logger.hpp"
Giulio Grassi624f6c62014-02-18 19:42:14 +010030
31namespace nfd {
32
Davide Pesaventod8d4d982014-03-21 18:47:58 +010033template <class Protocol>
Giulio Grassi624f6c62014-02-18 19:42:14 +010034class DatagramFace : public Face
35{
36public:
Davide Pesaventod8d4d982014-03-21 18:47:58 +010037 typedef Protocol protocol;
Alexander Afanasyev355c0662014-03-20 18:08:17 -070038
39 /** \brief Construct datagram face
40 *
Alexander Afanasyev355c0662014-03-20 18:08:17 -070041 * \param socket Protocol-specific socket for the created face
42 * \param isOnDemand If true, the face can be closed after it remains
Davide Pesaventod8d4d982014-03-21 18:47:58 +010043 * unused for a certain amount of time
Alexander Afanasyev355c0662014-03-20 18:08:17 -070044 */
Junxiao Shi79494162014-04-02 18:25:11 -070045 DatagramFace(const FaceUri& remoteUri, const FaceUri& localUri,
Giulio Grassi69871f02014-03-09 16:14:44 +010046 const shared_ptr<typename protocol::socket>& socket,
Alexander Afanasyev355c0662014-03-20 18:08:17 -070047 bool isOnDemand);
Giulio Grassi624f6c62014-02-18 19:42:14 +010048
49 virtual
50 ~DatagramFace();
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -060051
Giulio Grassi624f6c62014-02-18 19:42:14 +010052 // from Face
53 virtual void
54 sendInterest(const Interest& interest);
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -060055
Giulio Grassi624f6c62014-02-18 19:42:14 +010056 virtual void
57 sendData(const Data& data);
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -060058
Giulio Grassi624f6c62014-02-18 19:42:14 +010059 virtual void
60 close();
61
62 void
63 handleSend(const boost::system::error_code& error,
64 const Block& wire);
65
66 void
67 handleReceive(const boost::system::error_code& error,
68 size_t nBytesReceived);
69
Giulio Grassi69871f02014-03-09 16:14:44 +010070 /**
71 * \brief Set m_hasBeenUsedRecently to false
72 */
73 void
74 resetRecentUsage();
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -060075
Giulio Grassi69871f02014-03-09 16:14:44 +010076 bool
77 hasBeenUsedRecently() const;
Alexander Afanasyev355c0662014-03-20 18:08:17 -070078
79 void
80 setOnDemand(bool isOnDemand);
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -060081
Giulio Grassi624f6c62014-02-18 19:42:14 +010082protected:
Giulio Grassi624f6c62014-02-18 19:42:14 +010083 void
84 receiveDatagram(const uint8_t* buffer,
85 size_t nBytesReceived,
86 const boost::system::error_code& error);
87
88 void
89 keepFaceAliveUntilAllHandlersExecuted(const shared_ptr<Face>& face);
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -060090
Giulio Grassi624f6c62014-02-18 19:42:14 +010091 void
92 closeSocket();
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -060093
Giulio Grassi624f6c62014-02-18 19:42:14 +010094protected:
95 shared_ptr<typename protocol::socket> m_socket;
96 uint8_t m_inputBuffer[MAX_NDN_PACKET_SIZE];
Giulio Grassi69871f02014-03-09 16:14:44 +010097 bool m_hasBeenUsedRecently;
98
Giulio Grassi624f6c62014-02-18 19:42:14 +010099 NFD_LOG_INCLASS_DECLARE();
Giulio Grassi624f6c62014-02-18 19:42:14 +0100100};
101
Davide Pesavento1bdef282014-04-08 20:59:50 +0200102
Giulio Grassi624f6c62014-02-18 19:42:14 +0100103template <class T>
104inline
Junxiao Shi79494162014-04-02 18:25:11 -0700105DatagramFace<T>::DatagramFace(const FaceUri& remoteUri, const FaceUri& localUri,
Giulio Grassi69871f02014-03-09 16:14:44 +0100106 const shared_ptr<typename DatagramFace::protocol::socket>& socket,
Alexander Afanasyev355c0662014-03-20 18:08:17 -0700107 bool isOnDemand)
Junxiao Shi79494162014-04-02 18:25:11 -0700108 : Face(remoteUri, localUri)
Alexander Afanasyeva39b90b2014-03-05 15:31:00 +0000109 , m_socket(socket)
Giulio Grassi624f6c62014-02-18 19:42:14 +0100110{
Alexander Afanasyev355c0662014-03-20 18:08:17 -0700111 setOnDemand(isOnDemand);
112
Giulio Grassi624f6c62014-02-18 19:42:14 +0100113 m_socket->async_receive(boost::asio::buffer(m_inputBuffer, MAX_NDN_PACKET_SIZE), 0,
114 bind(&DatagramFace<T>::handleReceive, this, _1, _2));
115}
116
117template <class T>
118inline
119DatagramFace<T>::~DatagramFace()
120{
121}
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600122
Giulio Grassi624f6c62014-02-18 19:42:14 +0100123template <class T>
124inline void
125DatagramFace<T>::sendInterest(const Interest& interest)
126{
Alexander Afanasyev7e698e62014-03-07 16:48:35 +0000127 this->onSendInterest(interest);
Giulio Grassi624f6c62014-02-18 19:42:14 +0100128 m_socket->async_send(boost::asio::buffer(interest.wireEncode().wire(),
129 interest.wireEncode().size()),
130 bind(&DatagramFace<T>::handleSend, this, _1, interest.wireEncode()));
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600131
Giulio Grassi624f6c62014-02-18 19:42:14 +0100132 // anything else should be done here?
133}
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600134
Giulio Grassi624f6c62014-02-18 19:42:14 +0100135template <class T>
136inline void
137DatagramFace<T>::sendData(const Data& data)
138{
Alexander Afanasyev7e698e62014-03-07 16:48:35 +0000139 this->onSendData(data);
Giulio Grassi624f6c62014-02-18 19:42:14 +0100140 m_socket->async_send(boost::asio::buffer(data.wireEncode().wire(),
141 data.wireEncode().size()),
142 bind(&DatagramFace<T>::handleSend, this, _1, data.wireEncode()));
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600143
Giulio Grassi624f6c62014-02-18 19:42:14 +0100144 // anything else should be done here?
145}
146
147template <class T>
148inline void
149DatagramFace<T>::handleSend(const boost::system::error_code& error,
150 const Block& wire)
151{
152 if (error != 0) {
153 if (error == boost::system::errc::operation_canceled) // when socket is closed by someone
154 return;
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600155
Giulio Grassi624f6c62014-02-18 19:42:14 +0100156 if (!m_socket->is_open())
157 {
158 onFail("Tunnel closed");
159 return;
160 }
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600161
Giulio Grassi624f6c62014-02-18 19:42:14 +0100162 NFD_LOG_WARN("[id:" << this->getId()
163 << ",endpoint:" << m_socket->local_endpoint()
164 << "] Send operation failed, closing socket: "
165 << error.category().message(error.value()));
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600166
Giulio Grassi624f6c62014-02-18 19:42:14 +0100167 closeSocket();
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600168
Giulio Grassi624f6c62014-02-18 19:42:14 +0100169 if (error == boost::asio::error::eof)
170 {
171 onFail("Tunnel closed");
172 }
173 else
174 {
175 onFail("Send operation failed, closing socket: " +
176 error.category().message(error.value()));
177 }
178 return;
179 }
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600180
Giulio Grassi624f6c62014-02-18 19:42:14 +0100181 NFD_LOG_TRACE("[id:" << this->getId()
182 << ",endpoint:" << m_socket->local_endpoint()
183 << "] Successfully sent: " << wire.size() << " bytes");
184 // do nothing (needed to retain validity of wire memory block
185}
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600186
Giulio Grassi624f6c62014-02-18 19:42:14 +0100187template <class T>
188inline void
189DatagramFace<T>::close()
190{
191 if (!m_socket->is_open())
192 return;
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600193
Giulio Grassi624f6c62014-02-18 19:42:14 +0100194 NFD_LOG_INFO("[id:" << this->getId()
195 << ",endpoint:" << m_socket->local_endpoint()
196 << "] Close tunnel");
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600197
Giulio Grassi624f6c62014-02-18 19:42:14 +0100198 closeSocket();
199 onFail("Close tunnel");
200}
201
202template <class T>
203inline void
204DatagramFace<T>::handleReceive(const boost::system::error_code& error,
205 size_t nBytesReceived)
206{
Alexander Afanasyev7e698e62014-03-07 16:48:35 +0000207 NFD_LOG_DEBUG("handleReceive: " << nBytesReceived);
Giulio Grassi624f6c62014-02-18 19:42:14 +0100208 receiveDatagram(m_inputBuffer, nBytesReceived, error);
Giulio Grassi69871f02014-03-09 16:14:44 +0100209 if (m_socket->is_open())
210 m_socket->async_receive(boost::asio::buffer(m_inputBuffer, MAX_NDN_PACKET_SIZE), 0,
211 bind(&DatagramFace<T>::handleReceive, this, _1, _2));
Giulio Grassi624f6c62014-02-18 19:42:14 +0100212}
213
214template <class T>
215inline void
216DatagramFace<T>::receiveDatagram(const uint8_t* buffer,
217 size_t nBytesReceived,
218 const boost::system::error_code& error)
219{
220 if (error != 0 || nBytesReceived == 0) {
221 if (error == boost::system::errc::operation_canceled) // when socket is closed by someone
222 return;
223
224 // this should be unnecessary, but just in case
225 if (!m_socket->is_open())
226 {
227 onFail("Tunnel closed");
228 return;
229 }
230
231 NFD_LOG_WARN("[id:" << this->getId()
232 << ",endpoint:" << m_socket->local_endpoint()
233 << "] Receive operation failed: "
234 << error.category().message(error.value()));
235
236 closeSocket();
237
238 if (error == boost::asio::error::eof)
239 {
240 onFail("Tunnel closed");
241 }
242 else
243 {
244 onFail("Receive operation failed, closing socket: " +
245 error.category().message(error.value()));
246 }
247 return;
248 }
249
250 NFD_LOG_TRACE("[id:" << this->getId()
251 << ",endpoint:" << m_socket->local_endpoint()
252 << "] Received: " << nBytesReceived << " bytes");
253
Alexander Afanasyev5a8d8d82014-03-21 14:08:41 -0700254 Block element;
255 bool isOk = Block::fromBuffer(buffer, nBytesReceived, element);
256 if (!isOk)
257 {
258 NFD_LOG_WARN("[id:" << this->getId()
259 << ",endpoint:" << m_socket->local_endpoint()
260 << "] Failed to parse incoming packet");
261 // This message won't extend the face lifetime
262 return;
263 }
Giulio Grassi624f6c62014-02-18 19:42:14 +0100264
Alexander Afanasyev5a8d8d82014-03-21 14:08:41 -0700265 if (element.size() != nBytesReceived)
266 {
267 NFD_LOG_WARN("[id:" << this->getId()
268 << ",endpoint:" << m_socket->local_endpoint()
269 << "] Received datagram size and decoded "
270 << "element size don't match");
271 // This message won't extend the face lifetime
272 return;
273 }
274
275 if (!this->decodeAndDispatchInput(element))
276 {
277 NFD_LOG_WARN("[id:" << this->getId()
278 << ",endpoint:" << m_socket->local_endpoint()
279 << "] Received unrecognized block of type ["
280 << element.type() << "]");
281 // This message won't extend the face lifetime
282 return;
283 }
284
Giulio Grassi69871f02014-03-09 16:14:44 +0100285 m_hasBeenUsedRecently = true;
Giulio Grassi624f6c62014-02-18 19:42:14 +0100286}
287
288
289template <class T>
290inline void
291DatagramFace<T>::keepFaceAliveUntilAllHandlersExecuted(const shared_ptr<Face>& face)
292{
293}
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600294
Giulio Grassi624f6c62014-02-18 19:42:14 +0100295template <class T>
296inline void
297DatagramFace<T>::closeSocket()
298{
Giulio Grassi69871f02014-03-09 16:14:44 +0100299 NFD_LOG_DEBUG("closeSocket " << m_socket->local_endpoint());
Giulio Grassi624f6c62014-02-18 19:42:14 +0100300 boost::asio::io_service& io = m_socket->get_io_service();
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600301
Giulio Grassi624f6c62014-02-18 19:42:14 +0100302 // use the non-throwing variants and ignore errors, if any
303 boost::system::error_code error;
304 m_socket->shutdown(protocol::socket::shutdown_both, error);
305 m_socket->close(error);
306 // after this, handlers will be called with an error code
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600307
Giulio Grassi624f6c62014-02-18 19:42:14 +0100308 // ensure that the Face object is alive at least until all pending
309 // handlers are dispatched
310 io.post(bind(&DatagramFace<T>::keepFaceAliveUntilAllHandlersExecuted,
311 this, this->shared_from_this()));
312}
313
Giulio Grassi69871f02014-03-09 16:14:44 +0100314template <class T>
315inline void
Alexander Afanasyev355c0662014-03-20 18:08:17 -0700316DatagramFace<T>::setOnDemand(bool isOnDemand)
Giulio Grassi69871f02014-03-09 16:14:44 +0100317{
Alexander Afanasyev355c0662014-03-20 18:08:17 -0700318 Face::setOnDemand(isOnDemand);
Giulio Grassi69871f02014-03-09 16:14:44 +0100319}
320
321template <class T>
322inline void
323DatagramFace<T>::resetRecentUsage()
324{
325 m_hasBeenUsedRecently = false;
326}
327
328template <class T>
329inline bool
330DatagramFace<T>::hasBeenUsedRecently() const
331{
332 return m_hasBeenUsedRecently;
333}
334
Giulio Grassi624f6c62014-02-18 19:42:14 +0100335} // namespace nfd
336
Alexander Afanasyev613e2a92014-04-15 13:36:58 -0700337#endif // NFD_DAEMON_FACE_DATAGRAM_FACE_HPP