SDRAngel  4.11.5
Developer docs for <a href="https://github.com/f4exb/sdrangel">SDRangel<\a>, an Open Source Qt5 / OpenGL 3.0+ SDR and signal analyzer frontend to various hardware.
UDPSocket.cpp
Go to the documentation of this file.
1 // Remote - send I/Q samples read from a SDR device over the network via UDP. //
3 // //
4 // Copyright (C) 2015 Edouard Griffiths, F4EXB //
5 // //
6 // This program 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 as version 3 of the License, or //
9 // (at your option) any later version. //
10 // //
11 // This program is distributed in the hope that it will be useful, //
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of //
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
14 // GNU General Public License V3 for more details. //
15 // //
16 // You should have received a copy of the GNU General Public License //
17 // along with this program. If not, see <http://www.gnu.org/licenses/>. //
19 
20 // Original code is posted at: https://cppcodetips.wordpress.com/2014/01/29/udp-socket-class-in-c/
21 
22 #include "UDPSocket.h"
23 
24 #include <errno.h>
25 #include <cstring>
26 #include <fcntl.h>
27 #include <iostream>
28 #include <cstdlib>
29 #include <cstdio>
30 #include <pthread.h>
31 #include <unistd.h>
32 #include <net/if.h>
33 
34 CSocketException::CSocketException( const string &sMessage, bool blSysMsg /*= false*/ ) throw() :m_sMsg(sMessage)
35 {
36  if (blSysMsg) {
37  m_sMsg.append(": ");
38  m_sMsg.append(strerror(errno));
39  }
40 }
41 
43 {
44 
45 }
46 
48 {
49  ::close(m_sockDesc);
50  m_sockDesc = -1;
51 }
52 
53 CSocket::CSocket( SocketType type, NetworkLayerProtocol protocol ):m_sockDesc(-1)
54 {
55  m_sockDesc = socket(protocol, type, 0);
56  if (m_sockDesc < 0)
57  {
58  throw CSocketException("Socket creation failed (socket())", true);
59  }
60 }
61 
62 CSocket::CSocket( int sockDesc )
63 {
64  m_sockDesc = sockDesc;
65 }
66 
68 {
69  m_sockDesc = sock.m_sockDesc;
70 }
71 
72 void CSocket::operator=(const CSocket &sock)
73 {
74  m_sockDesc = sock.m_sockDesc;
75 }
76 
78 {
79  sockaddr_in addr;
80  unsigned int addr_len = sizeof(addr);
81 
82  if (getsockname(m_sockDesc, (sockaddr *) &addr, (socklen_t *) &addr_len) < 0) {
83  throw CSocketException("Fetch of local address failed (getsockname())", true);
84  }
85  return inet_ntoa(addr.sin_addr);
86 }
87 
88 unsigned short CSocket::GetLocalPort()
89 {
90  sockaddr_in addr;
91  unsigned int addr_len = sizeof(addr);
92 
93  if (getsockname(m_sockDesc, (sockaddr *) &addr, (socklen_t *) &addr_len) < 0) {
94  throw CSocketException("Fetch of local port failed (getsockname())", true);
95  }
96  return ntohs(addr.sin_port);
97 }
98 
99 void CSocket::BindLocalPort( unsigned short localPort )
100 {
101  // Bind the socket to its port
102  sockaddr_in localAddr;
103  memset(&localAddr, 0, sizeof(localAddr));
104  localAddr.sin_family = AF_INET;
105  localAddr.sin_addr.s_addr = htonl(INADDR_ANY);
106  localAddr.sin_port = htons(localPort);
107 
108  if (bind(m_sockDesc, (sockaddr *) &localAddr, sizeof(sockaddr_in)) < 0) {
109  throw CSocketException("Set of local port failed (bind())", true);
110  }
111 }
112 
113 void CSocket::BindLocalAddressAndPort( const string &localAddress, unsigned short localPort /*= 0*/ )
114 {
115  // Get the address of the requested host
116  sockaddr_in localAddr;
117  FillAddr(localAddress, localPort, localAddr);
118 
119  if (bind(m_sockDesc, (sockaddr *) &localAddr, sizeof(sockaddr_in)) < 0) {
120  throw CSocketException("Set of local address and port failed (bind())", true);
121  }
122 }
123 
124 void CSocket::FillAddr( const string & localAddress, unsigned short localPort, sockaddr_in& localAddr )
125 {
126  memset(&localAddr, 0, sizeof(localAddr)); // Zero out address structure
127  localAddr.sin_family = AF_INET; // Internet address
128 
129  hostent *host; // Resolve name
130  if ((host = gethostbyname(localAddress.c_str())) == NULL) {
131  // strerror() will not work for gethostbyname() and hstrerror()
132  // is supposedly obsolete
133  throw CSocketException("Failed to resolve name (gethostbyname())");
134  }
135  localAddr.sin_addr.s_addr = *((unsigned long *) host->h_addr_list[0]);
136 
137  localAddr.sin_port = htons(localPort); // Assign port in network byte order
138 }
139 
140 unsigned long int CSocket::GetReadBufferSize()
141 {
142  unsigned long int nSize;
143  socklen_t n = sizeof(nSize);
144  getsockopt(m_sockDesc,SOL_SOCKET,SO_RCVBUF,(void *)&nSize, (&n));
145  // now the variable nSize will have the socket size
146  return nSize;
147 }
148 
149 void CSocket::SetReadBufferSize( unsigned int nSize )
150 {
151  if (setsockopt(m_sockDesc, SOL_SOCKET, SO_RCVBUF, &nSize, sizeof(nSize)) == -1)
152  {
153  throw CSocketException("Error in setting socket buffer size ", true);
154  }
155 }
156 
157 void CSocket::SetNonBlocking( bool bBlocking )
158 {
159  int opts;
160 
161  opts = fcntl ( m_sockDesc, F_GETFL );
162 
163  if ( opts < 0 )
164  {
165  return;
166  }
167 
168  if ( bBlocking )
169  opts = ( opts | O_NONBLOCK );
170  else
171  opts = ( opts & ~O_NONBLOCK );
172 
173  fcntl ( m_sockDesc, F_SETFL,opts );
174 }
175 
176 void CSocket::ConnectToHost( const string &foreignAddress, unsigned short foreignPort )
177 {
178  // Get the address of the requested host
179  sockaddr_in destAddr;
180  FillAddr(foreignAddress, foreignPort, destAddr);
181 
182  // Try to connect to the given port
183  if (::connect(m_sockDesc, (sockaddr *) &destAddr, sizeof(destAddr)) < 0) {
184  throw CSocketException("Connect failed (connect())", true);
185  }
186 }
187 
188 void CSocket::Send( const void *buffer, int bufferLen )
189 {
190  if (::send(m_sockDesc, (void *) buffer, bufferLen, 0) < 0) {
191  throw CSocketException("Send failed (send())", true);
192  }
193 }
194 
195 int CSocket::Recv( void *buffer, int bufferLen )
196 {
197  int nBytes;
198  if ((nBytes = ::recv(m_sockDesc, (void *) buffer, bufferLen, 0)) < 0) {
199  throw CSocketException("Received failed (recv())", true);
200  }
201  char* sData = static_cast<char *>(buffer);
202  sData[nBytes] = '\0';
203  return nBytes;
204 }
205 
207 {
208  sockaddr_in addr;
209  unsigned int addr_len = sizeof(addr);
210 
211  if (getpeername(m_sockDesc, (sockaddr *) &addr,(socklen_t *) &addr_len) < 0) {
212  throw CSocketException("Fetch of foreign address failed (getpeername())", true);
213  }
214  return inet_ntoa(addr.sin_addr);
215 }
216 
217 unsigned short CSocket::GetPeerPort()
218 {
219  sockaddr_in addr;
220  unsigned int addr_len = sizeof(addr);
221 
222  if (getpeername(m_sockDesc, (sockaddr *) &addr, (socklen_t *) &addr_len) < 0) {
223  throw CSocketException("Fetch of foreign port failed (getpeername())", true);
224  }
225  return ntohs(addr.sin_port);
226 }
227 
228 CSocket& CSocket::operator<<(const string& sStr )
229 {
230  Send(sStr.c_str(), sStr.length());
231  return *this;
232 }
233 
234 CSocket& CSocket::operator>>( string& sStr )
235 {
236  char *buff = new char[GetReadBufferSize()];
237  Recv(buff, GetReadBufferSize());
238  sStr.append(buff);
239  delete [] buff;
240  return *this;
241 }
242 
243 int CSocket::OnDataRead(unsigned long timeToWait)
244 {
245  /* master file descriptor list */
246  fd_set master;
247 
248  /* temp file descriptor list for select() */
249  fd_set read_fds;
250 
251  /* maximum file descriptor number */
252  int fdmax;
253 
254  /* clear the master and temp sets */
255  FD_ZERO(&master);
256  FD_ZERO(&read_fds);
257 
258  /* add the listener to the master set */
259  FD_SET(m_sockDesc, &master);
260  /* keep track of the biggest file descriptor */
261  fdmax = m_sockDesc; /* so far, it's this one*/
262 
263  /* copy it */
264  read_fds = master;
265  int nRet;
266 
267  if (timeToWait == ULONG_MAX)
268  {
269  nRet = select(fdmax+1, &read_fds, NULL, NULL, NULL);
270  if (nRet == -1)
271  nRet = DATA_EXCEPTION;
272  else if (nRet > 0)
273  nRet = DATA_ARRIVED;
274  }
275  else
276  {
277  struct timeval timeout;
278  timeout.tv_sec = timeToWait;
279  timeout.tv_usec = 0;
280  nRet = select(fdmax+1, &read_fds, NULL, NULL, &timeout);
281  if (nRet == -1)
282  nRet = DATA_EXCEPTION;
283  else if (nRet > 0)
284  nRet = DATA_ARRIVED;
285  else if(nRet == 0)
286  nRet = DATA_TIMED_OUT;
287  }
288 
289  return nRet;
290 }
291 
292 void CSocket::SetBindToDevice( const string& sInterface )
293 {
294  struct ifreq ifr;
295  memset(&ifr, 0, sizeof(ifr));
296  snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s", sInterface.c_str());
297 }
298 
300 {
301  SetBroadcast();
302 }
303 
304 UDPSocket::UDPSocket( unsigned short localPort ):
306 {
307  BindLocalPort(localPort);
308  SetBroadcast();
309 }
310 
311 UDPSocket::UDPSocket( const string &localAddress, unsigned short localPort ):
313 {
314  BindLocalAddressAndPort(localAddress, localPort);
315  SetBroadcast();
316 }
317 
319 {
320  sockaddr_in nullAddr;
321  memset(&nullAddr, 0, sizeof(nullAddr));
322  nullAddr.sin_family = AF_UNSPEC;
323  // Try to disconnect
324  if (::connect(m_sockDesc, (sockaddr *) &nullAddr, sizeof(nullAddr)) < 0)
325  {
326  if (errno != EAFNOSUPPORT)
327  {
328  throw CSocketException("Disconnect failed (connect())", true);
329  }
330  }
331 }
332 
333 void UDPSocket::SendDataGram( const void *buffer, int bufferLen, const string &foreignAddress,
334  unsigned short foreignPort )
335 {
336  sockaddr_in destAddr;
337  FillAddr(foreignAddress, foreignPort, destAddr);
338  // Write out the whole buffer as a single message.
339  if (sendto(m_sockDesc, (void *) buffer, bufferLen, 0,(sockaddr *) &destAddr, sizeof(destAddr)) != bufferLen)
340  {
341  throw CSocketException("Send failed (sendto())", true);
342  }
343 
344 }
345 
346 int UDPSocket::RecvDataGram( void *buffer, int bufferLen, string &sourceAddress, unsigned short &sourcePort )
347 {
348  sockaddr_in clntAddr;
349  socklen_t addrLen = sizeof(clntAddr);
350  int nBytes;
351  if ((nBytes = recvfrom(m_sockDesc, (void *) buffer, bufferLen, 0, (sockaddr *) &clntAddr,
352  (socklen_t *) &addrLen)) < 0)
353  {
354  throw CSocketException("Receive failed (recvfrom())", true);
355  }
356  sourceAddress = inet_ntoa(clntAddr.sin_addr);
357  sourcePort = ntohs(clntAddr.sin_port);
358  char* sData = static_cast<char *>(buffer);
359  sData[nBytes] = '\0';
360  return nBytes;
361 }
362 
363 void UDPSocket::SetMulticastTTL( unsigned char multicastTTL )
364 {
365  if (setsockopt(m_sockDesc, IPPROTO_IP, IP_MULTICAST_TTL, (void *) &multicastTTL, sizeof(multicastTTL)) < 0)
366  {
367  throw CSocketException("Multicast TTL set failed (setsockopt())", true);
368  }
369 }
370 
371 void UDPSocket::JoinGroup( const string &multicastGroup )
372 {
373  struct ip_mreq multicastRequest;
374 
375  multicastRequest.imr_multiaddr.s_addr = inet_addr(multicastGroup.c_str());
376  multicastRequest.imr_interface.s_addr = htonl(INADDR_ANY);
377  if (setsockopt(m_sockDesc, IPPROTO_IP, IP_ADD_MEMBERSHIP,
378  (void *) &multicastRequest,
379  sizeof(multicastRequest)) < 0)
380  {
381  throw CSocketException("Multicast group join failed (setsockopt())", true);
382  }
383 
384 }
385 
386 void UDPSocket::LeaveGroup( const string &multicastGroup )
387 {
388  struct ip_mreq multicastRequest;
389 
390  multicastRequest.imr_multiaddr.s_addr = inet_addr(multicastGroup.c_str());
391  multicastRequest.imr_interface.s_addr = htonl(INADDR_ANY);
392  if (setsockopt(m_sockDesc, IPPROTO_IP, IP_DROP_MEMBERSHIP,
393  (void *) &multicastRequest,
394  sizeof(multicastRequest)) < 0)
395  {
396  throw CSocketException("Multicast group leave failed (setsockopt())", true);
397  }
398 
399 }
400 
402 {
403  // If this fails, we'll hear about it when we try to send. This will allow
404  // system that cannot broadcast to continue if they don't plan to broadcast
405  int broadcastPermission = 1;
406  setsockopt(m_sockDesc, SOL_SOCKET, SO_BROADCAST,
407  (void *) &broadcastPermission, sizeof(broadcastPermission));
408 
409 }
410 
411 
NetworkLayerProtocol
Definition: UDPSocket.h:95
void SetReadBufferSize(unsigned int nSize)
Definition: UDPSocket.cpp:149
CSocket(SocketType type, NetworkLayerProtocol protocol)
Definition: UDPSocket.cpp:53
void SetMulticastTTL(unsigned char multicastTTL)
Definition: UDPSocket.cpp:363
virtual ~CSocket()
Definition: UDPSocket.cpp:47
void BindLocalPort(unsigned short localPort)
Definition: UDPSocket.cpp:99
virtual int OnDataRead(unsigned long timeToWait=ULONG_MAX)
Definition: UDPSocket.cpp:243
unsigned long int GetReadBufferSize()
Definition: UDPSocket.cpp:140
void SetBindToDevice(const string &sInterface)
Definition: UDPSocket.cpp:292
void BindLocalAddressAndPort(const string &localAddress, unsigned short localPort=0)
Definition: UDPSocket.cpp:113
CSocket & operator<<(const string &sStr)
Definition: UDPSocket.cpp:228
void JoinGroup(const string &multicastGroup)
Definition: UDPSocket.cpp:371
unsigned short GetPeerPort()
Definition: UDPSocket.cpp:217
unsigned short GetLocalPort()
Definition: UDPSocket.cpp:88
void SetBroadcast()
Definition: UDPSocket.cpp:401
static void FillAddr(const string &localAddress, unsigned short localPort, sockaddr_in &localAddr)
Definition: UDPSocket.cpp:124
void ConnectToHost(const string &foreignAddress, unsigned short foreignPort)
Definition: UDPSocket.cpp:176
string GetLocalAddress()
Definition: UDPSocket.cpp:77
void operator=(const CSocket &sock)
Definition: UDPSocket.cpp:72
SocketType
Definition: UDPSocket.h:85
CSocket & operator>>(string &sStr)
Definition: UDPSocket.cpp:234
CSocketException(const string &message, bool bSysMsg=false)
Definition: UDPSocket.cpp:34
void SetNonBlocking(bool bBlocking)
Definition: UDPSocket.cpp:157
string GetPeerAddress()
Definition: UDPSocket.cpp:206
int Recv(void *buffer, int bufferLen)
Definition: UDPSocket.cpp:195
void LeaveGroup(const string &multicastGroup)
Definition: UDPSocket.cpp:386
int m_sockDesc
Definition: UDPSocket.h:235
virtual ~CSocketException()
Definition: UDPSocket.cpp:42
void SendDataGram(const void *buffer, int bufferLen, const string &foreignAddress, unsigned short foreignPort)
Definition: UDPSocket.cpp:333
void Send(const void *buffer, int bufferLen)
Definition: UDPSocket.cpp:188
void DisconnectFromHost()
Definition: UDPSocket.cpp:318
int RecvDataGram(void *buffer, int bufferLen, string &sourceAddress, unsigned short &sourcePort)
Definition: UDPSocket.cpp:346