UdpSocket.cpp
Go to the documentation of this file.
1 //
2 // Copyright (c) 2023 SICK AG, Waldkirch
3 //
4 // SPDX-License-Identifier: Unlicense
5 
6 #include "UdpSocket.h"
7 
8 #include <algorithm> // for max
9 #include <cstring>
10 #include <iostream>
11 
12 #include "NumericConv.h"
13 #include "SockRecord.h"
14 
15 namespace visionary {
16 
17 // Windows uses int also for send/recv buffer sizes and return values
18 #ifdef _WIN32
19 using bufsize_t = int;
20 #else
21 using bufsize_t = size_t;
22 #endif
23 
25 {
26 public:
28  {
29  reset();
30  }
31 
32  void reset()
33  {
34  memset(&sockaddr_in, 0, sizeof(sockaddr_in));
35  }
36 
38 };
39 
40 UdpSocket::UdpSocket() : m_pSockRecord(new SockRecord()), m_pSockAddrIn(new SockAddrIn)
41 {
42 }
43 
45 {
46  if (m_pSockRecord->isValid())
47  {
48  shutdown();
49  }
50 }
51 
52 int UdpSocket::connect(const std::string& ipaddr, std::uint16_t port)
53 {
54  int iResult = 0;
55  int trueVal = 1;
56  long timeoutSeconds = 5L;
57 
58  if (m_pSockRecord->isValid())
59  {
60  shutdown();
61  }
62 
63 #ifdef _WIN32
64  //-----------------------------------------------
65  // Initialize Winsock
66  WSADATA wsaData;
67  iResult = ::WSAStartup(MAKEWORD(2, 2), &wsaData);
68  if (iResult != NO_ERROR)
69  {
70  return iResult;
71  }
72 #endif
73 
74  //-----------------------------------------------
75  // Create a receiver socket to receive datagrams
76  SOCKET hsock = ::socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
77 
78  if (hsock == INVALID_SOCKET)
79  {
80  m_pSockRecord->invalidate();
81  return -1;
82  }
83  m_pSockRecord->set(hsock);
84 
85  //-----------------------------------------------
86  // Bind the socket to any address and the specified port.
87  m_pSockAddrIn->sockaddr_in.sin_family = AF_INET;
88  m_pSockAddrIn->sockaddr_in.sin_port = htons(port);
89  if (::inet_pton(AF_INET, ipaddr.c_str(), &m_pSockAddrIn->sockaddr_in.sin_addr.s_addr) <= 0)
90  {
91  // invalid address or buffer size
92  return -1;
93  }
94 
95  // Set the timeout for the socket to 5 seconds
96 #ifdef _WIN32
97  // On Windows timeout is a DWORD in milliseconds
98  // (https://docs.microsoft.com/en-us/windows/desktop/api/winsock/nf-winsock-setsockopt)
99  long timeoutMs = timeoutSeconds * 1000L;
100  iResult = ::setsockopt(
101  m_pSockRecord->socket(), SOL_SOCKET, SO_RCVTIMEO, reinterpret_cast<const char*>(&timeoutMs), sizeof(timeoutMs));
102 #else
103  struct timeval tv;
104  tv.tv_sec = timeoutSeconds; /* 5 seconds Timeout */
105  tv.tv_usec = 0L; // Not init'ing this can cause strange errors
106  iResult = ::setsockopt(
107  m_pSockRecord->socket(), SOL_SOCKET, SO_RCVTIMEO, reinterpret_cast<const char*>(&tv), sizeof(struct timeval));
108 #endif
109 
110  if (iResult >= 0)
111  {
112  iResult = ::setsockopt(
113  m_pSockRecord->socket(), SOL_SOCKET, SO_BROADCAST, reinterpret_cast<const char*>(&trueVal), sizeof(trueVal));
114  }
115 
116  return iResult;
117 }
118 
120 {
121  if (m_pSockRecord->isValid())
122  {
123  // Close the socket when finished receiving datagrams
124 #ifdef _WIN32
125  ::closesocket(m_pSockRecord->socket());
126  ::WSACleanup();
127 #else
128  ::close(m_pSockRecord->socket());
129 #endif
130  m_pSockRecord->invalidate();
131  }
132  return 0;
133 }
134 
135 ITransport::send_return_t UdpSocket::send(const char* pData, size_t size)
136 {
137  // send buffer via UDP socket
138  return ::sendto(m_pSockRecord->socket(),
139  pData,
140  castClamped<bufsize_t>(size),
141  0,
142  reinterpret_cast<struct sockaddr*>(&m_pSockAddrIn->sockaddr_in),
143  sizeof(m_pSockAddrIn->sockaddr_in));
144 }
145 
146 ITransport::recv_return_t UdpSocket::recv(ByteBuffer& buffer, std::size_t maxBytesToReceive)
147 {
148  const bufsize_t eff_maxsize = castClamped<bufsize_t>(maxBytesToReceive);
149 
150  buffer.resize(static_cast<std::size_t>(eff_maxsize));
151  char* pBuffer = reinterpret_cast<char*>(buffer.data());
152 
153  // receive from UDP Socket
154  const ITransport::recv_return_t retval = ::recv(m_pSockRecord->socket(), pBuffer, eff_maxsize, 0);
155 
156  if (retval >= 0)
157  {
158  buffer.resize(static_cast<size_t>(retval));
159  }
160 
161  return retval;
162 }
163 
164 ITransport::recv_return_t UdpSocket::read(ByteBuffer& buffer, std::size_t nBytesToReceive)
165 {
166  // receive from UDP Socket
167  buffer.resize(nBytesToReceive);
168 
169  char* const pBufferStart = reinterpret_cast<char*>(buffer.data());
170  char* pBuffer = pBufferStart;
171 
172  while (nBytesToReceive > 0)
173  {
174  const bufsize_t eff_maxsize = castClamped<bufsize_t>(nBytesToReceive);
175 
176  const ITransport::recv_return_t bytesReceived = ::recv(m_pSockRecord->socket(), pBuffer, eff_maxsize, 0);
177 
178  if (bytesReceived == SOCKET_ERROR) // 0 is also possible, but allowed - an
179  // empty datagram was sent
180  {
181  return -1;
182  }
183  pBuffer += bytesReceived;
184  nBytesToReceive -= static_cast<size_t>(bytesReceived);
185  }
186 
187  buffer.resize(static_cast<size_t>(pBuffer - pBufferStart));
188 
189  return static_cast<ITransport::recv_return_t>(buffer.size());
190 }
191 
193 {
194  int error_code;
195 #ifdef _WIN32
196  int error_code_size = sizeof(int);
197  ::getsockopt(m_pSockRecord->socket(), SOL_SOCKET, SO_ERROR, reinterpret_cast<char*>(&error_code), &error_code_size);
198 #else
199  socklen_t error_code_size = sizeof error_code;
200  if (::getsockopt(m_pSockRecord->socket(), SOL_SOCKET, SO_ERROR, &error_code, &error_code_size) != 0)
201  {
202  std::cout << "Error getting error code" << std::endl;
203  }
204 
205 #endif
206  return error_code;
207 }
208 
209 } // namespace visionary
SOCKET_ERROR
#define SOCKET_ERROR
Definition: SockRecord.h:30
visionary::SockAddrIn::reset
void reset()
Definition: UdpSocket.cpp:32
visionary::UdpSocket::recv
recv_return_t recv(ByteBuffer &buffer, std::size_t maxBytesToReceive) override
Definition: UdpSocket.cpp:146
visionary::UdpSocket::connect
int connect(const std::string &ipaddr, std::uint16_t port)
Definition: UdpSocket.cpp:52
visionary::bufsize_t
size_t bufsize_t
Definition: TcpSocket.cpp:21
visionary::UdpSocket::m_pSockAddrIn
std::unique_ptr< SockAddrIn > m_pSockAddrIn
Definition: UdpSocket.h:49
visionary::ITransport::recv_return_t
ssize_t recv_return_t
Definition: ITransport.h:29
visionary
Definition: MD5.cpp:44
SockRecord.h
visionary::ITransport::ByteBuffer
std::vector< std::uint8_t > ByteBuffer
Definition: ITransport.h:22
UdpSocket.h
visionary::UdpSocket::shutdown
int shutdown() override
Definition: UdpSocket.cpp:119
visionary::SockAddrIn::SockAddrIn
SockAddrIn()
Definition: UdpSocket.cpp:27
visionary::SockRecord
Definition: SockRecord.h:35
INVALID_SOCKET
#define INVALID_SOCKET
Definition: SockRecord.h:29
visionary::UdpSocket::UdpSocket
UdpSocket()
Definition: UdpSocket.cpp:40
visionary::UdpSocket::getLastError
int getLastError() override
Definition: UdpSocket.cpp:192
visionary::ITransport::send_return_t
ssize_t send_return_t
Definition: ITransport.h:28
SOCKET
int SOCKET
Definition: SockRecord.h:28
visionary::UdpSocket::read
recv_return_t read(ByteBuffer &buffer, std::size_t nBytesToReceive) override
Definition: UdpSocket.cpp:164
visionary::SockAddrIn::sockaddr_in
struct sockaddr_in sockaddr_in
Definition: UdpSocket.cpp:37
visionary::SockAddrIn
Definition: UdpSocket.cpp:24
visionary::UdpSocket::~UdpSocket
virtual ~UdpSocket()
Definition: UdpSocket.cpp:44
visionary::UdpSocket::m_pSockRecord
std::unique_ptr< SockRecord > m_pSockRecord
Definition: UdpSocket.h:48
NO_ERROR
NO_ERROR
boost::multi_index::safe_mode::error_code
error_code
Definition: safe_mode_errors.hpp:28
NumericConv.h
visionary::UdpSocket::send
send_return_t send(const char *pData, size_t size) override
Definition: UdpSocket.cpp:135


sick_visionary_ros
Author(s): SICK AG TechSupport 3D Snapshot
autogenerated on Thu Feb 8 2024 03:48:46