Visual Servoing Platform  version 3.1.0
vpUDPClient.cpp
1 /****************************************************************************
2  *
3  * This file is part of the ViSP software.
4  * Copyright (C) 2005 - 2017 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 #if !defined(_WIN32) && (defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__))) // UNIX
40 #include <arpa/inet.h>
41 #include <errno.h>
42 #include <netdb.h>
43 #include <unistd.h>
44 #define DWORD int
45 #else
46 #if defined(__MINGW32__)
47 #define _WIN32_WINNT _WIN32_WINNT_VISTA // 0x0600
48 #endif
49 #include <Ws2tcpip.h>
50 #endif
51 
52 #include <visp3/core/vpUDPClient.h>
53 
60 vpUDPClient::vpUDPClient(const std::string &hostname, const int port)
61  : m_serverAddress(), m_serverLength(0), m_socketFileDescriptor()
62 #if defined(_WIN32)
63  ,
64  m_wsa()
65 #endif
66 {
67  init(hostname, port);
68 }
69 
71 {
72 #if !defined(_WIN32) && (defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__))) // UNIX
73  close(m_socketFileDescriptor);
74 #else
75  closesocket(m_socketFileDescriptor);
76  WSACleanup();
77 #endif
78 }
79 
80 void vpUDPClient::init(const std::string &hostname, const int port)
81 {
82 #if defined(_WIN32)
83  if (WSAStartup(MAKEWORD(2, 2), &m_wsa) != 0) {
84  std::stringstream ss;
85  ss << "Failed WSAStartup for the server, error code: " << WSAGetLastError();
86  throw vpException(vpException::fatalError, ss.str());
87  }
88 #endif
89 
90  /* socket: create the socket */
91  m_socketFileDescriptor = socket(AF_INET, SOCK_DGRAM, 0);
92 #if defined(_WIN32)
93  if (m_socketFileDescriptor == INVALID_SOCKET)
94 #else
95  if (m_socketFileDescriptor < 0)
96 #endif
97  throw vpException(vpException::fatalError, "Error opening UDP socket for the client!");
98 
99  /* build the server's Internet address */
100  memset(&m_serverAddress, 0, sizeof(m_serverAddress));
101  std::stringstream ss;
102  ss << port;
103  struct addrinfo hints;
104  struct addrinfo *result = NULL;
105  struct addrinfo *ptr = NULL;
106 
107  memset(&hints, 0, sizeof(hints));
108  hints.ai_family = AF_INET;
109  hints.ai_socktype = SOCK_DGRAM;
110  hints.ai_protocol = IPPROTO_UDP;
111 
112  DWORD dwRetval = getaddrinfo(hostname.c_str(), ss.str().c_str(), &hints, &result);
113  if (dwRetval != 0) {
114  ss.str("");
115  ss << "getaddrinfo failed with error: " << dwRetval;
116  throw vpException(vpException::fatalError, ss.str());
117  }
118 
119  for (ptr = result; ptr != NULL; ptr = ptr->ai_next) {
120  if (ptr->ai_family == AF_INET && ptr->ai_socktype == SOCK_DGRAM) {
121  m_serverAddress = *(struct sockaddr_in *)ptr->ai_addr;
122  break;
123  }
124  }
125 
126  freeaddrinfo(result);
127 
128  m_serverLength = sizeof(m_serverAddress);
129 }
130 
153 int vpUDPClient::receive(std::string &msg, const int timeoutMs)
154 {
155  fd_set s;
156  FD_ZERO(&s);
157  FD_SET(m_socketFileDescriptor, &s);
158  struct timeval timeout;
159  if (timeoutMs > 0) {
160  timeout.tv_sec = timeoutMs / 1000;
161  timeout.tv_usec = (timeoutMs % 1000) * 1000;
162  }
163  int retval = select((int)m_socketFileDescriptor + 1, &s, NULL, NULL, timeoutMs > 0 ? &timeout : NULL);
164 
165  if (retval == -1) {
166  std::cerr << "Error select!" << std::endl;
167  return -1;
168  }
169 
170  if (retval > 0) {
171  /* recvfrom: receive a UDP datagram from the server */
172  int length = recvfrom(m_socketFileDescriptor, m_buf, sizeof(m_buf), 0, (struct sockaddr *)&m_serverAddress,
173  (socklen_t *)&m_serverLength);
174  if (length <= 0) {
175  return length < 0 ? -1 : 0;
176  }
177 
178  msg = std::string(m_buf, length);
179  return length;
180  }
181 
182  // Timeout
183  return 0;
184 }
185 
211 int vpUDPClient::send(const std::string &msg)
212 {
213  if (msg.size() > VP_MAX_UDP_PAYLOAD) {
214  std::cerr << "Message is too long!" << std::endl;
215  return 0;
216  }
217 
218 /* send the message to the server */
219 #if !defined(_WIN32) && (defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__))) // UNIX
220  return sendto(m_socketFileDescriptor, msg.c_str(), msg.size(), 0, (struct sockaddr *)&m_serverAddress,
221  m_serverLength);
222 #else
223  return sendto(m_socketFileDescriptor, msg.c_str(), (int)msg.size(), 0, (struct sockaddr *)&m_serverAddress,
224  m_serverLength);
225 #endif
226 }
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:60
int send(const std::string &msg)