tcp_socket.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2017, 2018 Jarek Potiuk (low bandwidth trajectory follower)
3  *
4  * Copyright 2017, 2018 Simon Rasmussen (refactor)
5  *
6  * Copyright 2015, 2016 Thomas Timm Andersen (original version)
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  */
20 
21 #include <arpa/inet.h>
22 #include <endian.h>
23 #include <netinet/tcp.h>
24 #include <unistd.h>
25 #include <cstring>
26 
27 #include "ur_modern_driver/log.h"
29 
30 TCPSocket::TCPSocket() : socket_fd_(-1), state_(SocketState::Invalid)
31 {
32 }
34 {
35  close();
36 }
37 
38 void TCPSocket::setOptions(int socket_fd)
39 {
40  int flag = 1;
41  setsockopt(socket_fd, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(int));
42  setsockopt(socket_fd, IPPROTO_TCP, TCP_QUICKACK, &flag, sizeof(int));
43 }
44 
45 bool TCPSocket::setup(std::string &host, int port)
46 {
48  return false;
49 
50  LOG_INFO("Setting up connection: %s:%d", host.c_str(), port);
51 
52  // gethostbyname() is deprecated so use getadderinfo() as described in:
53  // http://www.beej.us/guide/bgnet/output/html/multipage/syscalls.html#getaddrinfo
54 
55  const char *host_name = host.empty() ? nullptr : host.c_str();
56  std::string service = std::to_string(port);
57  struct addrinfo hints, *result;
58  std::memset(&hints, 0, sizeof(hints));
59 
60  hints.ai_family = AF_UNSPEC;
61  hints.ai_socktype = SOCK_STREAM;
62  hints.ai_flags = AI_PASSIVE;
63 
64  if (getaddrinfo(host_name, service.c_str(), &hints, &result) != 0)
65  {
66  LOG_ERROR("Failed to get address for %s:%d", host.c_str(), port);
67  return false;
68  }
69 
70  bool connected = false;
71  // loop through the list of addresses untill we find one that's connectable
72  for (struct addrinfo *p = result; p != nullptr; p = p->ai_next)
73  {
74  socket_fd_ = ::socket(p->ai_family, p->ai_socktype, p->ai_protocol);
75 
76  if (socket_fd_ != -1 && open(socket_fd_, p->ai_addr, p->ai_addrlen))
77  {
78  connected = true;
79  break;
80  }
81  }
82 
83  freeaddrinfo(result);
84 
85  if (!connected)
86  {
88  LOG_ERROR("Connection setup failed for %s:%d", host.c_str(), port);
89  }
90  else
91  {
94  LOG_INFO("Connection established for %s:%d", host.c_str(), port);
95  }
96  return connected;
97 }
98 
99 bool TCPSocket::setSocketFD(int socket_fd)
100 {
102  return false;
103  socket_fd_ = socket_fd;
105  return true;
106 }
107 
109 {
111  return;
114  socket_fd_ = -1;
115 }
116 
117 std::string TCPSocket::getIP()
118 {
119  sockaddr_in name;
120  socklen_t len = sizeof(name);
121  int res = ::getsockname(socket_fd_, (sockaddr *)&name, &len);
122 
123  if (res < 0)
124  {
125  LOG_ERROR("Could not get local IP");
126  return std::string();
127  }
128 
129  char buf[128];
130  inet_ntop(AF_INET, &name.sin_addr, buf, sizeof(buf));
131  return std::string(buf);
132 }
133 
134 bool TCPSocket::read(char *character)
135 {
136  size_t read_chars;
137  // It's inefficient, but in our case we read very small messages
138  // and the overhead connected with reading character by character is
139  // negligible - adding buffering would complicate the code needlessly.
140  return read((uint8_t *)character, 1, read_chars);
141 }
142 
143 bool TCPSocket::read(uint8_t *buf, size_t buf_len, size_t &read)
144 {
145  read = 0;
146 
148  return false;
149 
150  ssize_t res = ::recv(socket_fd_, buf, buf_len, 0);
151 
152  if (res == 0)
153  {
155  return false;
156  }
157  else if (res < 0)
158  return false;
159 
160  read = static_cast<size_t>(res);
161  return true;
162 }
163 
164 bool TCPSocket::write(const uint8_t *buf, size_t buf_len, size_t &written)
165 {
166  written = 0;
167 
169  return false;
170 
171  size_t remaining = buf_len;
172 
173  // handle partial sends
174  while (written < buf_len)
175  {
176  ssize_t sent = ::send(socket_fd_, buf + written, remaining, 0);
177 
178  if (sent <= 0)
179  return false;
180 
181  written += sent;
182  remaining -= sent;
183  }
184 
185  return true;
186 }
bool read(char *character)
Definition: tcp_socket.cpp:134
virtual ~TCPSocket()
Definition: tcp_socket.cpp:33
virtual bool open(int socket_fd, struct sockaddr *address, size_t address_len)
Definition: tcp_socket.h:42
std::atomic< int > socket_fd_
Definition: tcp_socket.h:38
virtual void setOptions(int socket_fd)
Definition: tcp_socket.cpp:38
bool setSocketFD(int socket_fd)
Definition: tcp_socket.cpp:99
#define LOG_INFO(format,...)
Definition: log.h:35
std::atomic< SocketState > state_
Definition: tcp_socket.h:39
bool write(const uint8_t *buf, size_t buf_len, size_t &written)
Definition: tcp_socket.cpp:164
std::string getIP()
Definition: tcp_socket.cpp:117
bool setup(std::string &host, int port)
Definition: tcp_socket.cpp:45
#define LOG_ERROR(format,...)
Definition: log.h:36
void close()
Definition: tcp_socket.cpp:108
SocketState
Definition: tcp_socket.h:27


ur_modern_driver
Author(s): Thomas Timm Andersen, Simon Rasmussen
autogenerated on Fri Jun 26 2020 03:37:01