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 
29 #include "ur_client_library/log.h"
31 
32 namespace urcl
33 {
34 namespace comm
35 {
36 TCPSocket::TCPSocket() : socket_fd_(-1), state_(SocketState::Invalid)
37 {
38 }
40 {
41  close();
42 }
43 
44 void TCPSocket::setOptions(int socket_fd)
45 {
46  int flag = 1;
47  setsockopt(socket_fd, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(int));
48  setsockopt(socket_fd, IPPROTO_TCP, TCP_QUICKACK, &flag, sizeof(int));
49 
50  if (recv_timeout_ != nullptr)
51  {
52  setsockopt(socket_fd, SOL_SOCKET, SO_RCVTIMEO, recv_timeout_.get(), sizeof(timeval));
53  }
54 }
55 
56 bool TCPSocket::setup(std::string& host, int port)
57 {
59  return false;
60 
61  URCL_LOG_DEBUG("Setting up connection: %s:%d", host.c_str(), port);
62 
63  // gethostbyname() is deprecated so use getadderinfo() as described in:
64  // https://beej.us/guide/bgnet/html/#getaddrinfoprepare-to-launch
65 
66  const char* host_name = host.empty() ? nullptr : host.c_str();
67  std::string service = std::to_string(port);
68  struct addrinfo hints, *result;
69  std::memset(&hints, 0, sizeof(hints));
70 
71  hints.ai_family = AF_UNSPEC;
72  hints.ai_socktype = SOCK_STREAM;
73  hints.ai_flags = AI_PASSIVE;
74 
75  if (getaddrinfo(host_name, service.c_str(), &hints, &result) != 0)
76  {
77  URCL_LOG_ERROR("Failed to get address for %s:%d", host.c_str(), port);
78  return false;
79  }
80 
81  bool connected = false;
82  // loop through the list of addresses untill we find one that's connectable
83  for (struct addrinfo* p = result; p != nullptr; p = p->ai_next)
84  {
85  socket_fd_ = ::socket(p->ai_family, p->ai_socktype, p->ai_protocol);
86 
87  if (socket_fd_ != -1 && open(socket_fd_, p->ai_addr, p->ai_addrlen))
88  {
89  connected = true;
90  break;
91  }
92  }
93 
94  freeaddrinfo(result);
95 
96  if (!connected)
97  {
99  URCL_LOG_ERROR("Connection setup failed for %s:%d", host.c_str(), port);
100  }
101  else
102  {
105  URCL_LOG_DEBUG("Connection established for %s:%d", host.c_str(), port);
106  }
107  return connected;
108 }
109 
111 {
112  if (socket_fd_ >= 0)
113  {
116  socket_fd_ = -1;
117  }
118 }
119 
120 std::string TCPSocket::getIP() const
121 {
122  sockaddr_in name;
123  socklen_t len = sizeof(name);
124  int res = ::getsockname(socket_fd_, (sockaddr*)&name, &len);
125 
126  if (res < 0)
127  {
128  URCL_LOG_ERROR("Could not get local IP");
129  return std::string();
130  }
131 
132  char buf[128];
133  inet_ntop(AF_INET, &name.sin_addr, buf, sizeof(buf));
134  return std::string(buf);
135 }
136 
137 bool TCPSocket::read(char* character)
138 {
139  size_t read_chars;
140  // It's inefficient, but in our case we read very small messages
141  // and the overhead connected with reading character by character is
142  // negligible - adding buffering would complicate the code needlessly.
143  return read((uint8_t*)character, 1, read_chars);
144 }
145 
146 bool TCPSocket::read(uint8_t* buf, const size_t buf_len, size_t& read)
147 {
148  read = 0;
149 
151  return false;
152 
153  ssize_t res = ::recv(socket_fd_, buf, buf_len, 0);
154 
155  if (res == 0)
156  {
158  return false;
159  }
160  else if (res < 0)
161  return false;
162 
163  read = static_cast<size_t>(res);
164  return true;
165 }
166 
167 bool TCPSocket::write(const uint8_t* buf, const size_t buf_len, size_t& written)
168 {
169  written = 0;
170 
172  {
173  URCL_LOG_ERROR("Attempt to write on a non-connected socket");
174  return false;
175  }
176 
177  size_t remaining = buf_len;
178 
179  // handle partial sends
180  while (written < buf_len)
181  {
182  ssize_t sent = ::send(socket_fd_, buf + written, remaining, 0);
183 
184  if (sent <= 0)
185  {
186  URCL_LOG_ERROR("Sending data through socket failed.");
187  return false;
188  }
189 
190  written += sent;
191  remaining -= sent;
192  }
193 
194  return true;
195 }
196 
197 void TCPSocket::setReceiveTimeout(const timeval& timeout)
198 {
199  recv_timeout_.reset(new timeval(timeout));
200 
202  {
204  }
205 }
206 
207 } // namespace comm
208 } // namespace urcl
#define URCL_LOG_ERROR(...)
Definition: log.h:37
bool write(const uint8_t *buf, const size_t buf_len, size_t &written)
Writes to the socket.
Definition: tcp_socket.cpp:167
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:63
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:137
#define URCL_LOG_DEBUG(...)
Definition: log.h:34
bool setup(std::string &host, int port)
Definition: tcp_socket.cpp:56
void close()
Closes the connection to the socket.
Definition: tcp_socket.cpp:110
std::string getIP() const
Determines the local IP address of the currently configured socket.
Definition: tcp_socket.cpp:120
Socket is connected and ready to use.
virtual void setOptions(int socket_fd)
Definition: tcp_socket.cpp:44
virtual bool open(int socket_fd, struct sockaddr *address, size_t address_len)
Definition: tcp_socket.h:55
void setReceiveTimeout(const timeval &timeout)
Setup Receive timeout used for this socket.
Definition: tcp_socket.cpp:197
TCPSocket()
Creates a TCPSocket object.
Definition: tcp_socket.cpp:36


ur_client_library
Author(s): Thomas Timm Andersen, Simon Rasmussen, Felix Exner, Lea Steffen, Tristan Schnell
autogenerated on Sun May 9 2021 02:16:26