blob: 2dbe8fa8cc9bf7faa4e86795201921db9ab833f4 [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/>.
24 **/
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
Davide Pesaventod8d4d982014-03-21 18:47:58 +010034template <class Protocol>
Giulio Grassi624f6c62014-02-18 19:42:14 +010035class DatagramFace : public Face
36{
37public:
Davide Pesaventod8d4d982014-03-21 18:47:58 +010038 typedef Protocol protocol;
Alexander Afanasyev355c0662014-03-20 18:08:17 -070039
40 /** \brief Construct datagram face
41 *
Alexander Afanasyev355c0662014-03-20 18:08:17 -070042 * \param socket Protocol-specific socket for the created face
43 * \param isOnDemand If true, the face can be closed after it remains
Davide Pesaventod8d4d982014-03-21 18:47:58 +010044 * unused for a certain amount of time
Alexander Afanasyev355c0662014-03-20 18:08:17 -070045 */
Junxiao Shi79494162014-04-02 18:25:11 -070046 DatagramFace(const FaceUri& remoteUri, const FaceUri& localUri,
Giulio Grassi69871f02014-03-09 16:14:44 +010047 const shared_ptr<typename protocol::socket>& socket,
Alexander Afanasyev355c0662014-03-20 18:08:17 -070048 bool isOnDemand);
Giulio Grassi624f6c62014-02-18 19:42:14 +010049
50 virtual
51 ~DatagramFace();
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -060052
Giulio Grassi624f6c62014-02-18 19:42:14 +010053 // from Face
54 virtual void
55 sendInterest(const Interest& interest);
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -060056
Giulio Grassi624f6c62014-02-18 19:42:14 +010057 virtual void
58 sendData(const Data& data);
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -060059
Giulio Grassi624f6c62014-02-18 19:42:14 +010060 virtual void
61 close();
62
63 void
64 handleSend(const boost::system::error_code& error,
65 const Block& wire);
66
67 void
68 handleReceive(const boost::system::error_code& error,
69 size_t nBytesReceived);
70
Giulio Grassi69871f02014-03-09 16:14:44 +010071 /**
72 * \brief Set m_hasBeenUsedRecently to false
73 */
74 void
75 resetRecentUsage();
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -060076
Giulio Grassi69871f02014-03-09 16:14:44 +010077 bool
78 hasBeenUsedRecently() const;
Alexander Afanasyev355c0662014-03-20 18:08:17 -070079
80 void
81 setOnDemand(bool isOnDemand);
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -060082
Giulio Grassi624f6c62014-02-18 19:42:14 +010083protected:
Giulio Grassi624f6c62014-02-18 19:42:14 +010084 void
85 receiveDatagram(const uint8_t* buffer,
86 size_t nBytesReceived,
87 const boost::system::error_code& error);
88
89 void
90 keepFaceAliveUntilAllHandlersExecuted(const shared_ptr<Face>& face);
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -060091
Giulio Grassi624f6c62014-02-18 19:42:14 +010092 void
93 closeSocket();
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -060094
Giulio Grassi624f6c62014-02-18 19:42:14 +010095protected:
96 shared_ptr<typename protocol::socket> m_socket;
97 uint8_t m_inputBuffer[MAX_NDN_PACKET_SIZE];
Giulio Grassi69871f02014-03-09 16:14:44 +010098 bool m_hasBeenUsedRecently;
99
Giulio Grassi624f6c62014-02-18 19:42:14 +0100100 NFD_LOG_INCLASS_DECLARE();
Giulio Grassi624f6c62014-02-18 19:42:14 +0100101};
102
Davide Pesavento1bdef282014-04-08 20:59:50 +0200103
Giulio Grassi624f6c62014-02-18 19:42:14 +0100104template <class T>
105inline
Junxiao Shi79494162014-04-02 18:25:11 -0700106DatagramFace<T>::DatagramFace(const FaceUri& remoteUri, const FaceUri& localUri,
Giulio Grassi69871f02014-03-09 16:14:44 +0100107 const shared_ptr<typename DatagramFace::protocol::socket>& socket,
Alexander Afanasyev355c0662014-03-20 18:08:17 -0700108 bool isOnDemand)
Junxiao Shi79494162014-04-02 18:25:11 -0700109 : Face(remoteUri, localUri)
Alexander Afanasyeva39b90b2014-03-05 15:31:00 +0000110 , m_socket(socket)
Giulio Grassi624f6c62014-02-18 19:42:14 +0100111{
Alexander Afanasyev355c0662014-03-20 18:08:17 -0700112 setOnDemand(isOnDemand);
113
Giulio Grassi624f6c62014-02-18 19:42:14 +0100114 m_socket->async_receive(boost::asio::buffer(m_inputBuffer, MAX_NDN_PACKET_SIZE), 0,
115 bind(&DatagramFace<T>::handleReceive, this, _1, _2));
116}
117
118template <class T>
119inline
120DatagramFace<T>::~DatagramFace()
121{
122}
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600123
Giulio Grassi624f6c62014-02-18 19:42:14 +0100124template <class T>
125inline void
126DatagramFace<T>::sendInterest(const Interest& interest)
127{
Alexander Afanasyev7e698e62014-03-07 16:48:35 +0000128 this->onSendInterest(interest);
Giulio Grassi624f6c62014-02-18 19:42:14 +0100129 m_socket->async_send(boost::asio::buffer(interest.wireEncode().wire(),
130 interest.wireEncode().size()),
131 bind(&DatagramFace<T>::handleSend, this, _1, interest.wireEncode()));
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600132
Giulio Grassi624f6c62014-02-18 19:42:14 +0100133 // anything else should be done here?
134}
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600135
Giulio Grassi624f6c62014-02-18 19:42:14 +0100136template <class T>
137inline void
138DatagramFace<T>::sendData(const Data& data)
139{
Alexander Afanasyev7e698e62014-03-07 16:48:35 +0000140 this->onSendData(data);
Giulio Grassi624f6c62014-02-18 19:42:14 +0100141 m_socket->async_send(boost::asio::buffer(data.wireEncode().wire(),
142 data.wireEncode().size()),
143 bind(&DatagramFace<T>::handleSend, this, _1, data.wireEncode()));
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600144
Giulio Grassi624f6c62014-02-18 19:42:14 +0100145 // anything else should be done here?
146}
147
148template <class T>
149inline void
150DatagramFace<T>::handleSend(const boost::system::error_code& error,
151 const Block& wire)
152{
153 if (error != 0) {
154 if (error == boost::system::errc::operation_canceled) // when socket is closed by someone
155 return;
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600156
Giulio Grassi624f6c62014-02-18 19:42:14 +0100157 if (!m_socket->is_open())
158 {
Junxiao Shi08d07a72014-06-09 23:17:57 -0700159 fail("Tunnel closed");
Giulio Grassi624f6c62014-02-18 19:42:14 +0100160 return;
161 }
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600162
Giulio Grassi624f6c62014-02-18 19:42:14 +0100163 NFD_LOG_WARN("[id:" << this->getId()
164 << ",endpoint:" << m_socket->local_endpoint()
165 << "] Send operation failed, closing socket: "
166 << error.category().message(error.value()));
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600167
Giulio Grassi624f6c62014-02-18 19:42:14 +0100168 closeSocket();
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600169
Giulio Grassi624f6c62014-02-18 19:42:14 +0100170 if (error == boost::asio::error::eof)
171 {
Junxiao Shi08d07a72014-06-09 23:17:57 -0700172 fail("Tunnel closed");
Giulio Grassi624f6c62014-02-18 19:42:14 +0100173 }
174 else
175 {
Junxiao Shi08d07a72014-06-09 23:17:57 -0700176 fail("Send operation failed, closing socket: " +
Giulio Grassi624f6c62014-02-18 19:42:14 +0100177 error.category().message(error.value()));
178 }
179 return;
180 }
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600181
Giulio Grassi624f6c62014-02-18 19:42:14 +0100182 NFD_LOG_TRACE("[id:" << this->getId()
183 << ",endpoint:" << m_socket->local_endpoint()
184 << "] Successfully sent: " << wire.size() << " bytes");
185 // do nothing (needed to retain validity of wire memory block
186}
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600187
Giulio Grassi624f6c62014-02-18 19:42:14 +0100188template <class T>
189inline void
190DatagramFace<T>::close()
191{
192 if (!m_socket->is_open())
193 return;
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600194
Giulio Grassi624f6c62014-02-18 19:42:14 +0100195 NFD_LOG_INFO("[id:" << this->getId()
196 << ",endpoint:" << m_socket->local_endpoint()
197 << "] Close tunnel");
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600198
Giulio Grassi624f6c62014-02-18 19:42:14 +0100199 closeSocket();
Junxiao Shi08d07a72014-06-09 23:17:57 -0700200 fail("Close tunnel");
Giulio Grassi624f6c62014-02-18 19:42:14 +0100201}
202
203template <class T>
204inline void
205DatagramFace<T>::handleReceive(const boost::system::error_code& error,
206 size_t nBytesReceived)
207{
Alexander Afanasyev7e698e62014-03-07 16:48:35 +0000208 NFD_LOG_DEBUG("handleReceive: " << nBytesReceived);
Giulio Grassi624f6c62014-02-18 19:42:14 +0100209 receiveDatagram(m_inputBuffer, nBytesReceived, error);
Giulio Grassi69871f02014-03-09 16:14:44 +0100210 if (m_socket->is_open())
211 m_socket->async_receive(boost::asio::buffer(m_inputBuffer, MAX_NDN_PACKET_SIZE), 0,
212 bind(&DatagramFace<T>::handleReceive, this, _1, _2));
Giulio Grassi624f6c62014-02-18 19:42:14 +0100213}
214
215template <class T>
216inline void
217DatagramFace<T>::receiveDatagram(const uint8_t* buffer,
218 size_t nBytesReceived,
219 const boost::system::error_code& error)
220{
221 if (error != 0 || nBytesReceived == 0) {
222 if (error == boost::system::errc::operation_canceled) // when socket is closed by someone
223 return;
224
225 // this should be unnecessary, but just in case
226 if (!m_socket->is_open())
227 {
Junxiao Shi08d07a72014-06-09 23:17:57 -0700228 fail("Tunnel closed");
Giulio Grassi624f6c62014-02-18 19:42:14 +0100229 return;
230 }
231
232 NFD_LOG_WARN("[id:" << this->getId()
233 << ",endpoint:" << m_socket->local_endpoint()
234 << "] Receive operation failed: "
235 << error.category().message(error.value()));
236
237 closeSocket();
238
239 if (error == boost::asio::error::eof)
240 {
Junxiao Shi08d07a72014-06-09 23:17:57 -0700241 fail("Tunnel closed");
Giulio Grassi624f6c62014-02-18 19:42:14 +0100242 }
243 else
244 {
Junxiao Shi08d07a72014-06-09 23:17:57 -0700245 fail("Receive operation failed, closing socket: " +
Giulio Grassi624f6c62014-02-18 19:42:14 +0100246 error.category().message(error.value()));
247 }
248 return;
249 }
250
251 NFD_LOG_TRACE("[id:" << this->getId()
252 << ",endpoint:" << m_socket->local_endpoint()
253 << "] Received: " << nBytesReceived << " bytes");
254
Alexander Afanasyev5a8d8d82014-03-21 14:08:41 -0700255 Block element;
256 bool isOk = Block::fromBuffer(buffer, nBytesReceived, element);
257 if (!isOk)
258 {
259 NFD_LOG_WARN("[id:" << this->getId()
260 << ",endpoint:" << m_socket->local_endpoint()
261 << "] Failed to parse incoming packet");
262 // This message won't extend the face lifetime
263 return;
264 }
Giulio Grassi624f6c62014-02-18 19:42:14 +0100265
Alexander Afanasyev5a8d8d82014-03-21 14:08:41 -0700266 if (element.size() != nBytesReceived)
267 {
268 NFD_LOG_WARN("[id:" << this->getId()
269 << ",endpoint:" << m_socket->local_endpoint()
270 << "] Received datagram size and decoded "
271 << "element size don't match");
272 // This message won't extend the face lifetime
273 return;
274 }
275
276 if (!this->decodeAndDispatchInput(element))
277 {
278 NFD_LOG_WARN("[id:" << this->getId()
279 << ",endpoint:" << m_socket->local_endpoint()
280 << "] Received unrecognized block of type ["
281 << element.type() << "]");
282 // This message won't extend the face lifetime
283 return;
284 }
285
Giulio Grassi69871f02014-03-09 16:14:44 +0100286 m_hasBeenUsedRecently = true;
Giulio Grassi624f6c62014-02-18 19:42:14 +0100287}
288
289
290template <class T>
291inline void
292DatagramFace<T>::keepFaceAliveUntilAllHandlersExecuted(const shared_ptr<Face>& face)
293{
294}
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600295
Giulio Grassi624f6c62014-02-18 19:42:14 +0100296template <class T>
297inline void
298DatagramFace<T>::closeSocket()
299{
Giulio Grassi69871f02014-03-09 16:14:44 +0100300 NFD_LOG_DEBUG("closeSocket " << m_socket->local_endpoint());
Giulio Grassi624f6c62014-02-18 19:42:14 +0100301 boost::asio::io_service& io = m_socket->get_io_service();
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600302
Giulio Grassi624f6c62014-02-18 19:42:14 +0100303 // use the non-throwing variants and ignore errors, if any
304 boost::system::error_code error;
305 m_socket->shutdown(protocol::socket::shutdown_both, error);
306 m_socket->close(error);
307 // after this, handlers will be called with an error code
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600308
Giulio Grassi624f6c62014-02-18 19:42:14 +0100309 // ensure that the Face object is alive at least until all pending
310 // handlers are dispatched
311 io.post(bind(&DatagramFace<T>::keepFaceAliveUntilAllHandlersExecuted,
312 this, this->shared_from_this()));
313}
314
Giulio Grassi69871f02014-03-09 16:14:44 +0100315template <class T>
316inline void
Alexander Afanasyev355c0662014-03-20 18:08:17 -0700317DatagramFace<T>::setOnDemand(bool isOnDemand)
Giulio Grassi69871f02014-03-09 16:14:44 +0100318{
Alexander Afanasyev355c0662014-03-20 18:08:17 -0700319 Face::setOnDemand(isOnDemand);
Giulio Grassi69871f02014-03-09 16:14:44 +0100320}
321
322template <class T>
323inline void
324DatagramFace<T>::resetRecentUsage()
325{
326 m_hasBeenUsedRecently = false;
327}
328
329template <class T>
330inline bool
331DatagramFace<T>::hasBeenUsedRecently() const
332{
333 return m_hasBeenUsedRecently;
334}
335
Giulio Grassi624f6c62014-02-18 19:42:14 +0100336} // namespace nfd
337
Alexander Afanasyev613e2a92014-04-15 13:36:58 -0700338#endif // NFD_DAEMON_FACE_DATAGRAM_FACE_HPP