blob: e7798b168c02a6f8e5835c0814959246ba8c814f [file] [log] [blame]
Giulio Grassi624f6c62014-02-18 19:42:14 +01001/* -*- 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#ifndef NFD_FACE_DATAGRAM_FACE_HPP
8#define NFD_FACE_DATAGRAM_FACE_HPP
9
10#include "face.hpp"
11
12namespace nfd {
13
14template <class T>
15class DatagramFace : public Face
16{
17public:
18 typedef T protocol;
19
20 explicit
Alexander Afanasyeva39b90b2014-03-05 15:31:00 +000021 DatagramFace(const FaceUri& uri,
22 const shared_ptr<typename protocol::socket>& socket);
Giulio Grassi624f6c62014-02-18 19:42:14 +010023
24 virtual
25 ~DatagramFace();
26
27 // from Face
28 virtual void
29 sendInterest(const Interest& interest);
30
31 virtual void
32 sendData(const Data& data);
33
34 virtual void
35 close();
36
37 void
38 handleSend(const boost::system::error_code& error,
39 const Block& wire);
40
41 void
42 handleReceive(const boost::system::error_code& error,
43 size_t nBytesReceived);
44
45protected:
46
47 void
48 receiveDatagram(const uint8_t* buffer,
49 size_t nBytesReceived,
50 const boost::system::error_code& error);
51
52 void
53 keepFaceAliveUntilAllHandlersExecuted(const shared_ptr<Face>& face);
54
55 void
56 closeSocket();
57
58protected:
59 shared_ptr<typename protocol::socket> m_socket;
60 uint8_t m_inputBuffer[MAX_NDN_PACKET_SIZE];
61
62 NFD_LOG_INCLASS_DECLARE();
63
64};
65
66template <class T>
67inline
Alexander Afanasyeva39b90b2014-03-05 15:31:00 +000068DatagramFace<T>::DatagramFace(const FaceUri& uri,
69 const shared_ptr<typename DatagramFace::protocol::socket>& socket)
70 : Face(uri)
71 , m_socket(socket)
Giulio Grassi624f6c62014-02-18 19:42:14 +010072{
73 m_socket->async_receive(boost::asio::buffer(m_inputBuffer, MAX_NDN_PACKET_SIZE), 0,
74 bind(&DatagramFace<T>::handleReceive, this, _1, _2));
75}
76
77template <class T>
78inline
79DatagramFace<T>::~DatagramFace()
80{
81}
82
83template <class T>
84inline void
85DatagramFace<T>::sendInterest(const Interest& interest)
86{
Alexander Afanasyev7e698e62014-03-07 16:48:35 +000087 this->onSendInterest(interest);
Giulio Grassi624f6c62014-02-18 19:42:14 +010088 m_socket->async_send(boost::asio::buffer(interest.wireEncode().wire(),
89 interest.wireEncode().size()),
90 bind(&DatagramFace<T>::handleSend, this, _1, interest.wireEncode()));
91
92 // anything else should be done here?
93}
94
95template <class T>
96inline void
97DatagramFace<T>::sendData(const Data& data)
98{
Alexander Afanasyev7e698e62014-03-07 16:48:35 +000099 this->onSendData(data);
Giulio Grassi624f6c62014-02-18 19:42:14 +0100100 m_socket->async_send(boost::asio::buffer(data.wireEncode().wire(),
101 data.wireEncode().size()),
102 bind(&DatagramFace<T>::handleSend, this, _1, data.wireEncode()));
103
104 // anything else should be done here?
105}
106
107template <class T>
108inline void
109DatagramFace<T>::handleSend(const boost::system::error_code& error,
110 const Block& wire)
111{
112 if (error != 0) {
113 if (error == boost::system::errc::operation_canceled) // when socket is closed by someone
114 return;
115
116 if (!m_socket->is_open())
117 {
118 onFail("Tunnel closed");
119 return;
120 }
121
122 NFD_LOG_WARN("[id:" << this->getId()
123 << ",endpoint:" << m_socket->local_endpoint()
124 << "] Send operation failed, closing socket: "
125 << error.category().message(error.value()));
126
127 closeSocket();
128
129 if (error == boost::asio::error::eof)
130 {
131 onFail("Tunnel closed");
132 }
133 else
134 {
135 onFail("Send operation failed, closing socket: " +
136 error.category().message(error.value()));
137 }
138 return;
139 }
140
141 NFD_LOG_TRACE("[id:" << this->getId()
142 << ",endpoint:" << m_socket->local_endpoint()
143 << "] Successfully sent: " << wire.size() << " bytes");
144 // do nothing (needed to retain validity of wire memory block
145}
146
147template <class T>
148inline void
149DatagramFace<T>::close()
150{
151 if (!m_socket->is_open())
152 return;
153
154 NFD_LOG_INFO("[id:" << this->getId()
155 << ",endpoint:" << m_socket->local_endpoint()
156 << "] Close tunnel");
157
158 closeSocket();
159 onFail("Close tunnel");
160}
161
162template <class T>
163inline void
164DatagramFace<T>::handleReceive(const boost::system::error_code& error,
165 size_t nBytesReceived)
166{
Alexander Afanasyev7e698e62014-03-07 16:48:35 +0000167 NFD_LOG_DEBUG("handleReceive: " << nBytesReceived);
Giulio Grassi624f6c62014-02-18 19:42:14 +0100168 receiveDatagram(m_inputBuffer, nBytesReceived, error);
169 m_socket->async_receive(boost::asio::buffer(m_inputBuffer, MAX_NDN_PACKET_SIZE), 0,
170 bind(&DatagramFace<T>::handleReceive, this, _1, _2));
171}
172
173template <class T>
174inline void
175DatagramFace<T>::receiveDatagram(const uint8_t* buffer,
176 size_t nBytesReceived,
177 const boost::system::error_code& error)
178{
179 if (error != 0 || nBytesReceived == 0) {
180 if (error == boost::system::errc::operation_canceled) // when socket is closed by someone
181 return;
182
183 // this should be unnecessary, but just in case
184 if (!m_socket->is_open())
185 {
186 onFail("Tunnel closed");
187 return;
188 }
189
190 NFD_LOG_WARN("[id:" << this->getId()
191 << ",endpoint:" << m_socket->local_endpoint()
192 << "] Receive operation failed: "
193 << error.category().message(error.value()));
194
195 closeSocket();
196
197 if (error == boost::asio::error::eof)
198 {
199 onFail("Tunnel closed");
200 }
201 else
202 {
203 onFail("Receive operation failed, closing socket: " +
204 error.category().message(error.value()));
205 }
206 return;
207 }
208
209 NFD_LOG_TRACE("[id:" << this->getId()
210 << ",endpoint:" << m_socket->local_endpoint()
211 << "] Received: " << nBytesReceived << " bytes");
212
213 /// @todo Eliminate reliance on exceptions in this path
214 try {
215 Block element(buffer, nBytesReceived);
216
217 if (element.size() != nBytesReceived)
218 {
219 NFD_LOG_WARN("[id:" << this->getId()
220 << ",endpoint:" << m_socket->local_endpoint()
221 << "] Received datagram size and decoded "
222 << "element size don't match");
223 /// @todo this message should not extend the face lifetime
224 return;
225 }
226 if (!this->decodeAndDispatchInput(element))
227 {
228 NFD_LOG_WARN("[id:" << this->getId()
229 << ",endpoint:" << m_socket->local_endpoint()
230 << "] Received unrecognized block of type ["
231 << element.type() << "]");
232 // ignore unknown packet and proceed
233 /// @todo this message should not extend the face lifetime
234 return;
235 }
236 }
237 catch(const tlv::Error& e) {
238 NFD_LOG_WARN("[id:" << this->getId()
239 << ",endpoint:" << m_socket->local_endpoint()
240 << "] Received input is invalid");
241 /// @todo this message should not extend the face lifetime
242 return;
243 }
244}
245
246
247template <class T>
248inline void
249DatagramFace<T>::keepFaceAliveUntilAllHandlersExecuted(const shared_ptr<Face>& face)
250{
251}
252
253template <class T>
254inline void
255DatagramFace<T>::closeSocket()
256{
257 boost::asio::io_service& io = m_socket->get_io_service();
258
259 // use the non-throwing variants and ignore errors, if any
260 boost::system::error_code error;
261 m_socket->shutdown(protocol::socket::shutdown_both, error);
262 m_socket->close(error);
263 // after this, handlers will be called with an error code
264
265 // ensure that the Face object is alive at least until all pending
266 // handlers are dispatched
267 io.post(bind(&DatagramFace<T>::keepFaceAliveUntilAllHandlersExecuted,
268 this, this->shared_from_this()));
269}
270
271} // namespace nfd
272
273#endif // NFD_FACE_DATAGRAM_FACE_HPP