blob: 4bf85d7f35f7754227f347d60931cc92bed2b122 [file] [log] [blame]
Alexander Afanasyevfe3b1502013-12-18 16:45:03 -08001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
2/**
3 * Copyright (C) 2013 Regents of the University of California.
4 * @author: Jeff Thompson <jefft0@remap.ucla.edu>
5 * See COPYING for copyright and distribution information.
6 */
7
8#include <stdexcept>
9#include <stdlib.h>
10
11#include <ndn-cpp/face.hpp>
12#include <ndn-cpp/transport/unix-transport.hpp>
Alexander Afanasyev328e23d2013-12-28 20:47:38 -080013#include <ndn-cpp/c/util/ndn_memory.h>
Alexander Afanasyevfe3b1502013-12-18 16:45:03 -080014
15#include <boost/asio.hpp>
16#include <boost/bind.hpp>
17
18using namespace std;
Alexander Afanasyeve2e0d752014-01-03 13:30:30 -080019typedef boost::asio::local::stream_protocol protocol;
Alexander Afanasyevfe3b1502013-12-18 16:45:03 -080020
21namespace ndn {
22
23const size_t MAX_LENGTH = 9000;
24
25class UnixTransport::Impl
26{
27public:
Alexander Afanasyeve2e0d752014-01-03 13:30:30 -080028 Impl(UnixTransport &transport)
Alexander Afanasyev328e23d2013-12-28 20:47:38 -080029 : transport_(transport)
30 , socket_(*transport_.ioService_)
31 , partialDataSize_(0)
Alexander Afanasyevfe3b1502013-12-18 16:45:03 -080032 {
33 }
34
Alexander Afanasyeve2e0d752014-01-03 13:30:30 -080035 void
36 connect()
Alexander Afanasyevfe3b1502013-12-18 16:45:03 -080037 {
38 socket_.open();
Alexander Afanasyeve2e0d752014-01-03 13:30:30 -080039 socket_.connect(protocol::endpoint(transport_.unixSocket_));
Alexander Afanasyevfe3b1502013-12-18 16:45:03 -080040 // socket_.async_connect(protocol::endpoint(unixSocket));
41
Alexander Afanasyev328e23d2013-12-28 20:47:38 -080042 partialDataSize_ = 0;
Alexander Afanasyevfe3b1502013-12-18 16:45:03 -080043 socket_.async_receive(boost::asio::buffer(inputBuffer_, MAX_LENGTH), 0,
44 boost::bind(&Impl::handle_async_receive, this, _1, _2));
Alexander Afanasyevfe3b1502013-12-18 16:45:03 -080045 }
46
47 void
Alexander Afanasyevfe3b1502013-12-18 16:45:03 -080048 close()
49 {
50 socket_.close();
51 }
Alexander Afanasyeve2e0d752014-01-03 13:30:30 -080052
53 void
54 send(const Block &wire)
55 {
56 socket_.async_send(boost::asio::buffer(wire.wire(), wire.size()),
57 boost::bind(&Impl::handle_async_send, this, _1, wire));
58 }
Alexander Afanasyev328e23d2013-12-28 20:47:38 -080059
60 inline void
61 processAll(uint8_t *buffer, size_t &offset, size_t availableSize)
62 {
63 while(offset < availableSize)
64 {
65 Block element(buffer + offset, availableSize - offset);
66 transport_.receive(element);
67
68 offset += element.size();
69 }
70 }
Alexander Afanasyeve2e0d752014-01-03 13:30:30 -080071
72 void
73 handle_async_receive(const boost::system::error_code& error, std::size_t bytes_recvd)
74 {
75 /// @todo The socket is not datagram, so need to have internal buffer to handle partial data reception
Alexander Afanasyev328e23d2013-12-28 20:47:38 -080076
Alexander Afanasyeva557d5a2013-12-28 21:59:03 -080077 if (error)
78 {
79 socket_.close(); // closing at this point may not be that necessary
80 transport_.errorCallback_();
81 }
82
Alexander Afanasyeve2e0d752014-01-03 13:30:30 -080083 if (!error && bytes_recvd > 0)
84 {
Alexander Afanasyev328e23d2013-12-28 20:47:38 -080085 try
86 {
87 // inputBuffer_ has bytes_recvd received bytes of data
88 if (partialDataSize_ > 0)
89 {
90 size_t newDataSize = std::min(bytes_recvd, MAX_LENGTH-partialDataSize_);
91 ndn_memcpy(partialData_ + partialDataSize_, inputBuffer_, newDataSize);
92 partialDataSize_ += newDataSize;
93
94 size_t offset = 0;
95 try
96 {
97 processAll(partialData_, offset, partialDataSize_);
98
99 // no exceptions => processed the whole thing
100 if (bytes_recvd - newDataSize > 0)
101 {
102 // there is a little bit more data available
103
104 offset = 0;
105 partialDataSize_ = bytes_recvd - newDataSize;
106 ndn_memcpy(partialData_, inputBuffer_ + newDataSize, partialDataSize_);
107
108 processAll(partialData_, offset, partialDataSize_);
109
110 // no exceptions => processed the whole thing
111 partialDataSize_ = 0;
112 }
113 else
114 {
115 // done processing
116 partialDataSize_ = 0;
117 }
118 }
119 catch(Block::Error &)
120 {
121 if (offset > 0)
122 {
123 partialDataSize_ -= offset;
124 ndn_memcpy(partialData_, partialData_ + offset, partialDataSize_);
125 }
126 else if (offset == 0 && partialDataSize_ == MAX_LENGTH)
127 {
128 // very bad... should close connection
Alexander Afanasyev328e23d2013-12-28 20:47:38 -0800129 socket_.close();
Alexander Afanasyeva557d5a2013-12-28 21:59:03 -0800130 transport_.errorCallback_();
Alexander Afanasyev328e23d2013-12-28 20:47:38 -0800131 }
132 }
133 }
134 else
135 {
136 size_t offset = 0;
137 try
138 {
139 processAll(inputBuffer_, offset, bytes_recvd);
140 }
141 catch(Block::Error &error)
142 {
143 if (offset > 0)
144 {
145 partialDataSize_ = bytes_recvd - offset;
146 ndn_memcpy(partialData_, inputBuffer_ + offset, partialDataSize_);
147 }
148 }
149 }
150 }
Alexander Afanasyeve2e0d752014-01-03 13:30:30 -0800151 catch(Tlv::Error &error)
152 {
Alexander Afanasyev328e23d2013-12-28 20:47:38 -0800153 std::cerr << "[[handle_async_receive]] Tlv::Error: " << error.what() << std::endl;
Alexander Afanasyeve2e0d752014-01-03 13:30:30 -0800154 // pass
155 }
156 }
157
158 socket_.async_receive(boost::asio::buffer(inputBuffer_, MAX_LENGTH), 0,
159 boost::bind(&Impl::handle_async_receive, this, _1, _2));
160 }
161
162 void
163 handle_async_send(const boost::system::error_code& error, const Block &wire)
164 {
Alexander Afanasyev328e23d2013-12-28 20:47:38 -0800165 // pass (needed to keep data block alive during the send)
Alexander Afanasyeve2e0d752014-01-03 13:30:30 -0800166 }
Alexander Afanasyevfe3b1502013-12-18 16:45:03 -0800167
168private:
Alexander Afanasyeve2e0d752014-01-03 13:30:30 -0800169 UnixTransport &transport_;
170
Alexander Afanasyevfe3b1502013-12-18 16:45:03 -0800171 protocol::socket socket_;
Alexander Afanasyevfe3b1502013-12-18 16:45:03 -0800172 uint8_t inputBuffer_[MAX_LENGTH];
Alexander Afanasyev328e23d2013-12-28 20:47:38 -0800173
174 uint8_t partialData_[MAX_LENGTH];
175 size_t partialDataSize_;
Alexander Afanasyevfe3b1502013-12-18 16:45:03 -0800176};
177
178UnixTransport::UnixTransport(const std::string &unixSocket/* = "/tmp/.ndnd.sock"*/)
179 : unixSocket_(unixSocket)
Alexander Afanasyevfe3b1502013-12-18 16:45:03 -0800180{
181}
182
183UnixTransport::~UnixTransport()
184{
185}
186
187void
Alexander Afanasyeva557d5a2013-12-28 21:59:03 -0800188UnixTransport::connect(boost::asio::io_service &ioService,
189 const ReceiveCallback &receiveCallback,
190 const ErrorCallback &errorCallback)
Alexander Afanasyevfe3b1502013-12-18 16:45:03 -0800191{
Alexander Afanasyeva557d5a2013-12-28 21:59:03 -0800192 Transport::connect(ioService, receiveCallback, errorCallback);
Alexander Afanasyeve2e0d752014-01-03 13:30:30 -0800193
194 impl_ = std::auto_ptr<UnixTransport::Impl> (new UnixTransport::Impl(*this));
195 impl_->connect();
196
197 isConnected_ = true;
Alexander Afanasyevfe3b1502013-12-18 16:45:03 -0800198}
199
200void
Alexander Afanasyeve2e0d752014-01-03 13:30:30 -0800201UnixTransport::send(const Block &wire)
Alexander Afanasyevfe3b1502013-12-18 16:45:03 -0800202{
Alexander Afanasyeve2e0d752014-01-03 13:30:30 -0800203 impl_->send(wire);
Alexander Afanasyevfe3b1502013-12-18 16:45:03 -0800204}
205
206void
207UnixTransport::close()
208{
209 impl_->close();
210}
211
212}