Visual Servoing Platform  version 3.2.0 under development (2019-01-22)
vpUDPClient.cpp
1 /****************************************************************************
2  *
3  * ViSP, open source Visual Servoing Platform software.
4  * Copyright (C) 2005 - 2019 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 http://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 vpUDPClient::vpUDPClient(const std::string &hostname, const int port)
68  : m_serverAddress(), m_serverLength(0), m_socketFileDescriptor()
69 #if defined(_WIN32)
70  ,
71  m_wsa()
72 #endif
73 {
74  init(hostname, port);
75 }
76 
78 {
79 #if !defined(_WIN32) && (defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__))) // UNIX
80  close(m_socketFileDescriptor);
81 #else
82  closesocket(m_socketFileDescriptor);
83  WSACleanup();
84 #endif
85 }
86 
87 void vpUDPClient::init(const std::string &hostname, const int port)
88 {
89 #if defined(_WIN32)
90  if (WSAStartup(MAKEWORD(2, 2), &m_wsa) != 0) {
91  std::stringstream ss;
92  ss << "Failed WSAStartup for the server, error code: " << WSAGetLastError();
93  throw vpException(vpException::fatalError, ss.str());
94  }
95 #endif
96 
97  /* socket: create the socket */
98  m_socketFileDescriptor = socket(AF_INET, SOCK_DGRAM, 0);
99 #if defined(_WIN32)
100  if (m_socketFileDescriptor == INVALID_SOCKET)
101 #else
102  if (m_socketFileDescriptor < 0)
103 #endif
104  throw vpException(vpException::fatalError, "Error opening UDP socket for the client!");
105 
106  /* build the server's Internet address */
107  memset(&m_serverAddress, 0, sizeof(m_serverAddress));
108  std::stringstream ss;
109  ss << port;
110  struct addrinfo hints;
111  struct addrinfo *result = NULL;
112  struct addrinfo *ptr = NULL;
113 
114  memset(&hints, 0, sizeof(hints));
115  hints.ai_family = AF_INET;
116  hints.ai_socktype = SOCK_DGRAM;
117  hints.ai_protocol = IPPROTO_UDP;
118 
119  DWORD dwRetval = getaddrinfo(hostname.c_str(), ss.str().c_str(), &hints, &result);
120  if (dwRetval != 0) {
121  ss.str("");
122  ss << "getaddrinfo failed with error: " << dwRetval;
123  throw vpException(vpException::fatalError, ss.str());
124  }
125 
126  for (ptr = result; ptr != NULL; ptr = ptr->ai_next) {
127  if (ptr->ai_family == AF_INET && ptr->ai_socktype == SOCK_DGRAM) {
128  m_serverAddress = *(struct sockaddr_in *)ptr->ai_addr;
129  break;
130  }
131  }
132 
133  freeaddrinfo(result);
134 
135  m_serverLength = sizeof(m_serverAddress);
136 }
137 
160 int vpUDPClient::receive(std::string &msg, const int timeoutMs)
161 {
162  fd_set s;
163  FD_ZERO(&s);
164  FD_SET(m_socketFileDescriptor, &s);
165  struct timeval timeout;
166  if (timeoutMs > 0) {
167  timeout.tv_sec = timeoutMs / 1000;
168  timeout.tv_usec = (timeoutMs % 1000) * 1000;
169  }
170  int retval = select((int)m_socketFileDescriptor + 1, &s, NULL, NULL, timeoutMs > 0 ? &timeout : NULL);
171 
172  if (retval == -1) {
173  std::cerr << "Error select!" << std::endl;
174  return -1;
175  }
176 
177  if (retval > 0) {
178  /* recvfrom: receive a UDP datagram from the server */
179  int length = static_cast<int>(recvfrom(m_socketFileDescriptor, m_buf, sizeof(m_buf), 0, (struct sockaddr *)&m_serverAddress,
180  (socklen_t *)&m_serverLength));
181  if (length <= 0) {
182  return length < 0 ? -1 : 0;
183  }
184 
185  msg = std::string(m_buf, length);
186  return length;
187  }
188 
189  // Timeout
190  return 0;
191 }
192 
218 int vpUDPClient::send(const std::string &msg)
219 {
220  if (msg.size() > VP_MAX_UDP_PAYLOAD) {
221  std::cerr << "Message is too long!" << std::endl;
222  return 0;
223  }
224 
225 /* send the message to the server */
226 #if !defined(_WIN32) && (defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__))) // UNIX
227  return static_cast<int>(sendto(m_socketFileDescriptor, msg.c_str(), msg.size(), 0, (struct sockaddr *)&m_serverAddress,
228  m_serverLength));
229 #else
230  return sendto(m_socketFileDescriptor, msg.c_str(), (int)msg.size(), 0, (struct sockaddr *)&m_serverAddress,
231  m_serverLength);
232 #endif
233 }
234 
235 #elif !defined(VISP_BUILD_SHARED_LIBS)
236 // Work arround to avoid warning: libvisp_core.a(vpUDPClient.cpp.o) has no symbols
237 void dummy_vpUDPClient(){};
238 #endif
int receive(std::string &msg, const int timeoutMs=0)
error that can be emited by ViSP classes.
Definition: vpException.h:71
vpUDPClient(const std::string &hostname, const int port)
Definition: vpUDPClient.cpp:67
virtual ~vpUDPClient()
Definition: vpUDPClient.cpp:77
int send(const std::string &msg)