ISTcpClient.cpp
Go to the documentation of this file.
1 /*
2 MIT LICENSE
3 
4 Copyright (c) 2014-2021 Inertial Sense, Inc. - http://inertialsense.com
5 
6 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions :
7 
8 The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
9 
10 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
11 */
12 
13 #include "ISConstants.h"
14 
15 #if PLATFORM_IS_LINUX || PLATFORM_IS_APPLE
16 
17 /* Assume that any non-Windows platform uses POSIX-style sockets instead. */
18 #include <sys/socket.h>
19 #include <sys/ioctl.h>
20 #include <arpa/inet.h>
21 #include <netdb.h> /* Needed for getaddrinfo() and freeaddrinfo() */
22 #include <unistd.h> /* Needed for close() */
23 #include <fcntl.h>
24 #include <errno.h>
25 
26 #endif
27 
28 #include "ISTcpClient.h"
29 #include "ISUtilities.h"
30 
31 #if PLATFORM_IS_WINDOWS
32 
33 #include <mutex>
34 
35 static uint32_t s_socketInitialized;
36 static mutex s_socketFrameworkMutex;
37 
38 #endif
39 
41 {
42 
43 #if PLATFORM_IS_WINDOWS
44 
45  lock_guard<mutex> locker(s_socketFrameworkMutex);
46  if (++s_socketInitialized != 1)
47  {
48  return;
49  }
50  WSADATA wsa_data;
51  WSAStartup(MAKEWORD(2, 2), &wsa_data);
52 
53 #endif
54 
55 }
56 
58 {
59 
60 #if PLATFORM_IS_WINDOWS
61 
62  lock_guard<mutex> locker(s_socketFrameworkMutex);
63  if (s_socketInitialized == 0)
64  {
65  return;
66  }
67  else if (--s_socketInitialized == 0)
68  {
69  WSACleanup();
70  }
71 
72 #endif
73 
74 }
75 
76 int ISSocketCanWrite(socket_t socket, int timeoutMilliseconds)
77 {
78  struct timeval tv = { timeoutMilliseconds / 1000, (timeoutMilliseconds % 1000) * 1000 };
79  fd_set ws;
80  FD_ZERO(&ws);
81  FD_SET(socket, &ws);
82  int numberOfSocketsThatCanWrite = select((int)(socket + 1), NULL, &ws, NULL, &tv);
83  return (numberOfSocketsThatCanWrite > 0);
84 }
85 
86 int ISSocketCanRead(socket_t socket, int timeoutMilliseconds)
87 {
88  struct timeval tv = { timeoutMilliseconds / 1000, (timeoutMilliseconds % 1000) * 1000 };
89  fd_set rs;
90  FD_ZERO(&rs);
91  FD_SET(socket, &rs);
92  int numberOfSocketsThatCanRead = select((int)(socket + 1), &rs, NULL, NULL, &tv);
93  return (numberOfSocketsThatCanRead > 0);
94 }
95 
96 int ISSocketWrite(socket_t socket, const uint8_t* data, int dataLength)
97 {
98  int totalWriteCount = 0;
99  int writeCount;
100 
101  while (totalWriteCount < dataLength)
102  {
103  if (!ISSocketCanWrite(socket))
104  {
105  break;
106  }
107  writeCount = send(socket, (const char*)data, dataLength, 0);
108  if (writeCount < 0)
109  {
110  break;
111  }
112  totalWriteCount += writeCount;
113  }
114 
115  return totalWriteCount;
116 }
117 
118 int ISSocketRead(socket_t socket, uint8_t* data, int dataLength)
119 {
120  int count = recv(socket, (char*)data, dataLength, 0);
121  if (count < 0)
122  {
123 
124 #if PLATFORM_IS_WINDOWS
125 
126  DWORD err = GetLastError();
127  if (err == SO_RCVTIMEO || err == WSAETIMEDOUT || err == WSAEWOULDBLOCK)
128  {
129  return 0;
130  }
131 
132 #else
133 
134  if (errno == EAGAIN || errno == EWOULDBLOCK)
135  {
136  return 0;
137  }
138 
139 #endif
140 
141  }
142  return count;
143 }
144 
145 int ISSocketSetBlocking(socket_t socket, bool blocking)
146 {
147 
148 #if PLATFORM_IS_WINDOWS
149 
150  u_long blockingInt = (blocking ? 0 : 1);
151  return ioctlsocket(socket, FIONBIO, &blockingInt);
152 
153 #else
154 
155  int opts = fcntl(socket, F_GETFL);
156  if (opts < 0)
157  {
158  return -1;
159  }
160  opts = (blocking ? opts & (~O_NONBLOCK) : opts | O_NONBLOCK);
161  return fcntl(socket, F_SETFL, opts);
162 
163 #endif
164 
165 }
166 
167 int ISSocketSetReadTimeout(socket_t socket, int timeoutMilliseconds)
168 {
169 
170 #if PLATFORM_IS_WINDOWS
171 
172  DWORD timeout = timeoutMilliseconds;
173  return setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout, sizeof(timeout));
174 
175 #else
176 
177  struct timeval tv;
178  tv.tv_sec = timeoutMilliseconds / 1000;
179  tv.tv_usec = (timeoutMilliseconds % 1000) * 1000;
180  return setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof(tv));
181 
182 #endif
183 
184 }
185 
186 int ISSocketClose(socket_t& socket)
187 {
188  int status = 0;
189  if (socket != 0)
190  {
191 
192 #if PLATFORM_IS_WINDOWS
193 
194  status = shutdown(socket, SD_BOTH);
195  if (status == 0)
196  {
197  status = closesocket(socket);
198  }
199 
200 #else
201 
202  status = shutdown(socket, SHUT_RDWR);
203  if (status == 0)
204  {
205  status = close(socket);
206  }
207 
208 #endif
209 
210  }
211 
212  socket = 0;
213 
214  return status;
215 }
216 
218 {
219  m_socket = 0;
220  m_port = 0;
221  m_blocking = true;
223 }
224 
226 {
227  Close();
229 }
230 
231 int cISTcpClient::Open(const string& host, int port, int timeoutMilliseconds)
232 {
233  Close();
234  int status;
235  this->m_host = host;
236  m_port = port;
237  char portString[64];
238  snprintf(portString, sizeof(portString), "%ld", (long)m_port);
239  addrinfo* result = NULL;
240  addrinfo hints = addrinfo();
241  hints.ai_family = AF_INET;
242  hints.ai_socktype = SOCK_STREAM;
243  hints.ai_protocol = IPPROTO_TCP;
244 
245  // attempt to get info about the host and port
246  status = getaddrinfo(m_host.c_str(), portString, &hints, &result);
247  if (status != 0)
248  {
249  // no info, fail
250  Close();
251  return status;
252  }
253 
254  // create the socket
255  m_socket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
256  if (m_socket == 0)
257  {
258  // no socket, fail
259  freeaddrinfo(result);
260  Close();
261  return -1;
262  }
263 
264  // make non-blocking socket
265  SetBlocking(false);
266 
267  // because non-blocking, connect returns immediately
268  connect(m_socket, result->ai_addr, (int)result->ai_addrlen);
269 
270  // in order to detect connection we determine whether the socket is writeable
271  status = ISSocketCanWrite(m_socket, timeoutMilliseconds);
272 
273  // cleanup
274  freeaddrinfo(result);
275  if (status <= 0)
276  {
277  // no socket was writeable, fail
278  Close();
279  return -1;
280  }
281 
282  return 0;
283 }
284 
286 {
287  return ISSocketClose(m_socket);
288 }
289 
290 int cISTcpClient::Read(void* data, int dataLength)
291 {
292  int count = ISSocketRead(m_socket, (uint8_t*)data, dataLength);
293  if (count < 0)
294  {
295  Close();
296  }
297  return count;
298 }
299 
300 int cISTcpClient::Write(const void* data, int dataLength)
301 {
302  int count = ISSocketWrite(m_socket, (const uint8_t*)data, dataLength);
303  if (count < 0)
304  {
305  Close();
306  }
307  return count;
308 }
309 
310 void cISTcpClient::HttpGet(const string& subUrl, const string& userAgent, const string& userName, const string& password)
311 {
312  string msg = "GET /" + subUrl + " HTTP/1.1\r\n";
313  msg += "User-Agent: " + userAgent + "\r\n";
314  if (userName.size() != 0 && password.size() != 0)
315  {
316  string auth = userName + ":" + password;
317  msg += "Authorization: Basic " + base64Encode((const unsigned char*)auth.data(), (int)auth.size()) + "\r\n";
318  }
319  msg += "Accept: */*\r\nConnection: close\r\n\r\n";
320  Write((uint8_t*)msg.data(), (int)msg.size());
321 }
322 
323 int cISTcpClient::SetBlocking(bool blocking)
324 {
325  m_blocking = blocking;
326  return ISSocketSetBlocking(m_socket, blocking);
327 }
NMI_API sint8 connect(SOCKET sock, struct sockaddr *pstrAddr, uint8 u8AddrLen)
Definition: socket.c:674
socket_t m_socket
Definition: ISTcpClient.h:99
NMI_API SOCKET socket(uint16 u16Domain, uint8 u8Type, uint8 u8Flags)
Definition: socket.c:477
int ISSocketClose(socket_t &socket)
virtual ~cISTcpClient()
int ISSocketCanWrite(socket_t socket, int timeoutMilliseconds)
Definition: ISTcpClient.cpp:76
NMI_API sint16 recv(SOCKET sock, void *pvRecvBuf, uint16 u16BufLen, uint32 u32Timeoutmsec)
Definition: socket.c:822
int ISSocketRead(socket_t socket, uint8_t *data, int dataLength)
#define AF_INET
Definition: socket.h:72
size_t count(InputIterator first, InputIterator last, T const &item)
Definition: catch.hpp:3206
int Close() OVERRIDE
#define NULL
Definition: nm_bsp.h:52
int Read(void *data, int dataLength) OVERRIDE
int ISSocketCanRead(socket_t socket, int timeoutMilliseconds)
Definition: ISTcpClient.cpp:86
void ISSocketFrameworkShutdown()
Definition: ISTcpClient.cpp:57
NMI_API sint8 setsockopt(SOCKET socket, uint8 u8Level, uint8 option_name, const void *option_value, uint16 u16OptionLen)
Definition: socket.c:1175
unsigned long DWORD
Definition: integer.h:33
int SetBlocking(bool blocking)
int Open(const string &host, int port, int timeoutMilliseconds=IS_SOCKET_DEFAULT_TIMEOUT_MS)
string base64Encode(const unsigned char *bytes_to_encode, unsigned int in_len)
Definition: ISUtilities.cpp:53
int ISSocketSetBlocking(socket_t socket, bool blocking)
USBInterfaceDescriptor data
void ISSocketFrameworkInitialize()
Definition: ISTcpClient.cpp:40
#define SOL_SOCKET
Definition: socket.h:112
NMI_API sint8 close(SOCKET sock)
Definition: socket.c:879
string m_host
Definition: ISTcpClient.h:100
#define snprintf
Definition: test_suite.cpp:86
ROSCONSOLE_DECL void shutdown()
int ISSocketWrite(socket_t socket, const uint8_t *data, int dataLength)
Definition: ISTcpClient.cpp:96
int errno
NMI_API sint16 send(SOCKET sock, void *pvSendBuffer, uint16 u16SendLength, uint16 u16Flags)
Definition: socket.c:715
void HttpGet(const string &subUrl, const string &userAgent, const string &userName, const string &password)
int Write(const void *data, int dataLength) OVERRIDE
#define SOCK_STREAM
Definition: socket.h:79
int ISSocketSetReadTimeout(socket_t socket, int timeoutMilliseconds)


inertial_sense_ros
Author(s):
autogenerated on Sun Feb 28 2021 03:17:57