Visual Servoing Platform  version 3.6.1 under development (2024-05-26)
vpUDPClient.cpp
1 /****************************************************************************
2  *
3  * ViSP, open source Visual Servoing Platform software.
4  * Copyright (C) 2005 - 2023 by Inria. All rights reserved.
5  *
6  * This software is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  * See the file LICENSE.txt at the root directory of this source
11  * distribution for additional information about the GNU GPL.
12  *
13  * For using ViSP with software that can not be combined with the GNU
14  * GPL, please contact Inria about acquiring a ViSP Professional
15  * Edition License.
16  *
17  * See https://visp.inria.fr for more information.
18  *
19  * This software was developed at:
20  * Inria Rennes - Bretagne Atlantique
21  * Campus Universitaire de Beaulieu
22  * 35042 Rennes Cedex
23  * France
24  *
25  * If you have questions regarding the use of this file, please contact
26  * Inria at visp@inria.fr
27  *
28  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
29  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
30  *
31  * Description:
32  * UDP Client
33  *
34 *****************************************************************************/
35 
36 #include <cstring>
37 #include <sstream>
38 
39 #include <visp3/core/vpConfig.h>
40 
41 // inet_ntop() not supported on win XP
42 #ifdef VISP_HAVE_FUNC_INET_NTOP
43 
44 #if !defined(_WIN32) && (defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__))) // UNIX
45 #include <arpa/inet.h>
46 #include <errno.h>
47 #include <netdb.h>
48 #include <unistd.h>
49 #define DWORD int
50 #else
51 #if defined(__MINGW32__)
52 #ifndef _WIN32_WINNT
53 #define _WIN32_WINNT _WIN32_WINNT_VISTA // 0x0600
54 #endif
55 #endif
56 #include <Ws2tcpip.h>
57 #endif
58 
59 #include <visp3/core/vpUDPClient.h>
60 
67  : m_is_init(false), m_serverAddress(), m_serverLength(0), m_socketFileDescriptor()
68 #if defined(_WIN32)
69  ,
70  m_wsa()
71 #endif
72 {
73 }
74 
81 vpUDPClient::vpUDPClient(const std::string &hostname, int port)
82  : m_is_init(false), m_serverAddress(), m_serverLength(0), m_socketFileDescriptor()
83 #if defined(_WIN32)
84  ,
85  m_wsa()
86 #endif
87 {
88  init(hostname, port);
89 }
90 
95 
99 void vpUDPClient::close()
100 {
101  if (m_is_init) {
102 #if !defined(_WIN32) && (defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__))) // UNIX
103  ::close(m_socketFileDescriptor);
104 #else
105  closesocket(m_socketFileDescriptor);
106  WSACleanup();
107 #endif
108  m_is_init = false;
109  }
110 }
111 
118 void vpUDPClient::init(const std::string &hostname, int port)
119 {
120  // Close connexion if already initialized
121  close();
122 
123 #if defined(_WIN32)
124  if (WSAStartup(MAKEWORD(2, 2), &m_wsa) != 0) {
125  std::stringstream ss;
126  ss << "Failed WSAStartup for the server, error code: " << WSAGetLastError();
127  throw vpException(vpException::fatalError, ss.str());
128  }
129 #endif
130 
131  /* socket: create the socket */
132  m_socketFileDescriptor = socket(AF_INET, SOCK_DGRAM, 0);
133 #if defined(_WIN32)
134  if (m_socketFileDescriptor == INVALID_SOCKET)
135 #else
136  if (m_socketFileDescriptor < 0)
137 #endif
138  throw vpException(vpException::fatalError, "Error opening UDP socket for the client!");
139 
140  /* build the server's Internet address */
141  memset(&m_serverAddress, 0, sizeof(m_serverAddress));
142  std::stringstream ss;
143  ss << port;
144  struct addrinfo hints;
145  struct addrinfo *result = nullptr;
146  struct addrinfo *ptr = nullptr;
147 
148  memset(&hints, 0, sizeof(hints));
149  hints.ai_family = AF_INET;
150  hints.ai_socktype = SOCK_DGRAM;
151  hints.ai_protocol = IPPROTO_UDP;
152 
153  DWORD dwRetval = getaddrinfo(hostname.c_str(), ss.str().c_str(), &hints, &result);
154  if (dwRetval != 0) {
155  ss.str("");
156  ss << "getaddrinfo failed with error: " << dwRetval;
157  throw vpException(vpException::fatalError, ss.str());
158  }
159 
160  for (ptr = result; ptr != nullptr; ptr = ptr->ai_next) {
161  if (ptr->ai_family == AF_INET && ptr->ai_socktype == SOCK_DGRAM) {
162  m_serverAddress = *(struct sockaddr_in *)ptr->ai_addr;
163  break;
164  }
165  }
166 
167  freeaddrinfo(result);
168 
169  m_serverLength = sizeof(m_serverAddress);
170  m_is_init = true;
171 }
172 
195 int vpUDPClient::receive(std::string &msg, int timeoutMs)
196 {
197  if (!m_is_init) {
198  throw(vpException(vpException::notInitialized, "UDP client is not initialized"));
199  }
200  fd_set s;
201  FD_ZERO(&s);
202  FD_SET(m_socketFileDescriptor, &s);
203  struct timeval timeout;
204  if (timeoutMs > 0) {
205  timeout.tv_sec = timeoutMs / 1000;
206  timeout.tv_usec = (timeoutMs % 1000) * 1000;
207  }
208  int retval = select((int)m_socketFileDescriptor + 1, &s, nullptr, nullptr, timeoutMs > 0 ? &timeout : nullptr);
209 
210  if (retval == -1) {
211  std::cerr << "Error select!" << std::endl;
212  return -1;
213  }
214 
215  if (retval > 0) {
216  /* recvfrom: receive a UDP datagram from the server */
217  int length = static_cast<int>(recvfrom(m_socketFileDescriptor, m_buf, sizeof(m_buf), 0,
218  (struct sockaddr *)&m_serverAddress, (socklen_t *)&m_serverLength));
219  if (length <= 0) {
220  return length < 0 ? -1 : 0;
221  }
222 
223  msg = std::string(m_buf, length);
224  return length;
225  }
226 
227  // Timeout
228  return 0;
229 }
230 
241 int vpUDPClient::receive(void *msg, size_t len, int timeoutMs)
242 {
243  if (!m_is_init) {
244  throw(vpException(vpException::notInitialized, "UDP client is not initialized"));
245  }
246  fd_set s;
247  FD_ZERO(&s);
248  FD_SET(m_socketFileDescriptor, &s);
249  struct timeval timeout;
250  if (timeoutMs > 0) {
251  timeout.tv_sec = timeoutMs / 1000;
252  timeout.tv_usec = (timeoutMs % 1000) * 1000;
253  }
254  int retval = select((int)m_socketFileDescriptor + 1, &s, nullptr, nullptr, timeoutMs > 0 ? &timeout : nullptr);
255 
256  if (retval == -1) {
257  std::cerr << "Error select!" << std::endl;
258  return -1;
259  }
260 
261  if (retval > 0) {
262  /* recvfrom: receive a UDP datagram from the server */
263  int length = static_cast<int>(recvfrom(m_socketFileDescriptor, (char *)msg, (int)len, 0,
264  (struct sockaddr *)&m_serverAddress, (socklen_t *)&m_serverLength));
265  if (length <= 0) {
266  return length < 0 ? -1 : 0;
267  }
268 
269  return length;
270  }
271 
272  // Timeout
273  return 0;
274 }
275 
301 int vpUDPClient::send(const std::string &msg)
302 {
303  if (!m_is_init) {
304  throw(vpException(vpException::notInitialized, "UDP client is not initialized"));
305  }
306  if (msg.size() > VP_MAX_UDP_PAYLOAD) {
307  std::cerr << "Message is too long!" << std::endl;
308  return 0;
309  }
310 
311 /* send the message to the server */
312 #if !defined(_WIN32) && (defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__))) // UNIX
313  return static_cast<int>(
314  sendto(m_socketFileDescriptor, msg.c_str(), msg.size(), 0, (struct sockaddr *)&m_serverAddress, m_serverLength));
315 #else
316  return sendto(m_socketFileDescriptor, msg.c_str(), (int)msg.size(), 0, (struct sockaddr *)&m_serverAddress,
317  m_serverLength);
318 #endif
319 }
320 
330 int vpUDPClient::send(const void *msg, size_t len)
331 {
332  if (!m_is_init) {
333  throw(vpException(vpException::notInitialized, "UDP client is not initialized"));
334  }
335  if (len > VP_MAX_UDP_PAYLOAD) {
336  std::cerr << "Message is too long!" << std::endl;
337  return 0;
338  }
339 
340 /* send the message to the server */
341 #if !defined(_WIN32) && (defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__))) // UNIX
342  return static_cast<int>(
343  sendto(m_socketFileDescriptor, msg, len, 0, (struct sockaddr *)&m_serverAddress, m_serverLength));
344 #else
345  return sendto(m_socketFileDescriptor, (char *)msg, (int)len, 0, (struct sockaddr *)&m_serverAddress, m_serverLength);
346 #endif
347 }
348 
349 #elif !defined(VISP_BUILD_SHARED_LIBS)
350 // Work around to avoid warning: libvisp_core.a(vpUDPClient.cpp.o) has no symbols
351 void dummy_vpUDPClient(){};
352 #endif
error that can be emitted by ViSP classes.
Definition: vpException.h:59
@ notInitialized
Used to indicate that a parameter is not initialized.
Definition: vpException.h:73
@ fatalError
Fatal error.
Definition: vpException.h:71
int receive(std::string &msg, int timeoutMs=0)
virtual ~vpUDPClient()
Definition: vpUDPClient.cpp:94
void init(const std::string &hostname, int port)
bool m_is_init
Definition: vpUDPClient.h:182
int send(const std::string &msg)