tcp_socket.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2019, FZI Forschungszentrum Informatik (refactor)
3  *
4  * Copyright 2017, 2018 Jarek Potiuk (low bandwidth trajectory follower)
5  *
6  * Copyright 2017, 2018 Simon Rasmussen (refactor)
7  *
8  * Copyright 2015, 2016 Thomas Timm Andersen (original version)
9  *
10  * Licensed under the Apache License, Version 2.0 (the "License");
11  * you may not use this file except in compliance with the License.
12  * You may obtain a copy of the License at
13  *
14  * http://www.apache.org/licenses/LICENSE-2.0
15  *
16  * Unless required by applicable law or agreed to in writing, software
17  * distributed under the License is distributed on an "AS IS" BASIS,
18  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19  * See the License for the specific language governing permissions and
20  * limitations under the License.
21  */
22 
23 #include <arpa/inet.h>
24 #include <endian.h>
25 #include <netinet/tcp.h>
26 #include <unistd.h>
27 #include <cstring>
28 #include <sstream>
29 #include <thread>
30 
31 #include "ur_client_library/log.h"
33 
34 namespace urcl
35 {
36 namespace comm
37 {
38 TCPSocket::TCPSocket() : socket_fd_(-1), state_(SocketState::Invalid), reconnection_time_(std::chrono::seconds(10))
39 {
40 }
42 {
43  close();
44 }
45 
46 void TCPSocket::setOptions(int socket_fd)
47 {
48  int flag = 1;
49  setsockopt(socket_fd, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(int));
50  setsockopt(socket_fd, IPPROTO_TCP, TCP_QUICKACK, &flag, sizeof(int));
51 
52  if (recv_timeout_ != nullptr)
53  {
54  setsockopt(socket_fd, SOL_SOCKET, SO_RCVTIMEO, recv_timeout_.get(), sizeof(timeval));
55  }
56 }
57 
58 bool TCPSocket::setup(std::string& host, int port)
59 {
61  return false;
62 
63  URCL_LOG_DEBUG("Setting up connection: %s:%d", host.c_str(), port);
64 
65  // gethostbyname() is deprecated so use getadderinfo() as described in:
66  // https://beej.us/guide/bgnet/html/#getaddrinfoprepare-to-launch
67 
68  const char* host_name = host.empty() ? nullptr : host.c_str();
69  std::string service = std::to_string(port);
70  struct addrinfo hints, *result;
71  std::memset(&hints, 0, sizeof(hints));
72 
73  hints.ai_family = AF_UNSPEC;
74  hints.ai_socktype = SOCK_STREAM;
75  hints.ai_flags = AI_PASSIVE;
76 
77  bool connected = false;
78  while (!connected)
79  {
80  if (getaddrinfo(host_name, service.c_str(), &hints, &result) != 0)
81  {
82  URCL_LOG_ERROR("Failed to get address for %s:%d", host.c_str(), port);
83  return false;
84  }
85  // loop through the list of addresses untill we find one that's connectable
86  for (struct addrinfo* p = result; p != nullptr; p = p->ai_next)
87  {
88  socket_fd_ = ::socket(p->ai_family, p->ai_socktype, p->ai_protocol);
89 
90  if (socket_fd_ != -1 && open(socket_fd_, p->ai_addr, p->ai_addrlen))
91  {
92  connected = true;
93  break;
94  }
95  }
96 
97  freeaddrinfo(result);
98 
99  if (!connected)
100  {
102  std::stringstream ss;
103  ss << "Failed to connect to robot on IP " << host_name
104  << ". Please check that the robot is booted and reachable on " << host_name << ". Retrying in "
105  << reconnection_time_.count() << " seconds";
106  URCL_LOG_ERROR("%s", ss.str().c_str());
107  std::this_thread::sleep_for(reconnection_time_);
108  }
109  }
112  URCL_LOG_DEBUG("Connection established for %s:%d", host.c_str(), port);
113  return connected;
114 }
115 
117 {
118  if (socket_fd_ >= 0)
119  {
122  socket_fd_ = -1;
123  }
124 }
125 
126 std::string TCPSocket::getIP() const
127 {
128  sockaddr_in name;
129  socklen_t len = sizeof(name);
130  int res = ::getsockname(socket_fd_, (sockaddr*)&name, &len);
131 
132  if (res < 0)
133  {
134  URCL_LOG_ERROR("Could not get local IP");
135  return std::string();
136  }
137 
138  char buf[128];
139  inet_ntop(AF_INET, &name.sin_addr, buf, sizeof(buf));
140  return std::string(buf);
141 }
142 
143 bool TCPSocket::read(char* character)
144 {
145  size_t read_chars;
146  // It's inefficient, but in our case we read very small messages
147  // and the overhead connected with reading character by character is
148  // negligible - adding buffering would complicate the code needlessly.
149  return read((uint8_t*)character, 1, read_chars);
150 }
151 
152 bool TCPSocket::read(uint8_t* buf, const size_t buf_len, size_t& read)
153 {
154  read = 0;
155 
157  return false;
158 
159  ssize_t res = ::recv(socket_fd_, buf, buf_len, 0);
160 
161  if (res == 0)
162  {
164  return false;
165  }
166  else if (res < 0)
167  return false;
168 
169  read = static_cast<size_t>(res);
170  return true;
171 }
172 
173 bool TCPSocket::write(const uint8_t* buf, const size_t buf_len, size_t& written)
174 {
175  written = 0;
176 
178  {
179  URCL_LOG_ERROR("Attempt to write on a non-connected socket");
180  return false;
181  }
182 
183  size_t remaining = buf_len;
184 
185  // handle partial sends
186  while (written < buf_len)
187  {
188  ssize_t sent = ::send(socket_fd_, buf + written, remaining, 0);
189 
190  if (sent <= 0)
191  {
192  URCL_LOG_ERROR("Sending data through socket failed.");
193  return false;
194  }
195 
196  written += sent;
197  remaining -= sent;
198  }
199 
200  return true;
201 }
202 
203 void TCPSocket::setReceiveTimeout(const timeval& timeout)
204 {
205  recv_timeout_.reset(new timeval(timeout));
206 
208  {
210  }
211 }
212 
213 } // namespace comm
214 } // namespace urcl
#define URCL_LOG_ERROR(...)
Definition: log.h:26
bool write(const uint8_t *buf, const size_t buf_len, size_t &written)
Writes to the socket.
Definition: tcp_socket.cpp:173
std::atomic< SocketState > state_
Definition: tcp_socket.h:52
Connection to socket got closed.
std::atomic< int > socket_fd_
Definition: tcp_socket.h:51
SocketState
State the socket can be in.
Definition: tcp_socket.h:37
std::unique_ptr< timeval > recv_timeout_
Definition: tcp_socket.h:64
Socket is initialized or setup failed.
Socket is disconnected and cannot be used.
bool read(char *character)
Reads one byte from the socket.
Definition: tcp_socket.cpp:143
std::string getIP() const
Determines the local IP address of the currently configured socket.
Definition: tcp_socket.cpp:126
#define URCL_LOG_DEBUG(...)
Definition: log.h:23
bool setup(std::string &host, int port)
Definition: tcp_socket.cpp:58
void close()
Closes the connection to the socket.
Definition: tcp_socket.cpp:116
Socket is connected and ready to use.
virtual void setOptions(int socket_fd)
Definition: tcp_socket.cpp:46
virtual bool open(int socket_fd, struct sockaddr *address, size_t address_len)
Definition: tcp_socket.h:56
std::chrono::seconds reconnection_time_
Definition: tcp_socket.h:53
void setReceiveTimeout(const timeval &timeout)
Setup Receive timeout used for this socket.
Definition: tcp_socket.cpp:203
TCPSocket()
Creates a TCPSocket object.
Definition: tcp_socket.cpp:38


ur_client_library
Author(s): Thomas Timm Andersen, Simon Rasmussen, Felix Exner, Lea Steffen, Tristan Schnell
autogenerated on Tue Jul 4 2023 02:09:47