Visual Servoing Platform version 3.7.0
Loading...
Searching...
No Matches
vpUDPClient.cpp
1/*
2 * ViSP, open source Visual Servoing Platform software.
3 * Copyright (C) 2005 - 2025 by Inria. All rights reserved.
4 *
5 * This software is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 * See the file LICENSE.txt at the root directory of this source
10 * distribution for additional information about the GNU GPL.
11 *
12 * For using ViSP with software that can not be combined with the GNU
13 * GPL, please contact Inria about acquiring a ViSP Professional
14 * Edition License.
15 *
16 * See https://visp.inria.fr for more information.
17 *
18 * This software was developed at:
19 * Inria Rennes - Bretagne Atlantique
20 * Campus Universitaire de Beaulieu
21 * 35042 Rennes Cedex
22 * France
23 *
24 * If you have questions regarding the use of this file, please contact
25 * Inria at visp@inria.fr
26 *
27 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
28 * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
29 *
30 * Description:
31 * UDP Client
32 */
33
34#include <cstring>
35#include <sstream>
36
37#include <visp3/core/vpConfig.h>
38
39// inet_ntop() not supported on win XP
40#ifdef VISP_HAVE_FUNC_INET_NTOP
41
42#if !defined(_WIN32) && (defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__))) // UNIX
43#include <arpa/inet.h>
44#include <errno.h>
45#include <netdb.h>
46#include <unistd.h>
47#define DWORD int
48#else
49#if defined(__MINGW32__)
50#ifndef _WIN32_WINNT
51#define _WIN32_WINNT _WIN32_WINNT_VISTA // 0x0600
52#endif
53#endif
54
55#if defined(__clang__)
56// Mute warning : non-portable path to file '<WS2tcpip.h>'; specified path differs in case from file name on disk [-Wnonportable-system-include-path]
57# pragma clang diagnostic push
58# pragma clang diagnostic ignored "-Wnonportable-system-include-path"
59#endif
60
61#include <Ws2tcpip.h>
62
63#if defined(__clang__)
64# pragma clang diagnostic pop
65#endif
66
67#endif
68
69#include <visp3/core/vpUDPClient.h>
70
78 : m_is_init(false), m_serverAddress(), m_serverLength(0), m_socketFileDescriptor()
79#if defined(_WIN32)
80 ,
81 m_wsa()
82#endif
83{ }
84
86{
87 *this = client;
88}
89
91{
92 m_is_init = client.m_is_init;
93 m_serverAddress = client.m_serverAddress;
94 m_serverLength = client.m_serverLength;
95 m_socketFileDescriptor = client.m_socketFileDescriptor;
96#if defined(_WIN32)
97 m_wsa = client.m_wsa;
98#endif
99 return *this;
100}
101
108vpUDPClient::vpUDPClient(const std::string &hostname, int port)
109 : m_is_init(false), m_serverAddress(), m_serverLength(0), m_socketFileDescriptor()
110#if defined(_WIN32)
111 ,
112 m_wsa()
113#endif
114{
115 init(hostname, port);
116}
117
122
126void vpUDPClient::close()
127{
128 if (m_is_init) {
129#if !defined(_WIN32) && (defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__))) // UNIX
130 ::close(m_socketFileDescriptor);
131#else
132 closesocket(m_socketFileDescriptor);
133 WSACleanup();
134#endif
135 m_is_init = false;
136 }
137}
138
145void vpUDPClient::init(const std::string &hostname, int port)
146{
147 // Close connexion if already initialized
148 close();
149
150#if defined(_WIN32)
151 if (WSAStartup(MAKEWORD(2, 2), &m_wsa) != 0) {
152 std::stringstream ss;
153 ss << "Failed WSAStartup for the server, error code: " << WSAGetLastError();
154 throw vpException(vpException::fatalError, ss.str());
155 }
156#endif
157
158 /* socket: create the socket */
159 m_socketFileDescriptor = socket(AF_INET, SOCK_DGRAM, 0);
160#if defined(_WIN32)
161 if (m_socketFileDescriptor == INVALID_SOCKET)
162#else
163 if (m_socketFileDescriptor < 0)
164#endif
165 throw vpException(vpException::fatalError, "Error opening UDP socket for the client!");
166
167 /* build the server's Internet address */
168 memset(&m_serverAddress, 0, sizeof(m_serverAddress));
169 std::stringstream ss;
170 ss << port;
171 struct addrinfo hints;
172 struct addrinfo *result = nullptr;
173 struct addrinfo *ptr = nullptr;
174
175 memset(&hints, 0, sizeof(hints));
176 hints.ai_family = AF_INET;
177 hints.ai_socktype = SOCK_DGRAM;
178 hints.ai_protocol = IPPROTO_UDP;
179
180 DWORD dwRetval = getaddrinfo(hostname.c_str(), ss.str().c_str(), &hints, &result);
181 if (dwRetval != 0) {
182 ss.str("");
183 ss << "getaddrinfo failed with error: " << dwRetval;
184 throw vpException(vpException::fatalError, ss.str());
185 }
186
187 for (ptr = result; ptr != nullptr; ptr = ptr->ai_next) {
188 if (ptr->ai_family == AF_INET && ptr->ai_socktype == SOCK_DGRAM) {
189 m_serverAddress = *(struct sockaddr_in *)ptr->ai_addr;
190 break;
191 }
192 }
193
194 freeaddrinfo(result);
195
196 m_serverLength = sizeof(m_serverAddress);
197 m_is_init = true;
198}
199
222int vpUDPClient::receive(std::string &msg, int timeoutMs)
223{
224 if (!m_is_init) {
225 throw(vpException(vpException::notInitialized, "UDP client is not initialized"));
226 }
227 fd_set s;
228 FD_ZERO(&s);
229 FD_SET(m_socketFileDescriptor, &s);
230 struct timeval timeout;
231 if (timeoutMs > 0) {
232 timeout.tv_sec = timeoutMs / 1000;
233 timeout.tv_usec = (timeoutMs % 1000) * 1000;
234 }
235 int retval = select(static_cast<int>(m_socketFileDescriptor) + 1, &s, nullptr, nullptr, timeoutMs > 0 ? &timeout : nullptr);
236
237 if (retval == -1) {
238 std::cerr << "Error select!" << std::endl;
239 return -1;
240 }
241
242 if (retval > 0) {
243 /* recvfrom: receive a UDP datagram from the server */
244 int length = static_cast<int>(recvfrom(m_socketFileDescriptor, m_buf, sizeof(m_buf), 0,
245 (struct sockaddr *)&m_serverAddress, (socklen_t *)&m_serverLength));
246 if (length <= 0) {
247 return length < 0 ? -1 : 0;
248 }
249
250 msg = std::string(m_buf, length);
251 return length;
252 }
253
254 // Timeout
255 return 0;
256}
257
268int vpUDPClient::receive(void *msg, size_t len, int timeoutMs)
269{
270 if (!m_is_init) {
271 throw(vpException(vpException::notInitialized, "UDP client is not initialized"));
272 }
273 fd_set s;
274 FD_ZERO(&s);
275 FD_SET(m_socketFileDescriptor, &s);
276 struct timeval timeout;
277 if (timeoutMs > 0) {
278 timeout.tv_sec = timeoutMs / 1000;
279 timeout.tv_usec = (timeoutMs % 1000) * 1000;
280 }
281 int retval = select(static_cast<int>(m_socketFileDescriptor) + 1, &s, nullptr, nullptr, timeoutMs > 0 ? &timeout : nullptr);
282
283 if (retval == -1) {
284 std::cerr << "Error select!" << std::endl;
285 return -1;
286 }
287
288 if (retval > 0) {
289 /* recvfrom: receive a UDP datagram from the server */
290 int length = static_cast<int>(recvfrom(m_socketFileDescriptor, (char *)msg, static_cast<int>(len), 0,
291 (struct sockaddr *)&m_serverAddress, (socklen_t *)&m_serverLength));
292 if (length <= 0) {
293 return length < 0 ? -1 : 0;
294 }
295
296 return length;
297 }
298
299 // Timeout
300 return 0;
301}
302
328int vpUDPClient::send(const std::string &msg)
329{
330 if (!m_is_init) {
331 throw(vpException(vpException::notInitialized, "UDP client is not initialized"));
332 }
333 if (msg.size() > VP_MAX_UDP_PAYLOAD) {
334 std::cerr << "Message is too long!" << std::endl;
335 return 0;
336 }
337
338/* send the message to the server */
339#if !defined(_WIN32) && (defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__))) // UNIX
340 return static_cast<int>(
341 sendto(m_socketFileDescriptor, msg.c_str(), msg.size(), 0, (struct sockaddr *)&m_serverAddress, m_serverLength));
342#else
343 return sendto(m_socketFileDescriptor, msg.c_str(), static_cast<int>(msg.size()), 0, (struct sockaddr *)&m_serverAddress,
344 m_serverLength);
345#endif
346}
347
357int vpUDPClient::send(const void *msg, size_t len)
358{
359 if (!m_is_init) {
360 throw(vpException(vpException::notInitialized, "UDP client is not initialized"));
361 }
362 if (len > VP_MAX_UDP_PAYLOAD) {
363 std::cerr << "Message is too long!" << std::endl;
364 return 0;
365 }
366
367/* send the message to the server */
368#if !defined(_WIN32) && (defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__))) // UNIX
369 return static_cast<int>(
370 sendto(m_socketFileDescriptor, msg, len, 0, (struct sockaddr *)&m_serverAddress, m_serverLength));
371#else
372 return sendto(m_socketFileDescriptor, (char *)msg, static_cast<int>(len), 0, (struct sockaddr *)&m_serverAddress, m_serverLength);
373#endif
374}
375END_VISP_NAMESPACE
376#elif !defined(VISP_BUILD_SHARED_LIBS)
377// Work around to avoid warning: libvisp_core.a(vpUDPClient.cpp.o) has no symbols
378void dummy_vpUDPClient() { }
379#endif
error that can be emitted by ViSP classes.
Definition vpException.h:60
@ notInitialized
Used to indicate that a parameter is not initialized.
Definition vpException.h:74
@ fatalError
Fatal error.
Definition vpException.h:72
int receive(std::string &msg, int timeoutMs=0)
virtual ~vpUDPClient()
void init(const std::string &hostname, int port)
vpUDPClient & operator=(const vpUDPClient &client)
int send(const std::string &msg)