YARP
Yet Another Robot Platform
UnixSockTwoWayStream.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2006-2020 Istituto Italiano di Tecnologia (IIT)
3  * All rights reserved.
4  *
5  * This software may be modified and distributed under the terms of the
6  * BSD-3-Clause license. See the accompanying LICENSE file for details.
7  */
8 
9 #include <yarp/conf/system.h>
10 
11 #include <yarp/os/LogStream.h>
12 #include <yarp/os/NetType.h>
13 #include <yarp/os/SystemClock.h>
14 
15 #include "UnixSockTwoWayStream.h"
16 #include "UnixSocketLogComponent.h"
17 #include <cerrno>
18 #include <cstring>
19 #include <fcntl.h> /* For O_* constants */
20 #include <sys/socket.h>
21 #include <sys/stat.h> /* For mode constants */
22 #include <sys/un.h>
23 #include <unistd.h>
24 
25 using namespace yarp::os;
26 
27 UnixSockTwoWayStream::UnixSockTwoWayStream(const std::string& _socketPath) :
28  socketPath(_socketPath)
29 {
30 }
31 
32 bool UnixSockTwoWayStream::open(bool sender)
33 {
34  openedAsReader = !sender;
35  struct sockaddr_un addr;
36  if ((reader_fd = ::socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
37  yCError(UNIXSOCK_CARRIER, "%d, %s", errno, strerror(errno));
38  return false;
39  }
40 
41  memset(&addr, 0, sizeof(addr));
42  addr.sun_family = AF_UNIX;
43 
44  if (socketPath.empty()) {
45  *addr.sun_path = '\0';
46  strncpy(addr.sun_path + 1, socketPath.c_str() + 1, sizeof(addr.sun_path) - 2);
47  } else {
48  strncpy(addr.sun_path, socketPath.c_str(), sizeof(addr.sun_path) - 1);
49  if (!sender) {
50  ::unlink(socketPath.c_str());
51  }
52  }
53 
54  if (sender) {
55  size_t attempts = 0;
56  // try connection 5 times, waiting that the receiver bind the socket
57  while (attempts < maxAttempts) {
58  int result = ::connect(reader_fd, reinterpret_cast<struct sockaddr*>(&addr), sizeof(addr));
59  if (result == 0) {
60  break;
61  }
62  yarp::os::SystemClock::delaySystem(delayBetweenAttempts);
63  attempts++;
64  }
65 
66  if (attempts >= maxAttempts) {
67  yCError(UNIXSOCK_CARRIER, "connect() error, I tried %zu times: %d, %s", maxAttempts, errno, strerror(errno));
68  return false;
69  }
70  } else {
71  if (::bind(reader_fd, reinterpret_cast<struct sockaddr*>(&addr), sizeof(addr)) == -1) {
72  yCError(UNIXSOCK_CARRIER, "bind() error: %d, %s", errno, strerror(errno));
73  return false;
74  }
75 
76  // the socket will listen only 1 client
77  if (::listen(reader_fd, 2) == -1) {
78  yCError(UNIXSOCK_CARRIER, "listen() error: %d, %s", errno, strerror(errno));
79  return false;
80  }
81  struct sockaddr_un remote;
82  uint lenRemote = sizeof(remote);
83 
84  if ((sender_fd = ::accept(reader_fd, reinterpret_cast<struct sockaddr*>(&remote), &lenRemote)) == -1) {
85  yCError(UNIXSOCK_CARRIER, "accept() error: %d, %s", errno, strerror(errno));
86  return false;
87  }
88  }
89 
90  return true;
91 }
92 
94 {
95  close();
96 }
97 
99 {
100  return *this;
101 }
102 
104 {
105  return *this;
106 }
107 
109 {
110  return localAddress;
111 }
112 
114 {
115  return remoteAddress;
116 }
117 
119 {
120  localAddress = _localAddress;
121 }
122 
124 {
125  remoteAddress = _remoteAddress;
126 }
127 
129 {
130  yCDebug(UNIXSOCK_CARRIER, "Interrupting socket");
131  close();
132 }
133 
135 {
136  // If the connect descriptor is valid close socket
137  // and free the memory dedicated.
138  // socket closure
139  if (sender_fd > 0) {
140  ::shutdown(sender_fd, SHUT_RDWR);
141  ::close(sender_fd);
142  sender_fd = -1;
143  }
144 
145  if (reader_fd > 0) {
146  ::shutdown(reader_fd, SHUT_RDWR);
147  ::close(reader_fd);
148  reader_fd = -1;
149  }
150 
151  ::unlink(socketPath.c_str());
152  happy = false;
153 }
154 
156 {
157  if (closed || !happy) {
158  return -1;
159  }
160  int result;
161  result = ::read(openedAsReader ? sender_fd : reader_fd, b.get(), b.length());
162  if (closed || result == 0) {
163  happy = false;
164  return -1;
165  }
166  if (result < 0) {
167  yCError(UNIXSOCK_CARRIER, "read() error: %d, %s", errno, strerror(errno));
168  return -1;
169  }
170  return result;
171 }
172 
174 {
175  if (reader_fd < 0) {
176  close();
177  return;
178  }
179  int writtenMem = ::write(openedAsReader ? sender_fd : reader_fd, b.get(), b.length());
180  if (writtenMem < 0) {
181  yCError(UNIXSOCK_CARRIER, "write() error: %d, %s", errno, strerror(errno));
182  if (errno != ETIMEDOUT) {
183  close();
184  }
185  return;
186  }
187 }
188 
190 {
191  return happy;
192 }
193 
195 {
196 }
197 
199 {
200 }
201 
203 {
204 }
LogStream.h
UnixSockTwoWayStream::~UnixSockTwoWayStream
~UnixSockTwoWayStream() override
Definition: UnixSockTwoWayStream.cpp:93
SystemClock.h
UnixSocketLogComponent.h
yarp::os::OutputStream
Simple specification of the minimum functions needed from output streams.
Definition: OutputStream.h:25
UnixSockTwoWayStream.h
UnixSockTwoWayStream::setLocalAddress
void setLocalAddress(yarp::os::Contact &_localAddress)
Definition: UnixSockTwoWayStream.cpp:118
UnixSockTwoWayStream::write
void write(const yarp::os::Bytes &b) override
Write a block of bytes to the stream.
Definition: UnixSockTwoWayStream.cpp:173
NetType.h
UnixSockTwoWayStream::setRemoteAddress
void setRemoteAddress(yarp::os::Contact &_remoteAddress)
Definition: UnixSockTwoWayStream.cpp:123
yarp::os::SystemClock::delaySystem
static void delaySystem(double seconds)
Definition: SystemClock.cpp:32
yarp::os::Bytes::get
const char * get() const
Definition: Bytes.cpp:30
yarp::os::Bytes::length
size_t length() const
Definition: Bytes.cpp:25
yarp::conf::ssize_t
::ssize_t ssize_t
Definition: numeric.h:60
UnixSockTwoWayStream::UnixSockTwoWayStream
UnixSockTwoWayStream(const std::string &_socketPath="")
Definition: UnixSockTwoWayStream.cpp:27
yarp::os::Bytes
A simple abstraction for a block of bytes.
Definition: Bytes.h:28
UnixSockTwoWayStream::open
bool open(bool sender=false)
Definition: UnixSockTwoWayStream.cpp:32
system.h
UnixSockTwoWayStream::beginPacket
void beginPacket() override
Mark the beginning of a logical packet.
Definition: UnixSockTwoWayStream.cpp:198
UnixSockTwoWayStream::getOutputStream
OutputStream & getOutputStream() override
Get an OutputStream to write to.
Definition: UnixSockTwoWayStream.cpp:103
yCError
#define yCError(component,...)
Definition: LogComponent.h:157
UnixSockTwoWayStream::reset
void reset() override
Reset the stream.
Definition: UnixSockTwoWayStream.cpp:194
UnixSockTwoWayStream::getLocalAddress
const yarp::os::Contact & getLocalAddress() const override
Get the address of the local side of the stream.
Definition: UnixSockTwoWayStream.cpp:108
UnixSockTwoWayStream::interrupt
void interrupt() override
Interrupt the stream.
Definition: UnixSockTwoWayStream.cpp:128
UnixSockTwoWayStream::endPacket
void endPacket() override
Mark the end of a logical packet (see beginPacket).
Definition: UnixSockTwoWayStream.cpp:202
yarp::os::InputStream::read
virtual int read()
Read and return a single byte.
Definition: InputStream.cpp:23
yarp::os
An interface to the operating system, including Port based communication.
Definition: AbstractCarrier.h:17
yCDebug
#define yCDebug(component,...)
Definition: LogComponent.h:112
UNIXSOCK_CARRIER
const yarp::os::LogComponent & UNIXSOCK_CARRIER()
Definition: UnixSocketLogComponent.cpp:16
yarp::os::Contact
Represents how to reach a part of a YARP network.
Definition: Contact.h:39
UnixSockTwoWayStream::getRemoteAddress
const yarp::os::Contact & getRemoteAddress() const override
Get the address of the remote side of the stream.
Definition: UnixSockTwoWayStream.cpp:113
UnixSockTwoWayStream::isOk
bool isOk() const override
Check if the stream is ok or in an error state.
Definition: UnixSockTwoWayStream.cpp:189
UnixSockTwoWayStream::getInputStream
InputStream & getInputStream() override
Get an InputStream to read from.
Definition: UnixSockTwoWayStream.cpp:98
yarp::os::InputStream
Simple specification of the minimum functions needed from input streams.
Definition: InputStream.h:29
UnixSockTwoWayStream::close
void close() override
Terminate the stream.
Definition: UnixSockTwoWayStream.cpp:134