udp_sockets.h
Go to the documentation of this file.
1 #include "sick_scan/sick_scan_base.h" /* Base definitions included in all header files, added by add_sick_scan_base_header.py. Do not edit this line. */
2 /*
3  * @brief udp_sockets implement udp sender and receiver
4  *
5  * Copyright (C) 2020 Ing.-Buero Dr. Michael Lehning, Hildesheim
6  * Copyright (C) 2020 SICK AG, Waldkirch
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  * All rights reserved.
21  *
22  * Redistribution and use in source and binary forms, with or without
23  * modification, are permitted provided that the following conditions are met:
24  *
25  * * Redistributions of source code must retain the above copyright
26  * notice, this list of conditions and the following disclaimer.
27  * * Redistributions in binary form must reproduce the above copyright
28  * notice, this list of conditions and the following disclaimer in the
29  * documentation and/or other materials provided with the distribution.
30  * * Neither the name of SICK AG nor the names of its
31  * contributors may be used to endorse or promote products derived from
32  * this software without specific prior written permission
33  * * Neither the name of Ing.-Buero Dr. Michael Lehning nor the names of its
34  * contributors may be used to endorse or promote products derived from
35  * this software without specific prior written permission
36  *
37  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
38  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
39  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
40  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
41  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
42  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
43  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
44  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
45  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
46  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
47  * POSSIBILITY OF SUCH DAMAGE.
48  *
49  * Authors:
50  * Michael Lehning <michael.lehning@lehning.de>
51  *
52  * Copyright 2020 SICK AG
53  * Copyright 2020 Ing.-Buero Dr. Michael Lehning
54  *
55  */
56 #ifndef __SICK_SCANSEGMENT_XD_UDP_SOCKETS_H
57 #define __SICK_SCANSEGMENT_XD_UDP_SOCKETS_H
58 
59 #include <string>
60 #if defined WIN32 || defined _MSC_VER
61 #ifndef _WINSOCK_DEPRECATED_NO_WARNINGS
62 #define _WINSOCK_DEPRECATED_NO_WARNINGS
63 #endif
64 #include <winsock2.h>
65 #define UNLINK _unlink
66 static std::string getErrorMessage(void)
67 {
68  int error_num = WSAGetLastError();
69  char error_message[1024] = { 0 };
70  FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, error_num, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), error_message, sizeof(error_message), NULL);
71  return std::to_string(error_num) + " (" + std::string(error_message) + ")";
72 }
73 #else
74 #include <string.h>
75 #include <unistd.h>
76 #include <arpa/inet.h>
77 #include <netinet/ip.h>
78 #include <netinet/udp.h>
79 #include <sys/types.h>
80 #include <sys/socket.h>
81 typedef int SOCKET;
82 typedef struct sockaddr SOCKADDR;
83 #define INVALID_SOCKET (-1)
84 #define UNLINK unlink
85 #define closesocket close
86 static std::string getErrorMessage(void) { return std::to_string(errno) + " (" + std::string(strerror(errno)) + ")"; }
87 #endif
88 
92 
93 namespace sick_scansegment_xd
94 {
95  /*
96  * Shortcut to convert 4 byte to uint32t assuming little endian.
97  */
98  static uint32_t Convert4Byte(const uint8_t* p_data)
99  {
100  return (p_data[0]) | (p_data[1] << 8) | (p_data[2] << 16) | (p_data[3] << 24);
101  }
102 
103  /*
104  * @brief the udp socket to receive udp data
105  */
107  {
108  public:
109 
112  {
113  }
114 
117  {
118  try
119  {
121  {
122  // shutdown(m_udp_socket, SHUT_RDWR);
125  }
126  }
127  catch (std::exception & e)
128  {
129  ROS_ERROR_STREAM("## ERROR ~UdpReceiverSocketImpl: can't close socket, " << e.what());
130  }
131  }
132 
133  /*
134  ** @brief Opens a udp socket
135  ** @param[in] udp_sender ip v4 address of sender (e.g. "192.168.0.100"), or "" for any
136  ** @param[in] udp_port port number (e.g. 2115 for multiScan)
137  ** @param[in] blocking option to recv blocking (true) or non-blocking (false, default)
138  */
139  bool Init(const std::string& udp_sender, int udp_port, bool blocking = false)
140  {
141  m_running = false;
142  try
143  {
144  wsa_init();
145  m_udp_sender = udp_sender;
147  m_udp_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
149  {
150  ROS_ERROR_STREAM("## ERROR UdpReceiverSocketImpl::Init(" << m_udp_sender << ":" << m_udp_port << "): can't open socket, error: " << getErrorMessage());
151  return false;
152  }
153  // #if defined WIN32 || defined _MSC_VER
154  // char broadcast_opt = 1, reuse_addr_opt = 1, reuse_port_opt = 1;
155  // #else
156  // int broadcast_opt = 1, reuse_addr_opt = 1, reuse_port_opt = 1;
157  // #endif
158  // setsockopt(m_udp_socket, SOL_SOCKET, SO_BROADCAST, &broadcast_opt, sizeof(broadcast_opt));
159  // setsockopt(m_udp_socket, SOL_SOCKET, SO_REUSEADDR, &reuse_addr_opt, sizeof(reuse_addr_opt));
160  // setsockopt(m_udp_socket, SOL_SOCKET, SO_REUSEPORT, &reuse_port_opt, sizeof(reuse_port_opt));
161  struct sockaddr_in sim_servaddr = { 0 };
162  if(m_udp_sender.empty())
163  sim_servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
164  else
165  sim_servaddr.sin_addr.s_addr = inet_addr(m_udp_sender.c_str());
166  sim_servaddr.sin_family = AF_INET;
167  sim_servaddr.sin_port = htons(m_udp_port);
168  ROS_INFO_STREAM("UdpReceiverSocketImpl: udp socket created, binding to port " << ntohs(sim_servaddr.sin_port) << " ... ");
169  if (bind(m_udp_socket, (SOCKADDR*)&sim_servaddr, sizeof(sim_servaddr)) < 0)
170  {
171  ROS_ERROR_STREAM("## ERROR UdpReceiverSocketImpl::Init(" << m_udp_sender << ":" << m_udp_port << "): can't bind socket, error: " << getErrorMessage());
174  return false;
175  }
176  // Set socket to blocking or non-blocking recv mode
177  m_recv_blocking = blocking;
178 # ifdef _MSC_VER
179  u_long recv_mode = (m_recv_blocking ? 0 : 1); // FIONBIO enables or disables the blocking mode for the socket. If iMode = 0, blocking is enabled, if iMode != 0, non-blocking mode is enabled.
180  ioctlsocket(m_udp_socket, FIONBIO, &recv_mode);
181 # else
182  if (!m_recv_blocking)
183  m_recv_flags |= MSG_DONTWAIT;
184 # endif
185  m_running = true;
186  return true;
187  }
188  catch (std::exception & e)
189  {
191  ROS_ERROR_STREAM("## ERROR UdpReceiverSocketImpl::Init(): can't open socket to " << m_udp_sender << ":" << m_udp_port << ", exception: " << e.what());
192  return false;
193  }
194  }
195 
197  size_t Receive(std::vector<uint8_t>& msg_payload)
198  {
199  int64_t bytes_received = 0;
200  while (m_running && bytes_received <= 0)
201  {
202  bytes_received = recv(m_udp_socket, (char*)msg_payload.data(), (int)msg_payload.size(), m_recv_flags);
203  if (m_recv_blocking && bytes_received < 0)
204  return 0; // socket error
205  }
206  if (!m_running || bytes_received < 0)
207  return 0; // socket error
208  return (size_t)bytes_received;
209  }
210 
212  size_t Receive(std::vector<uint8_t>& msg_payload, double timeout, const std::vector<uint8_t>& udp_msg_start_seq)
213  {
215  size_t headerlength = udp_msg_start_seq.size() + sizeof(uint32_t); // 8 byte header: 0x02020202 + Payloadlength
216  size_t bytes_received = 0;
217  size_t bytes_to_receive = msg_payload.size();
218  // Receive \x02\x02\x02\x02 | 4Bytes payloadlength incl. CRC | Payload | CRC32
219  while (m_running && bytes_received < bytes_to_receive && (timeout < 0 || sick_scansegment_xd::Seconds(start_timestamp, chrono_system_clock::now()) < timeout))
220  {
221  int64_t chunk_bytes_received = recv(m_udp_socket, (char*)msg_payload.data() + bytes_received, (int)msg_payload.size() - bytes_received, m_recv_flags);
222  if (chunk_bytes_received <= 0)
223  {
224  std::this_thread::sleep_for(std::chrono::milliseconds(1));
225  continue;
226  }
227  // std::cout << "UdpSenderSocketImpl::Receive(): chunk of " << std::dec << chunk_bytes_received << " bytes received: " << std::endl;
228  // for(int n = 0; n < chunk_bytes_received; n++)
229  // std::cout << std::setfill('0') << std::setw(2) << std::hex << (int)(msg_payload.data()[bytes_received + n] & 0xFF);
230  // std::cout << std::endl;
231  if (bytes_received == 0 && chunk_bytes_received > (int64_t)headerlength && std::equal(msg_payload.begin(), msg_payload.begin() + udp_msg_start_seq.size(), udp_msg_start_seq.begin())) // start of new msgpack
232  {
233  // Start of new message: restart timeout
235  // Decode 8 byte header: 0x02020202 + Payloadlength
236  size_t Payloadlength= Convert4Byte(msg_payload.data() + udp_msg_start_seq.size());
237  bytes_to_receive = Payloadlength + headerlength + sizeof(uint32_t); // 8 byte header + payload + 4 byte CRC
238  if(bytes_to_receive > msg_payload.size())
239  {
240  ROS_ERROR_STREAM("## ERROR UdpReceiverSocketImpl::Receive(): unexpected payloadlength " << Payloadlength << " byte incl CRC received");
241  break;
242  }
243  bytes_received += chunk_bytes_received;
244  }
245  else if (bytes_received > 0) // continue receiving a msgpack
246  {
247  bytes_received += chunk_bytes_received;
248  }
249  }
250  return (m_running ? bytes_received : 0);
251  }
252 
254  int port(void) const { return m_udp_port; }
255 
257  bool& running(void) { return m_running; }
258 
259  protected:
260 
261  std::string m_udp_sender; // IP of udp sender
262  int m_udp_port; // udp port
263  SOCKET m_udp_socket; // udp raw socket
264  bool m_running; // true: ready to receive, false: not initialized / stop receiving
265  bool m_recv_blocking; // option to recv blocking (true) or non-blocking (false)
266  int m_recv_flags; // flag for socket recv, 0 (default) or MSG_DONTWAIT for non-blocking operation
267  };
268 
273  {
274  public:
275 
281  UdpSenderSocketImpl(const std::string& server_address = "192.168.0.1", int udp_port = 2115)
283  {
284  try
285  {
286  m_server_address = server_address;
288  if ((m_udp_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == INVALID_SOCKET)
289  {
290  ROS_ERROR_STREAM("## ERROR UdpSenderSocketImpl::init(" << server_address << ":" << udp_port << "): can't create socket, error: " << getErrorMessage());
291  }
292  else
293  {
294  #if defined WIN32 || defined _MSC_VER
295  char broadcast_opt = 1; // reuse_addr_opt = 1
296  #else
297  int broadcast_opt = 1; // reuse_addr_opt = 1
298  #endif
299  if (setsockopt(m_udp_socket, SOL_SOCKET, SO_BROADCAST, &broadcast_opt, sizeof(broadcast_opt)) < 0)
300  {
301  ROS_ERROR_STREAM("## ERROR UdpSenderSocketImpl::init(" << server_address << ":" << udp_port << "): setsockopt(SO_BROADCAST) failed, error: " << getErrorMessage());
302  }
303  // setsockopt(m_udp_socket, SOL_SOCKET, SO_REUSEADDR, &reuse_addr_opt, sizeof(reuse_addr_opt));
304  }
305  }
306  catch (const std::exception& e)
307  {
309  ROS_ERROR_STREAM("## ERROR UdpSenderSocketImpl(): socket initialization failed, exception: " << e.what());
310  }
311  }
312 
317  {
318  try
319  {
321  {
322  // shutdown(m_udp_socket, SHUT_RDWR);
325  }
326  }
327  catch (const std::exception& e)
328  {
329  ROS_ERROR_STREAM("## ERROR ~UdpSenderSocketImpl(): socket shutdown and close failed, exception: " << e.what());
330  }
331  }
332 
336  bool IsOpen(void) const { return (m_udp_socket != INVALID_SOCKET); }
337 
341  bool Send(std::vector<uint8_t>& message)
342  {
343  size_t bytes_sent = 0;
345  {
346  try
347  {
348  struct sockaddr_in sim_servaddr = { 0 };
349  if(m_server_address.empty())
350  {
351  sim_servaddr.sin_addr.s_addr = htonl(INADDR_BROADCAST);
352  }
353  else
354  {
355  #if defined WIN32 || defined _MSC_VER
356  sim_servaddr.sin_addr.s_addr = inet_addr(m_server_address.c_str());
357  #else
358  struct in_addr sim_in_addr;
359  if (inet_aton(m_server_address.c_str(), &sim_in_addr) != 0)
360  {
361  sim_servaddr.sin_addr.s_addr = sim_in_addr.s_addr;
362  }
363  else
364  {
365  ROS_ERROR_STREAM("## ERROR UdpSenderSocketImpl()::Send(): inet_aton(" << m_server_address << ") failed (invalid address)");
366  sim_servaddr.sin_addr.s_addr = inet_addr(m_server_address.c_str());
367  }
368  #endif
369  }
370  sim_servaddr.sin_family = AF_INET;
371  sim_servaddr.sin_port = htons(m_udp_port);
372  bytes_sent = sendto(m_udp_socket, (const char*)message.data(), message.size(), 0, (SOCKADDR*)&sim_servaddr, sizeof(sim_servaddr));
373  if (bytes_sent != message.size())
374  {
375  ROS_ERROR_STREAM("## ERROR UdpSenderSocketImpl()::Send() failed, " << bytes_sent << " of " << message.size() << " bytes sent.");
376  }
377  }
378  catch (const std::exception& e)
379  {
380  ROS_ERROR_STREAM("## ERROR UdpSenderSocketImpl()::Send() failed, exception: " << e.what());
381  }
382  }
383  else
384  {
385  ROS_ERROR_STREAM("## ERROR UdpSenderSocketImpl()::Send(): udp socket not initialized");
386  }
387  return (bytes_sent == message.size());
388  }
389 
390  protected:
391 
392  bool m_socket_opened; // true if the udp socket is opened and ready to send, or false otherwise
393  std::string m_server_address; // ip address
394  int m_udp_port; // udp port
395  SOCKET m_udp_socket; // udp raw socket
396  };
397 } // namespace sick_scansegment_xd
398 #endif // __SICK_SCANSEGMENT_XD_UDP_SOCKETS_H
sick_scansegment_xd::UdpReceiverSocketImpl::UdpReceiverSocketImpl
UdpReceiverSocketImpl()
Definition: udp_sockets.h:111
common.h
sick_scansegment_xd::UdpReceiverSocketImpl::port
int port(void) const
Definition: udp_sockets.h:254
SOCKET
int SOCKET
Definition: udp_sockets.h:81
sick_scansegment_xd::UdpReceiverSocketImpl::~UdpReceiverSocketImpl
~UdpReceiverSocketImpl()
Definition: udp_sockets.h:116
NULL
#define NULL
sick_scansegment_xd::UdpReceiverSocketImpl::m_recv_blocking
bool m_recv_blocking
Definition: udp_sockets.h:265
sick_scansegment_xd::UdpReceiverSocketImpl::running
bool & running(void)
Definition: udp_sockets.h:257
sick_scansegment_xd
Definition: include/sick_scansegment_xd/common.h:138
sick_scansegment_xd::UdpSenderSocketImpl::m_server_address
std::string m_server_address
Definition: udp_sockets.h:393
sick_scansegment_xd::UdpSenderSocketImpl::Send
bool Send(std::vector< uint8_t > &message)
Definition: udp_sockets.h:341
sick_scansegment_xd::UdpSenderSocketImpl::m_socket_opened
bool m_socket_opened
Definition: udp_sockets.h:392
sick_scansegment_xd::UdpReceiverSocketImpl::Receive
size_t Receive(std::vector< uint8_t > &msg_payload)
Definition: udp_sockets.h:197
sick_scansegment_xd::UdpSenderSocketImpl::IsOpen
bool IsOpen(void) const
Definition: udp_sockets.h:336
sick_ros_wrapper.h
sick_scansegment_xd::UdpSenderSocketImpl::~UdpSenderSocketImpl
~UdpSenderSocketImpl()
Definition: udp_sockets.h:316
ROS::now
ROS::Time now(void)
Definition: ros_wrapper.cpp:116
message
def message(msg, *args, **kwargs)
chrono_system_time
std::chrono::time_point< std::chrono::system_clock > chrono_system_time
Definition: include/sick_scansegment_xd/common.h:134
sick_scansegment_xd::UdpReceiverSocketImpl::m_udp_socket
SOCKET m_udp_socket
Definition: udp_sockets.h:263
ROS_INFO_STREAM
#define ROS_INFO_STREAM(...)
Definition: sick_scan_ros2_example.cpp:71
multiscan_pcap_player.udp_port
int udp_port
Definition: multiscan_pcap_player.py:137
wsa_init
void wsa_init(void)
Definition: wsa_init.cpp:36
sick_scansegment_xd::UdpSenderSocketImpl::m_udp_socket
SOCKET m_udp_socket
Definition: udp_sockets.h:395
sick_scansegment_xd::UdpReceiverSocketImpl::m_running
bool m_running
Definition: udp_sockets.h:264
getErrorMessage
static std::string getErrorMessage(void)
Definition: udp_sockets.h:86
pcap_json_converter.start_timestamp
float start_timestamp
Definition: pcap_json_converter.py:129
sick_scansegment_xd::UdpReceiverSocketImpl::Receive
size_t Receive(std::vector< uint8_t > &msg_payload, double timeout, const std::vector< uint8_t > &udp_msg_start_seq)
Definition: udp_sockets.h:212
unistd.h
sick_scansegment_xd::UdpReceiverSocketImpl::Init
bool Init(const std::string &udp_sender, int udp_port, bool blocking=false)
Definition: udp_sockets.h:139
closesocket
#define closesocket
Definition: udp_sockets.h:85
wsa_init.hpp
sick_scansegment_xd::UdpSenderSocketImpl::UdpSenderSocketImpl
UdpSenderSocketImpl(const std::string &server_address="192.168.0.1", int udp_port=2115)
Definition: udp_sockets.h:281
sick_scan_base.h
sick_generic_device_finder.timeout
timeout
Definition: sick_generic_device_finder.py:113
sick_scansegment_xd::Convert4Byte
static uint32_t Convert4Byte(const uint8_t *p_data)
Definition: udp_sockets.h:98
sick_scansegment_xd::UdpReceiverSocketImpl::m_recv_flags
int m_recv_flags
Definition: udp_sockets.h:266
ROS_ERROR_STREAM
#define ROS_ERROR_STREAM(...)
Definition: sick_scan_ros2_example.cpp:72
sick_scansegment_xd::Seconds
static double Seconds(const chrono_system_time &timestamp_start, const chrono_system_time &timestamp_end=chrono_system_clock::now())
Definition: include/sick_scansegment_xd/common.h:143
sick_scansegment_xd::UdpSenderSocketImpl
class UdpSenderSocketImpl implements the udp socket for sending udp packages
Definition: udp_sockets.h:272
sick_scansegment_xd::UdpSenderSocketImpl::m_udp_port
int m_udp_port
Definition: udp_sockets.h:394
sick_scansegment_xd::UdpReceiverSocketImpl::m_udp_port
int m_udp_port
Definition: udp_sockets.h:262
sick_scansegment_xd::UdpReceiverSocketImpl::m_udp_sender
std::string m_udp_sender
Definition: udp_sockets.h:261
sick_scansegment_xd::UdpReceiverSocketImpl
Definition: udp_sockets.h:106
SOCKADDR
struct sockaddr SOCKADDR
Definition: udp_sockets.h:82
INVALID_SOCKET
#define INVALID_SOCKET
Definition: udp_sockets.h:83


sick_scan_xd
Author(s): Michael Lehning , Jochen Sprickerhof , Martin Günther
autogenerated on Fri Oct 25 2024 02:47:13