blob: ebc7e77f2a6ce07bd1463b963e1b34387e9b32e6 [file] [log] [blame]
Davide Pesaventobc4dd8c2014-02-14 20:01:01 +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#include "unix-stream-channel.hpp"
8
9#include <boost/filesystem.hpp>
Davide Pesavento9cec8ee2014-02-19 11:21:59 +010010#include <sys/stat.h> // for chmod()
Davide Pesaventobc4dd8c2014-02-14 20:01:01 +010011
12namespace nfd {
13
14NFD_LOG_INIT("UnixStreamChannel");
15
16using namespace boost::asio::local;
17
18UnixStreamChannel::UnixStreamChannel(boost::asio::io_service& ioService,
19 const unix_stream::Endpoint& endpoint)
20 : m_ioService(ioService)
21 , m_endpoint(endpoint)
22{
23}
24
25UnixStreamChannel::~UnixStreamChannel()
26{
27 if (m_acceptor)
28 {
29 // use the non-throwing variants during destruction
30 // and ignore any errors
31 boost::system::error_code error;
32 m_acceptor->close(error);
33 boost::filesystem::remove(m_endpoint.path(), error);
34 }
35}
36
37void
38UnixStreamChannel::listen(const FaceCreatedCallback& onFaceCreated,
39 const ConnectFailedCallback& onAcceptFailed,
40 int backlog/* = acceptor::max_connections*/)
41{
42 if (m_acceptor) // already listening
43 return;
44
45 namespace fs = boost::filesystem;
46 fs::path p(m_endpoint.path());
47 if (fs::symlink_status(p).type() == fs::socket_file)
48 {
49 // for safety, remove an already existing file only if it's a socket
50 fs::remove(p);
51 }
52
53 m_acceptor = make_shared<stream_protocol::acceptor>(boost::ref(m_ioService));
54 m_acceptor->open(m_endpoint.protocol());
55 m_acceptor->bind(m_endpoint);
56 m_acceptor->listen(backlog);
57
Davide Pesavento9cec8ee2014-02-19 11:21:59 +010058 if (::chmod(m_endpoint.path().c_str(), 0666) < 0)
59 {
60 throw Error("Failed to chmod() socket file at " + m_endpoint.path());
61 }
62
Davide Pesaventobc4dd8c2014-02-14 20:01:01 +010063 shared_ptr<stream_protocol::socket> clientSocket =
64 make_shared<stream_protocol::socket>(boost::ref(m_ioService));
65 m_acceptor->async_accept(*clientSocket,
66 bind(&UnixStreamChannel::handleSuccessfulAccept, this, _1,
67 clientSocket, onFaceCreated, onAcceptFailed));
68}
69
70void
71UnixStreamChannel::createFace(const shared_ptr<stream_protocol::socket>& socket,
72 const FaceCreatedCallback& onFaceCreated)
73{
74 shared_ptr<UnixStreamFace> face = make_shared<UnixStreamFace>(boost::cref(socket));
75 onFaceCreated(face);
76}
77
78void
79UnixStreamChannel::handleSuccessfulAccept(const boost::system::error_code& error,
80 const shared_ptr<stream_protocol::socket>& socket,
81 const FaceCreatedCallback& onFaceCreated,
82 const ConnectFailedCallback& onAcceptFailed)
83{
84 if (error) {
85 if (error == boost::system::errc::operation_canceled) // when socket is closed by someone
86 return;
87
88 NFD_LOG_DEBUG("Connection failed: "
89 << error.category().message(error.value()));
90
91 onAcceptFailed("Connection failed: " +
92 error.category().message(error.value()));
93 return;
94 }
95
96 // prepare accepting the next connection
97 shared_ptr<stream_protocol::socket> clientSocket =
98 make_shared<stream_protocol::socket>(boost::ref(m_ioService));
99 m_acceptor->async_accept(*clientSocket,
100 bind(&UnixStreamChannel::handleSuccessfulAccept, this, _1,
101 clientSocket, onFaceCreated, onAcceptFailed));
102
103 NFD_LOG_DEBUG("[" << m_endpoint << "] << Incoming connection");
104 createFace(socket, onFaceCreated);
105}
106
107} // namespace nfd